Search code examples
pythonlinuxpytestpyenv

pytest running with another version of python


I've installed pyenv and have different versions of python installed with it:

$ pyenv versions
  system
  2.7.1
  3.2.5
  3.5.0
  3.5.1
* 3.5.2

I use the following command to switch to python 3.5.2:

pyenv shell 3.5.2

And when I check the python version this is what I get:

$ python --version
Python 3.5.2

But when I run pytest, it still runs under python 2.7.6:

pytest -v
==================================================================== test session starts ====================================================================
platform linux2 -- Python 2.7.6, pytest-3.0.3, py-1.4.31, pluggy-0.4.0 -- /usr/bin/python

Why is pytest running under the older version?


Solution

  • Bottom line: run

    • python -m pytest, or
    • py.test-<version> if your alternative Python and pytest are installed with system package manager, or
    • if your alternative Python has been installed with pyenv, switch with pyenv to that version and make sure you have pytest installed for it. Then you can just run pytest.
      • since the pip executable is also among the ones being switched, you need to switch to the alternative Python before installing pytest for it, too.

    As I can see, /usr/bin/pytest (that belongs to the system package manager's python-pytest package) has a shebang !#/usr/bin/python since it corresponds to the system python's installation.

    pyenv, as its README.md says, does not replace /usr/bin/python - because it indeed should not be replaced to avoid breaking system packages.

    Instead, it adds its directory to PATH and inserts a launcher there (called "shim") which is what gets invoked when you type "python". As you probably guessed, this hack is ignored by a shebang like the above - as it should.

    • Running python -m pytest will make whichever python that launches itself use the package from its installation.
    • Alternatively, pytest for your other Python version may include versioned executables on the PATH named py.test-<version> (e.g. py.test-3 or py.test-3.6) depending on the way you installed it.
      • If it's from a system package manager's package for nonstandard python - like python36-pytest - this is virtually guaranteed.
      • I checked that if you install a version with pip, it only creates an unversioned executable (though you can create a versioned one yourself). Moreover, if you install the same package for a different Python version but with the same --prefix, it will overwrite the existing one's executable!
    • pyenv's suggested way seems to be to install all python versions of interest and packages for them under ~/.pyenv/versions.
      • This is not applicable for the system's Python but the default /usr/local can be used for it.
      • Once you switch to an alternative Python version, it claims to create shims for all scripts (including pip!) that are currently installed for that version, so invoking those scripts without a path would run those shims.
        • So, if a package (and thus its script) is not installed for the alternative version but installed for system version, trying to run its executable would "fall through" to /usr/local with just the result you're seeing now.