Skip to content

Pytest plugin has side effect and is extremely unintuitive to use #566

@codethief

Description

@codethief

This might not be considered a bug, but it is – at the very least – a severe code smell.

Describe the bug
Once pyfakefs is installed, the pytest plugin seems to get loaded automatically and register a fixture with pytest. This has severe consequences:

  • I don't even have to import pyfakefs anywhere in my project's code and yet I still have a dependency on pyfakefs that is completely non-obvious.
  • It is hard to read someone else's unit tests, as it is unclear where that fs parameter is coming from
  • If I try to make the dependency on pyfakefs obvious by e.g. doing from pyfakefs.pytest_plugin import fs, the import will seem un-used and linters and code formatters will complain about it or even remove it automatically.
  • I cannot have different fs fixtures in different tests. The pytest fixture that pyfakefs registers is global state.
  • I cannot use the @patchfs decorator on one of my pytest unit tests to make the pyfakefs dependency more obvious as @patchfs uses the same named parameter fs and employs functools.wraps to make the wrapped function look like the original one (including its named parameters). (Attempting to use @patchfs on a unit test results in a recursion error. Let me know if I should file a separate bug report for this.)

I am aware that a large part of this issue is caused by pytest's weird approach of having a global registry of fixtures. However, the fixture in pyfakefs exacerbates this by orders of magnitude.

Suggestions:

  • Wrap the pytest fixture in pyfakefs.pytest_plugin in a function that the user has to call explicitly somewhere in her/his code in order to register the fixture. (Clearly, this would be a breaking change.)
  • As an alternative, get rid of the fixture – the same functionality could be obtained by using @patchfs and using fixtures is essentially global state. (This would be a breaking change, too.)
  • At least make @patchfs pass the FakeFilesystem instance to the decorated function as the first parameter, instead of as a named parameter fs. This way, one could still use @patchfs on pytest unit tests without interfering with the fixture. (This could break some existing code.)
  • At the very least: Document this very strange behavior. It even took me a while to understand that the example in the current docs is not just a code snippet that's missing setup code and imports but it's all the code that's needed. It is uncompletely unclear that the pytest plugin that's mentioned in the docs gets loaded automatically and the fixture will be registered by default. In fact, in order to learn all this I had to dig through pyfakefs's code.

While a breaking change seems little desirable, it is IMO the only real solution in the long term. One could try to smoothen the transition process by e.g. deprecating the fixture first.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions