-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Allow to dynamically create fixture in plugin #12376
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
The ask here is very unclear Unfortunately it's pretty much a open research question |
What part should I clarify? |
Both the ask here and the documentation of the plugin are entirely unclear I'm not going to guess and I'm not going to try and figure it from the source code |
At this moment, you can only create fixture using In pytest-mh, we are passing custom values to each test. The values are objects that are unique for each tests and they are dynamically created as needed by the test. For example: def test_example(client: ClientRole, ldap: LDAPRole):
pass This will pass to the test client and ldap objects that provide high-level API to manage relevant services. We can't convert these parameters into fixtures using One of the reason is a thing we call "topology parametrization", which means that single test can be run against different hosts (backends) and then parameter called The way I am doing it currently is by putting these parameters into @pytest.fixture
def my_fixture(client: ClientRole):
pass
def test_example(client: ClientRole, ldap: LDAPRole, my_fixture):
pass Then pytest raises exception because What I would like to have is an option to dynamically register and unregister fixture. So when I am at I hope this clarifies things. Please, let me know if it is still unclear. |
@pbrezina Yes it is my intention to make However, I don't think it it will satisfy your requirements, since in pytest fixtures must be registered during the collection phase, and there is no way to unregister them, while you want to do it on setup/teardown. |
Just to comment on this bit:
I don't think we need to expose FixtureManager, perhaps just a public function would suffice? Say: def register_fixture(function: Callable, scope: FixtureScope, location: Node) -> None: |
@nicoddemus The implementation itself does need to get at the FixtureManager. So it needs to take |
Yep, that's why I added |
Ah missed the type. The minor problem here is one I hinted at above, namely that there a case where pytest/src/_pytest/fixtures.py Lines 1668 to 1676 in 48cb8a2
|
I see, well no problem adding a |
Well... having this functionality would be very nice. In the mean time, I have implemented the following workaround: def mh_fixture(scope: Literal["function"] = "function"):
def decorator(fn):
full_sig = inspect.signature(fn)
mh_args = []
for arg, hint in get_type_hints(fn).items():
if issubclass(hint, MultihostRole):
mh_args.append(arg)
continue
@wraps(fn)
def wrapper(mh: MultihostFixture, *args, **kwargs):
if 'mh' in full_sig.parameters:
kwargs['mh'] = mh
for arg in mh_args:
if arg not in mh.fixtures:
raise KeyError(f"{fn.__name__}: Parameter {arg} is not a valid topology fixture")
kwargs[arg] = mh.fixtures[arg]
return fn(*args, **kwargs)
cb = wraps(fn)(partial(wrapper, **{arg: None for arg in mh_args}))
fixture = pytest.fixture(scope="function")(cb)
partial_parameters = [inspect.Parameter('mh', inspect._POSITIONAL_OR_KEYWORD)]
partial_parameters.extend([param for key, param in full_sig.parameters.items() if key != 'mh' and key not in mh_args])
fixture.__pytest_wrapped__.obj.func.__signature__ = inspect.Signature(partial_parameters, return_annotation=full_sig.return_annotation)
return fixture
return decorator But I don't really like that it is using internal pytest knowledge ( And of course, it quite a hack and it requires user to use type hints. But this works: @mh_fixture
def my_fixture(client: Client, request):
print(client)
print(request) |
What's the problem this feature will solve?
I am the author of next-actions/pytest-mh which is a multihost testing plugin for pytest. We are doing some black magic to dynamically create test fixtures and map them to some custom objects. Some user-focused details are described here but TLDR we are doing this:
In this scenario,
client
andldap
are passed to the test_example by setting it initem.funcargs
in runtest hook to internal objects created per-tests.pytest_fixture
is standard pytest fixture. This works nicely and it is using only public fields (I'm not sure if funcargs is documented, but at the very least it is not prefix with_
).However, accessing these data from pytest fixture fails, obviously:
... because
client
is not a registered fixture. I probably could manage that by accessing pytest private stuff, but I'd like to avoid that.I would like to be able to create and delete fixture (at least function-scoped) inside hooks.
Describe the solution you'd like
Provide API to dynamically register and unregister fixtures from pytest hooks.
Alternative Solutions
Currently, deep and private pytest objects and attributes are required.
Additional context
The text was updated successfully, but these errors were encountered: