Skip to content

Fixture definition check in parsefactories is too strict #13564

Open
@eldjh3

Description

@eldjh3

What's the problem this feature will solve?

Since pytest >= 8.4.0 the check that fixtures are of type FixtureFunctionDefinition causes issues for plugins. One such plugin that I use in my test suite is pytest_lambda.

Now, I'm not sure this is the case for all, but one could easily argue that these plugins rely on internal implementation details that are not guaranteed and subject to change, so caveat emptor. Nevertheless, they worked and are now broken.

pytest_lambda specifically relied on returning an instance of itself from its lambda_fixture function. Later it would resolve fixtures into the actual underlying calls. To do this it relied on PytestWrapped and other internals which no longer exist.

I'm a mere user of it, but I've attempted to make some changes to make it work with pytest >= 8.4.0.

In doing so, one restriction that has been problematic is the check in parsefactories:

            if type(obj_ub) is FixtureFunctionDefinition:
                marker = obj_ub._fixture_function_marker

This forces the return from all fixture generating functions to be the exact type FixtureFunctionDefinition. You can't subclass it or the type won't match.

pytest_lambda against older pytest supports various nice syntaxes to declare fixtures (see https://pypi.org/project/pytest-lambda/). In order to support these, without being able to subclass FixtureFunctionDefinition requires hackery to replace the __class__/type with a different type, detect this later in the plugin when its iterating over all names in pytest_collectstart or pytest_pycollect_makeitem, do what's necessary with the derived type and then replace the __class__ attribute so the fixture gets registered.

It feels like this would be a lot less brittle if there was an officially supported way to do such things. An easy way would appear to be allowing subclasses of FixtureFunctionDefinition.

NOTE - I did try to invert the logic in pytest_lambda to remove all dependence on internal and just call pytest.fixture from pytest_lambda code, but that suffers the same issue in that it doesn't expose hooks to allow for more advanced usage (e.g. destructuring the return value of a fixture generation function by returning an iterator instead of a FixtureFunctionDefinition).

Describe the solution you'd like

Make FixtureFunctionDefinition an exposed type (i.e. in pytest namespace) and allow subclassing of to enable more advanced fixture generation.

Alternatively, provide an alternative means to do the same.

Additional context

Problematic scenarios/syntaxes:

# Destructuring the return value.  Requires hacking an iterator onto FixtureFunctionDefinition
x, y, z = lambda_fixture('aa', 'bb', 'cc')

# Destructuring param values (used to generate parameterised tests)
# I don't personally use this, but was attempting to keep feature parity
pa, pb, pc, pd = lambda_fixture(params=[
    pytest.param('alfalfa', 'better', 'dolt', 'gamer'),
])

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions