Replies: 9 comments 35 replies
-
I use explicit type annotation just fine, jedi and a number of ides also have basic support for inferring |
Beta Was this translation helpful? Give feedback.
-
Getting rid of the existing fixture mechanism is a non-starter, IMHO - it would be a major rewrite for anything using pytest. That massive code churn is hard to justify, and not going to be liked. Also, not everyone likes using types (I do!). One thing I had in the back of my head for a while is class fixtures. In a nutshell:
This would be backwards compatible, but allow using imports and type annotations for fixtures where desired. Probably should see how hard it is to implement and/or cook up a more detailed proposal at some point... |
Beta Was this translation helpful? Give feedback.
-
Not sure I follow this statement...
IDEs (well at least PyCharm) infer the type of the fixtures in tests (because they have specific support for pytest). I believe VSCode does too. Could you elaborate on both points please? I think it is important to clarify them because someone might "fly by" over the pool and leave with the impression that they can't use type annotations with pytest, or they are incompatible somehow (which is not true). |
Beta Was this translation helpful? Give feedback.
-
This is a hard pass from me. One of the big advantages pytest offers over other test platforms is the "magic" of fixture dependency injection. Changing that behavior, to require explicit imports in order to benefit the subsection of users that also use types, would likely keep most users from upgrading to that pytest version. I think a better way would be to recommend specific rules for fixture organization in a project. IDEs and tools like mypy could then make a best effort to discover fixtures based on these rules. This is the approach I'm taking with a project I'm working on that also needs to solve the fixture resolution problem. |
Beta Was this translation helpful? Give feedback.
-
Out of curiosity - what would the imported version look like? The current "magic" way of course can't be removed: that being said, I'm in the camp that magic isn't real and providing an alternative certainly wouldn't be bad. I haven't seen a concrete list of reasons (goals) that an import-related syntax might be preferred but here are a couple things I can think of:
However, I'm having a bit of a tough time imagining how this might look practically. Importing the fixtures directly to use them has the slight disadvantage that property-like objects now need to be called as functions (I think, unless pytest can change the function definitions to objects. But that sounds messy for typing). Another downside is confusing during migration - global imported callable fixtures would have the same name as kwargs. One random brainstorming thought was that # Current syntax
# my_fixture in conftest.py, my_local_fixture in this file
def test_something(my_fixture: str, my_local_fixture: int):
assert my_fixture == "abcd"
assert my_local_fixture == 4 # Potential new syntax
# Same fixture definitions as above assumed
# Plus nonlocal_fixture defined in tests/otherfile.py
from pytest import fx
# decorator optional, something to indicate can't use fixtures as arguments
@pytest.mark.strict_fixtures
def test_something():
fix_str = fx.my_fixture. # property-like syntax possible
fix_int = fx.my_local_fixture
fix_other = fx.otherfile.nonlocal_fixture # Nonlocal fixtures accessible
assert fix_str == "abcd"
... Interested to see what the original idea looked like |
Beta Was this translation helpful? Give feedback.
-
First, I think there is nothing wrong with injecting fixtures as a parameters and otherwise it would be difficult to manage scopes (i.e. how to express session-scoped fixture?) with ordinary imports. The most important is to have type annotation for function parameter - how fixture can be used. This is pretty much covered in #9947. It also looks like the discussion is between using type or parameter name as a key for injection. Right now pytest uses parameter name and type is ignored completely. However, both type and parameter name are part of function interface (if we think about a test as an ordinary API function) - you can't change either freely without breaking users. And it doesn't really matter where pytest takes the actual values to be passed as parameters to the test. There are other alternatives, each has pros and cons.
|
Beta Was this translation helpful? Give feedback.
-
While this post seems to have some age, as it is still open, I would like to point out that the magic dependency injection also has significant downsides. As with any magic operating on a global namespace, it fails to respect modularity principles, which makes composition hard. The fact that typing tools have a problem with that is just one manifestation. The current design makes that namespace as global as it just could be, which has led to hard-to-debug bugs in the past (see e.g. #3966) and has led to the request of alternate ways of pulling fixtures (see e.g. #3834). Thus, anything that follows the rules of python should be preferred over domain-specific magic. |
Beta Was this translation helpful? Give feedback.
-
I think while the discussion here is interesting, we can close this as pytest will not implement such a breaking change. We are trying to improve the internal so plugins might be able to change and add to the existing fixture mechanism, so alternatives can be implemented outside the core. Thanks everyone! |
Beta Was this translation helpful? Give feedback.
-
If you look at the way that FastAPI uses dependency injection, you will also find a pattern that's compatible with typehints and type checkers. Following the footsteps of FastAPI is certainly a proven track-record, so also seems safe and to repeat experience/knowledge that many developers might already have. Previous: @pytest.fixture
def my_fixture():
return [1, 2, 3]
def test_something(my_fixture):
assert sum(my_fixture) == 6 This could become something like: from typing import Annotated, List
from pytest import Depends
def get_my_fixture() -> List[int]:
return [1, 2, 3]
def test_something(my_fixture=Annotated(List[int], Depends(get_my_fixture))):
assert sum(my_fixture) == 6 |
Beta Was this translation helpful? Give feedback.
-
As we know, part of pytest design was to magically discover/load fixtures and make them available to tests, so test writer would not have to remember to import them.
That magic used was dependency injection and it was made very long time ago, far before python typing was introduced. Sadly,it does not play very well with typing because runtime checkers like mypy cannot really infer the types for test method signatures. Lack of it causes confusiones and usually breaks auto-complete in IDEs.
Inside #5981 it was suggested that maybe we should reconsider this architecture decision, so we do not cripple the typing support.
Please note that this poll result does not mean it would be acten on, think about it as a survey.
180 votes ·
Beta Was this translation helpful? Give feedback.
All reactions