Automate Python Virtual Environment with a Script
Issue
There are 2 things that annoy me every time when I create a python virtual environment.
Note
Below instructions are related to the python’s default venv module.
If you are using any other version/virtual environment management tools, like Conda, Poetry, Pyenv, below doesn’t apply.
The first one is that I have to type every time:
$ python -m venv ./.venv
$ . ./.venv/bin/activate
# or
# $ source ./.venv/bin/activate
The second thing is that after installing any package I’m getting below pip
version WARNING:
WARNING: You are using pip version 21.1.1; however, version 22.0.4 is available.
You should consider upgrading via the '/path/to/project/.venv/bin/python3.8 -m pip install --upgrade pip' command.
It is an expected behavior, ‘cause python -m venv
calls python -m ensurepip
to
install pip
.
And there is no way to globally upgrade since pip
is installed with bundled
version which is almost out of date. You can check it like below:
>>> import ensurepip
>>> ensurepip.version()
'21.1.1'
Even though you can’t upgrade to the latest version with below commands as mentioned in ensurepip doc:
$ python -m ensurepip --upgrade
Because ensurepip
will only install the bundled version even with the
--upgrade
option.
There is no official option to update the bundled pip
and setuptools
, yet.
Solution
Okay, since we are developers, we always find our ways and produce our solutions that suits our needs.
My solution comes from a shell script. You can put it in your shell
configuration file, like .zshrc
, .bashrc
, config.fish
.
With below function, when I enter ve
command, it will create my virtual
environment — if it doesn’t exist, activate it and upgrade to the latest pip
version.
|
|
This function may seem complex, so let me walk through it line by line.
$1
is the first argument, the desired python version, $2
is the second
argument which is virtual environment’s name/directory, provided to the function
ve()
. If no arguments provided function will use default values: python3.8
and .venv
. You can these default values according to your needs.
ve() {
local py=${1:-python3.8}
local venv="${2:-./.venv}"
local bin="${venv}/bin/activate"
...
}
You can provide positional arguments like:
$ ve python3.9 .venv2
After creating local variables
, if we are already in a virtual environment,
it just gives “already in a virtual environment” message. It decides this
whether we’re in a virtual environment by checking if there is a environment
variable called $VIRTUAL_ENV
exported from activate
—
.venv/bin/activate
, script.
|
|
If we’re not in a virtual environment, it will control if .venv
directory
exists. If the directory exists, it will be activated:
|
|
However, if .venv
directory does not exist, it will:
- Create virtual environment
.venv
with global packages included (line 7), - Add exporting desired python version environment variable into
activate
script (line 8) - Activate the virtual environment (line 9)
- Upgrade the current
pip
version to the latest one (line 11)
|
|
Info
You probably don’t need line 8, I’m adding this, because using this environment
variable in my other aliases
/functions
/binaries
.
Conclusion
In the end, with this shell script we solved our annoying bugs and make us more productive again.
You can find this script in this gist or in function from my dotfiles repo.
All done!
Changelog
- 2022-05-10 : Added gist and dotfiles link references