-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Better handling of mark signatures #5418
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
Comments
API for 5.1 (or later)There are two aspects here: how to provide the mark signature and when. HowThe user provides a Python function with the desired signature: def skipif(condition, *, reason=None):
... The return value must be a pair of def skipif(condition, *, reason=None):
return (condition,), dict(reason=reason)
def parametrize(argnames, argvalues, *, indirect=False, ids=None, scope=None):
return (argnames, argvalues), dict(indirect=indirect, ids=ids, scope=scope) The idea of returning a custom object which would then be returned by WhenRight now makers are registered during def pytest_configure(config):
config.addinivalue_line(
"markers", "env(name): mark test to run only on named environment"
) We can follow the same idea and provide a function in the def pytest_configure(config):
def env_marker(name):
"""mark test to run only on named environment"""
return (name,), {}
config.register_marker("env", env_marker) Perhaps we can swap the order of the parameters and use the name of the function as default for the name of the marker: def pytest_configure(config):
def env(name):
"""mark test to run only on named environment"""
return (name,), {}
config.register_marker(env, name=None) # name is optional One small problem with the above approach (including the existing If we want to restrict users to only call def pytest_configure(marker_registry):
def env(name):
"""mark test to run only on named environment"""
return (name,), {}
marker_registry.register_marker(env, name=None) # name is optional Thoughts? |
-10 on it, we should aim for type based markers in general and registering marker constructors by name this whole mess randomly combined data has to go |
That's harsh. 😳 I assume you mean the proposal for the API, not the first proposal about using function signatures to validate the builtin markers?
You mean supporting different types of marks? My proposal for the API allows for that, you can use |
i dont mean "type" as in kinds, i mean Type as in instead of
and registration should have a primary metadata entrypoint aka
this would allow the marker registry to set up pretty early in the configuration process on top of that there should e a mechanism to add back the legacy markers, and for backward compatibility for quite a while there should be name based legacy markers, and type based modern markers additionally a marker "constructor" should be able to return none to skip out, and it should be possible t have more than one type of marker per marker name (so the runtime can choose which implementations of a marker apply) |
I see, that's what I had in mind: register_marker("skipif", ConditionalSkip)
Point taken about being able to register this as meta-data, either in setup(
entry_points={
"pytest11": ["timeout = pytest_timeout"],
"pytest-markers": ["pytest_timeout.TimeoutMark"],
},
...
) But does this mean you don't want any type of runtime registration?
How about: [pytest.markers]
slow = "pytest.Marker" # name-based marker
timeout = "pytest_timeout.TimeoutMark"
Not sure I follow, could you elaborate? |
i already had the static registration example in my initial writeup the problem is, that if we go from on order to keep api consumers working we need a mechanism so that both exist for a while, slowly opting out of the legacy api/marker declaration mechanism |
OK. Does the example of using the entry points in
Just declaring named markers is very useful and probably the most common use case out there, for example |
that reminds we that there should be a more correct mechanism for symbolic markers |
Closing in favor of #5424 |
A known problem when dealing with marks is to properly support the intended signature, as this can be tricky and error prone.
For example, the official signature of
skipif
is:But the skipping plugin needs to manually handle this signature using
args
andkwargs
, which is error prone and has been a source of errors in the past (letting an unknown keyword argument slip through silently for example).Someone mentioned about using actual Python functions to declare mark signatures in our pytest sprint back in 2016 (I think it was @RonnyPfannschmidt or @hpk42). I decided to play a bit with it and got excited about how simple it was to get this working (thanks to @RonnyPfannschmidt's large mark refactoring):
If we pass the wrong arguments, we get the expected error:
And even better, at collection time instead of at runtime.
While we should have a large discussion on the design of an API to expose this functionality to users for custom marks, I propose we adopt this strategy in 5.0 for the builtin marks. This will help users catch errors now, while not exposing any implementation detail. Even if we decide on a completely different approach in the future, this is transparent to users.
The text was updated successfully, but these errors were encountered: