diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 239650e5a..2bcea39d8 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -172,13 +172,36 @@ * Add proposal to docs for a new feature that enables users to combine multiple fixtures into one. Thanks to `@hpk42`_ and `@hackebrot`_. +* Rename ``getfuncargvalue`` to ``getfixturevalue``. ``getfuncargvalue`` is + deprecated but still present. Thanks to `@RedBeardCode`_ and `@tomviner`_ + for PR (`#1626`_). + +* Always include full assertion explanation. The previous behaviour was hiding + sub-expressions that happened to be False, assuming this was redundant information. + Thanks `@bagerard`_ for reporting (`#1503`_). Thanks to `@davehunt`_ and + `@tomviner`_ for PR. + +* Renamed the pytest ``pdb`` module (plugin) into ``debugging``. + +* Improve of the test output for logical expression with brackets. + Fixes(`#925`_). Thanks `@DRMacIver`_ for reporting. Thanks to `@RedBeardCode`_ + for PR. + +* ImportErrors in plugins now are a fatal error instead of issuing a .. _#1632: https://github.com/pytest-dev/pytest/issues/1632 + + pytest warning (`#1479`_). Thanks to `@The-Compiler`_ for the PR. + .. _#1580: https://github.com/pytest-dev/pytest/pull/1580 .. _#1605: https://github.com/pytest-dev/pytest/issues/1605 .. _#1597: https://github.com/pytest-dev/pytest/pull/1597 .. _#460: https://github.com/pytest-dev/pytest/pull/460 .. _#1553: https://github.com/pytest-dev/pytest/issues/1553 +.. _#1626: https://github.com/pytest-dev/pytest/pull/1626 +.. _#1503: https://github.com/pytest-dev/pytest/issues/1503 +.. _#1479: https://github.com/pytest-dev/pytest/issues/1479 +.. _#925: https://github.com/pytest-dev/pytest/issues/925 .. _@graingert: https://github.com/graingert .. _@taschini: https://github.com/taschini @@ -187,6 +210,9 @@ .. _@Vogtinator: https://github.com/Vogtinator .. _@blueyed: https://github.com/blueyed .. _@fengxx: https://github.com/fengxx +.. _@bagerard: https://github.com/bagerard +.. _@davehunt: https://github.com/davehunt +.. _@DRMacIver: https://github.com/DRMacIver * Fix `#1421`_: Exit tests if a collection error occurs and add ``--continue-on-collection-errors`` option to restore previous behaviour. diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index bedc82c65..947d4e655 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -120,6 +120,8 @@ the following: - an issue tracker for bug reports and enhancement requests. +- a `changelog `_ + If no contributor strongly objects and two agree, the repository can then be transferred to the ``pytest-dev`` organisation. diff --git a/_pytest/assertion/rewrite.py b/_pytest/assertion/rewrite.py index 921d17a10..06944b016 100644 --- a/_pytest/assertion/rewrite.py +++ b/_pytest/assertion/rewrite.py @@ -1,6 +1,7 @@ """Rewrite assertion AST to produce nice error messages""" import ast +import _ast import errno import itertools import imp @@ -876,6 +877,8 @@ class AssertionRewriter(ast.NodeVisitor): def visit_Compare(self, comp): self.push_format_context() left_res, left_expl = self.visit(comp.left) + if isinstance(comp.left, (_ast.Compare, _ast.BoolOp)): + left_expl = "({0})".format(left_expl) res_variables = [self.variable() for i in range(len(comp.ops))] load_names = [ast.Name(v, ast.Load()) for v in res_variables] store_names = [ast.Name(v, ast.Store()) for v in res_variables] @@ -885,6 +888,8 @@ class AssertionRewriter(ast.NodeVisitor): results = [left_res] for i, op, next_operand in it: next_res, next_expl = self.visit(next_operand) + if isinstance(next_operand, (_ast.Compare, _ast.BoolOp)): + next_expl = "({0})".format(next_expl) results.append(next_res) sym = binop_map[op.__class__] syms.append(ast.Str(sym)) diff --git a/_pytest/assertion/util.py b/_pytest/assertion/util.py index 8bf425caf..2481cf34c 100644 --- a/_pytest/assertion/util.py +++ b/_pytest/assertion/util.py @@ -38,44 +38,11 @@ def format_explanation(explanation): displaying diffs. """ explanation = ecu(explanation) - explanation = _collapse_false(explanation) lines = _split_explanation(explanation) result = _format_lines(lines) return u('\n').join(result) -def _collapse_false(explanation): - """Collapse expansions of False - - So this strips out any "assert False\n{where False = ...\n}" - blocks. - """ - where = 0 - while True: - start = where = explanation.find("False\n{False = ", where) - if where == -1: - break - level = 0 - prev_c = explanation[start] - for i, c in enumerate(explanation[start:]): - if prev_c + c == "\n{": - level += 1 - elif prev_c + c == "\n}": - level -= 1 - if not level: - break - prev_c = c - else: - raise AssertionError("unbalanced braces: %r" % (explanation,)) - end = start + i - where = end - if explanation[end - 1] == '\n': - explanation = (explanation[:start] + explanation[start+15:end-1] + - explanation[end+1:]) - where -= 17 - return explanation - - def _split_explanation(explanation): """Return a list of individual lines in the explanation diff --git a/_pytest/config.py b/_pytest/config.py index 463d8f04f..dfc066675 100644 --- a/_pytest/config.py +++ b/_pytest/config.py @@ -63,7 +63,7 @@ class UsageError(Exception): _preinit = [] default_plugins = ( - "mark main terminal runner python pdb unittest capture skipping " + "mark main terminal runner python debugging unittest capture skipping " "tmpdir monkeypatch recwarn pastebin helpconfig nose assertion " "junitxml resultlog doctest cacheprovider freeze_support " "setuponly setupplan").split() @@ -656,20 +656,17 @@ class Argument: self._long_opts.append(opt) def __repr__(self): - retval = 'Argument(' + args = [] if self._short_opts: - retval += '_short_opts: ' + repr(self._short_opts) + ', ' + args += ['_short_opts: ' + repr(self._short_opts)] if self._long_opts: - retval += '_long_opts: ' + repr(self._long_opts) + ', ' - retval += 'dest: ' + repr(self.dest) + ', ' + args += ['_long_opts: ' + repr(self._long_opts)] + args += ['dest: ' + repr(self.dest)] if hasattr(self, 'type'): - retval += 'type: ' + repr(self.type) + ', ' + args += ['type: ' + repr(self.type)] if hasattr(self, 'default'): - retval += 'default: ' + repr(self.default) + ', ' - if retval[-2:] == ', ': # always long enough to test ("Argument(" ) - retval = retval[:-2] - retval += ')' - return retval + args += ['default: ' + repr(self.default)] + return 'Argument({0})'.format(', '.join(args)) class OptionGroup: @@ -928,10 +925,7 @@ class Config(object): args[:] = self.getini("addopts") + args self._checkversion() self.pluginmanager.consider_preparse(args) - try: - self.pluginmanager.load_setuptools_entrypoints("pytest11") - except ImportError as e: - self.warn("I2", "could not load setuptools entry import: %s" % (e,)) + self.pluginmanager.load_setuptools_entrypoints("pytest11") self.pluginmanager.consider_env() self.known_args_namespace = ns = self._parser.parse_known_args(args, namespace=self.option.copy()) if self.known_args_namespace.confcutdir is None and self.inifile: diff --git a/_pytest/pdb.py b/_pytest/debugging.py similarity index 100% rename from _pytest/pdb.py rename to _pytest/debugging.py diff --git a/_pytest/doctest.py b/_pytest/doctest.py index 4411158ab..b1babf1e6 100644 --- a/_pytest/doctest.py +++ b/_pytest/doctest.py @@ -70,7 +70,7 @@ class DoctestItem(pytest.Item): def setup(self): if self.dtest is not None: self.fixture_request = _setup_fixtures(self) - globs = dict(getfixture=self.fixture_request.getfuncargvalue) + globs = dict(getfixture=self.fixture_request.getfixturevalue) for name, value in self.fixture_request.getfuncargvalue('doctest_namespace').items(): globs[name] = value self.dtest.globs.update(globs) diff --git a/_pytest/python.py b/_pytest/python.py index a0624839b..c959b21d8 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -6,8 +6,9 @@ import inspect import re import types import sys -import math +import warnings import collections +import math import py import pytest @@ -1855,7 +1856,7 @@ class FixtureRequest(FuncargnamesCompatAttr): fixturedefs = self._arg2fixturedefs.get(argname, None) if fixturedefs is None: # we arrive here because of a a dynamic call to - # getfuncargvalue(argname) usage which was naturally + # getfixturevalue(argname) usage which was naturally # not known at parsing/collection time fixturedefs = self._fixturemanager.getfixturedefs( argname, self._pyfuncitem.parent.nodeid) @@ -1950,7 +1951,7 @@ class FixtureRequest(FuncargnamesCompatAttr): fixturenames = getattr(item, "fixturenames", self.fixturenames) for argname in fixturenames: if argname not in item.funcargs: - item.funcargs[argname] = self.getfuncargvalue(argname) + item.funcargs[argname] = self.getfixturevalue(argname) def cached_setup(self, setup, teardown=None, scope="module", extrakey=None): """ (deprecated) Return a testing resource managed by ``setup`` & @@ -1984,17 +1985,23 @@ class FixtureRequest(FuncargnamesCompatAttr): self._addfinalizer(finalizer, scope=scope) return val - def getfuncargvalue(self, argname): - """ Dynamically retrieve a named fixture function argument. + def getfixturevalue(self, argname): + """ Dynamically run a named fixture function. - As of pytest-2.3, it is easier and usually better to access other - fixture values by stating it as an input argument in the fixture - function. If you only can decide about using another fixture at test + Declaring fixtures via function argument is recommended where possible. + But if you can only decide whether to use another fixture at test setup time, you may use this function to retrieve it inside a fixture - function body. + or test function body. """ return self._get_active_fixturedef(argname).cached_result[0] + def getfuncargvalue(self, argname): + """ Deprecated, use getfixturevalue. """ + warnings.warn( + "use of getfuncargvalue is deprecated, use getfixturevalue", + DeprecationWarning) + return self.getfixturevalue(argname) + def _get_active_fixturedef(self, argname): try: return self._fixturedefs[argname] @@ -2010,7 +2017,7 @@ class FixtureRequest(FuncargnamesCompatAttr): raise # remove indent to prevent the python3 exception # from leaking into the call - result = self._getfuncargvalue(fixturedef) + result = self._getfixturevalue(fixturedef) self._funcargs[argname] = result self._fixturedefs[argname] = fixturedef return fixturedef @@ -2026,7 +2033,7 @@ class FixtureRequest(FuncargnamesCompatAttr): l.append(fixturedef) current = current._parent_request - def _getfuncargvalue(self, fixturedef): + def _getfixturevalue(self, fixturedef): # prepare a subrequest object before calling fixture function # (latter managed by fixturedef) argname = fixturedef.argname diff --git a/appveyor.yml b/appveyor.yml index 4b73645f7..2bd72db45 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,6 +5,13 @@ environment: # using pytestbot account as detailed here: # https://www.appveyor.com/docs/build-configuration#secure-variables + matrix: + # create multiple jobs to execute a set of tox runs on each; this is to workaround having + # builds timing out in AppVeyor + - TOXENV: "linting,py26,py27,py33,py34,py35,pypy" + - TOXENV: "py27-pexpect,py27-xdist,py27-trial,py35-pexpect,py35-xdist,py35-trial" + - TOXENV: "py27-nobyte,doctesting,py27-cxfreeze" + install: - echo Installed Pythons - dir c:\Python* diff --git a/doc/en/_templates/layout.html b/doc/en/_templates/layout.html index 0ce480be3..2fc8e2a7f 100644 --- a/doc/en/_templates/layout.html +++ b/doc/en/_templates/layout.html @@ -1,19 +1,5 @@ {% extends "!layout.html" %} {% block header %} -
-

- Want to help improve pytest? Please - - contribute to - - or - - join - - our upcoming sprint in June 2016! - -

-
{{super()}} {% endblock %} {% block footer %} diff --git a/doc/en/_templates/links.html b/doc/en/_templates/links.html index 200258e16..56486a750 100644 --- a/doc/en/_templates/links.html +++ b/doc/en/_templates/links.html @@ -1,10 +1,5 @@

Useful Links