Switch setuponly and setupplan options to a hook-based implementation.
This commit is contained in:
		
							parent
							
								
									c6af737d4e
								
							
						
					
					
						commit
						032ce8baf6
					
				|  | @ -65,7 +65,7 @@ _preinit = [] | ||||||
| default_plugins = ( | default_plugins = ( | ||||||
|      "mark main terminal runner python pdb unittest capture skipping " |      "mark main terminal runner python pdb unittest capture skipping " | ||||||
|      "tmpdir monkeypatch recwarn pastebin helpconfig nose assertion genscript " |      "tmpdir monkeypatch recwarn pastebin helpconfig nose assertion genscript " | ||||||
|      "junitxml resultlog doctest cacheprovider").split() |      "junitxml resultlog doctest cacheprovider setuponly setupplan").split() | ||||||
| 
 | 
 | ||||||
| builtin_plugins = set(default_plugins) | builtin_plugins = set(default_plugins) | ||||||
| builtin_plugins.add("pytester") | builtin_plugins.add("pytester") | ||||||
|  |  | ||||||
|  | @ -218,6 +218,19 @@ def pytest_runtest_logreport(report): | ||||||
|     """ process a test setup/call/teardown report relating to |     """ process a test setup/call/teardown report relating to | ||||||
|     the respective phase of executing a test. """ |     the respective phase of executing a test. """ | ||||||
| 
 | 
 | ||||||
|  | # ------------------------------------------------------------------------- | ||||||
|  | # Fixture related hooks | ||||||
|  | # ------------------------------------------------------------------------- | ||||||
|  | 
 | ||||||
|  | @hookspec(firstresult=True) | ||||||
|  | def pytest_fixture_setup(fixturedef, request): | ||||||
|  |     """ performs fixture setup execution. """ | ||||||
|  | 
 | ||||||
|  | def pytest_fixture_post_finalizer(fixturedef): | ||||||
|  |     """ called after fixture teardown, but before the cache is cleared so | ||||||
|  |     the fixture result cache ``fixturedef.cached_result`` can | ||||||
|  |     still be accessed.""" | ||||||
|  | 
 | ||||||
| # ------------------------------------------------------------------------- | # ------------------------------------------------------------------------- | ||||||
| # test session related hooks | # test session related hooks | ||||||
| # ------------------------------------------------------------------------- | # ------------------------------------------------------------------------- | ||||||
|  |  | ||||||
|  | @ -2475,25 +2475,18 @@ class FixtureDef: | ||||||
|                 func = self._finalizer.pop() |                 func = self._finalizer.pop() | ||||||
|                 func() |                 func() | ||||||
|         finally: |         finally: | ||||||
|  |             ihook = self._fixturemanager.session.ihook | ||||||
|  |             ihook.pytest_fixture_post_finalizer(fixturedef=self) | ||||||
|             # even if finalization fails, we invalidate |             # even if finalization fails, we invalidate | ||||||
|             # the cached fixture value |             # the cached fixture value | ||||||
|             if hasattr(self, "cached_result"): |             if hasattr(self, "cached_result"): | ||||||
|                 config = self._fixturemanager.config |  | ||||||
|                 if config.option.setuponly or config.option.setupplan: |  | ||||||
|                     self._show_fixture_action('TEARDOWN') |  | ||||||
|                     if hasattr(self, "cached_param"): |  | ||||||
|                         del self.cached_param |  | ||||||
|                 del self.cached_result |                 del self.cached_result | ||||||
| 
 | 
 | ||||||
|     def execute(self, request): |     def execute(self, request): | ||||||
|         # get required arguments and register our own finish() |         # get required arguments and register our own finish() | ||||||
|         # with their finalization |         # with their finalization | ||||||
|         kwargs = {} |  | ||||||
|         for argname in self.argnames: |         for argname in self.argnames: | ||||||
|             fixturedef = request._get_active_fixturedef(argname) |             fixturedef = request._get_active_fixturedef(argname) | ||||||
|             result, arg_cache_key, exc = fixturedef.cached_result |  | ||||||
|             request._check_scope(argname, request.scope, fixturedef.scope) |  | ||||||
|             kwargs[argname] = result |  | ||||||
|             if argname != "request": |             if argname != "request": | ||||||
|                 fixturedef.addfinalizer(self.finish) |                 fixturedef.addfinalizer(self.finish) | ||||||
| 
 | 
 | ||||||
|  | @ -2511,76 +2504,44 @@ class FixtureDef: | ||||||
|             self.finish() |             self.finish() | ||||||
|             assert not hasattr(self, "cached_result") |             assert not hasattr(self, "cached_result") | ||||||
| 
 | 
 | ||||||
|         fixturefunc = self.func |         ihook = self._fixturemanager.session.ihook | ||||||
| 
 |         ihook.pytest_fixture_setup(fixturedef=self, request=request) | ||||||
|         if self.unittest: |  | ||||||
|             if request.instance is not None: |  | ||||||
|                 # bind the unbound method to the TestCase instance |  | ||||||
|                 fixturefunc = self.func.__get__(request.instance) |  | ||||||
|         else: |  | ||||||
|             # the fixture function needs to be bound to the actual |  | ||||||
|             # request.instance so that code working with "self" behaves |  | ||||||
|             # as expected. |  | ||||||
|             if request.instance is not None: |  | ||||||
|                 fixturefunc = getimfunc(self.func) |  | ||||||
|                 if fixturefunc != self.func: |  | ||||||
|                     fixturefunc = fixturefunc.__get__(request.instance) |  | ||||||
| 
 |  | ||||||
|         try: |  | ||||||
|             config = request.config |  | ||||||
|             if config.option.setupplan: |  | ||||||
|                 result = None |  | ||||||
|             else: |  | ||||||
|                 result = call_fixture_func(fixturefunc, request, kwargs) |  | ||||||
|             if config.option.setuponly or config.option.setupplan: |  | ||||||
|                 if hasattr(request, 'param'): |  | ||||||
|                     # Save the fixture parameter so ._show_fixture_action() can |  | ||||||
|                     # display it now and during the teardown (in .finish()). |  | ||||||
|                     if self.ids: |  | ||||||
|                         if callable(self.ids): |  | ||||||
|                             self.cached_param = self.ids(request.param) |  | ||||||
|                         else: |  | ||||||
|                             self.cached_param = self.ids[request.param_index] |  | ||||||
|                     else: |  | ||||||
|                         self.cached_param = request.param |  | ||||||
|                 self._show_fixture_action('SETUP') |  | ||||||
|         except Exception: |  | ||||||
|             self.cached_result = (None, my_cache_key, sys.exc_info()) |  | ||||||
|             raise |  | ||||||
|         self.cached_result = (result, my_cache_key, None) |  | ||||||
|         return result |  | ||||||
| 
 |  | ||||||
|     def _show_fixture_action(self, what): |  | ||||||
|         config = self._fixturemanager.config |  | ||||||
|         capman = config.pluginmanager.getplugin('capturemanager') |  | ||||||
|         if capman: |  | ||||||
|             out, err = capman.suspendcapture() |  | ||||||
| 
 |  | ||||||
|         tw = config.get_terminal_writer() |  | ||||||
|         tw.line() |  | ||||||
|         tw.write(' ' * 2 * self.scopenum) |  | ||||||
|         tw.write('{step} {scope} {fixture}'.format( |  | ||||||
|             step=what.ljust(8),  # align the output to TEARDOWN |  | ||||||
|             scope=self.scope[0].upper(), |  | ||||||
|             fixture=self.argname)) |  | ||||||
| 
 |  | ||||||
|         if what == 'SETUP': |  | ||||||
|             deps = sorted(arg for arg in self.argnames if arg != 'request') |  | ||||||
|             if deps: |  | ||||||
|                 tw.write(' (fixtures used: {0})'.format(', '.join(deps))) |  | ||||||
| 
 |  | ||||||
|         if hasattr(self, 'cached_param'): |  | ||||||
|             tw.write('[{0}]'.format(self.cached_param)) |  | ||||||
| 
 |  | ||||||
|         if capman: |  | ||||||
|             capman.resumecapture() |  | ||||||
|             sys.stdout.write(out) |  | ||||||
|             sys.stderr.write(err) |  | ||||||
| 
 | 
 | ||||||
|     def __repr__(self): |     def __repr__(self): | ||||||
|         return ("<FixtureDef name=%r scope=%r baseid=%r >" % |         return ("<FixtureDef name=%r scope=%r baseid=%r >" % | ||||||
|                 (self.argname, self.scope, self.baseid)) |                 (self.argname, self.scope, self.baseid)) | ||||||
| 
 | 
 | ||||||
|  | def pytest_fixture_setup(fixturedef, request): | ||||||
|  |     """ Execution of fixture setup. """ | ||||||
|  |     kwargs = {} | ||||||
|  |     for argname in fixturedef.argnames: | ||||||
|  |         fixdef = request._get_active_fixturedef(argname) | ||||||
|  |         result, arg_cache_key, exc = fixdef.cached_result | ||||||
|  |         request._check_scope(argname, request.scope, fixdef.scope) | ||||||
|  |         kwargs[argname] = result | ||||||
|  | 
 | ||||||
|  |     fixturefunc = fixturedef.func | ||||||
|  |     if fixturedef.unittest: | ||||||
|  |         if request.instance is not None: | ||||||
|  |             # bind the unbound method to the TestCase instance | ||||||
|  |             fixturefunc = fixturedef.func.__get__(request.instance) | ||||||
|  |     else: | ||||||
|  |         # the fixture function needs to be bound to the actual | ||||||
|  |         # request.instance so that code working with "fixturedef" behaves | ||||||
|  |         # as expected. | ||||||
|  |         if request.instance is not None: | ||||||
|  |             fixturefunc = getimfunc(fixturedef.func) | ||||||
|  |             if fixturefunc != fixturedef.func: | ||||||
|  |                 fixturefunc = fixturefunc.__get__(request.instance) | ||||||
|  |     my_cache_key = request.param_index | ||||||
|  |     try: | ||||||
|  |         result = call_fixture_func(fixturefunc, request, kwargs) | ||||||
|  |     except Exception: | ||||||
|  |         fixturedef.cached_result = (None, my_cache_key, sys.exc_info()) | ||||||
|  |         raise | ||||||
|  |     fixturedef.cached_result = (result, my_cache_key, None) | ||||||
|  |     return result | ||||||
|  | 
 | ||||||
| def num_mock_patch_args(function): | def num_mock_patch_args(function): | ||||||
|     """ return number of arguments used up by mock arguments (if any) """ |     """ return number of arguments used up by mock arguments (if any) """ | ||||||
|     patchings = getattr(function, "patchings", None) |     patchings = getattr(function, "patchings", None) | ||||||
|  |  | ||||||
|  | @ -0,0 +1,54 @@ | ||||||
|  | import pytest | ||||||
|  | import sys | ||||||
|  | 
 | ||||||
|  | @pytest.hookimpl(hookwrapper=True) | ||||||
|  | def pytest_fixture_setup(fixturedef, request): | ||||||
|  |     yield | ||||||
|  |     config = request.config | ||||||
|  |     if config.option.setuponly: | ||||||
|  |         if hasattr(request, 'param'): | ||||||
|  |             # Save the fixture parameter so ._show_fixture_action() can | ||||||
|  |             # display it now and during the teardown (in .finish()). | ||||||
|  |             if fixturedef.ids: | ||||||
|  |                 if callable(fixturedef.ids): | ||||||
|  |                     fixturedef.cached_param = fixturedef.ids(request.param) | ||||||
|  |                 else: | ||||||
|  |                     fixturedef.cached_param = fixturedef.ids[request.param_index] | ||||||
|  |             else: | ||||||
|  |                 fixturedef.cached_param = request.param | ||||||
|  |         _show_fixture_action(fixturedef, 'SETUP') | ||||||
|  | 
 | ||||||
|  | def pytest_fixture_post_finalizer(fixturedef): | ||||||
|  |     if hasattr(fixturedef, "cached_result"): | ||||||
|  |         config = fixturedef._fixturemanager.config | ||||||
|  |         if config.option.setuponly: | ||||||
|  |             _show_fixture_action(fixturedef, 'TEARDOWN') | ||||||
|  |             if hasattr(fixturedef, "cached_param"): | ||||||
|  |                 del fixturedef.cached_param | ||||||
|  | 
 | ||||||
|  | def _show_fixture_action(fixturedef, msg): | ||||||
|  |     config = fixturedef._fixturemanager.config | ||||||
|  |     capman = config.pluginmanager.getplugin('capturemanager') | ||||||
|  |     if capman: | ||||||
|  |         out, err = capman.suspendcapture() | ||||||
|  | 
 | ||||||
|  |     tw = config.get_terminal_writer() | ||||||
|  |     tw.line() | ||||||
|  |     tw.write(' ' * 2 * fixturedef.scopenum) | ||||||
|  |     tw.write('{step} {scope} {fixture}'.format( | ||||||
|  |         step=msg.ljust(8),  # align the output to TEARDOWN | ||||||
|  |         scope=fixturedef.scope[0].upper(), | ||||||
|  |         fixture=fixturedef.argname)) | ||||||
|  | 
 | ||||||
|  |     if msg == 'SETUP': | ||||||
|  |         deps = sorted(arg for arg in fixturedef.argnames if arg != 'request') | ||||||
|  |         if deps: | ||||||
|  |             tw.write(' (fixtures used: {0})'.format(', '.join(deps))) | ||||||
|  | 
 | ||||||
|  |     if hasattr(fixturedef, 'cached_param'): | ||||||
|  |         tw.write('[{0}]'.format(fixturedef.cached_param)) | ||||||
|  | 
 | ||||||
|  |     if capman: | ||||||
|  |         capman.resumecapture() | ||||||
|  |         sys.stdout.write(out) | ||||||
|  |         sys.stderr.write(err) | ||||||
|  | @ -0,0 +1,14 @@ | ||||||
|  | import pytest | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @pytest.hookimpl(tryfirst=True) | ||||||
|  | def pytest_fixture_setup(fixturedef, request): | ||||||
|  |     # Will return a dummy fixture if the setuponly option is provided. | ||||||
|  |     if request.config.option.setupplan: | ||||||
|  |         fixturedef.cached_result = (None, None, None) | ||||||
|  |         return fixturedef.cached_result | ||||||
|  | 
 | ||||||
|  | @pytest.hookimpl(tryfirst=True) | ||||||
|  | def pytest_cmdline_main(config): | ||||||
|  |     if config.option.setupplan: | ||||||
|  |         config.option.setuponly = True | ||||||
		Loading…
	
		Reference in New Issue