pyenv-virtualenv icon indicating copy to clipboard operation
pyenv-virtualenv copied to clipboard

.python-version doesn't refer to python version

Open mehulkar opened this issue 7 years ago • 27 comments

I'm a little confused by how this is supposed to work.

From what I understand, to use this project, the .python-version should be the name of the virtualenv, (as opposed to the actual python version) I want my project to use.

The way I expected to use this project is something like:

echo "2.7" >> .python-version
echo "some_name" >> .python-virtualenv
pyenv install $(cat .python-version) $(cat .python-virtualenv)

This is similar to how .ruby-version and .ruby-gemset files are used.

The main issue I'm facing here is, if .python-version contains the name of the virtualenv, where should I be configuring the python version? I don't think this should belong in documentation.

Also note that I'm a new to Python world, so it's very possible that I'm overlooking something.

Thank you for this project and pyenv though! I'm mostly pretty happy that this is available for use!


Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

mehulkar avatar Sep 26 '16 21:09 mehulkar

The feature where cd'ing into a directory activates the virtual specified in .python-version seems the most confusing to me. Perhaps this feature could fallback to a .python-virtualenv file so that .python-version can contain the real python version? or maybe .python-version can contain both the version and the virtualenv?

mehulkar avatar Sep 26 '16 22:09 mehulkar

AFAIK, unlike RVM's gemset, a virtualenv is tightly coupled with specific Python installation. Because of that, in pyenv-virtualenv, I implemented to manage a virtual environment as a version in pyenv. Splitting .python-version and .python-virtualenv will just introduce unnecessary complexity without benefit.

yyuu avatar Sep 27 '16 00:09 yyuu

@yyuu I see, that sort of makes sense. How do you usually configure the actual version then when using pyenv and pyenv-virtualenv? Does that live in source control?

mehulkar avatar Sep 27 '16 17:09 mehulkar

@mehulkar The virtualenv you are using yourself is local to your system really (and therefore .python-version with its name would not be in source control). You usually do not require a specific Python version for a project, and if so it would be probably defined in setup.py etc.

blueyed avatar Sep 27 '16 18:09 blueyed

@blueyed hmm, that is really different from Ruby world. There are a couple of things that seem weird to me:

  1. that a python version is not usually defined for projects
  2. There isn't a reliable way to tell users or the shell what version of python should be installed.

Isn't this a pain for people joining a new project? (regardless of whether they use pyenv).

I guess this question then isn't really about pyenv then, and more about how Pythonistas manage versions at all :/

mehulkar avatar Sep 27 '16 19:09 mehulkar

It's more important what versions your requirements are at, and for that you have requirements.txt (which is used to build the virtualenv then). It does not really matter (for development) if you have 3.5 or 3.4 in the end.

As for me: using Arch Linux gives me the latest always, and for checking other versions (with tox etc) I use pyenv.

blueyed avatar Sep 27 '16 19:09 blueyed

As a new pyenv user (and also coming form the world of rbenv), I have a bit of an issue with this as well.

First, though: is pyenv intended solely to be a personal productivity tool, or are build integration and environment reproducibility a goal as with rbenv?

If it's exclusively for personal productivity, I think this is fine.

If .python-version is meant to be checked into version control and shared among team members, or perhaps even used to install runtimes or to be integrated with tox during builds, the virtualenv name in the version file becomes meaningless and my environment isn't reproducible by others (or builds).

There are plenty of potential breaking changes in minor version changes; for example, I ran across this code today that breaks on 3.3 and works on 3.4, which led me to pyenv so I could pin the version in my project, and... here I am :).

Just a thought. In general, great project! It's nice to have a modern approach to version management in Python.

zachwalton avatar Oct 06 '16 18:10 zachwalton

First, though: is pyenv intended solely to be a personal productivity tool, or are build integration and environment reproducibility a goal as with rbenv?

Agreed, i think this is a good question to ask. Thanks @zachwalton. Based on @blueyed's response from before, it sounds like it's not something that's meant to be shared between teams or in automation.

My question as a new user then would be, what is the way to share this type of environment setup in Python world?

mehulkar avatar Oct 06 '16 20:10 mehulkar

My question as a new user then would be, what is the way to share this type of environment setup in Python world?

For Heroku-compatible projects (and I've seen this convention applied to various build pipelines and one-off, non-Heroku projects), runtime.txt.

You can always fall back on that as a convention even if yours isn't a Heroku app; it at least gives users an intuitive way to reproduce the environment.

zachwalton avatar Oct 06 '16 21:10 zachwalton

This also got me today, coming from rbenv/nodenv I assumed .python-version would specify the python version and nothing else. Then a separate file, or just .venv folder would contain the actual virtualenv.

The ruby analogue would be rbenv+bundler, the first is solely for managing ruby version and the latter for application specific gems, aka pip, dependencies. Of course you can have a plugin for rbenv that integrates bundler, and here I thought this plugin would be the equivalent for pyenv.

For node it's something similar, .node-version specifies the node version and npm* handles the dependencies, which are always installed locally into node_modules.


To be concrete, overloading .python-version is going to keep shooting people in the foot. But to avoid even more .<name>-version files, why not always keep the virtualenv in the same folder with some useful name? Then it can be easily git/hgignored and it would be obvious which virtualenv is which.

It would even allow easy detecting, just walk up the directory tree and look for a .venv folder.

*or any npm compatible tool, yarn/jspm/…

maxnordlund avatar Feb 06 '17 12:02 maxnordlund

It does not really matter (for development) if you have 3.5 or 3.4 in the end.

It really does matter. People want reproducible builds so there is no chance of a newcomer running into unexpected issues.

Seems like the workaround for now is to specify the version in your virtualenv, as the Usage example:

$ pyenv virtualenv 2.7.10 my-virtual-env-2.7.10

New users can create a virtualenv of the same name.

For my projects, I will commit the .python-version file.

jcrben avatar Mar 04 '17 22:03 jcrben

I will commit the .python-version file, too, as is a common practice in the Ruby community.

The .ruby-version file isn't only used by rbenv, either. For example, it's respected by RVM (a predecessor of and "competitor" to rbenv that's still popular) and Google App Engine depends on it.

gohanlon avatar Apr 18 '17 23:04 gohanlon

I ended up writing my own plugin (in fish) that automatically picks up a .venv file which specifies the virtual env to use. It's in my dotfiles, see pyenv.d and bin, if anyone is interested.

It's only for python 3's venv module though, since that's what I use, but could be adopted for virtualenv as well.

maxnordlund avatar Apr 19 '17 05:04 maxnordlund

The way I was trying to use pyenv-virtualenv was on top of pyenv itself, for local development only. But my projects are using pyenv to specify the python version needed on different stages.

Example: Local dev : pyenv + pyenv-virtualenv CI: pyenv (no venv, system install in a VM) Prod: pyenv (no venv, system install in a Docker image)

Example: CircleCI is using pyenv for version management.

@yyuu Can you share your opinion about this flow?

pior avatar Jun 08 '17 14:06 pior

Just for reference: there is also a recipe for zsh-autoenv to automatically activate virtualenvs at https://github.com/Tarrasch/zsh-autoenv#automatically-activate-python-virtualenvs.

blueyed avatar Jun 08 '17 14:06 blueyed

This bit us today, given how .ruby-version and .node-version/.nvmrc files works I've always assumed .python-version was intended for the same workflow of committing the file to lock down the interpreter for all developers and CI tools.

gaggle avatar Oct 17 '17 11:10 gaggle

After a year of working in Python, I can come back to this issue and say a couple more things I've learned:

  • Python version is pretty consistent across projects and the version of your dependencies is the more important thing. This is very different to someone from the Ruby or Node community where language runtime versions are more important.
  • Virtualenv is usually a local thing on your computer and not committed to source control. We did use a virtualenv in production for one project, but the name of it didn't matter.

For every python project I've worked on (usually scripts and daemons, not web apps), I've adopted the workflow of creating a virtualenv inside the project directory and activating it manually every time I'm working on the project. Forgetting to activate it or navigating between projects/directories while one env is activated can sometimes lead to accidental pip installs, etc, but those are pretty easy to reverse. I also don't typically jump between projects much so this wasn't a problem for me.

So, I think the main value-add of using this project is if you want to share virtualenvs between projects or if you want to store a virtualenv outside the project directory in some common location. That way, giving each virtualenv a name becomes useful and activating that env becomes useful.

I still think the file that this project reads should not be called .python-version, but that is a pretty minor point in the grand scheme of things.

Hope this helps!

mehulkar avatar Oct 17 '17 17:10 mehulkar

Related HTH: https://github.com/Tarrasch/zsh-autoenv - which has a recipe for automatically enabling .venv also.

blueyed avatar Oct 17 '17 22:10 blueyed

(emphasis mine)

For every python project I've worked on (usually scripts and daemons, not web apps), I've adopted the workflow of creating a virtualenv inside the project directory and activating it manually every time I'm working on the project.

That's the entire point of having the .python-version and using pyenv local so that it always happens automatically. Whether it's stored on disk in your directory is somewhat irrelevant.

jimmywan avatar Oct 23 '17 18:10 jimmywan

That's the entire point of having the .python-version

that would be fine, if that file is ignored from the repo. If it's committed to source control then it makes things confusing because I'm imposing the convention on team members who will be confused about why a filed called "python version" has nothing to do with the python version.

mehulkar avatar Oct 23 '17 19:10 mehulkar

btw: there are tools like zsh-autoenv and others (see the references there in the README) that are better handling setting up envs.

Check out https://github.com/Tarrasch/zsh-autoenv#automatically-activate-python-virtualenvs to automatically activate any .venv.

(mentioned it already, so unsubscribing.. ;))

blueyed avatar Oct 23 '17 20:10 blueyed

btw^2: pyenv works very well by itself without pyenv-virtualenv.

blueyed avatar Oct 23 '17 20:10 blueyed

If it's committed to source control then it makes things confusing...

Don't commit it. Problem solved.

jimmywan avatar Oct 23 '17 22:10 jimmywan

@jimmywan that was one of the core things being challenged in this PR: "is this intended for sharing/CI or just personal use".

mehulkar avatar Oct 25 '17 18:10 mehulkar

this is a pain point for me as well, i ended up using the following format: .python-version:

3.6.3/envs/nameofmyenv

then in each project readme, i require the following to be run as a setup step, which is unfortunate:

# install the correct python version
pyenv install $(sed "s/\/envs.*//" .python-version)
# create a virtualenv
pyenv virtualenv $(sed "s/\/envs\// /" .python-version)

one idea is to extend pyenv virtualenv to with a command like pyenv install (without params) that reads this file/format and both ensures the right python version and the virtualenv exist, if not installs/creates them. would this work for anyone else?

nathantsoi avatar Nov 03 '17 16:11 nathantsoi

I use this for personal use. When sharing and I care to ensure that my code works for multiple versions of python I use tox and pyenv and do not use virtual environments.

I use pyenv to install all of the python versions I want to test against.
In my project the .python-version file looks like:

2.7.14
3.3.7
3.4.7
3.5.4
3.6.3

In my tox.ini I have

envlist = clean,py27,py34,py35,py36,docs-html,coverage-report
skip_missing_interpreters = True`

Which will test against python version 2.7, 3.4, 3.5, and 3.6 and skip interpreters that don't exist.

if someone else want to test, or to integrate into CI/CD then .python-version show exactly what python versions I am testing against and folks can choose what versions they want to test.

I was just revisiting an old gradle/groovy/spock project. Python is much less formal in its approach.

quagly avatar Dec 24 '17 19:12 quagly

As a newbie to pyev-virtualenv I was also shut in the foot by .python-version (see this github issue and this stackoverflow question) The word version in it made me think about the Python version installed e.g. via pyenv install 3.8.1 so when using pyenv local I just entered 3.8.1 and not the name of virtualenv.

I think that .python-version besides for personal use could also be usefull for teams, provided that there are clear development environment setup instructions and each team member has the same Python versions and virtualenv names installed on the system.

However for sharing purpose we have docker and docker images now.

So for me the .python-version is confusing and should be changed to something like .python-venv or .venv. Also the command pyenv versions is a little bit confusing as it list all virtual environments (names proceeded with versions) and not just Python versions installed via pyenv install, but this is less painful...

When creating a virtualenv a specific Python version was specified so putting just the virtualenv name in .python-version should be enough.

tony-bony avatar Feb 22 '20 09:02 tony-bony