Python stuff
Python
Problem, we have multiple versions of python, each version of python can have different set of module/package versions. Computer OS’s come with specific versions, different production stacks may have different setups. How do we manage to test & develop across all flavours using the same development machine?
pyenv
pyenv is a mature tool for installing and managing multiple Python versions on macOS. Despite the similarity in names (pyvenv vs pyenv), pyenv is different in that its focus is to help you switch between Python versions on a system-level as well as a project-level. While the purpose of pyvenv is to separate out modules, the purpose of pyenv is to separate Python versions.
1
2
3
4
5
6
7
8
9
$ brew install pyenv
$ pyenv versions
* system
$ python --version
Python 2.7.10
$ pyenv install 3.7.3 # This may take some time
$ pyenv versions
* system
3.7.3
Alternative installer
1
$ curl -L https://raw.githubusercontent.com/yyuu/pyenv-installer/master/bin/pyenv-installer | bash
You can manage which Python you’d like to use in your current session, globally, or on a per-project basis as well. pyenv will make the python command point to whichever Python you specify. Note that none of these overrides the default system Python for other applications, so you’re safe to use them however they work best for you within your Python environment;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ pyenv global 3.7.3
$ pyenv versions
system
* 3.7.3 (set by /Users/dhillard/.pyenv/version)
$ pyenv local 3.7.3
$ pyenv versions
system
* 3.7.3 (set by /Users/dhillard/myproj/.python-version)
$ pyenv shell 3.7.3
$ pyenv versions
system
* 3.7.3 (set by PYENV_VERSION environment variable)
$ python --version
Python 3.7.3
Virtual Environments
Why? Virutal environments allow you to isolate python projects from the pre-installed stuff thats comes with the OS. Also allows each python project to have its own dependancies that won’t interfere/disrupt other python projects on the same box. This is especially important when using third-party packages, running different versions of python etc.
Which one? Several to choose from; virtualenv, python environment wrapper (pew), venv, pipenv, pyenv
venv
venv ships with Python >= v3.3. venv builds on top of the original independent virtualenv project. venv is useful if working with only one version of python, and, since its bundled with python no additional software needs to be installed to use it.
1
2
3
$ python3 -m venv ~/.virtualenv/my_environments/foo # creates a folder ~/.virtualenv/my_environments/foo
$ source ~/.virtualenvs/my_environments/foo/
$ deactivate
virtualenv
If you’re using python versions <3.3 then virtualenv is usually installed (via pip)
1
2
3
4
5
6
7
8
$ pip install virtualenv
$ mkdir ~/project/python-virtual-environments && cd ~/project/python-virtual-environments
$ # Python 2
$ virtualenv my_env # creates the environment
$ source env/bin/activate # starts the environment
(env) $
(env) $ deactivate # to exit the environment
$
virtualenvwrapper
virtualenvwrapper is a set of extensions to the virtualenv tool. It provides similar features to pyenv-virtualenv.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ pip install virtualenvwrapper # python2
$ pip3 install virtualenvwrapper # python3
# path is different if installed locally not system wide.
$ which virtualenvwrapper.sh
/usr/local/bin/virtualenvwrapper.sh
$ export WORKON_HOME=$HOME/.virtualenvs # Optional or add it to .bashrc
$ export PROJECT_HOME=$HOME/projects # or equivalent
$ source /usr/local/bin/virtualenvwrapper.sh
$ mkvirtualenv my-new-project
(my-new-project) $
(my-new-project) $ deactivate
$ workon # list environments
my-new-project
my-django-project
web-scraper
# Create a virtual env using a specific version of Python
$ virtualenv -p $(which python3) blog_virtualenv
$
pyvenv
Between python v3.3 and v3.4 the recommended way to create virtual environments was by using the pyvenv cmd which comes with python3.
From python v3.6 onwards that recommendation changed to python3 -m venv blah
pyenv-virtualenv
pyenv-virtualenv enhances pyenv by adding a subcommand to manage virtual environments using multiple python versions.
1
2
3
4
5
6
7
$ brew install pyenv-virtualenv # Use brew if thats how pyenv was installed
$ eval "$(pyenv init -)" # Add to shell profile, only need to do this once.
# This line runs activate/deactivate automatically when entering/leaving
# dir containing a .python-version file file that contains the name
# of a valid virtual environment as shown in the output of pyenv virtualenvs
$ eval "$(pyenv virtualenv-init -)"
Usage, create a virtualenv using the current version of Python in use by pyenv;
1
2
3
$ pyenv version
3.4.3 (set by foobar)
$ pyenv virtualenv my_venv3.4.3
Create a virtual environment using a specific version of python
1
2
3
$ pyenv version
3.4.3 (set by foobar)
$ pyenv virtualenv 2.7.10 my_venv-2.7.10
1
2
3
4
5
$ pyenv virtualenvs # List virtual environments
$ pyenv activate <name> # activate virtualenv
$ pyenv deactivate # deactivate
$ pyenv uninstall my-virtual-env # Delete venvs, two ways not sure
$ pyenv virtualenv-delete my-virtual-env # what the diff is?
What’s really nice about pyenv-virtualenv is that you can configure a virtual environment using the pyenv local command and have pyenv-virtualenv auto-activate the right environments as you switch to different directories:
1
2
3
4
5
6
7
8
9
10
11
12
$ pyenv virtualenv 3.7.3 proj2
$ cd /Users/dhillard/proj1
$ pyenv local proj1
(proj1)$ cd ../proj2
$ pyenv local proj2
(proj2)$ pyenv versions
system
3.7.3
3.7.3/envs/proj1
3.7.3/envs/proj2
proj1
* proj2 (set by /Users/dhillard/proj2/.python-version)
pyenv-virtualenv uses python -m venv
if it is available and the virtualenv command is not available.
Python PIP
pip is the package installer for Python. You can use pip to install packages from the Python Package Index and other indexes.
pip is already installed if you are using Python 2 >=2.7.9 or Python 3 >=3.4 downloaded from python.org or if you are working in a Virtual Environment created by virtualenv or pyvenv. See pip Installation.
Use pip to install python packages;
1
2
3
4
5
6
$ pip <pip arguments>
$ pip help # usefull summary of available commands
$ python -m pip <pip arguments> # Run pip commands through python
$ pip install <package_name>
$ pip install package_name==1.0.4 # Install specific version
$ pip install 'package_name>=1.0.4' # Install minimum version
Requirements file
A “requirements” file capture a list of items to be installed using pip install
When working with virtual environments, its common to install specific packages/package versions whilst developing new code.
The requirements file can capture the specific list of packages using;
1
$ pip freeze > requirements.txt
requirements.txt can then be checked into version control with your project.
The same environment can be restored by reinstalling the same set of packages within a virtual environment, using;
1
$ pip install -r requirements.txt
Tools to help debug
Loguru
Print better exceptions (using a decorator)
pip install loguru
snoop
Print the lines of code being executed in a function (using a decorator)
pip install snoop
heartrate
Visualise the execution of a python program in real-time within a browser (localhost)
pip install heartrate
Python dictionary comprehension
Lots of examples on the web, but more likely to remember one of my own; See example json response, wish to split into to key value pairs, hence strip the keys “Name” and “Value” for unique keys
import json
response='{ "UserAttributes":[ { "Name":"custom:postcode", "Value":"OX5 1LU" }, { "Name":"sub", "Value":"bd2c8db5-0b08-4f0f-be9e-069564b654f3" }, { "Name":"address", "Value":"|6||Stocks Tree Close|Yarnton|KIDLINGTON|Oxfordshire|OX5 1LU||||9Z3|ElecM|GasM|NoIGT|" }, { "Name":"email_verified", "Value":"true" }, { "Name":"given_name", "Value":"Test4" }, { "Name":"family_name", "Value":"Test6" }, { "Name":"custom:initial_email_optout", "Value":"false" }, { "Name":"email", "Value":"atul.patel@trustpower.com" } ], "Username":"bd2c8db5-0b08-4f0f-be9e-069564b654f3" }'
json_resp = json.loads(response)
UserAttr = {}
# Using a for-loop
for key in json_resp['UserAttributes']:
UserAttr[f"{key['Name']}"] = key['Value']
# Using a dictionary comprehension
UserAt = {f"{key['Name']}" : key['Value'] for key in json_resp['UserAttributes']}
print(UserAttr['sub'])
print(UserAt['sub'])
Pdb - debugger
ToDo
structuring python code Object Oriented Design Gang-of-four OOD best practice Pipenv python plotting data Python best practice