Python types have reference cycles to themselves when they are created. This is
partially caused by descriptors which get / set values from the __dict__
attribute for getattr / setattr on classes.
This is not normally an issue since types tend to remain referenced for the
lifetime of the Python process (and thus never become garbage).
However, in the case of PseudoFixtureDef, the class is generated in
_get_active_fixturedef and later discarded when pytest_fixture_setup returns.
As a result, the generated PseudoFixtureDef type becomes garbage.
This is not really a performance issue but it can lead to some problems when
making tests and assertions about garbage when using pytest.
This garbage creation problem can be rectified by returning a namedtuple
instance which is functionally the same. In the modified code, the namedtuple
is allocated / deallocated using reference counting rather than having to use
the garbage collector.
The leak was caused by the (unused) `FixtureRequest._fixture_values`
cache.
This was introduced because the `partial` object (created to call
FixtureDef.finish() bound with the Request) is kept alive
through the entire session when a function-scoped fixture depends
on a session-scoped (or higher) fixture because of the nested
`addfinalizer` calls.
FixtureDef.finish() started receiving a request object in order to
obtain the proper hook proxy object (#2127), but this does not seem
useful at all in practice because `pytest_fixture_post_finalizer`
will be called with the `request` object of the moment the fixture value
was *created*, not the request object active when the fixture value
is being destroyed. We should probably deprecate/remove the request
parameter from `pytest_fixture_post_finalizer`.
Fix#2981
This implicit definition really tripped me while debugging #2127,
unfortunately hidden as it was in the middle of all the variable
declarations.
I think the explicit definition is much easier for the eyes and IDEs
to find.
fixtures.reorder_items is non-deterministic because it reorders based
on iteration over an (unordered) set. Change the code to use an
OrderedDict instead so that we get deterministic behaviour, fixes#920.