html tool

显示标签为“read_code,”的博文。显示所有博文
显示标签为“read_code,”的博文。显示所有博文

2019年5月13日星期一

pytest-warnigs模块


概述: waring.warn -默认使用, err,filter定义,fromat定义


https://www.quxihuan.com/python-module-warnings
https://pymotw.com/2/warnings/

- 定义:

模块 warnings 在程序运行中,向用户报告非严重错误,它是由 Python 3.0 版本引入的。使用的情况包括向库调用者警告一些函数将来可能废弃,或者提示一些错误的配置信息,不支持的特性等等。[popexizhi: 2.7的doc中就有此方法,这里引入版本3.0的说法是不对的 , https://docs.python.org/2/library/warnings.html#available-functions]

-- 目的:

因为报告的不是严重的错误,一个程序可能会遇到多个重复的问题。warnings 可以抑制重复的错误信息,使你不用多次看到他们。方法是可以通过命令行传递参数或者调用 warnings 内的函数。

- 使用:

1) 生成 warnings,依然执行,默认的方式:

最简单的生成 warning 是调用 warn() 函数,传递的参数为消息内容。
# warnings-gen.py
import warnings

print('warnings generate')
warnings.warn('warning message')
print('warnings end')
执行:
alexdeMacBook-Pro:quxihuan-python-code alex$ python3 warnings-gen.py 
warnings generate
warnings-gen.py:5: UserWarning: warning message
  warnings.warn('warning message')
warnings end
可以看到,虽然 warning 调用了,但是程序还是继续往下运行,默认的行为会继续运行下去。

2) 将warnings 的执行转变为异常 : warnings.simplefilter('error', UserWarning)


可以调用函数 simplefilter() 改变这种行为。
# warnings-filter.py
import warnings

warnings.simplefilter('error', UserWarning)

print('warnings generate')
warnings.warn('warning message')
print('warnings end')
执行:
alexdeMacBook-Pro:quxihuan-python-code alex$ python3 warnings-filter.py 
warnings generate
Traceback (most recent call last):
  File "warnings-filter.py", line 7, in <module>
    warnings.warn('warning message')
UserWarning: warning message
在这个例子中,使用 simplefilter() 函数告诉 warnings 模块内部当发生警告 UserWarning时,触发异常。查看输出,最后打印数据的语句没有执行,程序中途停止运行了。

3)warnings.warn的stacklevel的作用:

参见:https://pymotw.com/2/warnings/
You’ll notice that by default the warning message includes the source line that generated it, when available. It’s not all that useful to see the line of code with the actual warning message, though. Instead, you can tell warn() how far up the stack it has to go to find the line the called the function containing the warning. That way users of a deprecated function see where the function is called, instead of the implementation of the function
import warnings

def old_function():
    warnings.warn(
        'old_function() is deprecated, use new_function() instead', 
        stacklevel=2)

def caller_of_old_function():
    old_function()
    
caller_of_old_function()
Notice that in this example warn() needs to go up the stack 2 levels, one for itself and one for old_function().
$ python warnings_warn_stacklevel.py

warnings_warn_stacklevel.py:18: UserWarning: old_function() is deprecated, use new_function() instead
  old_function()

4) 模式过滤

filterwarnings() 过滤更复杂的匹配
还可以通过函数 filterwarnings() 过滤更复杂的匹配,例如设定一个正则表达式过滤消息内容。
# warnings-re.py
import warnings

warnings.filterwarnings('ignore', '.*hello.*')

warnings.warn('hello python')
warnings.warn('hi python')
执行:
alexdeMacBook-Pro:quxihuan-python-code alex$ python3 warnings-re.py 
warnings-re.py:7: UserWarning: hi python
  warnings.warn('hi python')
本例忽略包含 hello 消息的警告,还可以通过命令行修改过滤行为,查看下面的例子。
# warnings-cmd.py
import warnings

warnings.warn('hello python')
warnings.warn('hi python')
执行:
alexdeMacBook-Pro:quxihuan-python-code alex$ python3 -W "ignore:hello:UserWarning::0" warnings-cmd.py 
warnings-cmd.py:5: UserWarning: hi python
  warnings.warn('hi python')
alexdeMacBook-Pro:quxihuan-python-code alex$ python3 -W "ignore:hi:UserWarning::0" warnings-cmd.py 
warnings-cmd.py:4: UserWarning: hello python
  warnings.warn('hello python')

5) 格式化消息

如果想自定义消息格式,可以修改模块函数 formatwarning() [popexizhi:这个对自定义的log类是不是会有帮助呢?!]
如果想自定义消息格式,可以修改模块函数 formatwarning()
# warnings-format.py
import warnings

def my_format(message, category, filename, lineno,
    file=None, line=None):
    return ': {}:{} {}:{}\n'.format(
        filename, lineno,
        category.__name__, message
        )

warnings.warn('a warning')
warnings.formatwarning = my_format
warnings.warn('a warning')
执行:
alexdeMacBook-Pro:quxihuan-python-code alex$ python3 warnings-format.py 
warnings-format.py:11: UserWarning: a warning
  warnings.warn('a warning')
: warnings-format.py:13 UserWarning:a warning

2019年4月29日星期一

@staticmethod和@classmethod的作用与区别


问题:


       1.  @classmethod 的含义
       2.  PytestExperimentalApiWarning.simple("testdir.copy_example") 这里为什么只有1个参数,声明定义中不是两个吗?


pytest 的testing 阅读中发现如下的使用
源码:

0) from _pytest.warning_types import PYTESTER_COPY_EXAMPL
在 /src/_pytest/warning_types.py中
 60 PYTESTER_COPY_EXAMPLE = PytestExperimentalApiWarning.simple("testdir.copy_example")

而这个  PytestExperimentalApiWarning.simple 定义在src/_pytest/warning_types.py,如下:
 28 class PytestExperimentalApiWarning(PytestWarning, FutureWarning):
 29     """
 30     Bases: :class:`pytest.PytestWarning`, :class:`FutureWarning`.
 31       
 32     Warning category used to denote experiments in pytest. Use sparingly as the API might     change or even be
 33     removed completely in future version
 34     """
 35       
 36     @classmethod                      
 37     def simple(cls, apiname):         
 38         return cls(                   
 39             "{apiname} is an experimental api that may change over time".format(
 40                 apiname=apiname       
 41             )                         
 42         )                             
 43                                       
 44              


解释:

参考:
https://blog.csdn.net/handsomekang/article/details/9615239
https://blog.csdn.net/nyist327/article/details/47679771

要使用某个类的方法,需要先实例化一个对象再调用方法。

而使用@staticmethod或@classmethod,就可以不需要实例化,直接类名.方法名()来调用。
这有利于组织代码,把某些应该属于某个类的函数给放到那个类里去,同时有利于命名空间的整洁。

既然@staticmethod和@classmethod都可以直接类名.方法名()来调用,那他们有什么区别呢
从它们的使用上来看,

  • @staticmethod不需要表示自身对象的self和自身类的cls参数,就跟使用函数一样。
  • @classmethod也不需要self参数,但第一个参数需要是表示自身类的cls参数。

如果在@staticmethod中要调用到这个类的一些属性方法,只能直接类名.属性名或类名.方法名。
@classmethod因为持有cls参数,可以来调用类的属性,类的方法,实例化对象等,避免硬编码。


一是通过def定义的 普通的一般的,需要至少传递一个参数,一般用self,这样的方法必须通过一个类的实例去访问,类似于c++中通过对象去访问;

二是在def前面加上@classmethod,这种类方法的一个特点就是可以通过类名去调用,但是也必须传递一个参数,一般用cls表示class,表示可以通过类直接调用;

三是在def前面加上@staticmethod,这种类方法是静态的类方法,类似于c++的静态函数,他的一个特点是参数可以为空,同样支持类名和对象两种调用方式;