diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f75e83bbed6..70295eaef4e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,186 @@ .. towncrier release notes start +Pytest 3.3.0 (2017-11-23) +========================= + +Deprecations and Removals +------------------------- + +- Pytest no longer supports Python **2.6** and **3.3**. Those Python versions + are EOL for some time now and incur maintenance and compatibility costs on + the pytest core team, and following up with the rest of the community we + decided that they will no longer be supported starting on this version. Users + which still require those versions should pin pytest to ``<3.3``. (`#2812 + `_) + +- Remove internal ``_preloadplugins()`` function. This removal is part of the + ``pytest_namespace()`` hook deprecation. (`#2236 + `_) + +- Internally change ``CallSpec2`` to have a list of marks instead of a broken + mapping of keywords. This removes the keywords attribute of the internal + ``CallSpec2`` class. (`#2672 + `_) + +- Remove ParameterSet.deprecated_arg_dict - its not a public api and the lack + of the underscore was a naming error. (`#2675 + `_) + +- Remove the internal multi-typed attribute ``Node._evalskip`` and replace it + with the boolean ``Node._skipped_by_mark``. (`#2767 + `_) + +Features +-------- + +- ``pytest_fixture_post_finalizer`` hook can now receive a ``request`` + argument. (`#2124 `_) + +- Replace the old introspection code in compat.py that determines the available + arguments of fixtures with inspect.signature on Python 3 and + funcsigs.signature on Python 2. This should respect ``__signature__`` + declarations on functions. (`#2267 + `_) + +- Report tests with global ``pytestmark`` variable only once. (`#2549 + `_) + +- Now pytest displays the total progress percentage while running tests. The + previous output style can be set by configuring the ``console_output_style`` + setting to ``classic``. (`#2657 `_) + +- Match ``warns`` signature to ``raises`` by adding ``match`` keyword. (`#2708 + `_) + +- Pytest now captures and displays output from the standard `logging` module. + The user can control the logging level to be captured by specifying options + in ``pytest.ini``, the command line and also during individual tests using + markers. Also, a ``caplog`` fixture is available that enables users to test + the captured log during specific tests (similar to ``capsys`` for example). + For more information, please see the `logging docs + `_. This feature was + introduced by merging the popular `pytest-catchlog + `_ plugin, thanks to `Thomas Hisch + `_. Be advised that during the merging the + backward compatibility interface with the defunct ``pytest-capturelog`` has + been dropped. (`#2794 `_) + +- Add ``allow_module_level`` kwarg to ``pytest.skip()``, enabling to skip the + whole module. (`#2808 `_) + +- Allow setting ``file_or_dir``, ``-c``, and ``-o`` in PYTEST_ADDOPTS. (`#2824 + `_) + +- Return stdout/stderr capture results as a ``namedtuple``, so ``out`` and + ``err`` can be accessed by attribute. (`#2879 + `_) + +- Add ``capfdbinary``, a version of ``capfd`` which returns bytes from + ``readouterr()``. (`#2923 + `_) + +- Add ``capsysbinary`` a version of ``capsys`` which returns bytes from + ``readouterr()``. (`#2934 + `_) + +- Implement feature to skip ``setup.py`` files when run with + ``--doctest-modules``. (`#502 + `_) + + +Bug Fixes +--------- + +- Resume output capturing after ``capsys/capfd.disabled()`` context manager. + (`#1993 `_) + +- ``pytest_fixture_setup`` and ``pytest_fixture_post_finalizer`` hooks are now + called for all ``conftest.py`` files. (`#2124 + `_) + +- If an exception happens while loading a plugin, pytest no longer hides the + original traceback. In python2 it will show the original traceback with a new + message that explains in which plugin. In python3 it will show 2 canonized + exceptions, the original exception while loading the plugin in addition to an + exception that PyTest throws about loading a plugin. (`#2491 + `_) + +- ``capsys`` and ``capfd`` can now be used by other fixtures. (`#2709 + `_) + +- Internal ``pytester`` plugin properly encodes ``bytes`` arguments to + ``utf-8``. (`#2738 `_) + +- ``testdir`` now uses use the same method used by ``tmpdir`` to create its + temporary directory. This changes the final structure of the ``testdir`` + directory slightly, but should not affect usage in normal scenarios and + avoids a number of potential problems. (`#2751 + `_) + +- Pytest no longer complains about warnings with unicode messages being + non-ascii compatible even for ascii-compatible messages. As a result of this, + warnings with unicode messages are converted first to an ascii representation + for safety. (`#2809 `_) + +- Change return value of pytest command when ``--maxfail`` is reached from + ``2`` (interrupted) to ``1`` (failed). (`#2845 + `_) + +- Fix issue in assertion rewriting which could lead it to rewrite modules which + should not be rewritten. (`#2939 + `_) + +- Handle marks without description in ``pytest.ini``. (`#2942 + `_) + + +Trivial/Internal Changes +------------------------ + +- pytest now depends on `attrs `_ for internal + structures to ease code maintainability. (`#2641 + `_) + +- Refactored internal Python 2/3 compatibility code to use ``six``. (`#2642 + `_) + +- Stop vendoring ``pluggy`` - we're missing out on its latest changes for not + much benefit (`#2719 `_) + +- Internal refactor: simplify ascii string escaping by using the + backslashreplace error handler in newer Python 3 versions. (`#2734 + `_) + +- Remove unnecessary mark evaluator in unittest plugin (`#2767 + `_) + +- Calls to ``Metafunc.addcall`` now emit a deprecation warning. This function + is scheduled to be removed in ``pytest-4.0``. (`#2876 + `_) + +- Internal move of the parameterset extraction to a more maintainable place. + (`#2877 `_) + +- Internal refactoring to simplify scope node lookup. (`#2910 + `_) + +- Configure ``pytest`` to prevent pip from installing pytest in unsupported + Python versions. (`#2922 + `_) + + +Pytest 3.2.5 (2017-11-15) +========================= + +Bug Fixes +--------- + +- Remove ``py<1.5`` restriction from ``pytest`` as this can cause version + conflicts in some installations. (`#2926 + `_) + + Pytest 3.2.4 (2017-11-13) ========================= @@ -28,6 +208,8 @@ Bug Fixes failed example in the docstring is < 9. (`#2882 `_) +- Match fixture paths against actual path segments in order to avoid matching folders which share a prefix. + (`#2836 `_) Improved Documentation ---------------------- @@ -179,7 +361,7 @@ Deprecations and Removals ------------------------- - ``pytest.approx`` no longer supports ``>``, ``>=``, ``<`` and ``<=`` - operators to avoid surprising/inconsistent behavior. See `the docs + operators to avoid surprising/inconsistent behavior. See `the approx docs `_ for more information. (`#2003 `_) diff --git a/_pytest/assertion/rewrite.py b/_pytest/assertion/rewrite.py index 1ab474cf7f1..d0f90db9f0a 100644 --- a/_pytest/assertion/rewrite.py +++ b/_pytest/assertion/rewrite.py @@ -168,7 +168,7 @@ def _should_rewrite(self, name, fn_pypath, state): return True for marked in self._must_rewrite: - if name.startswith(marked): + if name == marked or name.startswith(marked + '.'): state.trace("matched marked file %r (from %r)" % (name, marked)) return True diff --git a/_pytest/config.py b/_pytest/config.py index b65ce9a514a..6eb2d6c5c90 100644 --- a/_pytest/config.py +++ b/_pytest/config.py @@ -242,6 +242,10 @@ def parse_hookspec_opts(self, module_or_class, name): return opts def register(self, plugin, name=None): + if name == 'pytest_catchlog': + self._warn('pytest-catchlog plugin has been merged into the core, ' + 'please remove it from your requirements.') + return ret = super(PytestPluginManager, self).register(plugin, name) if ret: self.hook.pytest_plugin_registered.call_historic( @@ -931,7 +935,7 @@ def warn(self, code, message, fslocation=None, nodeid=None): fslocation=fslocation, nodeid=nodeid)) def get_terminal_writer(self): - return self.pluginmanager.get_plugin("terminalreporter").writer + return self.pluginmanager.get_plugin("terminalreporter")._tw def pytest_cmdline_parse(self, pluginmanager, args): # REF1 assert self == pluginmanager.config, (self, pluginmanager.config) diff --git a/_pytest/debugging.py b/_pytest/debugging.py index a67752751bb..d7dca780956 100644 --- a/_pytest/debugging.py +++ b/_pytest/debugging.py @@ -83,7 +83,7 @@ def _enter_pdb(node, excinfo, rep): # XXX we re-use the TerminalReporter's terminalwriter # because this seems to avoid some encoding related troubles # for not completely clear reasons. - tw = node.config.pluginmanager.getplugin("terminalreporter").writer + tw = node.config.pluginmanager.getplugin("terminalreporter")._tw tw.line() tw.sep(">", "traceback") rep.toterminal(tw) diff --git a/_pytest/helpconfig.py b/_pytest/helpconfig.py index 8438c3004cc..e744637f866 100644 --- a/_pytest/helpconfig.py +++ b/_pytest/helpconfig.py @@ -107,7 +107,7 @@ def pytest_cmdline_main(config): def showhelp(config): reporter = config.pluginmanager.get_plugin('terminalreporter') - tw = reporter.writer + tw = reporter._tw tw.write(config._parser.optparser.format_help()) tw.line() tw.line() diff --git a/_pytest/mark.py b/_pytest/mark.py index b7d50e05eb4..3f1f01b1a2e 100644 --- a/_pytest/mark.py +++ b/_pytest/mark.py @@ -141,7 +141,9 @@ def pytest_cmdline_main(config): config._do_configure() tw = _pytest.config.create_terminal_writer(config) for line in config.getini("markers"): - name, rest = line.split(":", 1) + parts = line.split(":", 1) + name = parts[0] + rest = parts[1] if len(parts) == 2 else '' tw.write("@pytest.mark.%s:" % name, bold=True) tw.line(rest) tw.line() @@ -298,7 +300,7 @@ def _check(self, name): pass self._markers = values = set() for line in self._config.getini("markers"): - marker, _ = line.split(":", 1) + marker = line.split(":", 1)[0] marker = marker.rstrip() x = marker.split("(", 1)[0] values.add(x) diff --git a/_pytest/pastebin.py b/_pytest/pastebin.py index 68aa331f758..b588b021b12 100644 --- a/_pytest/pastebin.py +++ b/_pytest/pastebin.py @@ -25,7 +25,7 @@ def pytest_configure(config): if tr is not None: # pastebin file will be utf-8 encoded binary file config._pastebinfile = tempfile.TemporaryFile('w+b') - oldwrite = tr.writer.write + oldwrite = tr._tw.write def tee_write(s, **kwargs): oldwrite(s, **kwargs) @@ -33,7 +33,7 @@ def tee_write(s, **kwargs): s = s.encode('utf-8') config._pastebinfile.write(s) - tr.writer.write = tee_write + tr._tw.write = tee_write def pytest_unconfigure(config): @@ -45,7 +45,7 @@ def pytest_unconfigure(config): del config._pastebinfile # undo our patching in the terminal reporter tr = config.pluginmanager.getplugin('terminalreporter') - del tr.writer.__dict__['write'] + del tr._tw.__dict__['write'] # write summary tr.write_sep("=", "Sending information to Paste Service") pastebinurl = create_new_paste(sessionlog) diff --git a/_pytest/skipping.py b/_pytest/skipping.py index ab46911e694..a1e5b43800b 100644 --- a/_pytest/skipping.py +++ b/_pytest/skipping.py @@ -308,9 +308,9 @@ def pytest_terminal_summary(terminalreporter): show_simple(terminalreporter, lines, 'passed', "PASSED %s") if lines: - tr.writer.sep("=", "short test summary info") + tr._tw.sep("=", "short test summary info") for line in lines: - tr.writer.line(line) + tr._tw.line(line) def show_simple(terminalreporter, lines, stat, format): diff --git a/_pytest/terminal.py b/_pytest/terminal.py index 7a18b94a7fb..8538ee6aa2e 100644 --- a/_pytest/terminal.py +++ b/_pytest/terminal.py @@ -8,7 +8,6 @@ import platform import sys import time -import warnings import pluggy import py @@ -145,25 +144,15 @@ def __init__(self, config, file=None): self.startdir = py.path.local() if file is None: file = sys.stdout - self._writer = _pytest.config.create_terminal_writer(config, file) - self._screen_width = self.writer.fullwidth + self._tw = _pytest.config.create_terminal_writer(config, file) + self._screen_width = self._tw.fullwidth self.currentfspath = None self.reportchars = getreportopt(config) - self.hasmarkup = self.writer.hasmarkup + self.hasmarkup = self._tw.hasmarkup self.isatty = file.isatty() self._progress_items_reported = 0 self._show_progress_info = self.config.getini('console_output_style') == 'progress' - @property - def writer(self): - return self._writer - - @property - def _tw(self): - warnings.warn(DeprecationWarning('TerminalReporter._tw is deprecated, use TerminalReporter.writer instead'), - stacklevel=2) - return self.writer - def hasopt(self, char): char = {'xfailed': 'x', 'skipped': 's'}.get(char, char) return char in self.reportchars @@ -175,33 +164,33 @@ def write_fspath_result(self, nodeid, res): self._write_progress_information_filling_space() self.currentfspath = fspath fspath = self.startdir.bestrelpath(fspath) - self.writer.line() - self.writer.write(fspath + " ") - self.writer.write(res) + self._tw.line() + self._tw.write(fspath + " ") + self._tw.write(res) def write_ensure_prefix(self, prefix, extra="", **kwargs): if self.currentfspath != prefix: - self.writer.line() + self._tw.line() self.currentfspath = prefix - self.writer.write(prefix) + self._tw.write(prefix) if extra: - self.writer.write(extra, **kwargs) + self._tw.write(extra, **kwargs) self.currentfspath = -2 self._write_progress_information_filling_space() def ensure_newline(self): if self.currentfspath: - self.writer.line() + self._tw.line() self.currentfspath = None def write(self, content, **markup): - self.writer.write(content, **markup) + self._tw.write(content, **markup) def write_line(self, line, **markup): if not isinstance(line, six.text_type): line = six.text_type(line, errors="replace") self.ensure_newline() - self.writer.line(line, **markup) + self._tw.line(line, **markup) def rewrite(self, line, **markup): """ @@ -214,22 +203,22 @@ def rewrite(self, line, **markup): """ erase = markup.pop('erase', False) if erase: - fill_count = self.writer.fullwidth - len(line) - 1 + fill_count = self._tw.fullwidth - len(line) - 1 fill = ' ' * fill_count else: fill = '' line = str(line) - self.writer.write("\r" + line + fill, **markup) + self._tw.write("\r" + line + fill, **markup) def write_sep(self, sep, title=None, **markup): self.ensure_newline() - self.writer.sep(sep, title, **markup) + self._tw.sep(sep, title, **markup) def section(self, title, sep="=", **kw): - self.writer.sep(sep, title, **kw) + self._tw.sep(sep, title, **kw) def line(self, msg, **kw): - self.writer.line(msg, **kw) + self._tw.line(msg, **kw) def pytest_internalerror(self, excrepr): for line in six.text_type(excrepr).split("\n"): @@ -282,7 +271,7 @@ def pytest_runtest_logreport(self, report): if not running_xdist and self.showfspath: self.write_fspath_result(rep.nodeid, letter) else: - self.writer.write(letter) + self._tw.write(letter) self._write_progress_if_past_edge() else: if markup is None: @@ -299,13 +288,13 @@ def pytest_runtest_logreport(self, report): self.write_ensure_prefix(line, word, **markup) else: self.ensure_newline() - self.writer.write("[%s]" % rep.node.gateway.id) + self._tw.write("[%s]" % rep.node.gateway.id) if self._show_progress_info: - self.writer.write(self._get_progress_information_message() + " ", cyan=True) + self._tw.write(self._get_progress_information_message() + " ", cyan=True) else: - self.writer.write(' ') - self.writer.write(word, **markup) - self.writer.write(" " + line) + self._tw.write(' ') + self._tw.write(word, **markup) + self._tw.write(" " + line) self.currentfspath = -2 def _write_progress_if_past_edge(self): @@ -316,10 +305,10 @@ def _write_progress_if_past_edge(self): self._write_progress_information_filling_space() return - past_edge = self.writer.chars_on_current_line + self._PROGRESS_LENGTH + 1 >= self._screen_width + past_edge = self._tw.chars_on_current_line + self._PROGRESS_LENGTH + 1 >= self._screen_width if past_edge: msg = self._get_progress_information_message() - self.writer.write(msg + '\n', cyan=True) + self._tw.write(msg + '\n', cyan=True) _PROGRESS_LENGTH = len(' [100%]') @@ -331,7 +320,7 @@ def _write_progress_information_filling_space(self): if not self._show_progress_info: return msg = self._get_progress_information_message() - fill = ' ' * (self.writer.fullwidth - self.writer.chars_on_current_line - len(msg) - 1) + fill = ' ' * (self._tw.fullwidth - self._tw.chars_on_current_line - len(msg) - 1) self.write(fill + msg, cyan=True) def pytest_collection(self): @@ -418,9 +407,9 @@ def pytest_collection_finish(self, session): if self.config.option.collectonly: self._printcollecteditems(session.items) if self.stats.get('failed'): - self.writer.sep("!", "collection failures") + self._tw.sep("!", "collection failures") for rep in self.stats.get('failed'): - rep.toterminal(self.writer) + rep.toterminal(self._tw) return 1 return 0 lines = self.config.hook.pytest_report_collectionfinish( @@ -438,12 +427,12 @@ def _printcollecteditems(self, items): name = item.nodeid.split('::', 1)[0] counts[name] = counts.get(name, 0) + 1 for name, count in sorted(counts.items()): - self.writer.line("%s: %d" % (name, count)) + self._tw.line("%s: %d" % (name, count)) else: for item in items: nodeid = item.nodeid nodeid = nodeid.replace("::()::", "::") - self.writer.line(nodeid) + self._tw.line(nodeid) return stack = [] indent = "" @@ -458,13 +447,13 @@ def _printcollecteditems(self, items): # if col.name == "()": # continue indent = (len(stack) - 1) * " " - self.writer.line("%s%s" % (indent, col)) + self._tw.line("%s%s" % (indent, col)) @pytest.hookimpl(hookwrapper=True) def pytest_sessionfinish(self, exitstatus): outcome = yield outcome.get_result() - self.writer.line("") + self._tw.line("") summary_exit_codes = ( EXIT_OK, EXIT_TESTSFAILED, EXIT_INTERRUPTED, EXIT_USAGEERROR, EXIT_NOTESTSCOLLECTED) @@ -494,10 +483,10 @@ def _report_keyboardinterrupt(self): self.write_sep("!", msg) if "KeyboardInterrupt" in msg: if self.config.option.fulltrace: - excrepr.toterminal(self.writer) + excrepr.toterminal(self._tw) else: - self.writer.line("to show a full traceback on KeyboardInterrupt use --fulltrace", yellow=True) - excrepr.reprcrash.toterminal(self.writer) + self._tw.line("to show a full traceback on KeyboardInterrupt use --fulltrace", yellow=True) + excrepr.reprcrash.toterminal(self._tw) def _locationline(self, nodeid, fspath, lineno, domain): def mkrel(nodeid): @@ -554,13 +543,13 @@ def summary_warnings(self): self.write_sep("=", "warnings summary", yellow=True, bold=False) for location, warning_records in grouped: - self.writer.line(str(location) or '') + self._tw.line(str(location) or '') for w in warning_records: lines = w.message.splitlines() indented = '\n'.join(' ' + x for x in lines) - self.writer.line(indented) - self.writer.line() - self.writer.line('-- Docs: http://doc.pytest.org/en/latest/warnings.html') + self._tw.line(indented) + self._tw.line() + self._tw.line('-- Docs: http://doc.pytest.org/en/latest/warnings.html') def summary_passes(self): if self.config.option.tbstyle != "no": @@ -577,10 +566,10 @@ def summary_passes(self): def print_teardown_sections(self, rep): for secname, content in rep.sections: if 'teardown' in secname: - self.writer.sep('-', secname) + self._tw.sep('-', secname) if content[-1:] == "\n": content = content[:-1] - self.writer.line(content) + self._tw.line(content) def summary_failures(self): if self.config.option.tbstyle != "no": @@ -620,12 +609,12 @@ def summary_errors(self): self._outrep_summary(rep) def _outrep_summary(self, rep): - rep.toterminal(self.writer) + rep.toterminal(self._tw) for secname, content in rep.sections: - self.writer.sep("-", secname) + self._tw.sep("-", secname) if content[-1:] == "\n": content = content[:-1] - self.writer.line(content) + self._tw.line(content) def summary_stats(self): session_duration = time.time() - self._sessionstarttime diff --git a/changelog/1993.bugfix b/changelog/1993.bugfix deleted file mode 100644 index 07a78cc9191..00000000000 --- a/changelog/1993.bugfix +++ /dev/null @@ -1 +0,0 @@ -Resume output capturing after ``capsys/capfd.disabled()`` context manager. diff --git a/changelog/2124.bugfix b/changelog/2124.bugfix deleted file mode 100644 index e1c5e044c2e..00000000000 --- a/changelog/2124.bugfix +++ /dev/null @@ -1 +0,0 @@ -``pytest_fixture_setup`` and ``pytest_fixture_post_finalizer`` hooks are now called for all ``conftest.py`` files. diff --git a/changelog/2124.feature b/changelog/2124.feature deleted file mode 100644 index 267fdabc972..00000000000 --- a/changelog/2124.feature +++ /dev/null @@ -1 +0,0 @@ -``pytest_fixture_post_finalizer`` hook can now receive a ``request`` argument. diff --git a/changelog/2236.removal b/changelog/2236.removal deleted file mode 100644 index 84f98d00987..00000000000 --- a/changelog/2236.removal +++ /dev/null @@ -1 +0,0 @@ -- Remove internal ``_preloadplugins()`` function. This removal is part of the ``pytest_namespace()`` hook deprecation. \ No newline at end of file diff --git a/changelog/2267.feature b/changelog/2267.feature deleted file mode 100644 index a2f14811e1b..00000000000 --- a/changelog/2267.feature +++ /dev/null @@ -1,4 +0,0 @@ -Replace the old introspection code in compat.py that determines the -available arguments of fixtures with inspect.signature on Python 3 and -funcsigs.signature on Python 2. This should respect __signature__ -declarations on functions. diff --git a/changelog/2491.bugfix b/changelog/2491.bugfix deleted file mode 100644 index fbb16e17edb..00000000000 --- a/changelog/2491.bugfix +++ /dev/null @@ -1,4 +0,0 @@ -If an exception happens while loading a plugin, pytest no longer hides the original traceback. -In python2 it will show the original traceback with a new message that explains in which plugin. -In python3 it will show 2 canonized exceptions, the original exception while loading the plugin -in addition to an exception that PyTest throws about loading a plugin. diff --git a/changelog/2549.feature b/changelog/2549.feature deleted file mode 100644 index 4866d990d1b..00000000000 --- a/changelog/2549.feature +++ /dev/null @@ -1 +0,0 @@ -Report only once tests with global ``pytestmark`` variable. \ No newline at end of file diff --git a/changelog/2641.trivial b/changelog/2641.trivial deleted file mode 100644 index 1799f90d2be..00000000000 --- a/changelog/2641.trivial +++ /dev/null @@ -1 +0,0 @@ -pytest now depends on `attrs `_ for internal structures to ease code maintainability. diff --git a/changelog/2642.trivial b/changelog/2642.trivial deleted file mode 100644 index bae449dbaa9..00000000000 --- a/changelog/2642.trivial +++ /dev/null @@ -1 +0,0 @@ -Refactored internal Python 2/3 compatibility code to use ``six``. diff --git a/changelog/2657.feature b/changelog/2657.feature deleted file mode 100644 index d0cc3bfd4fc..00000000000 --- a/changelog/2657.feature +++ /dev/null @@ -1 +0,0 @@ -Now pytest displays the total progress percentage while running tests. The previous output style can be set by setting the new ``console_output_style`` to ``classic``. diff --git a/changelog/2672.removal b/changelog/2672.removal deleted file mode 100644 index e660c27fd85..00000000000 --- a/changelog/2672.removal +++ /dev/null @@ -1,2 +0,0 @@ -Internally change ``CallSpec2`` to have a list of marks instead of a broken mapping of keywords. -This removes the keywords attribute of the internal ``CallSpec2`` class. \ No newline at end of file diff --git a/changelog/2675.removal b/changelog/2675.removal deleted file mode 100644 index 44f597892fc..00000000000 --- a/changelog/2675.removal +++ /dev/null @@ -1 +0,0 @@ -remove ParameterSet.deprecated_arg_dict - its not a public api and the lack of the underscore was a naming error. \ No newline at end of file diff --git a/changelog/2708.feature b/changelog/2708.feature deleted file mode 100644 index f6039ede928..00000000000 --- a/changelog/2708.feature +++ /dev/null @@ -1 +0,0 @@ -Match ``warns`` signature to ``raises`` by adding ``match`` keyworkd. \ No newline at end of file diff --git a/changelog/2709.bugfix b/changelog/2709.bugfix deleted file mode 100644 index 88503b05072..00000000000 --- a/changelog/2709.bugfix +++ /dev/null @@ -1 +0,0 @@ -``capsys`` and ``capfd`` can now be used by other fixtures. diff --git a/changelog/2719.trivial b/changelog/2719.trivial deleted file mode 100644 index 008f1dd205f..00000000000 --- a/changelog/2719.trivial +++ /dev/null @@ -1 +0,0 @@ -Stop vendoring ``pluggy`` - we're missing out on it's latest changes for not much benefit diff --git a/changelog/2734.trivial b/changelog/2734.trivial deleted file mode 100644 index b3f8471afe7..00000000000 --- a/changelog/2734.trivial +++ /dev/null @@ -1 +0,0 @@ -Internal refactor: simplify ascii string escaping by using the backslashreplace error handler in newer Python 3 versions. diff --git a/changelog/2738.bugfix b/changelog/2738.bugfix deleted file mode 100644 index c53869f49ca..00000000000 --- a/changelog/2738.bugfix +++ /dev/null @@ -1 +0,0 @@ -Internal ``pytester`` plugin properly encodes ``bytes`` arguments to ``utf-8``. diff --git a/changelog/2751.bugfix b/changelog/2751.bugfix deleted file mode 100644 index 76004a653e8..00000000000 --- a/changelog/2751.bugfix +++ /dev/null @@ -1 +0,0 @@ -``testdir`` now uses use the same method used by ``tmpdir`` to create its temporary directory. This changes the final structure of the ``testdir`` directory slightly, but should not affect usage in normal scenarios and avoids a number of potential problems. \ No newline at end of file diff --git a/changelog/2767.removal b/changelog/2767.removal deleted file mode 100644 index b9c3984cdbb..00000000000 --- a/changelog/2767.removal +++ /dev/null @@ -1 +0,0 @@ -Remove the internal multi-typed attribute ``Node._evalskip`` and replace it with the boolean ``Node._skipped_by_mark``. \ No newline at end of file diff --git a/changelog/2767.trivial b/changelog/2767.trivial deleted file mode 100644 index c42a06e07dc..00000000000 --- a/changelog/2767.trivial +++ /dev/null @@ -1 +0,0 @@ -* remove unnecessary mark evaluator in unittest plugin \ No newline at end of file diff --git a/changelog/2794.feature b/changelog/2794.feature deleted file mode 100644 index 9cff1c4bb6c..00000000000 --- a/changelog/2794.feature +++ /dev/null @@ -1,3 +0,0 @@ -Pytest now captures and displays output from the standard `logging` module. The user can control the logging level to be captured by specifying options in ``pytest.ini``, the command line and also during individual tests using markers. Also, a ``caplog`` fixture is available that enables users to test the captured log during specific tests (similar to ``capsys`` for example). For more information, please see the `docs `_. - -This feature was introduced by merging the popular `pytest-catchlog `_ plugin, thanks to `Thomas Hisch `_. Be advised that during the merging the backward compatibility interface with the defunct ``pytest-capturelog`` has been dropped. \ No newline at end of file diff --git a/changelog/2803.removal b/changelog/2803.removal deleted file mode 100644 index 4ebdb903ee7..00000000000 --- a/changelog/2803.removal +++ /dev/null @@ -1 +0,0 @@ -``TerminalReporter._tw`` has been deprecated in favor of ``TerminalReporter.writer`` and will be removed in a future version. Also, ``TerminalReporter.writer`` is now read-only. diff --git a/changelog/2808.feature b/changelog/2808.feature deleted file mode 100644 index 26245f04773..00000000000 --- a/changelog/2808.feature +++ /dev/null @@ -1 +0,0 @@ -Add ``allow_module_level`` kwarg to ``pytest.skip()``, enabling to skip the whole module. diff --git a/changelog/2809.bugfix b/changelog/2809.bugfix deleted file mode 100644 index 6db7e8c6c57..00000000000 --- a/changelog/2809.bugfix +++ /dev/null @@ -1 +0,0 @@ -Pytest no longer complains about warnings with unicode messages being non-ascii compatible even for ascii-compatible messages. As a result of this, warnings with unicode messages are converted first to an ascii representation for safety. \ No newline at end of file diff --git a/changelog/2812.removal b/changelog/2812.removal deleted file mode 100644 index 74894e0ef36..00000000000 --- a/changelog/2812.removal +++ /dev/null @@ -1 +0,0 @@ -Pytest no longer supports Python **2.6** and **3.3**. Those Python versions are EOL for some time now and incurr maintanance and compatibility costs on the pytest core team, and following up with the rest of the community we decided that they will no longer be supported starting on this version. Users which still require those versions should pin pytest to ``<3.3``. diff --git a/changelog/2824.feature b/changelog/2824.feature deleted file mode 100644 index 690ca939a0b..00000000000 --- a/changelog/2824.feature +++ /dev/null @@ -1 +0,0 @@ -Allow setting ``file_or_dir``, ``-c``, and ``-o`` in PYTEST_ADDOPTS. diff --git a/changelog/2836.bug b/changelog/2836.bug deleted file mode 100644 index afa1961d73e..00000000000 --- a/changelog/2836.bug +++ /dev/null @@ -1 +0,0 @@ -Match fixture paths against actual path segments in order to avoid matching folders which share a prefix. diff --git a/changelog/2845.bugfix b/changelog/2845.bugfix deleted file mode 100644 index c6767631eb6..00000000000 --- a/changelog/2845.bugfix +++ /dev/null @@ -1 +0,0 @@ -Change return value of pytest command when ``--maxfail`` is reached from ``2`` (interrupted) to ``1`` (failed). diff --git a/changelog/2876.trivial b/changelog/2876.trivial deleted file mode 100644 index 354f6ad5c5c..00000000000 --- a/changelog/2876.trivial +++ /dev/null @@ -1 +0,0 @@ -Calls to ``Metafunc.addcall`` now emit a deprecation warning. This function is scheduled to be removed in ``pytest-4.0``. diff --git a/changelog/2877.trivial b/changelog/2877.trivial deleted file mode 100644 index c4198af97f2..00000000000 --- a/changelog/2877.trivial +++ /dev/null @@ -1 +0,0 @@ -Internal move of the parameterset extraction to a more maintainable place. diff --git a/changelog/2879.feature b/changelog/2879.feature deleted file mode 100644 index 8932d8c3017..00000000000 --- a/changelog/2879.feature +++ /dev/null @@ -1 +0,0 @@ -Return stdout/stderr capture results as a ``namedtuple``, so ``out`` and ``err`` can be accessed by attribute. diff --git a/changelog/2910.trivial b/changelog/2910.trivial deleted file mode 100644 index 87bf00dfee5..00000000000 --- a/changelog/2910.trivial +++ /dev/null @@ -1 +0,0 @@ -Internal refactoring to simplify scope node lookup. diff --git a/changelog/2922.trivial b/changelog/2922.trivial deleted file mode 100644 index 06d1346bb83..00000000000 --- a/changelog/2922.trivial +++ /dev/null @@ -1 +0,0 @@ -Configure ``pytest`` to prevent pip from installing pytest in unsupported Python versions. diff --git a/changelog/2923.feature b/changelog/2923.feature deleted file mode 100644 index c6937741f07..00000000000 --- a/changelog/2923.feature +++ /dev/null @@ -1,2 +0,0 @@ -Add ``capfdbinary`` a version of ``capfd`` which returns bytes from -``readouterr()``. diff --git a/changelog/2934.feature b/changelog/2934.feature deleted file mode 100644 index 38dcb5f73e3..00000000000 --- a/changelog/2934.feature +++ /dev/null @@ -1,2 +0,0 @@ -Add ``capsysbinary`` a version of ``capsys`` which returns bytes from -``readouterr()``. diff --git a/changelog/502.feature b/changelog/502.feature deleted file mode 100644 index eb61640b9a2..00000000000 --- a/changelog/502.feature +++ /dev/null @@ -1 +0,0 @@ -Implement feature to skip ``setup.py`` files when ran with ``--doctest-modules``. diff --git a/doc/en/announce/index.rst b/doc/en/announce/index.rst index 2e3b45805c9..1a5f3760b68 100644 --- a/doc/en/announce/index.rst +++ b/doc/en/announce/index.rst @@ -6,6 +6,8 @@ Release announcements :maxdepth: 2 + release-3.3.0 + release-3.2.5 release-3.2.4 release-3.2.3 release-3.2.2 diff --git a/doc/en/announce/release-3.2.5.rst b/doc/en/announce/release-3.2.5.rst new file mode 100644 index 00000000000..a520ce2b333 --- /dev/null +++ b/doc/en/announce/release-3.2.5.rst @@ -0,0 +1,18 @@ +pytest-3.2.5 +======================================= + +pytest 3.2.5 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: + +* Bruno Oliveira + + +Happy testing, +The pytest Development Team diff --git a/doc/en/announce/release-3.3.0.rst b/doc/en/announce/release-3.3.0.rst new file mode 100644 index 00000000000..e0740e7d592 --- /dev/null +++ b/doc/en/announce/release-3.3.0.rst @@ -0,0 +1,50 @@ +pytest-3.3.0 +======================================= + +The pytest team is proud to announce the 3.3.0 release! + +pytest is a mature Python testing tool with more than a 1600 tests +against itself, passing on many different interpreters and platforms. + +This release contains a number of bugs fixes and improvements, so users are encouraged +to take a look at the CHANGELOG: + + http://doc.pytest.org/en/latest/changelog.html + +For complete documentation, please visit: + + http://docs.pytest.org + +As usual, you can upgrade from pypi via: + + pip install -U pytest + +Thanks to all who contributed to this release, among them: + +* Anthony Sottile +* Bruno Oliveira +* Ceridwen +* Daniel Hahler +* Dirk Thomas +* Dmitry Malinovsky +* Florian Bruhin +* George Y. Kussumoto +* Hugo +* Jesús Espino +* Joan Massich +* Ofir +* OfirOshir +* Ronny Pfannschmidt +* Samuel Dion-Girardeau +* Srinivas Reddy Thatiparthy +* Sviatoslav Abakumov +* Tarcisio Fischer +* Thomas Hisch +* Tyler Goodlet +* hugovk +* je +* prokaktus + + +Happy testing, +The Pytest Development Team diff --git a/doc/en/backwards-compatibility.rst b/doc/en/backwards-compatibility.rst index 8ceada52d66..84f2c43edaa 100644 --- a/doc/en/backwards-compatibility.rst +++ b/doc/en/backwards-compatibility.rst @@ -10,3 +10,96 @@ With the pytest 3.0 release we introduced a clear communication scheme for when To communicate changes we are already issuing deprecation warnings, but they are not displayed by default. In pytest 3.0 we changed the default setting so that pytest deprecation warnings are displayed if not explicitly silenced (with ``--disable-pytest-warnings``). We will only remove deprecated functionality in major releases (e.g. if we deprecate something in 3.0 we will remove it in 4.0), and keep it around for at least two minor releases (e.g. if we deprecate something in 3.9 and 4.0 is the next release, we will not remove it in 4.0 but in 5.0). + + +Deprecation Roadmap +------------------- + +This page lists deprecated features and when we plan to remove them. It is important to list the feature, the version where it got deprecated and the version we plan to remove it. + +Following our deprecation policy, we should aim to keep features for *at least* two minor versions after it was considered deprecated. + + +Future Releases +~~~~~~~~~~~~~~~ + +3.4 +^^^ + +**Old style classes** + +Issue: `#2147 `_. + +Deprecated in ``3.2``. + +4.0 +^^^ + +**Yield tests** + +Deprecated in ``3.0``. + +**pytest-namespace hook** + +deprecated in ``3.2``. + +**Marks in parameter sets** + +Deprecated in ``3.2``. + +**--result-log** + +Deprecated in ``3.0``. + +See `#830 `_ for more information. Suggested alternative: `pytest-tap `_. + +**metafunc.addcall** + +Issue: `#2876 `_. + +Deprecated in ``3.3``. + +**pytest_plugins in non-toplevel conftests** + +There is a deep conceptual confusion as ``conftest.py`` files themselves are activated/deactivated based on path, but the plugins they depend on aren't. + +Issue: `#2639 `_. + +Not yet officially deprecated. + +**passing a single string to pytest.main()** + +Pass a list of strings to ``pytest.main()`` instead. + +Deprecated in ``3.1``. + +**[pytest] section in setup.cfg** + +Use ``[tool:pytest]`` instead for compatibility with other tools. + +Deprecated in ``3.0``. + +Past Releases +~~~~~~~~~~~~~ + +3.0 +^^^ + +* The following deprecated commandline options were removed: + + * ``--genscript``: no longer supported; + * ``--no-assert``: use ``--assert=plain`` instead; + * ``--nomagic``: use ``--assert=plain`` instead; + * ``--report``: use ``-r`` instead; + +* Removed all ``py.test-X*`` entry points. The versioned, suffixed entry points + were never documented and a leftover from a pre-virtualenv era. These entry + points also created broken entry points in wheels, so removing them also + removes a source of confusion for users. + + + +3.3 +^^^ + +* Dropped support for EOL Python 2.6 and 3.3. \ No newline at end of file diff --git a/doc/en/example/parametrize.rst b/doc/en/example/parametrize.rst index 49852ed7b4f..dd01b25277a 100644 --- a/doc/en/example/parametrize.rst +++ b/doc/en/example/parametrize.rst @@ -411,11 +411,8 @@ is to be run with different sets of arguments for its three arguments: Running it results in some skips if we don't have all the python interpreters installed and otherwise runs all combinations (5 interpreters times 5 interpreters times 3 objects to serialize/deserialize):: . $ pytest -rs -q multipython.py - ssssssssssssssssssssssss... [100%] - ========================= short test summary info ========================== - SKIP [12] $REGENDOC_TMPDIR/CWD/multipython.py:24: 'python2.7' not found - SKIP [12] $REGENDOC_TMPDIR/CWD/multipython.py:24: 'python3.4' not found - 3 passed, 24 skipped in 0.12 seconds + ........................... [100%] + 27 passed in 0.12 seconds Indirect parametrization of optional implementations/imports -------------------------------------------------------------------- diff --git a/setup.py b/setup.py index f586101ea06..3eb38efe655 100644 --- a/setup.py +++ b/setup.py @@ -53,7 +53,7 @@ def main(): # if _PYTEST_SETUP_SKIP_PLUGGY_DEP is set, skip installing pluggy; # 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.6') + install_requires.append('pluggy>=0.5,<0.7') if has_environment_marker_support(): extras_require[':python_version<"3.0"'] = ['funcsigs'] extras_require[':sys_platform=="win32"'] = ['colorama'] diff --git a/tasks/__init__.py b/tasks/__init__.py index 992f4a4ade6..8ea038f0af0 100644 --- a/tasks/__init__.py +++ b/tasks/__init__.py @@ -4,10 +4,9 @@ import invoke -from . import generate, vendoring +from . import generate ns = invoke.Collection( generate, - vendoring ) diff --git a/testing/deprecated_test.py b/testing/deprecated_test.py index 6e1e16331af..f3c40cb3dbb 100644 --- a/testing/deprecated_test.py +++ b/testing/deprecated_test.py @@ -99,3 +99,16 @@ def test_func(i): "*Metafunc.addcall is deprecated*", "*2 passed, 2 warnings*", ]) + + +def test_pytest_catchlog_deprecated(testdir): + testdir.makepyfile(""" + def test_func(pytestconfig): + pytestconfig.pluginmanager.register(None, 'pytest_catchlog') + """) + res = testdir.runpytest() + assert res.ret == 0 + res.stdout.fnmatch_lines([ + "*pytest-catchlog plugin has been merged into the core*", + "*1 passed, 1 warnings*", + ]) diff --git a/testing/test_assertion.py b/testing/test_assertion.py index 6c1443c3020..0cce03f1daa 100644 --- a/testing/test_assertion.py +++ b/testing/test_assertion.py @@ -129,6 +129,24 @@ def test_foo(pytestconfig): result = testdir.runpytest_subprocess('--assert=rewrite') assert result.ret == 0 + def test_pytest_plugins_rewrite_module_names_correctly(self, testdir): + """Test that we match files correctly when they are marked for rewriting (#2939).""" + contents = { + 'conftest.py': """ + pytest_plugins = "ham" + """, + 'ham.py': "", + 'hamster.py': "", + 'test_foo.py': """ + def test_foo(pytestconfig): + assert pytestconfig.pluginmanager.rewrite_hook.find_module('ham') is not None + assert pytestconfig.pluginmanager.rewrite_hook.find_module('hamster') is None + """, + } + testdir.makepyfile(**contents) + result = testdir.runpytest_subprocess('--assert=rewrite') + assert result.ret == 0 + @pytest.mark.parametrize('mode', ['plain', 'rewrite']) @pytest.mark.parametrize('plugin_state', ['development', 'installed']) def test_installed_plugin_rewrite(self, testdir, mode, plugin_state): diff --git a/testing/test_mark.py b/testing/test_mark.py index 3ac42daee11..46bf0b0e778 100644 --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -161,11 +161,13 @@ def test_markers_option(testdir): markers = a1: this is a webtest marker a1some: another marker + nodescription """) result = testdir.runpytest("--markers", ) result.stdout.fnmatch_lines([ "*a1*this is a webtest*", "*a1some*another marker", + "*nodescription*", ]) @@ -186,6 +188,21 @@ def test_markers(): rec.assertoutcome(passed=1) +def test_marker_without_description(testdir): + testdir.makefile(".cfg", setup=""" + [tool:pytest] + markers=slow + """) + testdir.makeconftest(""" + import pytest + pytest.mark.xfail('FAIL') + """) + ftdir = testdir.mkdir("ft1_dummy") + testdir.tmpdir.join("conftest.py").move(ftdir.join("conftest.py")) + rec = testdir.runpytest_subprocess("--strict") + rec.assert_outcomes() + + def test_markers_option_with_plugin_in_current_dir(testdir): testdir.makeconftest('pytest_plugins = "flip_flop"') testdir.makepyfile(flip_flop="""\ @@ -576,7 +593,7 @@ def arg(request): request.applymarker(pytest.mark.hello) def pytest_terminal_summary(terminalreporter): values = terminalreporter.stats['passed'] - terminalreporter.writer.line("keyword: %s" % values[0].keywords) + terminalreporter._tw.line("keyword: %s" % values[0].keywords) """) testdir.makepyfile(""" def test_func(arg): diff --git a/testing/test_terminal.py b/testing/test_terminal.py index 485a3d8c4f0..98a8ca1215a 100644 --- a/testing/test_terminal.py +++ b/testing/test_terminal.py @@ -219,7 +219,7 @@ def test_rewrite(self, testdir, monkeypatch): f = py.io.TextIO() monkeypatch.setattr(f, 'isatty', lambda *args: True) tr = TerminalReporter(config, f) - tr.writer.fullwidth = 10 + tr._tw.fullwidth = 10 tr.write('hello') tr.rewrite('hey', erase=True) assert f.getvalue() == 'hello' + '\r' + 'hey' + (6 * ' ')