From 62381125e74e62e051176afe602feb937dabcef8 Mon Sep 17 00:00:00 2001 From: Robert Holt Date: Mon, 19 Aug 2019 15:57:39 -0400 Subject: [PATCH 1/2] Fix self reference in function scoped fixtures --- AUTHORS | 1 + changelog/2270.bugfix.rst | 1 + src/_pytest/fixtures.py | 4 ++++ testing/python/fixtures.py | 29 +++++++++++++++++++++++++++++ 4 files changed, 35 insertions(+) create mode 100644 changelog/2270.bugfix.rst diff --git a/AUTHORS b/AUTHORS index 88bbfe352..ad0c5c07b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -209,6 +209,7 @@ Raphael Castaneda Raphael Pierzina Raquel Alegre Ravi Chandra +Robert Holt Roberto Polli Roland Puntaier Romain Dorgueil diff --git a/changelog/2270.bugfix.rst b/changelog/2270.bugfix.rst new file mode 100644 index 000000000..45835deb6 --- /dev/null +++ b/changelog/2270.bugfix.rst @@ -0,0 +1 @@ +Fix ``self`` reference in function scoped fixtures that are in a plugin class diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index d5f9ad2d3..0640ebc90 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -897,6 +897,10 @@ def resolve_fixture_function(fixturedef, request): # request.instance so that code working with "fixturedef" behaves # as expected. if request.instance is not None: + if hasattr(fixturefunc, "__self__") and not isinstance( + request.instance, fixturefunc.__self__.__class__ + ): + return fixturefunc fixturefunc = getimfunc(fixturedef.func) if fixturefunc != fixturedef.func: fixturefunc = fixturefunc.__get__(request.instance) diff --git a/testing/python/fixtures.py b/testing/python/fixtures.py index 1f383e752..ee050b909 100644 --- a/testing/python/fixtures.py +++ b/testing/python/fixtures.py @@ -3945,6 +3945,35 @@ class TestScopeOrdering: reprec = testdir.inline_run() reprec.assertoutcome(passed=2) + def test_class_fixture_self_instance(self, testdir): + testdir.makeconftest( + """ + import pytest + + def pytest_configure(config): + config.pluginmanager.register(MyPlugin()) + + class MyPlugin(): + def __init__(self): + self.arg = 1 + + @pytest.fixture(scope='function') + def myfix(self): + assert isinstance(self, MyPlugin) + return self.arg + """ + ) + + testdir.makepyfile( + """ + class TestClass(object): + def test_1(self, myfix): + assert myfix == 1 + """ + ) + reprec = testdir.inline_run() + reprec.assertoutcome(passed=1) + def test_call_fixture_function_error(): """Check if an error is raised if a fixture function is called directly (#4545)""" From 3ddbc7fb2a63f6ca505f64368d5bd4dd939f0ea9 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 30 Aug 2019 11:20:19 -0300 Subject: [PATCH 2/2] Improve CHANGELOG and add some comments Ref: #5768 --- changelog/2270.bugfix.rst | 3 ++- src/_pytest/fixtures.py | 2 ++ testing/python/fixtures.py | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/changelog/2270.bugfix.rst b/changelog/2270.bugfix.rst index 45835deb6..0da084597 100644 --- a/changelog/2270.bugfix.rst +++ b/changelog/2270.bugfix.rst @@ -1 +1,2 @@ -Fix ``self`` reference in function scoped fixtures that are in a plugin class +Fixed ``self`` reference in function-scoped fixtures defined plugin classes: previously ``self`` +would be a reference to a *test* class, not the *plugin* class. diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index 0640ebc90..a8da1beec 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -897,6 +897,8 @@ def resolve_fixture_function(fixturedef, request): # request.instance so that code working with "fixturedef" behaves # as expected. if request.instance is not None: + # handle the case where fixture is defined not in a test class, but some other class + # (for example a plugin class with a fixture), see #2270 if hasattr(fixturefunc, "__self__") and not isinstance( request.instance, fixturefunc.__self__.__class__ ): diff --git a/testing/python/fixtures.py b/testing/python/fixtures.py index ee050b909..4f13dd245 100644 --- a/testing/python/fixtures.py +++ b/testing/python/fixtures.py @@ -3946,6 +3946,9 @@ class TestScopeOrdering: reprec.assertoutcome(passed=2) def test_class_fixture_self_instance(self, testdir): + """Check that plugin classes which implement fixtures receive the plugin instance + as self (see #2270). + """ testdir.makeconftest( """ import pytest