From 4c62cd451a44959f3f2ce3b55f94e4dff9ab0f94 Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Thu, 17 Nov 2016 21:25:22 +0000 Subject: [PATCH 01/26] Add section about how you become a committer --- CONTRIBUTING.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 19b31c7f4..d8f806be6 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -236,3 +236,15 @@ but here is a simple overview: 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 we forget 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. It however means you can +participate in the development process more fully since you can merge +pull requests from other contributors yourself after having reviewed +them. From 1f0d06641a3f0dbea673f1b2468c6a40da5861e1 Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Sun, 19 Feb 2017 15:16:34 -0300 Subject: [PATCH 02/26] Update text to only give access when wanted Also clarify merging perms given the PR approval now available. --- CONTRIBUTING.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index d8f806be6..42c9f645b 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -241,10 +241,10 @@ 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 we forget please send a friendly +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. It however means you can +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. From 586ecea6f219d70d4075434b84a3784ec7cc948d Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 13 Dec 2017 20:06:49 -0200 Subject: [PATCH 03/26] Check if symlink does not privileges on Windows for test_cmdline_python_package_symlink os.symlink might fail on Windows because users require a special policy to create symlinks (argh). This is not a problem on AppVeyor because it is logged in as an admin, but would be surprising for Windows users running pytest's test suite on their computer. --- testing/acceptance_test.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index 9da9091db..8f7de99f0 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")] From c90e76c371c20ef27655334274add16fe3d34baf Mon Sep 17 00:00:00 2001 From: Austin Date: Sat, 16 Dec 2017 08:25:02 -0600 Subject: [PATCH 04/26] Clarifiyng documentation for parameterize - Added snippet dealing with parameterize run order of tests --- doc/en/parametrize.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/doc/en/parametrize.rst b/doc/en/parametrize.rst index 7a4ac2e18..b1d62d486 100644 --- a/doc/en/parametrize.rst +++ b/doc/en/parametrize.rst @@ -126,6 +126,22 @@ To get all combinations of multiple parametrized arguments you can stack 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``. +Due to how decorators work it runs in reverse of expected order. +In this case:: + + $ pytest + =========================== test session starts ============================ + platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y + rootdir: $REGENDOC_TMPDIR, inifile: + collected 4 items + + test.py::test_foo[2-0] PASSED [ 25%] + test.py::test_foo[2-1] PASSED [ 50%] + test.py::test_foo[3-0] PASSED [ 75%] + test.py::test_foo[3-1] PASSED [100%] + + ========================== 4 passed in 0.01 seconds ======================== + .. _`pytest_generate_tests`: Basic ``pytest_generate_tests`` example From d7a76a4d07c9dc778c3d1ab6bbb783f8b95da719 Mon Sep 17 00:00:00 2001 From: Austin Date: Sat, 16 Dec 2017 09:04:18 -0600 Subject: [PATCH 05/26] Updated for more clarity - Changed original wording for parameterize. Should help be a little more clear --- doc/en/parametrize.rst | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/doc/en/parametrize.rst b/doc/en/parametrize.rst index b1d62d486..310e05d21 100644 --- a/doc/en/parametrize.rst +++ b/doc/en/parametrize.rst @@ -126,21 +126,9 @@ To get all combinations of multiple parametrized arguments you can stack 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``. -Due to how decorators work it runs in reverse of expected order. -In this case:: - - $ pytest - =========================== test session starts ============================ - platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y - rootdir: $REGENDOC_TMPDIR, inifile: - collected 4 items - - test.py::test_foo[2-0] PASSED [ 25%] - test.py::test_foo[2-1] PASSED [ 50%] - test.py::test_foo[3-0] PASSED [ 75%] - test.py::test_foo[3-1] PASSED [100%] - - ========================== 4 passed in 0.01 seconds ======================== +Note that due to how decorators work in python the tests actually exhaust parameters in +the order of the decorators. For example this program run in the order ``x=0/y=2``, +``x=1/y=2``, ``x=0/y=3``, and ``x=1/y=3``. .. _`pytest_generate_tests`: From 73eccb4c3676ca70bff9e69394dfd425d286ff65 Mon Sep 17 00:00:00 2001 From: Austin Date: Sat, 16 Dec 2017 09:21:27 -0600 Subject: [PATCH 06/26] Adding news fragment --- changelog/3001.doc | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog/3001.doc diff --git a/changelog/3001.doc b/changelog/3001.doc new file mode 100644 index 000000000..e9b4dbd52 --- /dev/null +++ b/changelog/3001.doc @@ -0,0 +1 @@ +Add clarifying note about behavior of multiple parametrized arguments From 70461d1eada70c24a4a511bf09ae670d22e899c8 Mon Sep 17 00:00:00 2001 From: Austin Date: Sat, 16 Dec 2017 09:31:48 -0600 Subject: [PATCH 07/26] Update parametrize.rst --- doc/en/parametrize.rst | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/doc/en/parametrize.rst b/doc/en/parametrize.rst index 310e05d21..7bc37ae38 100644 --- a/doc/en/parametrize.rst +++ b/doc/en/parametrize.rst @@ -123,12 +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``. - -Note that due to how decorators work in python the tests actually exhaust parameters in -the order of the decorators. For example this program run in the order ``x=0/y=2``, -``x=1/y=2``, ``x=0/y=3``, 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`: From 28a93b9eebf49b42c68d067106408766d54624cf Mon Sep 17 00:00:00 2001 From: Thomas Hisch Date: Wed, 13 Dec 2017 22:47:58 +0100 Subject: [PATCH 08/26] WIP #3013 --- _pytest/logging.py | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/_pytest/logging.py b/_pytest/logging.py index 9e82e801d..071387902 100644 --- a/_pytest/logging.py +++ b/_pytest/logging.py @@ -76,6 +76,9 @@ def pytest_addoption(parser): '--log-file-date-format', dest='log_file_date_format', default=DEFAULT_LOG_DATE_FORMAT, help='log date format as used by the logging module.') + add_option_ini( + '--capture-log', choices=['on-failure', 'off', 'live'], + dest='capture_log', default='on-failure') @contextmanager @@ -117,6 +120,16 @@ class LogCaptureHandler(logging.StreamHandler): logging.StreamHandler.emit(self, record) +class TerminalWriterHandler(logging.Handler): + def __init__(self): + # TODO sys.stderr is captured by default ?!??! + self.tw = py.io.TerminalWriter(sys.stderr) + super(TerminalWriterHandler, self).__init__() + + def emit(self, record): + self.tw.write(self.format(record)) + + class LogCaptureFixture(object): """Provides access and control of log capturing.""" @@ -241,6 +254,8 @@ class LoggingPlugin(object): The formatter can be safely shared across all handlers so create a single one for the entire test session here. """ + self.capture_log = get_option_ini(config, 'capture_log') + self.log_cli_level = get_actual_log_level( config, 'log_cli_level', 'log_level') or logging.WARNING @@ -249,18 +264,14 @@ class LoggingPlugin(object): get_option_ini(config, 'log_format'), get_option_ini(config, 'log_date_format')) - log_cli_handler = logging.StreamHandler(sys.stderr) + log_cli_format = get_option_ini( config, 'log_cli_format', 'log_format') log_cli_date_format = get_option_ini( config, 'log_cli_date_format', 'log_date_format') - log_cli_formatter = logging.Formatter( + self.log_cli_formatter = logging.Formatter( log_cli_format, datefmt=log_cli_date_format) - self.log_cli_handler = log_cli_handler # needed for a single unittest - self.live_logs = catching_logs(log_cli_handler, - formatter=log_cli_formatter, - level=self.log_cli_level) log_file = get_option_ini(config, 'log_file') if log_file: @@ -316,7 +327,20 @@ class LoggingPlugin(object): @pytest.hookimpl(hookwrapper=True) def pytest_runtestloop(self, session): """Runs all collected test items.""" - with self.live_logs: + + # TODO what should happen at the end of the tests? + if self.capture_log == 'live': + with catching_logs(TerminalWriterHandler(), + formatter=self.log_cli_formatter, + level=self.log_cli_level): + if self.log_file_handler is not None: + with closing(self.log_file_handler): + with catching_logs(self.log_file_handler, + level=self.log_file_level): + yield # run all the tests + else: + yield # run all the tests + elif self.capture_log == 'on-failure': if self.log_file_handler is not None: with closing(self.log_file_handler): with catching_logs(self.log_file_handler, @@ -324,3 +348,7 @@ class LoggingPlugin(object): yield # run all the tests else: yield # run all the tests + elif self.capture_log == 'off': + yield + else: + raise ValueError('capture_log: %s' % capture_log) From d6f75d28364b4434217b45b261573f07569f5cd8 Mon Sep 17 00:00:00 2001 From: Thomas Hisch Date: Sun, 17 Dec 2017 20:11:24 +0100 Subject: [PATCH 09/26] WIP --- _pytest/logging.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/_pytest/logging.py b/_pytest/logging.py index 071387902..8e0a2dcc0 100644 --- a/_pytest/logging.py +++ b/_pytest/logging.py @@ -5,6 +5,7 @@ from contextlib import closing, contextmanager import sys import six +import _pytest import pytest import py @@ -120,14 +121,15 @@ class LogCaptureHandler(logging.StreamHandler): logging.StreamHandler.emit(self, record) -class TerminalWriterHandler(logging.Handler): - def __init__(self): - # TODO sys.stderr is captured by default ?!??! - self.tw = py.io.TerminalWriter(sys.stderr) - super(TerminalWriterHandler, self).__init__() +class TerminalReporterHandler(logging.Handler): + def __init__(self, reporter): + self.reporter = reporter + super(TerminalReporterHandler, self).__init__() def emit(self, record): - self.tw.write(self.format(record)) + # FIXME: I don't get any output with the reporter obj + # self.reporter.write(self.format(record)) + print(self.format(record)) class LogCaptureFixture(object): @@ -264,7 +266,6 @@ class LoggingPlugin(object): get_option_ini(config, 'log_format'), get_option_ini(config, 'log_date_format')) - log_cli_format = get_option_ini( config, 'log_cli_format', 'log_format') log_cli_date_format = get_option_ini( @@ -273,6 +274,8 @@ class LoggingPlugin(object): log_cli_format, datefmt=log_cli_date_format) + self.reporter = _pytest.config.create_terminal_writer(config, sys.stdout) + log_file = get_option_ini(config, 'log_file') if log_file: self.log_file_level = get_actual_log_level( @@ -296,6 +299,10 @@ class LoggingPlugin(object): @contextmanager def _runtest_for(self, item, when): """Implements the internals of pytest_runtest_xxx() hook.""" + if self.capture_log != 'on-failure': + yield + return + with catching_logs(LogCaptureHandler(), formatter=self.formatter) as log_handler: item.catch_log_handler = log_handler @@ -328,9 +335,8 @@ class LoggingPlugin(object): def pytest_runtestloop(self, session): """Runs all collected test items.""" - # TODO what should happen at the end of the tests? if self.capture_log == 'live': - with catching_logs(TerminalWriterHandler(), + with catching_logs(TerminalReporterHandler(self.reporter), formatter=self.log_cli_formatter, level=self.log_cli_level): if self.log_file_handler is not None: From 76489d30f7452bd9e6053eff624920cd2826e607 Mon Sep 17 00:00:00 2001 From: Thomas Hisch Date: Sun, 17 Dec 2017 21:49:57 +0100 Subject: [PATCH 10/26] Revert "WIP" This reverts commit d6f75d28364b4434217b45b261573f07569f5cd8. --- _pytest/logging.py | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/_pytest/logging.py b/_pytest/logging.py index 8e0a2dcc0..071387902 100644 --- a/_pytest/logging.py +++ b/_pytest/logging.py @@ -5,7 +5,6 @@ from contextlib import closing, contextmanager import sys import six -import _pytest import pytest import py @@ -121,15 +120,14 @@ class LogCaptureHandler(logging.StreamHandler): logging.StreamHandler.emit(self, record) -class TerminalReporterHandler(logging.Handler): - def __init__(self, reporter): - self.reporter = reporter - super(TerminalReporterHandler, self).__init__() +class TerminalWriterHandler(logging.Handler): + def __init__(self): + # TODO sys.stderr is captured by default ?!??! + self.tw = py.io.TerminalWriter(sys.stderr) + super(TerminalWriterHandler, self).__init__() def emit(self, record): - # FIXME: I don't get any output with the reporter obj - # self.reporter.write(self.format(record)) - print(self.format(record)) + self.tw.write(self.format(record)) class LogCaptureFixture(object): @@ -266,6 +264,7 @@ class LoggingPlugin(object): get_option_ini(config, 'log_format'), get_option_ini(config, 'log_date_format')) + log_cli_format = get_option_ini( config, 'log_cli_format', 'log_format') log_cli_date_format = get_option_ini( @@ -274,8 +273,6 @@ class LoggingPlugin(object): log_cli_format, datefmt=log_cli_date_format) - self.reporter = _pytest.config.create_terminal_writer(config, sys.stdout) - log_file = get_option_ini(config, 'log_file') if log_file: self.log_file_level = get_actual_log_level( @@ -299,10 +296,6 @@ class LoggingPlugin(object): @contextmanager def _runtest_for(self, item, when): """Implements the internals of pytest_runtest_xxx() hook.""" - if self.capture_log != 'on-failure': - yield - return - with catching_logs(LogCaptureHandler(), formatter=self.formatter) as log_handler: item.catch_log_handler = log_handler @@ -335,8 +328,9 @@ class LoggingPlugin(object): def pytest_runtestloop(self, session): """Runs all collected test items.""" + # TODO what should happen at the end of the tests? if self.capture_log == 'live': - with catching_logs(TerminalReporterHandler(self.reporter), + with catching_logs(TerminalWriterHandler(), formatter=self.log_cli_formatter, level=self.log_cli_level): if self.log_file_handler is not None: From dfc5399cd7cae90fd355011fbd025fd200e6337d Mon Sep 17 00:00:00 2001 From: Thomas Hisch Date: Sun, 17 Dec 2017 21:50:17 +0100 Subject: [PATCH 11/26] Revert "WIP #3013" This reverts commit 28a93b9eebf49b42c68d067106408766d54624cf. --- _pytest/logging.py | 42 +++++++----------------------------------- 1 file changed, 7 insertions(+), 35 deletions(-) diff --git a/_pytest/logging.py b/_pytest/logging.py index 071387902..9e82e801d 100644 --- a/_pytest/logging.py +++ b/_pytest/logging.py @@ -76,9 +76,6 @@ def pytest_addoption(parser): '--log-file-date-format', dest='log_file_date_format', default=DEFAULT_LOG_DATE_FORMAT, help='log date format as used by the logging module.') - add_option_ini( - '--capture-log', choices=['on-failure', 'off', 'live'], - dest='capture_log', default='on-failure') @contextmanager @@ -120,16 +117,6 @@ class LogCaptureHandler(logging.StreamHandler): logging.StreamHandler.emit(self, record) -class TerminalWriterHandler(logging.Handler): - def __init__(self): - # TODO sys.stderr is captured by default ?!??! - self.tw = py.io.TerminalWriter(sys.stderr) - super(TerminalWriterHandler, self).__init__() - - def emit(self, record): - self.tw.write(self.format(record)) - - class LogCaptureFixture(object): """Provides access and control of log capturing.""" @@ -254,8 +241,6 @@ class LoggingPlugin(object): The formatter can be safely shared across all handlers so create a single one for the entire test session here. """ - self.capture_log = get_option_ini(config, 'capture_log') - self.log_cli_level = get_actual_log_level( config, 'log_cli_level', 'log_level') or logging.WARNING @@ -264,14 +249,18 @@ class LoggingPlugin(object): get_option_ini(config, 'log_format'), get_option_ini(config, 'log_date_format')) - + log_cli_handler = logging.StreamHandler(sys.stderr) log_cli_format = get_option_ini( config, 'log_cli_format', 'log_format') log_cli_date_format = get_option_ini( config, 'log_cli_date_format', 'log_date_format') - self.log_cli_formatter = logging.Formatter( + log_cli_formatter = logging.Formatter( log_cli_format, datefmt=log_cli_date_format) + self.log_cli_handler = log_cli_handler # needed for a single unittest + self.live_logs = catching_logs(log_cli_handler, + formatter=log_cli_formatter, + level=self.log_cli_level) log_file = get_option_ini(config, 'log_file') if log_file: @@ -327,20 +316,7 @@ class LoggingPlugin(object): @pytest.hookimpl(hookwrapper=True) def pytest_runtestloop(self, session): """Runs all collected test items.""" - - # TODO what should happen at the end of the tests? - if self.capture_log == 'live': - with catching_logs(TerminalWriterHandler(), - formatter=self.log_cli_formatter, - level=self.log_cli_level): - if self.log_file_handler is not None: - with closing(self.log_file_handler): - with catching_logs(self.log_file_handler, - level=self.log_file_level): - yield # run all the tests - else: - yield # run all the tests - elif self.capture_log == 'on-failure': + with self.live_logs: if self.log_file_handler is not None: with closing(self.log_file_handler): with catching_logs(self.log_file_handler, @@ -348,7 +324,3 @@ class LoggingPlugin(object): yield # run all the tests else: yield # run all the tests - elif self.capture_log == 'off': - yield - else: - raise ValueError('capture_log: %s' % capture_log) From ed293ec3e9a83f443f70e1e6788b4b341e301cb7 Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Sat, 16 Sep 2017 21:20:04 +0200 Subject: [PATCH 12/26] pytester: no ignore files used to obtain current user metadata in the fd leak detector --- _pytest/pytester.py | 7 +++++++ changelog/2784.bugfix | 1 + 2 files changed, 8 insertions(+) create mode 100644 changelog/2784.bugfix diff --git a/_pytest/pytester.py b/_pytest/pytester.py index ee7ca24cd..a362e04ed 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/changelog/2784.bugfix b/changelog/2784.bugfix new file mode 100644 index 000000000..21e2e67bc --- /dev/null +++ b/changelog/2784.bugfix @@ -0,0 +1 @@ +pytester: ignore files used to obtain current user metadata in the fd leak detector. \ No newline at end of file From 205e29d843427e0ad211d48e56ac357aaaf1cdd5 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Fri, 22 Dec 2017 08:29:48 -0800 Subject: [PATCH 13/26] Remove unnecessary `# noqa` comments. Commit automated with https://github.com/asottile/yesqa --- testing/code/test_excinfo.py | 2 +- testing/test_runner.py | 4 ++-- testing/test_skipping.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) 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')" From bd2d0d2c3c9bf92711e5a858e93e46d390dd4229 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 25 Dec 2017 20:38:27 +0000 Subject: [PATCH 14/26] Preparing release version 3.3.2 --- CHANGELOG.rst | 38 +++++++++++++++++++++++++++++++ changelog/2784.bugfix | 1 - changelog/2981.bugfix | 1 - changelog/2985.bugfix | 1 - changelog/2995.bugfix | 1 - changelog/3001.doc | 1 - changelog/3015.trivial | 1 - changelog/3018.trivial | 1 - changelog/3021.trivial | 1 - doc/en/announce/index.rst | 1 + doc/en/announce/release-3.3.2.rst | 28 +++++++++++++++++++++++ doc/en/example/simple.rst | 4 ++-- 12 files changed, 69 insertions(+), 10 deletions(-) delete mode 100644 changelog/2784.bugfix delete mode 100644 changelog/2981.bugfix delete mode 100644 changelog/2985.bugfix delete mode 100644 changelog/2995.bugfix delete mode 100644 changelog/3001.doc delete mode 100644 changelog/3015.trivial delete mode 100644 changelog/3018.trivial delete mode 100644 changelog/3021.trivial create mode 100644 doc/en/announce/release-3.3.2.rst diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5c2ed1759..210f43b13 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,44 @@ .. 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 and not use + deprecated features on Python 3. (`#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/changelog/2784.bugfix b/changelog/2784.bugfix deleted file mode 100644 index 21e2e67bc..000000000 --- a/changelog/2784.bugfix +++ /dev/null @@ -1 +0,0 @@ -pytester: ignore files used to obtain current user metadata in the fd leak detector. \ No newline at end of file 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/3001.doc b/changelog/3001.doc deleted file mode 100644 index e9b4dbd52..000000000 --- a/changelog/3001.doc +++ /dev/null @@ -1 +0,0 @@ -Add clarifying note about behavior of multiple parametrized arguments 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/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/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 From 52a7ccef57c480ce7c1219a714ffa0a08fb9c5b3 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 3 Jan 2018 16:58:57 -0200 Subject: [PATCH 15/26] Add pytest_runtestloop to the docs --- doc/en/writing_plugins.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/en/writing_plugins.rst b/doc/en/writing_plugins.rst index 8320d2c6a..35fc7010d 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 From f24c470403aa0e34371850cb51a516a55dca7599 Mon Sep 17 00:00:00 2001 From: Ian Lesperance Date: Wed, 3 Jan 2018 18:47:18 -0500 Subject: [PATCH 16/26] Assume not skipped by mark if attribute missing Fixes #3074. --- _pytest/skipping.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 0a6e086f9def9830e66413fe65bf93de37af7b13 Mon Sep 17 00:00:00 2001 From: Ian Lesperance Date: Wed, 3 Jan 2018 18:53:32 -0500 Subject: [PATCH 17/26] Add changelog entry --- changelog/3074.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog/3074.bugfix 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. From 25b504b4f02c75a96acfcccddde458ed78aac22d Mon Sep 17 00:00:00 2001 From: Ian Lesperance Date: Wed, 3 Jan 2018 18:54:49 -0500 Subject: [PATCH 18/26] Add self to authors list --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 0492a1659..1a138091e 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 From 554cb8d09c4bef44b90215ebd6b5ba223200f373 Mon Sep 17 00:00:00 2001 From: Pierre-Alexandre Fonta Date: Thu, 4 Jan 2018 14:47:05 +0100 Subject: [PATCH 19/26] Reword strange sentence on doctest flags --- doc/en/doctest.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 From ac6f257efc022f95cbb02e2a9bc667b29410e529 Mon Sep 17 00:00:00 2001 From: Pierre-Alexandre Fonta Date: Thu, 4 Jan 2018 14:58:30 +0100 Subject: [PATCH 20/26] Create news fragment for the pull request --- changelog/3076.doc | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog/3076.doc 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. From b93aa5e35f8ea95d6ab74c1953dead2ea3a14688 Mon Sep 17 00:00:00 2001 From: Jon Dufresne Date: Sat, 6 Jan 2018 08:01:34 -0800 Subject: [PATCH 21/26] Prefer https://*.readthedocs.io over http://*.rtfd.org - Requests URL using https instead of http - Avoids unnecessary redirect of *.rtfd.org -> *.readthedocs.io *.rtfd.org exists as a means for pasting short URLs, which doesn't much apply for links in documentation. --- changelog/3092.doc | 1 + doc/en/projects.rst | 2 +- doc/en/tmpdir.rst | 4 +--- 3 files changed, 3 insertions(+), 4 deletions(-) create mode 100644 changelog/3092.doc diff --git a/changelog/3092.doc b/changelog/3092.doc new file mode 100644 index 000000000..fef526d2c --- /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/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 From f3c666db3c6ff5d16544ded10496513c1153e8e4 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sat, 6 Jan 2018 14:08:15 -0200 Subject: [PATCH 22/26] Small formatting update in CHANGELOG --- changelog/3092.doc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog/3092.doc b/changelog/3092.doc index fef526d2c..6001b8e22 100644 --- a/changelog/3092.doc +++ b/changelog/3092.doc @@ -1 +1 @@ -Prefer https://*.readthedocs.io over http://*.rtfd.org for links in the documentation. +Prefer ``https://*.readthedocs.io`` over ``http://*.rtfd.org`` for links in the documentation. From d7e1f037d971c5eab735268a7e86d3aaa7250de6 Mon Sep 17 00:00:00 2001 From: Henk-Jaap Wagenaar Date: Sat, 6 Jan 2018 22:15:06 +0000 Subject: [PATCH 23/26] Fix issue 2985 blurb in changelog --- CHANGELOG.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 210f43b13..b72db97a9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -21,8 +21,7 @@ Bug Fixes by the garbage collector. (`#2981 `_) -- Fix conversion of pyargs to filename to not convert symlinks and not use - deprecated features on Python 3. (`#2985 +- 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 From 3dd24f8d218408f421aa9c88b7343bbb54e423f8 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 8 Jan 2018 20:32:45 -0200 Subject: [PATCH 24/26] Ignore ImportWarnings regarding package resolution The problem is described/discussed in #3061 Ideally this should be a temporary solution until we find a proper one which gets rid of the warning --- tox.ini | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tox.ini b/tox.ini index 38ebaf69f..32996626a 100644 --- a/tox.ini +++ b/tox.ini @@ -215,6 +215,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 From b6b36bc167b1d05b9b8353e38e2cedd124d1f4e1 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 8 Jan 2018 21:27:53 -0200 Subject: [PATCH 25/26] Handle pluggy package or module for traceback filtering Since 0.6.1 pluggy has been turned into a package --- _pytest/python.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/_pytest/python.py b/_pytest/python.py index 650171a9e..3940028fa 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 From b256cd2a6a81e72cb0b7e61a842465a45c1640c9 Mon Sep 17 00:00:00 2001 From: Tzu-ping Chung Date: Tue, 9 Jan 2018 14:17:25 +0800 Subject: [PATCH 26/26] Add support for new environment marker usages --- AUTHORS | 1 + setup.py | 27 +++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/AUTHORS b/AUTHORS index 1a138091e..862378be9 100644 --- a/AUTHORS +++ b/AUTHORS @@ -179,6 +179,7 @@ Tom Dalton Tom Viner Trevor Bekolay Tyler Goodlet +Tzu-ping Chung Vasily Kuznetsov Victor Uriarte Vidar T. Fauske 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: