Skip to content
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

How to correctly run pytest.main() programmatically multiple times? #3143

Closed
numirias opened this issue Jan 23, 2018 · 16 comments
Closed

How to correctly run pytest.main() programmatically multiple times? #3143

numirias opened this issue Jan 23, 2018 · 16 comments
Labels
good first issue easy issue that is friendly to new contributor type: docs documentation improvement, missing or needing clarification

Comments

@numirias
Copy link

numirias commented Jan 23, 2018

If I invoke pytest.main(['test_foo.py']) multiple time from the same running script, it will give the same result, even if test_foo.py changes between the runs. (This was also observed in #793.)

But then what is the correct way to rerun pytest programmatically? Could you point me to an example? Starting it in a subprocess feels quite clunky and also makes it more cumbersome to process the results.

(Also, could we possibly have a note about that behavior in the docs? At least to me, it was somewhat unexpected that I can't run pytest.main() in the same script twice.)

@pytestbot pytestbot added the type: bug problem that needs to be addressed label Jan 23, 2018
@RonnyPfannschmidt RonnyPfannschmidt added type: docs documentation improvement, missing or needing clarification and removed type: bug problem that needs to be addressed labels Jan 23, 2018
@RonnyPfannschmidt
Copy link
Member

python modules cache in side the same process and due to this property of python its not advisable to run pytest.main twice from the same process

while there may be exceptions to that rule, in general its more safe to run a new process since python is not safe for code reloading

@nicoddemus
Copy link
Member

I agree, we should just add a note to the docs regarding that.

@endolith
Copy link

endolith commented Jan 4, 2019

So the recommendation is to completely close python and start a new process every time you want to test your code? I don't remember this being a problem with pytest in the past, has it changed?

@nicoddemus
Copy link
Member

@endolith this does not have to with pytest, but how Python itself works: it caches the modules it imports.

For example:

# foo.py
def f(): return 1
>>> import foo
>>> foo.f()
1
>>>

Now if we change foo.py to:

# foo.py
def f(): return 2

and continue in the same session:

>>> import foo
>>> foo.f()
1
>>> foo.f()
1

I don't remember this being a problem with pytest in the past, has it changed?

Sorry, I'm reasonably sure pytest never supported this, because again it doesn't have to do with pytest but how Python works... and I don't think pytest had any special code in place to workaround this.

@nicoddemus
Copy link
Member

BTW there's a note at the bottom of the docs for exactly this issue: https://docs.pytest.org/en/latest/usage.html

@endolith
Copy link

endolith commented Jan 5, 2019

@nicoddemus Apparently the reason it works for me is a side effect of running inside of Spyder: https://stackoverflow.com/questions/54009371/pytestwarning-module-already-imported-so-cannot-be-rewritten-pytest-remotedata/54011939?noredirect=1#comment94930323_54011939 and the warnings about PytestWarning: Module already imported so cannot are the only thing that's changed?

@nicoddemus
Copy link
Member

Oh that explains it then. 👍

@endolith
Copy link

So what's the recommended way to do this? pytest.main() prints a bunch of warnings, subprocess.call(['pytest', ... doesn't print the output, etc.

@endolith
Copy link

Something like this works, but is kind of ugly:

if __name__ == "__main__":
    from subprocess import Popen, PIPE
    with Popen(['pytest',
                '--tb=short',  # shorter traceback format
                '--hypothesis-show-statistics',
                str(__file__)], stdout=PIPE, bufsize=1,
               universal_newlines=True) as p:
        for line in p.stdout:
            print(line, end='')

@nicoddemus
Copy link
Member

Indeed running as a subprocess is the recommended way to do this.

@endolith
Copy link

endolith commented Feb 19, 2019

@nicoddemus Maybe a convenience function can be written to do this? Or at least add some hints to the note at the bottom of https://docs.pytest.org/en/latest/usage.html

@nicoddemus
Copy link
Member

I'm OK with a note to the docs.

Btw, do you know the pytester fixture? It may be used to invoke python tests in a "block-box" style testing, if that's what you are doing.

@endolith
Copy link

endolith commented Apr 2, 2019

@nicoddemus No I don't know about pytester, would that help me? All I'm doing is writing a program and tests simultaneously in the same file, and running the tests each time I change the file to make sure I didn't break anything.

@blueyed
Copy link
Contributor

blueyed commented Apr 2, 2019

@endolith
Check out https://github.com/joeyespo/pytest-watch/ then maybe, or just use inotify tools/wrappers (e.g. https://github.com/blueyed/dotfiles/blob/master/usr/bin/inotify-run).
Also check out https://github.com/tarpas/pytest-testmon/ maybe to only re-run changed/affected tests.

@nicoddemus
Copy link
Member

For that use case @blueyed's suggestions are on point then. 👍

@endolith
Copy link

endolith commented Aug 6, 2022

pytest.main([__file__]) also prints colored text to the IDE, character-by-character, just like running pytest filename on the command line, while the monstrosity I posted above is still buffering on some level, so it only prints in chunks, and only white text. Is there really no way to make pytest.main work as expected, so we can edit the test file, run it, see the results in the IDE, fix mistakes, run it again, etc.?

There's no way to add an option like

if __name__ == '__main__':
    pytest.main([__file__], newprocess=True)

or something?

This is the junk I have at the end of every test_….py file to try to mimic the functionality of pytest.main() while still being compatible with numba and being able to be re-run repeatedly: https://github.com/endolith/elsim/blob/master/tests/test_star.py#L630

It feels wrong, but I don't see what the right way is.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue easy issue that is friendly to new contributor type: docs documentation improvement, missing or needing clarification
Projects
None yet
Development

No branches or pull requests

6 participants