simplify py.test.mark API,
add more plugin docs --HG-- branch : 1.0.x
This commit is contained in:
		
							parent
							
								
									5b205e0711
								
							
						
					
					
						commit
						dcf194ebb8
					
				|  | @ -1,6 +1,8 @@ | ||||||
| Changes between 1.0.0b8 and 1.0.0b9 | Changes between 1.0.0b8 and 1.0.0b9 | ||||||
| ===================================== | ===================================== | ||||||
| 
 | 
 | ||||||
|  | * simplified py.test.mark API  | ||||||
|  | 
 | ||||||
| * make assert-reinterpretation work better with comparisons not  | * make assert-reinterpretation work better with comparisons not  | ||||||
|   returning bools (reported with numpy from thanks maciej fijalkowski) |   returning bools (reported with numpy from thanks maciej fijalkowski) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -237,11 +237,15 @@ class/function names of a test function are put into the set | ||||||
| of keywords for a given test.  You can specify additional  | of keywords for a given test.  You can specify additional  | ||||||
| kewords like this:: | kewords like this:: | ||||||
| 
 | 
 | ||||||
|     @py.test.mark(webtest=True) |     @py.test.mark.webtest  | ||||||
|     def test_send_http(): |     def test_send_http(): | ||||||
|         ...  |         ...  | ||||||
| 
 | 
 | ||||||
| and then use those keywords to select tests.  | and then use those keywords to select tests.  See the `pytest_keyword`_ | ||||||
|  | plugin for more information.  | ||||||
|  | 
 | ||||||
|  | .. _`pytest_keyword`: plugin/keyword.html | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| disabling a test class | disabling a test class | ||||||
| ----------------------  | ----------------------  | ||||||
|  |  | ||||||
|  | @ -0,0 +1,35 @@ | ||||||
|  | 
 | ||||||
|  | pytest_hooklog plugin | ||||||
|  | ===================== | ||||||
|  | 
 | ||||||
|  | log invocations of extension hooks to a file. | ||||||
|  | 
 | ||||||
|  | .. contents:: | ||||||
|  |   :local: | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | command line options | ||||||
|  | -------------------- | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ``--hooklog=HOOKLOG`` | ||||||
|  |     write hook calls to the given file. | ||||||
|  | 
 | ||||||
|  | Start improving this plugin in 30 seconds | ||||||
|  | ========================================= | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Do you find the above documentation or the plugin itself lacking?  | ||||||
|  | 
 | ||||||
|  | 1. Download `pytest_hooklog.py`_ plugin source code  | ||||||
|  | 2. put it somewhere as ``pytest_hooklog.py`` into your import path  | ||||||
|  | 3. a subsequent ``py.test`` run will use your local version | ||||||
|  | 
 | ||||||
|  | Further information: extend_ documentation, other plugins_ or contact_.   | ||||||
|  | 
 | ||||||
|  | .. _`pytest_hooklog.py`: http://bitbucket.org/hpk42/py-trunk/raw/2b8d56b82ce6966960cf41d38dc2b794797912ba/py/test/plugin/pytest_hooklog.py | ||||||
|  | .. _`extend`: ../extend.html | ||||||
|  | .. _`plugins`: index.html | ||||||
|  | .. _`contact`: ../../contact.html | ||||||
|  | .. _`checkout the py.test development version`: ../../download.html#checkout | ||||||
|  | @ -0,0 +1,50 @@ | ||||||
|  | 
 | ||||||
|  | pytest_keyword plugin | ||||||
|  | ===================== | ||||||
|  | 
 | ||||||
|  | mark test functions with keywords that may hold values. | ||||||
|  | 
 | ||||||
|  | .. contents:: | ||||||
|  |   :local: | ||||||
|  | 
 | ||||||
|  | Marking functions and setting rich attributes | ||||||
|  | ---------------------------------------------------- | ||||||
|  | 
 | ||||||
|  | By default, all filename parts and class/function names of a test | ||||||
|  | function are put into the set of keywords for a given test.  You can | ||||||
|  | specify additional kewords like this:: | ||||||
|  | 
 | ||||||
|  |     @py.test.mark.webtest  | ||||||
|  |     def test_send_http(): | ||||||
|  |         ...  | ||||||
|  | 
 | ||||||
|  | This will set an attribute 'webtest' on the given test function | ||||||
|  | and by default all such attributes signal keywords.  You can  | ||||||
|  | also set values in this attribute which you could read from | ||||||
|  | a hook in order to do something special with respect to | ||||||
|  | the test function:: | ||||||
|  | 
 | ||||||
|  |     @py.test.mark.timeout(seconds=5) | ||||||
|  |     def test_receive(): | ||||||
|  |         ... | ||||||
|  | 
 | ||||||
|  | This will set the "timeout" attribute with a Marker object  | ||||||
|  | that has a 'seconds' attribute. | ||||||
|  | 
 | ||||||
|  | Start improving this plugin in 30 seconds | ||||||
|  | ========================================= | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Do you find the above documentation or the plugin itself lacking?  | ||||||
|  | 
 | ||||||
|  | 1. Download `pytest_keyword.py`_ plugin source code  | ||||||
|  | 2. put it somewhere as ``pytest_keyword.py`` into your import path  | ||||||
|  | 3. a subsequent ``py.test`` run will use your local version | ||||||
|  | 
 | ||||||
|  | Further information: extend_ documentation, other plugins_ or contact_.   | ||||||
|  | 
 | ||||||
|  | .. _`pytest_keyword.py`: http://bitbucket.org/hpk42/py-trunk/raw/2b8d56b82ce6966960cf41d38dc2b794797912ba/py/test/plugin/pytest_keyword.py | ||||||
|  | .. _`extend`: ../extend.html | ||||||
|  | .. _`plugins`: index.html | ||||||
|  | .. _`contact`: ../../contact.html | ||||||
|  | .. _`checkout the py.test development version`: ../../download.html#checkout | ||||||
|  | @ -0,0 +1,35 @@ | ||||||
|  | 
 | ||||||
|  | pytest_pdb plugin | ||||||
|  | ================= | ||||||
|  | 
 | ||||||
|  | interactive debugging with the Python Debugger. | ||||||
|  | 
 | ||||||
|  | .. contents:: | ||||||
|  |   :local: | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | command line options | ||||||
|  | -------------------- | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ``--pdb`` | ||||||
|  |     start pdb (the Python debugger) on errors. | ||||||
|  | 
 | ||||||
|  | Start improving this plugin in 30 seconds | ||||||
|  | ========================================= | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Do you find the above documentation or the plugin itself lacking?  | ||||||
|  | 
 | ||||||
|  | 1. Download `pytest_pdb.py`_ plugin source code  | ||||||
|  | 2. put it somewhere as ``pytest_pdb.py`` into your import path  | ||||||
|  | 3. a subsequent ``py.test`` run will use your local version | ||||||
|  | 
 | ||||||
|  | Further information: extend_ documentation, other plugins_ or contact_.   | ||||||
|  | 
 | ||||||
|  | .. _`pytest_pdb.py`: http://bitbucket.org/hpk42/py-trunk/raw/2b8d56b82ce6966960cf41d38dc2b794797912ba/py/test/plugin/pytest_pdb.py | ||||||
|  | .. _`extend`: ../extend.html | ||||||
|  | .. _`plugins`: index.html | ||||||
|  | .. _`contact`: ../../contact.html | ||||||
|  | .. _`checkout the py.test development version`: ../../download.html#checkout | ||||||
|  | @ -10,6 +10,8 @@ plugins = [ | ||||||
|             'unittest doctest oejskit restdoc'), |             'unittest doctest oejskit restdoc'), | ||||||
|     ('Plugins for generic reporting and failure logging',  |     ('Plugins for generic reporting and failure logging',  | ||||||
|             'pocoo resultlog terminal',), |             'pocoo resultlog terminal',), | ||||||
|  |     ('internal plugins / core functionality',  | ||||||
|  |         'pdb keyword hooklog') | ||||||
|     #('internal plugins / core functionality',  |     #('internal plugins / core functionality',  | ||||||
|     #    #'pdb keyword hooklog runner execnetcleanup # pytester', |     #    #'pdb keyword hooklog runner execnetcleanup # pytester', | ||||||
|     #    'pdb keyword hooklog runner execnetcleanup' # pytester', |     #    'pdb keyword hooklog runner execnetcleanup' # pytester', | ||||||
|  |  | ||||||
|  | @ -1,70 +1,86 @@ | ||||||
| """ | """ | ||||||
|     py.test.mark / keyword plugin  | mark test functions with keywords that may hold values.  | ||||||
|  | 
 | ||||||
|  | Marking functions and setting rich attributes | ||||||
|  | ---------------------------------------------------- | ||||||
|  | 
 | ||||||
|  | By default, all filename parts and class/function names of a test | ||||||
|  | function are put into the set of keywords for a given test.  You can | ||||||
|  | specify additional kewords like this:: | ||||||
|  | 
 | ||||||
|  |     @py.test.mark.webtest  | ||||||
|  |     def test_send_http(): | ||||||
|  |         ...  | ||||||
|  | 
 | ||||||
|  | This will set an attribute 'webtest' on the given test function | ||||||
|  | and by default all such attributes signal keywords.  You can  | ||||||
|  | also set values in this attribute which you could read from | ||||||
|  | a hook in order to do something special with respect to | ||||||
|  | the test function:: | ||||||
|  | 
 | ||||||
|  |     @py.test.mark.timeout(seconds=5) | ||||||
|  |     def test_receive(): | ||||||
|  |         ... | ||||||
|  | 
 | ||||||
|  | This will set the "timeout" attribute with a Marker object  | ||||||
|  | that has a 'seconds' attribute.  | ||||||
|  | 
 | ||||||
| """ | """ | ||||||
| import py | import py | ||||||
| 
 | 
 | ||||||
| def pytest_namespace(): | def pytest_namespace(): | ||||||
|     mark = KeywordDecorator({}) |     return {'mark': Mark()} | ||||||
|     return {'mark': mark} |  | ||||||
| 
 | 
 | ||||||
| class KeywordDecorator: |  | ||||||
|     """ decorator for setting function attributes. """ |  | ||||||
|     def __init__(self, keywords, lastname=None): |  | ||||||
|         self._keywords = keywords |  | ||||||
|         self._lastname = lastname |  | ||||||
| 
 |  | ||||||
|     def __call__(self, func=None, **kwargs): |  | ||||||
|         if func is None: |  | ||||||
|             kw = self._keywords.copy() |  | ||||||
|             kw.update(kwargs) |  | ||||||
|             return KeywordDecorator(kw) |  | ||||||
|         elif not hasattr(func, 'func_dict'): |  | ||||||
|             kw = self._keywords.copy() |  | ||||||
|             name = self._lastname |  | ||||||
|             if name is None: |  | ||||||
|                 name = "mark" |  | ||||||
|             kw[name] = func |  | ||||||
|             return KeywordDecorator(kw) |  | ||||||
|         func.func_dict.update(self._keywords) |  | ||||||
|         return func  |  | ||||||
| 
 | 
 | ||||||
|  | class Mark(object): | ||||||
|     def __getattr__(self, name): |     def __getattr__(self, name): | ||||||
|         if name[0] == "_": |         if name[0] == "_": | ||||||
|             raise AttributeError(name) |             raise AttributeError(name) | ||||||
|         kw = self._keywords.copy() |         return MarkerDecorator(name) | ||||||
|         kw[name] = True | 
 | ||||||
|         return self.__class__(kw, lastname=name) | class MarkerDecorator: | ||||||
|  |     """ decorator for setting function attributes. """ | ||||||
|  |     def __init__(self, name): | ||||||
|  |         self.markname = name | ||||||
|  | 
 | ||||||
|  |     def __repr__(self): | ||||||
|  |         d = self.__dict__.copy() | ||||||
|  |         name = d.pop('markname') | ||||||
|  |         return "<MarkerDecorator %r %r>" %(name, d) | ||||||
|  | 
 | ||||||
|  |     def __call__(self, *args, **kwargs): | ||||||
|  |         if not args: | ||||||
|  |             if hasattr(self, 'kwargs'): | ||||||
|  |                 raise TypeError("double mark-keywords?")  | ||||||
|  |             self.kwargs = kwargs.copy() | ||||||
|  |             return self  | ||||||
|  |         else: | ||||||
|  |             if not len(args) == 1 or not hasattr(args[0], 'func_dict'): | ||||||
|  |                 raise TypeError("need exactly one function to decorate, " | ||||||
|  |                                 "got %r" %(args,)) | ||||||
|  |             func = args[0] | ||||||
|  |             mh = MarkHolder(getattr(self, 'kwargs', {})) | ||||||
|  |             setattr(func, self.markname, mh) | ||||||
|  |             return func | ||||||
|  | 
 | ||||||
|  | class MarkHolder: | ||||||
|  |     def __init__(self, kwargs): | ||||||
|  |         self.__dict__.update(kwargs) | ||||||
|  | 
 | ||||||
|  | def test_pytest_mark_api(): | ||||||
|  |     mark = Mark() | ||||||
|  |     py.test.raises(TypeError, "mark(x=3)") | ||||||
| 
 | 
 | ||||||
| def test_pytest_mark_getattr(): |  | ||||||
|     mark = KeywordDecorator({}) |  | ||||||
|     def f(): pass |     def f(): pass | ||||||
| 
 |  | ||||||
|     mark.hello(f) |     mark.hello(f) | ||||||
|     assert f.hello == True |     assert f.hello | ||||||
| 
 | 
 | ||||||
|     mark.hello("test")(f) |     mark.world(x=3, y=4)(f) | ||||||
|     assert f.hello == "test" |     assert f.world  | ||||||
|  |     assert f.world.x == 3 | ||||||
|  |     assert f.world.y == 4 | ||||||
| 
 | 
 | ||||||
|     py.test.raises(AttributeError, "mark._hello") |     py.test.raises(TypeError, "mark.some(x=3)(f=5)") | ||||||
|     py.test.raises(AttributeError, "mark.__str__") |  | ||||||
| 
 |  | ||||||
| def test_pytest_mark_call(): |  | ||||||
|     mark = KeywordDecorator({}) |  | ||||||
|     def f(): pass |  | ||||||
|     mark(x=3)(f) |  | ||||||
|     assert f.x == 3 |  | ||||||
|     def g(): pass |  | ||||||
|     mark(g) |  | ||||||
|     assert not g.func_dict |  | ||||||
| 
 |  | ||||||
|     mark.hello(f) |  | ||||||
|     assert f.hello == True |  | ||||||
| 
 |  | ||||||
|     mark.hello("test")(f) |  | ||||||
|     assert f.hello == "test" |  | ||||||
| 
 |  | ||||||
|     mark("x1")(f) |  | ||||||
|     assert f.mark == "x1" |  | ||||||
| 
 | 
 | ||||||
| def test_mark_plugin(testdir): | def test_mark_plugin(testdir): | ||||||
|     p = testdir.makepyfile(""" |     p = testdir.makepyfile(""" | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue