diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4146670f2..2654fe7e1 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2079,7 +2079,7 @@ time or change existing behaviors in order to make them less surprising/more use - fix issue655: work around different ways that cause python2/3 to leak sys.exc_info into fixtures/tests causing failures in 3rd party code -- fix issue615: assertion re-writing did not correctly escape % signs +- fix issue615: assertion rewriting did not correctly escape % signs when formatting boolean operations, which tripped over mixing booleans with modulo operators. Thanks to Tom Viner for the report, triaging and fix. diff --git a/_pytest/assertion/rewrite.py b/_pytest/assertion/rewrite.py index 27026b0fe..55e8d2c3c 100644 --- a/_pytest/assertion/rewrite.py +++ b/_pytest/assertion/rewrite.py @@ -175,10 +175,10 @@ class AssertionRewritingHook(object): return False def mark_rewrite(self, *names): - """Mark import names as needing to be re-written. + """Mark import names as needing to be rewritten. The named module or package as well as any nested modules will - be re-written on import. + be rewritten on import. """ already_imported = set(names).intersection(set(sys.modules)) if already_imported: @@ -190,7 +190,7 @@ class AssertionRewritingHook(object): def _warn_already_imported(self, name): self.config.warn( 'P1', - 'Module already imported so can not be re-written: %s' % name) + 'Module already imported so cannot be rewritten: %s' % name) def load_module(self, name): # If there is an existing module object named 'fullname' in @@ -533,7 +533,7 @@ class AssertionRewriter(ast.NodeVisitor): """Assertion rewriting implementation. The main entrypoint is to call .run() with an ast.Module instance, - this will then find all the assert statements and re-write them to + this will then find all the assert statements and rewrite them to provide intermediate values and a detailed assertion error. See http://pybites.blogspot.be/2011/07/behind-scenes-of-pytests-new-assertion.html for an overview of how this works. @@ -542,7 +542,7 @@ class AssertionRewriter(ast.NodeVisitor): statements in an ast.Module and for each ast.Assert statement it finds call .visit() with it. Then .visit_Assert() takes over and is responsible for creating new ast statements to replace the - original assert statement: it re-writes the test of an assertion + original assert statement: it rewrites the test of an assertion to provide intermediate values and replace it with an if statement which raises an assertion error with a detailed explanation in case the expression is false. @@ -726,7 +726,7 @@ class AssertionRewriter(ast.NodeVisitor): def visit_Assert(self, assert_): """Return the AST statements to replace the ast.Assert instance. - This re-writes the test of an assertion to provide + This rewrites the test of an assertion to provide intermediate values and replace it with an if statement which raises an assertion error with a detailed explanation in case the expression is false. diff --git a/_pytest/config.py b/_pytest/config.py index 19835d2c3..6e2c4a2bd 100644 --- a/_pytest/config.py +++ b/_pytest/config.py @@ -1014,10 +1014,10 @@ class Config(object): self._override_ini = ns.override_ini or () def _consider_importhook(self, args): - """Install the PEP 302 import hook if using assertion re-writing. + """Install the PEP 302 import hook if using assertion rewriting. Needs to parse the --assert= option from the commandline - and find all the installed plugins to mark them for re-writing + and find all the installed plugins to mark them for rewriting by the importhook. """ ns, unknown_args = self._parser.parse_known_and_unknown_args(args) diff --git a/_pytest/pytester.py b/_pytest/pytester.py index 82aa00e0d..f041ae4cf 100644 --- a/_pytest/pytester.py +++ b/_pytest/pytester.py @@ -712,7 +712,7 @@ class Testdir: # When running py.test inline any plugins active in the main # test process are already imported. So this disables the # warning which will trigger to say they can no longer be - # re-written, which is fine as they are already re-written. + # rewritten, which is fine as they are already rewritten. orig_warn = AssertionRewritingHook._warn_already_imported def revert(): diff --git a/doc/en/announce/release-2.7.0.rst b/doc/en/announce/release-2.7.0.rst index 07ae44ca1..4e317ff8f 100644 --- a/doc/en/announce/release-2.7.0.rst +++ b/doc/en/announce/release-2.7.0.rst @@ -62,7 +62,7 @@ holger krekel - fix issue655: work around different ways that cause python2/3 to leak sys.exc_info into fixtures/tests causing failures in 3rd party code -- fix issue615: assertion re-writing did not correctly escape % signs +- fix issue615: assertion rewriting did not correctly escape % signs when formatting boolean operations, which tripped over mixing booleans with modulo operators. Thanks to Tom Viner for the report, triaging and fix. diff --git a/doc/en/writing_plugins.rst b/doc/en/writing_plugins.rst index 5dccdb884..b22c2d4d8 100644 --- a/doc/en/writing_plugins.rst +++ b/doc/en/writing_plugins.rst @@ -184,16 +184,16 @@ statements and the detailed introspection of expressions upon assertion failures. This is provided by "assertion rewriting" which modifies the parsed AST before it gets compiled to bytecode. This is done via a :pep:`302` import hook which gets installed early on when -``pytest`` starts up and will perform this re-writing when modules get +``pytest`` starts up and will perform this rewriting when modules get imported. However since we do not want to test different bytecode -then you will run in production this hook only re-writes test modules +then you will run in production this hook only rewrites test modules themselves as well as any modules which are part of plugins. Any -other imported module will not be re-written and normal assertion +other imported module will not be rewritten and normal assertion behaviour will happen. If you have assertion helpers in other modules where you would need assertion rewriting to be enabled you need to ask ``pytest`` -explicitly to re-write this module before it gets imported. +explicitly to rewrite this module before it gets imported. .. autofunction:: pytest.register_assert_rewrite @@ -216,10 +216,10 @@ With the following typical ``setup.py`` extract: ... ) -In this case only ``pytest_foo/plugin.py`` will be re-written. If the +In this case only ``pytest_foo/plugin.py`` will be rewritten. If the helper module also contains assert statements which need to be -re-written it needs to be marked as such, before it gets imported. -This is easiest by marking it for re-writing inside the +rewritten it needs to be marked as such, before it gets imported. +This is easiest by marking it for rewriting inside the ``__init__.py`` module, which will always be imported first when a module inside a package is imported. This way ``plugin.py`` can still import ``helper.py`` normally. The contents of @@ -263,7 +263,7 @@ for assertion rewriting (see :func:`pytest.register_assert_rewrite`). However for this to have any effect the module must not be imported already; if it was already imported at the time the ``pytest_plugins`` statement is processed, a warning will result and -assertions inside the plugin will not be re-written. To fix this you +assertions inside the plugin will not be rewritten. To fix this you can either call :func:`pytest.register_assert_rewrite` yourself before the module is imported, or you can arrange the code to delay the importing until after the plugin is registered. diff --git a/testing/test_assertion.py b/testing/test_assertion.py index 244b47516..e87fe6915 100644 --- a/testing/test_assertion.py +++ b/testing/test_assertion.py @@ -151,7 +151,7 @@ class TestImportHookInstallation(object): @pytest.mark.parametrize('plugin_state', ['development', 'installed']) def test_installed_plugin_rewrite(self, testdir, mode, plugin_state): # Make sure the hook is installed early enough so that plugins - # installed via setuptools are re-written. + # installed via setuptools are rewritten. testdir.tmpdir.join('hampkg').ensure(dir=1) contents = { 'hampkg/__init__.py': """