Developing Python CLIs with Poetry
2020 Feb 17
Poetry brings a simplified interface to Python’s packaging and distribution system. It makes all the right things easy to do.
Here’s how you use it to develop a new Python CLI project.
Getting started
We’ll make a CLI called hello-snake
, in a package and project called snake
.
First run poetry new
to create the project skeleton.
tom@tomtop 🎪:~/tmp
% poetry new snake
Created package snake in snake
The resulting directory tree:
tom@tomtop 🎪:~/tmp
% tree snake
snake
├── README.rst
├── pyproject.toml
├── snake
│ └── __init__.py
└── tests
├── __init__.py
└── test_snake.py
Change to the snake
project directory. Poetry will manage a virtualenv for
the project, tied to the project path and Python version. Create the
virtualenv and open a pre-activated shell with poetry shell
.
tom@tomtop 🎪:~/tmp
% cd snake
tom@tomtop 🎪:~/tmp/snake
% poetry shell
Creating virtualenv snake--jYlyyG6-py3.8 in /Users/tom/Library/Caches/pypoetry/virtualenvs
Spawning shell within /Users/tom/Library/Caches/pypoetry/virtualenvs/snake--jYlyyG6-py3.8
tom@tomtop 🎪:~/tmp/snake
% . /Users/tom/Library/Caches/pypoetry/virtualenvs/snake--jYlyyG6-py3.8/bin/activate
(snake--jYlyyG6-py3.8) tom@tomtop 🎪:~/tmp/snake
%
Our CLI entrypoint will be in the snake.console
module. Create it in
snake/console.py
, next to snake/__init__.py
, and add a run()
function to
serve as entrypoint.
def run():
print("🐍")
Our project will ship a single executable, named hello-snake
. Add it to the
tool.poetry.scripts
section of pyproject.toml
.
[tool.poetry.scripts]
hello-snake = 'snake.console:run'`
This specifies that the program hello-snake
executes the function run()
in
the module snake.console
.
Install the package and its dependencies to the virtualenv.
(snake--jYlyyG6-py3.8) tom@tomtop 🎪:~/tmp/snake
% poetry install
Updating dependencies
Resolving dependencies... (0.2s)
Writing lock file
Package operations: 9 installs, 0 updates, 0 removals
...
- Installing snake (0.1.0)
You can now run the new CLI as hello-snake
.
(snake--jYlyyG6-py3.8) tom@tomtop 🎪:~/tmp/snake
% hello-snake
🐍
The snake
package is installed to the virtualenv as “editable”, so that
changes made in the project source directory are reflected immediately whenever
you run hello-snake
. To try that out, let’s make the snake a little angrier.
Update console.py
.`
def run():
print("🐍 tsssssss")
And hello-snake
includes the change without having to re-install our package:
(snake--jYlyyG6-py3.8) tom@tomtop 🎪:~/tmp/snake
% hello-snake
🐍 tsssssss
All of this should continue to work the next time you open a poetry shell
for
this project.
Packaging and distribution
It’s easy to share and distribute your new CLI package. Use poetry build
to
create tarball and wheel packages under dist/
.
tom@tomtop 🎪:~/tmp/snake
% poetry build
Building snake (0.1.0)
- Building sdist
- Built snake-0.1.0.tar.gz
- Building wheel
- Built snake-0.1.0-py3-none-any.whl
The wheel file can be distributed to users, to be installed to their global Python environment:
tom@tomtop 🎪:~/tmp/snake
% pip install --user dist/snake-0.1.0-py3-none-any.whl
Processing ./dist/snake-0.1.0-py3-none-any.whl
Installing collected packages: snake
Successfully installed snake-0.1.0
WARNING: You are using pip version 19.2.3, however version 20.0.2 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
Once the wheel is installed, the users can run hello-snake
.
tom@tomtop 🎪:~/tmp/snake
% hello-snake
🐍 tsssssss