diff --git a/AUTHORS b/AUTHORS index 0492a1659..862378be9 100644 --- a/AUTHORS +++ b/AUTHORS @@ -78,6 +78,7 @@ Henk-Jaap Wagenaar Hugo van Kemenade Hui Wang (coldnight) Ian Bicking +Ian Lesperance Jaap Broekhuizen Jan Balster Janne Vanhala @@ -178,6 +179,7 @@ Tom Dalton Tom Viner Trevor Bekolay Tyler Goodlet +Tzu-ping Chung Vasily Kuznetsov Victor Uriarte Vidar T. Fauske diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5c2ed1759..b72db97a9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,43 @@ .. towncrier release notes start +Pytest 3.3.2 (2017-12-25) +========================= + +Bug Fixes +--------- + +- pytester: ignore files used to obtain current user metadata in the fd leak + detector. (`#2784 `_) + +- Fix **memory leak** where objects returned by fixtures were never destructed + by the garbage collector. (`#2981 + `_) + +- Fix conversion of pyargs to filename to not convert symlinks on Python 2. (`#2985 + `_) + +- ``PYTEST_DONT_REWRITE`` is now checked for plugins too rather than only for + test modules. (`#2995 `_) + + +Improved Documentation +---------------------- + +- Add clarifying note about behavior of multiple parametrized arguments (`#3001 + `_) + + +Trivial/Internal Changes +------------------------ + +- Code cleanup. (`#3015 `_, + `#3021 `_) + +- Clean up code by replacing imports and references of `_ast` to `ast`. (`#3018 + `_) + + Pytest 3.3.1 (2017-12-05) ========================= diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index d85a894b9..79be79fa6 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -276,3 +276,15 @@ Here is a simple overview, with pytest-specific bits: base: features # if it's a feature +Joining the Development Team +---------------------------- + +Anyone who has successfully seen through a pull request which did not +require any extra work from the development team to merge will +themselves gain commit access if they so wish (if we forget to ask please send a friendly +reminder). This does not mean your workflow to contribute changes, +everyone goes through the same pull-request-and-review process and +no-one merges their own pull requests unless already approved. It does however mean you can +participate in the development process more fully since you can merge +pull requests from other contributors yourself after having reviewed +them. diff --git a/_pytest/pytester.py b/_pytest/pytester.py index f02007dec..1ea851785 100644 --- a/_pytest/pytester.py +++ b/_pytest/pytester.py @@ -26,6 +26,11 @@ from _pytest.assertion.rewrite import AssertionRewritingHook PYTEST_FULLPATH = os.path.abspath(pytest.__file__.rstrip("oc")).replace("$py.class", ".py") +IGNORE_PAM = [ # filenames added when obtaining details about the current user + u'/var/lib/sss/mc/passwd' +] + + def pytest_addoption(parser): parser.addoption('--lsof', action="store_true", dest="lsof", default=False, @@ -66,6 +71,8 @@ class LsofFdLeakChecker(object): fields = line.split('\0') fd = fields[0][1:] filename = fields[1][1:] + if filename in IGNORE_PAM: + continue if filename.startswith('/'): open_files.append((fd, filename)) diff --git a/_pytest/python.py b/_pytest/python.py index 9a89ae10f..735489e48 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -30,9 +30,17 @@ from _pytest.compat import ( from _pytest.outcomes import fail from _pytest.mark import transfer_markers -cutdir1 = py.path.local(pluggy.__file__.rstrip("oc")) -cutdir2 = py.path.local(_pytest.__file__).dirpath() -cutdir3 = py.path.local(py.__file__).dirpath() + +# relative paths that we use to filter traceback entries from appearing to the user; +# see filter_traceback +# note: if we need to add more paths than what we have now we should probably use a list +# for better maintenance +_pluggy_dir = py.path.local(pluggy.__file__.rstrip("oc")) +# pluggy is either a package or a single module depending on the version +if _pluggy_dir.basename == '__init__.py': + _pluggy_dir = _pluggy_dir.dirpath() +_pytest_dir = py.path.local(_pytest.__file__).dirpath() +_py_dir = py.path.local(py.__file__).dirpath() def filter_traceback(entry): @@ -47,10 +55,10 @@ def filter_traceback(entry): is_generated = '<' in raw_filename and '>' in raw_filename if is_generated: return False - # entry.path might point to an inexisting file, in which case it will - # alsso return a str object. see #1133 + # entry.path might point to an non-existing file, in which case it will + # also return a str object. see #1133 p = py.path.local(entry.path) - return p != cutdir1 and not p.relto(cutdir2) and not p.relto(cutdir3) + return not p.relto(_pluggy_dir) and not p.relto(_pytest_dir) and not p.relto(_py_dir) def pyobj_property(name): @@ -563,7 +571,6 @@ class FunctionMixin(PyobjMixin): if ntraceback == traceback: ntraceback = ntraceback.cut(path=path) if ntraceback == traceback: - # ntraceback = ntraceback.cut(excludepath=cutdir2) ntraceback = ntraceback.filter(filter_traceback) if not ntraceback: ntraceback = traceback diff --git a/_pytest/skipping.py b/_pytest/skipping.py index a1e5b4380..98fc51c7f 100644 --- a/_pytest/skipping.py +++ b/_pytest/skipping.py @@ -261,7 +261,7 @@ def pytest_runtest_makereport(item, call): else: rep.outcome = "passed" rep.wasxfail = explanation - elif item._skipped_by_mark and rep.skipped and type(rep.longrepr) is tuple: + elif getattr(item, '_skipped_by_mark', False) and rep.skipped and type(rep.longrepr) is tuple: # skipped by mark.skipif; change the location of the failure # to point to the item definition, otherwise it will display # the location of where the skip exception was raised within pytest diff --git a/changelog/2981.bugfix b/changelog/2981.bugfix deleted file mode 100644 index fd6dde37a..000000000 --- a/changelog/2981.bugfix +++ /dev/null @@ -1 +0,0 @@ -Fix **memory leak** where objects returned by fixtures were never destructed by the garbage collector. diff --git a/changelog/2985.bugfix b/changelog/2985.bugfix deleted file mode 100644 index 1a268c0c5..000000000 --- a/changelog/2985.bugfix +++ /dev/null @@ -1 +0,0 @@ -Fix conversion of pyargs to filename to not convert symlinks and not use deprecated features on Python 3. diff --git a/changelog/2995.bugfix b/changelog/2995.bugfix deleted file mode 100644 index 7a3dde4c8..000000000 --- a/changelog/2995.bugfix +++ /dev/null @@ -1 +0,0 @@ -``PYTEST_DONT_REWRITE`` is now checked for plugins too rather than only for test modules. diff --git a/changelog/3015.trivial b/changelog/3015.trivial deleted file mode 100644 index a63ba06e6..000000000 --- a/changelog/3015.trivial +++ /dev/null @@ -1 +0,0 @@ -Code cleanup. diff --git a/changelog/3018.trivial b/changelog/3018.trivial deleted file mode 100644 index 8b4b4176b..000000000 --- a/changelog/3018.trivial +++ /dev/null @@ -1 +0,0 @@ -Clean up code by replacing imports and references of `_ast` to `ast`. diff --git a/changelog/3021.trivial b/changelog/3021.trivial deleted file mode 100644 index a63ba06e6..000000000 --- a/changelog/3021.trivial +++ /dev/null @@ -1 +0,0 @@ -Code cleanup. diff --git a/changelog/3074.bugfix b/changelog/3074.bugfix new file mode 100644 index 000000000..814f26ff1 --- /dev/null +++ b/changelog/3074.bugfix @@ -0,0 +1 @@ +Fix skipping plugin reporting hook when test aborted before plugin setup hook. diff --git a/changelog/3076.doc b/changelog/3076.doc new file mode 100644 index 000000000..2958af781 --- /dev/null +++ b/changelog/3076.doc @@ -0,0 +1 @@ +Fix the wording of a sentence on doctest flags use in pytest. diff --git a/changelog/3092.doc b/changelog/3092.doc new file mode 100644 index 000000000..6001b8e22 --- /dev/null +++ b/changelog/3092.doc @@ -0,0 +1 @@ +Prefer ``https://*.readthedocs.io`` over ``http://*.rtfd.org`` for links in the documentation. diff --git a/doc/en/announce/index.rst b/doc/en/announce/index.rst index b6255bc6d..bc8d46f1f 100644 --- a/doc/en/announce/index.rst +++ b/doc/en/announce/index.rst @@ -6,6 +6,7 @@ Release announcements :maxdepth: 2 + release-3.3.2 release-3.3.1 release-3.3.0 release-3.2.5 diff --git a/doc/en/announce/release-3.3.2.rst b/doc/en/announce/release-3.3.2.rst new file mode 100644 index 000000000..a994aff25 --- /dev/null +++ b/doc/en/announce/release-3.3.2.rst @@ -0,0 +1,28 @@ +pytest-3.3.2 +======================================= + +pytest 3.3.2 has just been released to PyPI. + +This is a bug-fix release, being a drop-in replacement. To upgrade:: + + pip install --upgrade pytest + +The full changelog is available at http://doc.pytest.org/en/latest/changelog.html. + +Thanks to all who contributed to this release, among them: + +* Anthony Sottile +* Antony Lee +* Austin +* Bruno Oliveira +* Florian Bruhin +* Floris Bruynooghe +* Henk-Jaap Wagenaar +* Jurko Gospodnetić +* Ronny Pfannschmidt +* Srinivas Reddy Thatiparthy +* Thomas Hisch + + +Happy testing, +The pytest Development Team diff --git a/doc/en/doctest.rst b/doc/en/doctest.rst index 4c5a878dd..61fbe04d4 100644 --- a/doc/en/doctest.rst +++ b/doc/en/doctest.rst @@ -81,9 +81,9 @@ Also, :ref:`usefixtures` and :ref:`autouse` fixtures are supported when executing text doctest files. The standard ``doctest`` module provides some setting flags to configure the -strictness of doctest tests. In pytest You can enable those flags those flags -using the configuration file. To make pytest ignore trailing whitespaces and -ignore lengthy exception stack traces you can just write: +strictness of doctest tests. In pytest, you can enable those flags using the +configuration file. To make pytest ignore trailing whitespaces and ignore +lengthy exception stack traces you can just write: .. code-block:: ini diff --git a/doc/en/example/simple.rst b/doc/en/example/simple.rst index 678a0db00..9c773aaed 100644 --- a/doc/en/example/simple.rst +++ b/doc/en/example/simple.rst @@ -385,9 +385,9 @@ Now we can profile which test functions execute the slowest:: test_some_are_slow.py ... [100%] ========================= slowest 3 test durations ========================= - 0.30s call test_some_are_slow.py::test_funcslow2 + 0.31s call test_some_are_slow.py::test_funcslow2 0.20s call test_some_are_slow.py::test_funcslow1 - 0.10s call test_some_are_slow.py::test_funcfast + 0.17s call test_some_are_slow.py::test_funcfast ========================= 3 passed in 0.12 seconds ========================= incremental testing - test steps diff --git a/doc/en/parametrize.rst b/doc/en/parametrize.rst index 7a4ac2e18..7bc37ae38 100644 --- a/doc/en/parametrize.rst +++ b/doc/en/parametrize.rst @@ -123,8 +123,8 @@ To get all combinations of multiple parametrized arguments you can stack def test_foo(x, y): pass -This will run the test with the arguments set to ``x=0/y=2``, ``x=0/y=3``, ``x=1/y=2`` and -``x=1/y=3``. +This will run the test with the arguments set to ``x=0/y=2``,``x=1/y=2``, +``x=0/y=3``, and ``x=1/y=3`` exhausting parameters in the order of the decorators. .. _`pytest_generate_tests`: diff --git a/doc/en/projects.rst b/doc/en/projects.rst index 86df99ab2..51f2d94fd 100644 --- a/doc/en/projects.rst +++ b/doc/en/projects.rst @@ -37,7 +37,7 @@ Here are some examples of projects using ``pytest`` (please send notes via :ref: * `mwlib `_ mediawiki parser and utility library * `The Translate Toolkit `_ for localization and conversion * `execnet `_ rapid multi-Python deployment -* `pylib `_ cross-platform path, IO, dynamic code library +* `pylib `_ cross-platform path, IO, dynamic code library * `Pacha `_ configuration management in five minutes * `bbfreeze `_ create standalone executables from Python scripts * `pdb++ `_ a fancier version of PDB diff --git a/doc/en/tmpdir.rst b/doc/en/tmpdir.rst index b8174484e..b9c371e40 100644 --- a/doc/en/tmpdir.rst +++ b/doc/en/tmpdir.rst @@ -106,6 +106,4 @@ When distributing tests on the local machine, ``pytest`` takes care to configure a basetemp directory for the sub processes such that all temporary data lands below a single per-test run basetemp directory. -.. _`py.path.local`: http://py.rtfd.org/en/latest/path.html - - +.. _`py.path.local`: https://py.readthedocs.io/en/latest/path.html diff --git a/doc/en/writing_plugins.rst b/doc/en/writing_plugins.rst index 0b3bafa37..9a74d6b4e 100644 --- a/doc/en/writing_plugins.rst +++ b/doc/en/writing_plugins.rst @@ -596,6 +596,7 @@ Generic "runtest" hooks All runtest related hooks receive a :py:class:`pytest.Item <_pytest.main.Item>` object. +.. autofunction:: pytest_runtestloop .. autofunction:: pytest_runtest_protocol .. autofunction:: pytest_runtest_setup .. autofunction:: pytest_runtest_call diff --git a/setup.py b/setup.py index 3eb38efe6..e08be845e 100644 --- a/setup.py +++ b/setup.py @@ -23,23 +23,34 @@ with open('README.rst') as fd: long_description = fd.read() -def has_environment_marker_support(): +def get_environment_marker_support_level(): """ - Tests that setuptools has support for PEP-426 environment marker support. + Tests how well setuptools supports PEP-426 environment marker. The first known release to support it is 0.7 (and the earliest on PyPI seems to be 0.7.2 - so we're using that), see: http://pythonhosted.org/setuptools/history.html#id142 + so we're using that), see: https://setuptools.readthedocs.io/en/latest/history.html#id350 + + The support is later enhanced to allow direct conditional inclusions inside install_requires, + which is now recommended by setuptools. It first appeared in 36.2.0, went broken with 36.2.1, and + again worked since 36.2.2, so we're using that. See: + https://setuptools.readthedocs.io/en/latest/history.html#v36-2-2 + https://github.com/pypa/setuptools/issues/1099 References: * https://wheel.readthedocs.io/en/latest/index.html#defining-conditional-dependencies * https://www.python.org/dev/peps/pep-0426/#environment-markers + * https://setuptools.readthedocs.io/en/latest/setuptools.html#declaring-platform-specific-dependencies """ try: - return pkg_resources.parse_version(setuptools.__version__) >= pkg_resources.parse_version('0.7.2') + version = pkg_resources.parse_version(setuptools.__version__) + if version >= pkg_resources.parse_version('36.2.2'): + return 2 + if version >= pkg_resources.parse_version('0.7.2'): + return 1 except Exception as exc: sys.stderr.write("Could not test setuptool's version: %s\n" % exc) - return False + return 0 def main(): @@ -54,7 +65,11 @@ def main(): # used by tox.ini to test with pluggy master if '_PYTEST_SETUP_SKIP_PLUGGY_DEP' not in os.environ: install_requires.append('pluggy>=0.5,<0.7') - if has_environment_marker_support(): + environment_marker_support_level = get_environment_marker_support_level() + if environment_marker_support_level >= 2: + install_requires.append('funcsigs;python_version<"3.0"') + install_requires.append('colorama;sys_platform=="win32"') + elif environment_marker_support_level == 1: extras_require[':python_version<"3.0"'] = ['funcsigs'] extras_require[':sys_platform=="win32"'] = ['colorama'] else: diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index 34843067d..729e93b7f 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -653,6 +653,13 @@ class TestInvocationVariants(object): test --pyargs option with packages with path containing symlink can have conftest.py in their package (#2985) """ + # dummy check that we can actually create symlinks: on Windows `os.symlink` is available, + # but normal users require special admin privileges to create symlinks. + if sys.platform == 'win32': + try: + os.symlink(str(testdir.tmpdir.ensure('tmpfile')), str(testdir.tmpdir.join('tmpfile2'))) + except OSError as e: + pytest.skip(six.text_type(e.args[0])) monkeypatch.delenv('PYTHONDONTWRITEBYTECODE', raising=False) search_path = ["lib", os.path.join("local", "lib")] diff --git a/testing/code/test_excinfo.py b/testing/code/test_excinfo.py index 34db8ffa1..58b1b1b67 100644 --- a/testing/code/test_excinfo.py +++ b/testing/code/test_excinfo.py @@ -542,7 +542,7 @@ raise ValueError() tb = FakeRawTB() excinfo.traceback = Traceback(tb) - fail = IOError() # noqa + fail = IOError() repr = pr.repr_excinfo(excinfo) assert repr.reprtraceback.reprentries[0].lines[0] == "> ???" if py.std.sys.version_info[0] >= 3: diff --git a/testing/test_runner.py b/testing/test_runner.py index c8e2a6463..a8dc8dfbd 100644 --- a/testing/test_runner.py +++ b/testing/test_runner.py @@ -32,7 +32,7 @@ class TestSetupState(object): def setup_module(mod): raise ValueError(42) def test_func(): pass - """) # noqa + """) ss = runner.SetupState() pytest.raises(ValueError, lambda: ss.prepare(item)) pytest.raises(ValueError, lambda: ss.prepare(item)) @@ -564,7 +564,7 @@ def test_importorskip(monkeypatch): importorskip("asdlkj") try: - sys = importorskip("sys") # noqa + sys = importorskip("sys") assert sys == py.std.sys # path = pytest.importorskip("os.path") # assert path == py.std.os.path diff --git a/testing/test_skipping.py b/testing/test_skipping.py index 978944876..db4e6d3f7 100644 --- a/testing/test_skipping.py +++ b/testing/test_skipping.py @@ -589,7 +589,7 @@ class TestSkipif(object): @pytest.mark.skipif("hasattr(os, 'sep')") def test_func(): pass - """) # noqa + """) x = pytest.raises(pytest.skip.Exception, lambda: pytest_runtest_setup(item)) assert x.value.msg == "condition: hasattr(os, 'sep')" diff --git a/tox.ini b/tox.ini index f9ae03739..b90bd432d 100644 --- a/tox.ini +++ b/tox.ini @@ -216,6 +216,9 @@ filterwarnings = ignore:.*type argument to addoption.*:DeprecationWarning # produced by python >=3.5 on execnet (pytest-xdist) ignore:.*inspect.getargspec.*deprecated, use inspect.signature.*:DeprecationWarning + # ignore warning about package resolution using __spec__ or __package__ + # should be a temporary solution, see #3061 for discussion + ignore:.*can't resolve package from __spec__ or __package__.*:ImportWarning [flake8] max-line-length = 120