Skip to content

monkeypatch fixture shared between testfunc and fixture func #981

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

Closed
codewarrior0 opened this issue Aug 29, 2015 · 8 comments
Closed

monkeypatch fixture shared between testfunc and fixture func #981

codewarrior0 opened this issue Aug 29, 2015 · 8 comments

Comments

@codewarrior0
Copy link
Contributor

Occurs with py.test 2.7.2 on multiple platforms and Python versions.

I have a fixture function that uses monkeypatch to modify sys.path, and a test function that also uses monkeypatch to modify the cwd and then restore it to its old value. When monkeypatch.undo() is called in the test function, it undoes the changes done in the fixture function:


@pytest.fixture
def builder(monkeypatch):
    monkeypatch.syspath_prepend(_MODULES_DIR)
    # ... return some object ...

def test_function(builder, monkeypatch):
    monkeypatch.chdir(_DATA_DIR)
    # ... do some stuff ...
    monkeypatch.undo()
    # Here, _MODULES_DIR is no longer in sys.path

Is there a way to get a different monkeypatch object in the test function?

@codewarrior0
Copy link
Contributor Author

The problem persists on master as of commit 553aef5

@codewarrior0
Copy link
Contributor Author

As a workaround, I think I will create a new fixture called builder_monkeypatch that returns a _pytest.monkeypatch.monkeypatch object and use that fixture only for builder. I'm a bit leery about importing anything from _pytest, though.

@The-Compiler
Copy link
Member

The current behaviour is definitely unfortunate in this case, but intended - fixtures have a given scope (function/class/module or session), and their return value is cached in the given scope. The default (and smallest) scope is function, i.e. a fixture will be called at most once for each test.

I'm not sure what a good solution would be for this kind of thing - maybe having a new unique (name TBD, of course) scope, which means the fixture function gets called every time the fixture gets used? That'd also need some special casing to allow unique fixtures to be used by function fixtures though...

Let's see if someone else can come up with a better solution.

@flub
Copy link
Member

flub commented Aug 29, 2015

While a unique scope might be a nice idea, I do not think calling monkeypatch.undo() manually is something that should be done. The whole purpose of the monkeypatch fixture is so that undo gets called automatically. It seems what this usecase wants is a context manager for the cwd (which pathlib in py3 might provide?).

I'd rather close this issue as I don't think its a use case for a unique scope and what's described here is indeed as intended. If there is a good use case for a unique scope then feel free to open a different issue requesting it.

Thanks

@flub flub closed this as completed Aug 29, 2015
@codewarrior0
Copy link
Contributor Author

I found it surprising that calling undo() in one function undoes monkeypatches done in another function. I also find it surprising that I shouldn't call undo() even though it is a public API. On the other hand, _pytest.monkeypatch.monkeypatch is not a public API, and I'm apparently forced to use that if I can't or won't apply pathlib (the test suite must run on Python 2.7, and if I need to undo a change to, say, os.environ or sys.path then it is no help anyway).

I guess I'll open an issue requesting a new scope if I ever actually need to undo a change to sys.path or undo some other attribute change...

codewarrior0 added a commit to codewarrior0/pytest that referenced this issue Aug 30, 2015
Note that calling `undo()` is generally not needed, and describe the "gotcha" discovered in pytest-dev#981.
@RonnyPfannschmidt
Copy link
Member

@codewarior0 we once did brainstorming on more granular monkeypatch, it quickly turned into something incomprehensible due to more and more edge cases

We want to retry in future, the main problem is finding a way to support their surroundings

@codewarrior0
Copy link
Contributor Author

I wonder if the granularity could be done by making monkeypatch itself into a context manager? A la:

def test_function(monkeypatch):
    with monkeypatch as mp1:
        mp1.syspath_prepend(FOO)
        # ... do some stuff ...
    with monkeypatch as mp2:
        mp2.syspath_prepend(BAR)
        # ... do some other stuff ...

@RonnyPfannschmidt
Copy link
Member

Yes, the details are at stuff like yield fixtures

I think we need a monkey patch manager fixture and a sub request scope,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants