The Poetry packaging and dependency management tool is the somewhat-new hotness for creating and maintaining a Python project.
This article is an introductory tutorial (also known as "I am writing this down so I learn it better now and have somewhere to look when I forget it later").
Install Poetry
To install Poetry on Windows, launch a powershell window, then:
(iwr https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py -UseBasicParsing).Content | python
Then make sure %USERPROFILE%\.poetry\bin
is on your PATH
variable. Search your start menu for "environment" and you should find somthing like "Edit environment variables for your account."
To do the same on Mac, Linux, etc.:
curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python
Then make sure $HOME/.poetry/bin
is in your PATH
variable. Most likely, Poetry has already modified your ~/.profile
to source $HOME/.poetry/env
, but you can double-check this or configure the PATH
in the way you choose.
The official Poetry docs provide further detail.
Initialize the project with poetry
Poetry can create the directory and initial structure.
poetry new --name greet --src pygreet
This will create a directory pygreet
with the package greet
in a src
directory.
While a variety of ways to structure your distribution package exist, I like the approach of placing Python code in a src
directory. Poetry supports this with the --src
flag, as shown above.
Add code
There are several decisions to be made about structuring code, and you are welcome to read my article on Python modules and packages.
For now, I am simply adding another module to the greet
package, and will call it location.py
. It contains the following code:
"""Send greetings."""
import arrow
def greet(tz):
"""Greet a location."""
now = arrow.now(tz)
friendly_time = now.format("h:mm a")
location = tz.split("/")[-1].replace("_"," ")
return f"Hello, {location}! The time is {friendly_time}."
So now the project directory looks like this:
pygreet/
├── README.rst
├── pyproject.toml
├── src
│ └── greet
│ ├── __init__.py
│ └── location.py
└── tests
├── __init__.py
└── test_greet.py
Adding dependencies
That import arrow
in our code requires the date library arrow to be installed as a dependency. To do so, use poetry add
:
poetry add arrow
If you need to hunt for more packages, Poetry has a convenient search utility in poetry search
, so that poetry search arrow
will return a list of all PyPI packages with "arrow" in the name.
Install package and dependencies
To install the package in developer mode, along with its dependencies:
poetry install
Using the virtual environment
The poetry run
command will execute the command in the virtual environment. For instance, try the following:
[pygreet]$ poetry run python
>>> from greet.location import greet
>>> greet("Asia/Shanghai")
'Hello, Shanghai! The time is 4:05 am.'
>>>
Executing a shell in the virtual environment (i.e. activating it) is also possible with poetry shell
after which we can execute python or other commands.
[pygreet]$ poetry shell
Spawning shell within
~/.cache/pypoetry/virtualenvs/pygreet-abcd1234-py3.8
[pygreet]$ . ~/.cache/pypoetry/virtualenvs/pygreet-abcd1234-py3.8/bin/activate
(pygreet-abcd1234-py3.8) [pygreet]$ python
>>> from greet.location import greet
>>>
And that is a great way to test the module we wrote... Uh, no. No, that's not it at all.
Write tests and use pytest with Poetry
Tests can be written while developing the project. Poetry has already partly scaffolded the initial tests by creating a tests
directory and an initial test_greet.py
file. Edit that file and add an additional test. Something like
from greet.location import greet
def test_greet():
result = greet("America/New_York")
assert "New York!" in result
Then either run poetry run pytest
or, if already in the shell launched by poetry shell
, just running pytest
will do.
If the tests passed, so have we. Nicely done.
Feel free to take a look at a follow-up article on building a command line tool with Poetry.
Top comments (5)
Your articles on poetry and typer/typer_cli have helped me a lot. Thank you so much!
Thanks for caring for windows!
Yeah, that makes sense. Thanks for the explanation!
This is great to hear! I am so curious about pyenv, too. I have used it, but haven't really found it necessary. Feel free to say more about the benefits of using pyenv with Poetry.
from greet.location import greet
doesn't miss src there?