Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

python: fix instance handling in static and class method tests #12096

Merged
merged 3 commits into from
Mar 10, 2024

Conversation

bluetech
Copy link
Member

@bluetech bluetech commented Mar 9, 2024

and also fixes a regression in pytest 8.0.0 where setup_method crashes if the class has static or class method tests.

It is allowed to have a test class with static/class methods which request non-static/class method fixtures (including setup_method xunit-fixture). I take it as a given that we need to support this somewhat odd scenario (stdlib unittest also supports it).

This raises a question -- when a staticmethod test requests a bound fixture, what is that fixture's self?

stdlib unittest says - a fresh instance for the test.

Previously, pytest said - some instance that is shared by all static/class methods. This is definitely broken since it breaks test isolation.

Change pytest to behave like stdlib unittest here.

In practice, this means stopping to rely on self.obj.__self__ to get to the instance from the test function's binding. This doesn't work because staticmethods are not bound to anything.

Instead, keep the instance explicitly and use that.

BTW, I think this will allow us to change Class's fixture collection (parsefactories) to happen on the class itself instead of a class instance, allowing us to avoid one class instantiation. But needs more work.

Fixes #12065.

bluetech added 3 commits March 9, 2024 10:16
No longer does unittest stuff. Also the rest of the sentence is not
really necessary for a docstring.
No need to compute the property multiple times.
and also fixes a regression in pytest 8.0.0 where `setup_method` crashes
if the class has static or class method tests.

It is allowed to have a test class with static/class methods which
request non-static/class method fixtures (including `setup_method`
xunit-fixture). I take it as a given that we need to support this
somewhat odd scenario (stdlib unittest also supports it).

This raises a question -- when a staticmethod test requests a bound
fixture, what is that fixture's `self`?

stdlib unittest says - a fresh instance for the test.

Previously, pytest said - some instance that is shared by all
static/class methods. This is definitely broken since it breaks test
isolation.

Change pytest to behave like stdlib unittest here.

In practice, this means stopping to rely on `self.obj.__self__` to get
to the instance from the test function's binding. This doesn't work
because staticmethods are not bound to anything.

Instead, keep the instance explicitly and use that.

BTW, I think this will allow us to change `Class`'s fixture collection
(`parsefactories`) to happen on the class itself instead of a class
instance, allowing us to avoid one class instantiation. But needs more
work.

Fixes pytest-dev#12065.
Copy link
Member

@nicoddemus nicoddemus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work!

assert isinstance(items[1], Function)
assert items[1].name == "test_method"
assert items[1].instance is not None
assert items[1].instance.__class__.__name__ == "TestIt"

# Even class and static methods get an instance!
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it is possible for this to break some plugin which is using instance to check if the method is a static/classmethod, but I suppose this is far fetched.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You prompted me to check how plugins use instance. Overall it's almost not used, the only prominent case I found is pytest-asyncio, whose usage is not problematic if I'm reading correctly and according to its tests.

pytest-asyncio however was broken by yesterday's removal of FixtureDef.unittest (#12089), for which I will send them a fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Pytest 8.1.0 AttributeError: 'NoneType' object has no attribute 'setup_method' with staticmethod test
2 participants