Merge master into features
This commit is contained in:
		
						commit
						0db5ccb0dd
					
				|  | @ -0,0 +1 @@ | ||||||
|  | Document common doctest fixture directory tree structure pitfalls | ||||||
|  | @ -0,0 +1 @@ | ||||||
|  | Validate arguments from the ``PYTEST_ADDOPTS`` environment variable and the ``addopts`` ini option separately. | ||||||
|  | @ -0,0 +1 @@ | ||||||
|  | When a fixture yields and a log call is made after the test runs, and, if the test is interrupted, capture attributes are ``None``. | ||||||
|  | @ -154,6 +154,9 @@ which can then be used in your doctests directly:: | ||||||
|         """ |         """ | ||||||
|         pass |         pass | ||||||
| 
 | 
 | ||||||
|  | Note that like the normal ``conftest.py``, the fixtures are discovered in the directory tree conftest is in. | ||||||
|  | Meaning that if you put your doctest with your source code, the relevant conftest.py needs to be in the same directory tree. | ||||||
|  | Fixtures will not be discovered in a sibling directory tree! | ||||||
| 
 | 
 | ||||||
| Output format | Output format | ||||||
| ------------- | ------------- | ||||||
|  |  | ||||||
|  | @ -156,4 +156,4 @@ More details can be found in the `original PR <https://github.com/pytest-dev/pyt | ||||||
| .. note:: | .. note:: | ||||||
| 
 | 
 | ||||||
|     in a future major relase of pytest we will introduce class based markers, |     in a future major relase of pytest we will introduce class based markers, | ||||||
|     at which points markers will no longer be limited to instances of :py:class:`Mark` |     at which point markers will no longer be limited to instances of :py:class:`Mark` | ||||||
|  |  | ||||||
|  | @ -1,5 +1,3 @@ | ||||||
| pygments-pytest>=1.0.4 | pygments-pytest>=1.1.0 | ||||||
| # pinning sphinx to 1.4.* due to search issues with rtd: | sphinx>=1.8.2 | ||||||
| # https://github.com/rtfd/readthedocs-sphinx-ext/issues/25 |  | ||||||
| sphinx ==1.4.* |  | ||||||
| sphinxcontrib-trio | sphinxcontrib-trio | ||||||
|  |  | ||||||
|  | @ -117,7 +117,10 @@ class CaptureManager(object): | ||||||
|             self._global_capturing = None |             self._global_capturing = None | ||||||
| 
 | 
 | ||||||
|     def resume_global_capture(self): |     def resume_global_capture(self): | ||||||
|         self._global_capturing.resume_capturing() |         # During teardown of the python process, and on rare occasions, capture | ||||||
|  |         # attributes can be `None` while trying to resume global capture. | ||||||
|  |         if self._global_capturing is not None: | ||||||
|  |             self._global_capturing.resume_capturing() | ||||||
| 
 | 
 | ||||||
|     def suspend_global_capture(self, in_=False): |     def suspend_global_capture(self, in_=False): | ||||||
|         cap = getattr(self, "_global_capturing", None) |         cap = getattr(self, "_global_capturing", None) | ||||||
|  |  | ||||||
|  | @ -777,12 +777,21 @@ class Config(object): | ||||||
|         for name in _iter_rewritable_modules(package_files): |         for name in _iter_rewritable_modules(package_files): | ||||||
|             hook.mark_rewrite(name) |             hook.mark_rewrite(name) | ||||||
| 
 | 
 | ||||||
|  |     def _validate_args(self, args): | ||||||
|  |         """Validate known args.""" | ||||||
|  |         self._parser.parse_known_and_unknown_args( | ||||||
|  |             args, namespace=copy.copy(self.option) | ||||||
|  |         ) | ||||||
|  |         return args | ||||||
|  | 
 | ||||||
|     def _preparse(self, args, addopts=True): |     def _preparse(self, args, addopts=True): | ||||||
|         if addopts: |         if addopts: | ||||||
|             args[:] = shlex.split(os.environ.get("PYTEST_ADDOPTS", "")) + args |             env_addopts = os.environ.get("PYTEST_ADDOPTS", "") | ||||||
|  |             if len(env_addopts): | ||||||
|  |                 args[:] = self._validate_args(shlex.split(env_addopts)) + args | ||||||
|         self._initini(args) |         self._initini(args) | ||||||
|         if addopts: |         if addopts: | ||||||
|             args[:] = self.getini("addopts") + args |             args[:] = self._validate_args(self.getini("addopts")) + args | ||||||
|         self._checkversion() |         self._checkversion() | ||||||
|         self._consider_importhook(args) |         self._consider_importhook(args) | ||||||
|         self.pluginmanager.consider_preparse(args) |         self.pluginmanager.consider_preparse(args) | ||||||
|  |  | ||||||
|  | @ -302,14 +302,14 @@ class TestLoggingInteraction(object): | ||||||
|             """\ |             """\ | ||||||
|             import logging |             import logging | ||||||
|             def setup_function(function): |             def setup_function(function): | ||||||
|                 logging.warn("hello1") |                 logging.warning("hello1") | ||||||
| 
 | 
 | ||||||
|             def test_logging(): |             def test_logging(): | ||||||
|                 logging.warn("hello2") |                 logging.warning("hello2") | ||||||
|                 assert 0 |                 assert 0 | ||||||
| 
 | 
 | ||||||
|             def teardown_function(function): |             def teardown_function(function): | ||||||
|                 logging.warn("hello3") |                 logging.warning("hello3") | ||||||
|                 assert 0 |                 assert 0 | ||||||
|             """ |             """ | ||||||
|         ) |         ) | ||||||
|  | @ -328,14 +328,14 @@ class TestLoggingInteraction(object): | ||||||
|             """\ |             """\ | ||||||
|             import logging |             import logging | ||||||
|             def setup_module(function): |             def setup_module(function): | ||||||
|                 logging.warn("hello1") |                 logging.warning("hello1") | ||||||
| 
 | 
 | ||||||
|             def test_logging(): |             def test_logging(): | ||||||
|                 logging.warn("hello2") |                 logging.warning("hello2") | ||||||
|                 assert 0 |                 assert 0 | ||||||
| 
 | 
 | ||||||
|             def teardown_module(function): |             def teardown_module(function): | ||||||
|                 logging.warn("hello3") |                 logging.warning("hello3") | ||||||
|                 assert 0 |                 assert 0 | ||||||
|             """ |             """ | ||||||
|         ) |         ) | ||||||
|  | @ -354,7 +354,7 @@ class TestLoggingInteraction(object): | ||||||
|             """\ |             """\ | ||||||
|                 import logging |                 import logging | ||||||
|                 logging.basicConfig() |                 logging.basicConfig() | ||||||
|                 logging.warn("hello435") |                 logging.warning("hello435") | ||||||
|             """ |             """ | ||||||
|         ) |         ) | ||||||
|         # make sure that logging is still captured in tests |         # make sure that logging is still captured in tests | ||||||
|  | @ -375,7 +375,7 @@ class TestLoggingInteraction(object): | ||||||
|             """\ |             """\ | ||||||
|             def test_hello(): |             def test_hello(): | ||||||
|                 import logging |                 import logging | ||||||
|                 logging.warn("hello433") |                 logging.warning("hello433") | ||||||
|                 assert 0 |                 assert 0 | ||||||
|             """ |             """ | ||||||
|         ) |         ) | ||||||
|  | @ -385,6 +385,40 @@ class TestLoggingInteraction(object): | ||||||
|         assert "something" not in result.stderr.str() |         assert "something" not in result.stderr.str() | ||||||
|         assert "operation on closed file" not in result.stderr.str() |         assert "operation on closed file" not in result.stderr.str() | ||||||
| 
 | 
 | ||||||
|  |     def test_logging_after_cap_stopped(self, testdir): | ||||||
|  |         testdir.makeconftest( | ||||||
|  |             """\ | ||||||
|  |                 import pytest | ||||||
|  |                 import logging | ||||||
|  | 
 | ||||||
|  |                 log = logging.getLogger(__name__) | ||||||
|  | 
 | ||||||
|  |                 @pytest.fixture | ||||||
|  |                 def log_on_teardown(): | ||||||
|  |                     yield | ||||||
|  |                     log.warning('Logging on teardown') | ||||||
|  |             """ | ||||||
|  |         ) | ||||||
|  |         # make sure that logging is still captured in tests | ||||||
|  |         p = testdir.makepyfile( | ||||||
|  |             """\ | ||||||
|  |             def test_hello(log_on_teardown): | ||||||
|  |                 import logging | ||||||
|  |                 logging.warning("hello433") | ||||||
|  |                 assert 1 | ||||||
|  |                 raise KeyboardInterrupt() | ||||||
|  |             """ | ||||||
|  |         ) | ||||||
|  |         result = testdir.runpytest_subprocess(p, "--log-cli-level", "info") | ||||||
|  |         assert result.ret != 0 | ||||||
|  |         result.stdout.fnmatch_lines( | ||||||
|  |             ["*WARNING*hello433*", "*WARNING*Logging on teardown*"] | ||||||
|  |         ) | ||||||
|  |         assert ( | ||||||
|  |             "AttributeError: 'NoneType' object has no attribute 'resume_capturing'" | ||||||
|  |             not in result.stderr.str() | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| class TestCaptureFixture(object): | class TestCaptureFixture(object): | ||||||
|     @pytest.mark.parametrize("opt", [[], ["-s"]]) |     @pytest.mark.parametrize("opt", [[], ["-s"]]) | ||||||
|  | @ -1300,13 +1334,13 @@ def test_capturing_and_logging_fundamentals(testdir, method): | ||||||
|                                      Capture=capture.%s) |                                      Capture=capture.%s) | ||||||
|         cap.start_capturing() |         cap.start_capturing() | ||||||
| 
 | 
 | ||||||
|         logging.warn("hello1") |         logging.warning("hello1") | ||||||
|         outerr = cap.readouterr() |         outerr = cap.readouterr() | ||||||
|         print("suspend, captured %%s" %%(outerr,)) |         print("suspend, captured %%s" %%(outerr,)) | ||||||
|         logging.warn("hello2") |         logging.warning("hello2") | ||||||
| 
 | 
 | ||||||
|         cap.pop_outerr_to_orig() |         cap.pop_outerr_to_orig() | ||||||
|         logging.warn("hello3") |         logging.warning("hello3") | ||||||
| 
 | 
 | ||||||
|         outerr = cap.readouterr() |         outerr = cap.readouterr() | ||||||
|         print("suspend2, captured %%s" %% (outerr,)) |         print("suspend2, captured %%s" %% (outerr,)) | ||||||
|  |  | ||||||
|  | @ -1083,6 +1083,33 @@ class TestOverrideIniArgs(object): | ||||||
|         config._preparse([], addopts=True) |         config._preparse([], addopts=True) | ||||||
|         assert config._override_ini == ["cache_dir=%s" % cache_dir] |         assert config._override_ini == ["cache_dir=%s" % cache_dir] | ||||||
| 
 | 
 | ||||||
|  |     def test_addopts_from_env_not_concatenated(self, monkeypatch): | ||||||
|  |         """PYTEST_ADDOPTS should not take values from normal args (#4265).""" | ||||||
|  |         from _pytest.config import get_config | ||||||
|  | 
 | ||||||
|  |         monkeypatch.setenv("PYTEST_ADDOPTS", "-o") | ||||||
|  |         config = get_config() | ||||||
|  |         with pytest.raises(SystemExit) as excinfo: | ||||||
|  |             config._preparse(["cache_dir=ignored"], addopts=True) | ||||||
|  |         assert excinfo.value.args[0] == _pytest.main.EXIT_USAGEERROR | ||||||
|  | 
 | ||||||
|  |     def test_addopts_from_ini_not_concatenated(self, testdir): | ||||||
|  |         """addopts from ini should not take values from normal args (#4265).""" | ||||||
|  |         testdir.makeini( | ||||||
|  |             """ | ||||||
|  |             [pytest] | ||||||
|  |             addopts=-o | ||||||
|  |         """ | ||||||
|  |         ) | ||||||
|  |         result = testdir.runpytest("cache_dir=ignored") | ||||||
|  |         result.stderr.fnmatch_lines( | ||||||
|  |             [ | ||||||
|  |                 "%s: error: argument -o/--override-ini: expected one argument" | ||||||
|  |                 % (testdir.request.config._parser.optparser.prog,) | ||||||
|  |             ] | ||||||
|  |         ) | ||||||
|  |         assert result.ret == _pytest.main.EXIT_USAGEERROR | ||||||
|  | 
 | ||||||
|     def test_override_ini_does_not_contain_paths(self): |     def test_override_ini_does_not_contain_paths(self): | ||||||
|         """Check that -o no longer swallows all options after it (#3103)""" |         """Check that -o no longer swallows all options after it (#3103)""" | ||||||
|         from _pytest.config import get_config |         from _pytest.config import get_config | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue