我是班级的新手,因此使用一个我在网上找到的示例来添加一些自定义日志记录级别。这将包含在一个库中,该库将导入到各种脚本中。它按预期工作,但添加的级别未显示在自动完成列表中(使用PyCharm),并且PyCharm抱怨LOGGER中有未解决的属性引用。当我编码时,输入“ LOGGER”。我看到正常的错误,警告,信息等可供选择,但我的自定义级别“详细”不在列表中。随着时间的流逝,将会添加更多的自定义级别,并且还将向一组开发人员推出,因此我需要进行这项工作。
有人知道为什么我的自动填充列表中没有冗长的选项吗?
这是我的文件。
px_logger.py
from logging import getLoggerClass, addLevelName, setLoggerClass, NOTSET
public class PxLogger(getLoggerClass()):
def __init__(self, name, level=NOTSET):
super(PxLogger, self).__init__(name, level)
addLevelName(5, "VERBOSE")
def verbose(self, msg, *args, **kwargs):
"""Custom logger level - verbose"""
if self.isEnabledFor(5):
self._log(5, msg, args, **kwargs)
my_script.py
import json
import logging.config
from px_logger import PxLogger
logging.setLoggerClass(PxLogger)
LOGGER = logging.getLogger(__name__)
with open('../logging.json') as f: # load logging config file
CONFIG_DICT = json.load(f)
logging.config.dictConfig(CONFIG_DICT)
LOGGER.verbose('Test verbose message')
屏幕输出
VERBOSE - Test verbose message
答案 0 :(得分:4)
PyCharm提供了多种方法来完成type hinting
在内部,它使用Typeshed来确定标准lib对象和常见的第三方包的类型。
这也是PyCharm从中获取logging.getLogger的返回值类型的原因,这就是为什么它不会在自动完成中显示子类的verbose
方法的原因,因为它假定LOGGER
是logging.Logger
。
告诉PyCharm类型检查器LOGGER
是PxLogger
的实例的最简单方法是分配期间代码中的类型注释。 仅适用于Python 3.5 + :
LOGGER: PxLogger = logging.getLogger(__name__)
如果更进一步,您将封装自定义记录器类的定义,将其定义为全局记录器类,并在模块内定义logging.getLogger
的包装器。
这将使您的同事可以直接导入模块而不是logging
并像使用原始logging
一样使用它,而不必担心将哪个类设置为记录器类或如何注释保存记录器的变量。
这条道路上有三个选项可以为类型检查器包括类型提示。
px_logger.py
# basically, import from logging whatever you may need and overwrite where necessary
from logging import getLogger as _getLogger, Logger, addLevelName, setLoggerClass, NOTSET
from typing import Optional # this only for the Python 3.5+ solution
class PxLogger(Logger): # Note: subclass logging.Logger explicitly
def __init__(self, name, level=NOTSET):
super(PxLogger, self).__init__(name, level)
addLevelName(5, "VERBOSE")
def verbose(self, msg, *args, **kwargs):
"""Custom logger level - verbose"""
if self.isEnabledFor(5):
self._log(5, msg, args, **kwargs)
setLoggerClass(PxLogger)
"""
Possible approaches, implement one of the below.
The first is Python 3.5+ only.
The second and third work for both, Python 2 and Python 3.
"""
# using type annotation syntax (py35+)
def getLogger(name: Optional[str]=None) -> PxLogger:
_logr: PxLogger = _getLogger(name)
return _logr
# using (legacy) docstring syntax (py2and3)
def getLogger(name=None)
"""
:param name: str
:rtype: PxLogger
"""
return _getLogger(name)
# using a stub file (py2and3)
def getLogger(name=None):
return _getLogger(name)
Python 2and3存根文件方法需要在程序包中实际模块文件py_logger.pyi
旁边的文件名为px_logger.py
的文件。
px_logger.pyi
# The PEP-484 syntax does not matter here.
# The Python interpreter will ignore this file,
# it is only relevant for the static type checker
import logging
class PxLogger(logging.Logger):
def verbose(self, msg, *args, **kwargs) -> None: ...
def getLogger(name) -> PxLogger: ...
对于所有三种方法,您的模块my_script
看起来都一样:
my_script.py
import logging.config
import px_logger
LOGGER = px_logger.getLogger(__name__)
# I used basicConfig here for simplicity, dictConfig should work just as well
logging.basicConfig(level=5,
format='%(asctime)s - %(levelname)s [%(filename)s]: %(name)s %(funcName)20s - Message: %(message)s',
datefmt='%d.%m.%Y %H:%M:%S',
filename='myapp.log',
filemode='a')
LOGGER.verbose('Test verbose message')
自动完成功能在以下三种方法中均能很好地发挥作用:
方法2和方法3已在PyCharm 2018.1 CE中使用Python 2.7.15和3.6.5进行了测试
注意:
在此答案的先前版本中,我说过docstring方法虽然显示了PxLogger类的自定义verbose()
方法,但缺少了基类的方法。那是因为您从logging.getLoggerClass
返回的值(即任意类)派生PxLogger。
如果将PxLogger明确地设为logging.Logger
的子类,则类型检查器将知道基类,并可以正确地解析其方法以实现自动完成。
无论如何,我不建议对getLoggerClass
的返回值进行子类化。您将要确定自己从中得到什么,而不要依赖返回正确结果的函数。
答案 1 :(得分:1)
通过键入注释变量。
LOGGER: PxLogger = logging.getLogger(__name__)
编辑:
以上解决方案适用于Python 3.6+。如@pLOPeGG在评论中指出的那样,对先前版本使用# type: type
注释。
LOGGER = logging.getLogger(__name__) # type: PxLogger