4. Problem with (Python) projects
Stuck in the 90s
Over-engineered
@SebaWitowski switowski.com
5. Problem with (Python) projects
Over-engineered
• Too many shiny new tools from
HackerNews
• Those tools gets abandoned
• You spend too much time
replacing old tools with new ones
Stuck in the 90s
@SebaWitowski switowski.com
6. Problem with (Python) projects
Over-engineered
• Too many shiny new tools from
HackerNews
• Those tools gets abandoned
• You spend too much time
replacing old tools with new ones
Stuck in the 90s
• Everything managed with Bash
scripts
• You have to maintain Bash
scripts or some other scripts
(as a Python developer)
@SebaWitowski switowski.com
7. How about a middle ground?
@SebaWitowski switowski.com
8. What will we talk about?
• pyenv - installing different Python versions on your computer
@SebaWitowski switowski.com
9. What will we talk about?
• pyenv - installing different Python versions on your computer
• venv - isolating dependencies of your projects
@SebaWitowski switowski.com
10. What will we talk about?
• pyenv - installing different Python versions on your computer
• venv - isolating dependencies of your projects
• pipx - installing global packages
@SebaWitowski switowski.com
11. What will we talk about?
• pyenv - installing different Python versions on your computer
• venv - isolating dependencies of your projects
• pipx - installing global packages
• pip-tools - dependency pinning
@SebaWitowski switowski.com
14. • Python version preinstalled on your OS is called “system Python”
System Python
@SebaWitowski switowski.com
15. • Python version preinstalled on your OS is called “system Python”
• Please, don’t use it
System Python
@SebaWitowski switowski.com
16. • Python version preinstalled on your OS is called “system Python”
• Please, don’t use it
• And don’t update it (you might break your OS)!
System Python
@SebaWitowski switowski.com
17. How to install a new Python version?
@SebaWitowski switowski.com
18. • Use an installer from python.org
How to install a new Python version?
@SebaWitowski switowski.com
19. • Use an installer from python.org
• Use your package manager
How to install a new Python version?
@SebaWitowski switowski.com
20. • Use an installer from python.org
• Use your package manager
• Compile it from the source files
How to install a new Python version?
@SebaWitowski switowski.com
21. Or you can use pyenv!
https://github.com/pyenv/pyenv
@SebaWitowski switowski.com
22. Or pyenv-win for Windows
https://github.com/pyenv-win/pyenv-win
@SebaWitowski switowski.com
26. Using pyenv
1. Find Python version to install
2. Install it
$ pyenv install 3.9.0
...
# Wait for a few minutes
...
# Done!
@SebaWitowski switowski.com
27. Using pyenv
1. Find Python version to install
2. Install it
3. Check if it’s installed correctly
$ pyenv versions
* system
3.9.0
@SebaWitowski switowski.com
28. Using pyenv
1. Find Python version to install
2. Install it
3. Check if it’s installed correctly
4. Start using this version
$ pyenv global 3.9.0
# or
$ pyenv local 3.9.0
# or
$ pyenv shell 3.9.0
@SebaWitowski switowski.com
29. 3 levels of pyenv
• pyenv global 3.9.0 - changes the global Python version on your computer
@SebaWitowski switowski.com
30. 3 levels of pyenv
• pyenv global 3.9.0 - changes the global Python version on your computer
• pyenv local 3.9.0 - changes Python version for the current folder and all the
sub-folders
@SebaWitowski switowski.com
31. 3 levels of pyenv
• pyenv global 3.9.0 - changes the global Python version on your computer
• pyenv local 3.9.0 - changes Python version for the current folder and all the
sub-folders
# projectA
$ pyenv local 3.9.0
# projectB
$ pyenv local 3.6.0
@SebaWitowski switowski.com
32. 3 levels of pyenv
• pyenv global 3.9.0 - changes the global Python version on your computer
• pyenv local 3.9.0 - changes Python version for the current folder and all the
sub-folders
• pyenv shell 2.7.18 - changes Python version for the current shell session
@SebaWitowski switowski.com
33. Problem with pip
You can only have one version of a given package installed!
@SebaWitowski switowski.com
34. $ pip install Django
...
Django 3.0 installed!
Problem with pip
@SebaWitowski switowski.com
35. Problem with pip
$ pip install Django==2.2
...
...
...
Django 2.2 installed!
@SebaWitowski switowski.com
36. $ pip install Django==2.2
...
Django==3.0 uninstalled!
...
Django 2.2 installed!
Problem with pip
@SebaWitowski switowski.com
37. # .../lib/python3.9/site-packages
$ ls -al
...
drwxr-xr-x 22 switowski 704 Oct 30 12:41 django/
drwxr-xr-x 12 switowski 384 Oct 30 12:41 django_redis/
drwxr-xr-x 16 switowski 512 Sep 28 17:58 docutils/
...
Problem with pip
@SebaWitowski switowski.com
38. # .../lib/python3.9/site-packages
$ ls -al
...
drwxr-xr-x 22 switowski 704 Oct 30 12:41 django/
drwxr-xr-x 12 switowski 384 Oct 30 12:41 django_redis/
drwxr-xr-x 16 switowski 512 Sep 28 17:58 docutils/
...
Problem with pip
@SebaWitowski switowski.com
39. Virtual environment
If pip installs every package in the same folder, why can’t we tell
it to temporarily install them in a different folder?
@SebaWitowski switowski.com
40. Virtual environment
If pip installs every package in the same folder, why can’t we tell
it to temporarily install them in a different folder?
Virtual environment:
• Creates a special folder with Python binaries
• Tells pip to install new packages to that folder
• Tells Python to use packages from that folder
@SebaWitowski switowski.com
42. Using virtual environments
1. Create new virtual environment
2. Activate it
$ source .venv/bin/activate
@SebaWitowski switowski.com
43. Using virtual environments
1. Create new virtual environment
2. Activate it
$ source .venv/bin/activate
# Your prompt should change:
(venv) $
@SebaWitowski switowski.com
44. Using virtual environments
1. Create new virtual environment
2. Activate it
3. Work on your Python project (install packages, run Python)
(venv) $ pip install Django==2.2
...
(venv) $ python manage.py runserver
@SebaWitowski switowski.com
45. Using virtual environments
1. Create new virtual environment
2. Activate it
3. Work on your Python project (install packages, run Python)
4. Deactivate virtual environment to stop using it
(venv) $ deactivate
$
@SebaWitowski switowski.com
51. Global Python packages
• Some tools should be installed globally (black, flake8, virtualenvwrapper)
@SebaWitowski switowski.com
52. Global Python packages
• Some tools should be installed globally (black, flake8, virtualenvwrapper)
• But if they require different versions of the same dependency, one of them
will break
@SebaWitowski switowski.com
53. Global Python packages
• Some tools should be installed globally (black, flake8, virtualenvwrapper)
• But if they require different versions of the same dependency, one of them
will break
• Installing global tools into separate virtual environments is a hassle (you
have to activate each virtual environment to use that tool)
@SebaWitowski switowski.com
54. pipx - global packages in separate environments
https://github.com/pipxproject/pipx
@SebaWitowski switowski.com
55. pipx in action
1. Install “black” package
$ pipx install black
installed package black 20.8b1, Python 3.8.5
These apps are now globally available
- black
- black-primer
- blackd
done! ✨ 🌟 ✨
@SebaWitowski switowski.com
56. pipx in action
1. Install “black” package
2. Use black
$ black hello_world.py
reformatted hello_world.py
All done! ✨ 🍰 ✨
1 file reformatted.
@SebaWitowski switowski.com
57. pipx in action
1. Install “black” package
2. Use black
3. “black” installed in a virtual env will shadow the global one
# Inside a virtual environment
(venv) $ black --version
black, version 19.3b0
# Outside of a virtual environment
$ black --version
black, version 20.8b1
@SebaWitowski switowski.com
58. pipx commands
$ pipx list - list all installed packages
$ pipx uninstall <package> - uninstall package
$ pipx upgrade-all - upgrade all packages
$ pipx inject pytest pytest-cov - install pytest-cov inside
pytest virtual env
@SebaWitowski switowski.com
64. Dependencies in your project
# requirements.txt
Django>=2.2,<3.0
django-redis==4.12.0
pytest==5.*
Dependency pinning:
@SebaWitowski switowski.com
65. Dependencies in your project
Always pin dependencies on production servers!
@SebaWitowski switowski.com
66. Dependencies in your project
Always pin dependencies on production servers!
And their sub-dependencies (3rd party packages)!
@SebaWitowski switowski.com
67. Dependencies in your project
Always pin dependencies on production servers!
And their sub-dependencies (3rd party packages)!
And don’t forget to update packages regularly!
@SebaWitowski switowski.com
68. Dependencies in your project
Always pin dependencies on production servers!
And their sub-dependencies (3rd party packages)!
And don’t forget to update packages regularly!
That’s a lot of work!
@SebaWitowski switowski.com
70. But do you really need them?
@SebaWitowski switowski.com
71. But do you really need them?
• What if they stop working?
@SebaWitowski switowski.com
72. But do you really need them?
• What if they stop working?
• What if they get discontinued?
@SebaWitowski switowski.com
73. But do you really need them?
• What if they stop working?
• What if they get discontinued?
• Do you really use ALL their features?
@SebaWitowski switowski.com
78. pip-compile
# requirements.in
Django>=2.2>,<3.0
pytest
# requirements.txt
#
# This file is autogenerated by pip-compile
# To update, run:
#
# pip-compile requirements.in
#
attrs==20.2.0 # via pytest
django==2.2.17 # via -r requirements.in
importlib-metadata==2.0.0 # via pluggy, pytest
iniconfig==1.1.1 # via pytest
packaging==20.4 # via pytest
pluggy==0.13.1 # via pytest
py==1.9.0 # via pytest
pyparsing==2.4.7 # via packaging
pytest==6.1.2 # via -r requirements.in
pytz==2020.4 # via django
six==1.15.0 # via packaging
sqlparse==0.4.1 # via django
toml==0.10.2 # via pytest
zipp==3.4.0 # via importlib-metadata
$ pip-compile requirements.in
79. pip-compile
# requirements.txt
#
# This file is autogenerated by pip-compile
# To update, run:
#
# pip-compile requirements.in
#
attrs==20.2.0 # via pytest
django==2.2.17 # via -r requirements.in
importlib-metadata==2.0.0 # via pluggy, pytest
iniconfig==1.1.1 # via pytest
packaging==20.4 # via pytest
pluggy==0.13.1 # via pytest
py==1.9.0 # via pytest
pyparsing==2.4.7 # via packaging
pytest==6.1.2 # via -r requirements.in
pytz==2020.4 # via django
six==1.15.0 # via packaging
sqlparse==0.4.1 # via django
toml==0.10.2 # via pytest
zipp==3.4.0 # via importlib-metadata
@SebaWitowski switowski.com
80. pip-compile
# requirements.txt
#
# This file is autogenerated by pip-compile
# To update, run:
#
# pip-compile requirements.in
#
attrs==20.2.0 # via pytest
django==2.2.17 # via -r requirements.in
importlib-metadata==2.0.0 # via pluggy, pytest
iniconfig==1.1.1 # via pytest
packaging==20.4 # via pytest
pluggy==0.13.1 # via pytest
py==1.9.0 # via pytest
pyparsing==2.4.7 # via packaging
pytest==6.1.2 # via -r requirements.in
pytz==2020.4 # via django
six==1.15.0 # via packaging
sqlparse==0.4.1 # via django
toml==0.10.2 # via pytest
zipp==3.4.0 # via importlib-metadata
@SebaWitowski switowski.com
81. pip-compile
# requirements.txt
#
# This file is autogenerated by pip-compile
# To update, run:
#
# pip-compile requirements.in
#
attrs==20.2.0 # via pytest
django==2.2.17 # via -r requirements.in
importlib-metadata==2.0.0 # via pluggy, pytest
iniconfig==1.1.1 # via pytest
packaging==20.4 # via pytest
pluggy==0.13.1 # via pytest
py==1.9.0 # via pytest
pyparsing==2.4.7 # via packaging
pytest==6.1.2 # via -r requirements.in
pytz==2020.4 # via django
six==1.15.0 # via packaging
sqlparse==0.4.1 # via django
toml==0.10.2 # via pytest
zipp==3.4.0 # via importlib-metadata
@SebaWitowski switowski.com
82. pip-compile
# requirements.txt
#
# This file is autogenerated by pip-compile
# To update, run:
#
# pip-compile requirements.in
#
attrs==20.2.0 # via pytest
django==2.2.17 # via -r requirements.in
importlib-metadata==2.0.0 # via pluggy, pytest
iniconfig==1.1.1 # via pytest
packaging==20.4 # via pytest
pluggy==0.13.1 # via pytest
py==1.9.0 # via pytest
pyparsing==2.4.7 # via packaging
pytest==6.1.2 # via -r requirements.in
pytz==2020.4 # via django
six==1.15.0 # via packaging
sqlparse==0.4.1 # via django
toml==0.10.2 # via pytest
zipp==3.4.0 # via importlib-metadata
@SebaWitowski switowski.com
83. pip-compile
# requirements.txt
#
# This file is autogenerated by pip-compile
# To update, run:
#
# pip-compile requirements.in
#
attrs==20.2.0 # via pytest
django==2.2.17 # via -r requirements.in
importlib-metadata==2.0.0 # via pluggy, pytest
iniconfig==1.1.1 # via pytest
packaging==20.4 # via pytest
pluggy==0.13.1 # via pytest
py==1.9.0 # via pytest
pyparsing==2.4.7 # via packaging
pytest==6.1.2 # via -r requirements.in
pytz==2020.4 # via django
six==1.15.0 # via packaging
sqlparse==0.4.1 # via django
toml==0.10.2 # via pytest
zipp==3.4.0 # via importlib-metadata
@SebaWitowski switowski.com
91. Summary
• Use pyenv to install/update Python versions
@SebaWitowski switowski.com
92. Summary
• Use pyenv to install/update Python versions
• Use venv/virtualenvwrapper to isolate dependencies of your projects
@SebaWitowski switowski.com
93. Summary
• Use pyenv to install/update Python versions
• Use venv/virtualenvwrapper to isolate dependencies of your projects
• Use pipx to install global tools
@SebaWitowski switowski.com
94. Summary
• Use pyenv to install/update Python versions
• Use venv/virtualenvwrapper to isolate dependencies of your projects
• Use pipx to install global tools
• Consider pip-tools when you just need to pin dependencies
@SebaWitowski switowski.com