Creating a Python Package | Poetry Quickstart Guide

PYTHON PACKAGING AND DEPENDENCY MANAGEMENT MADE EASY

What is Poetry?

Poetry is a Python packaging and dependency management tool. It makes it easy to manage dependencies and provides a poetry.lock file, which ensures that users' environments are consistent and reproducible.

Some perks of using poetry:

  • poetry automatically spawns and manages virtual environments for your project. Just run poetry shell to get into an isolated environment.

  • poetry can auto-update project/package dependencies. poetry update will update all your dependencies to their latest versions.

  • poetry can easily build and publish python packages to PyPI.

  • poetry can also export its dependency tree as a requirements.txt so it's compatible without other package managers.

For the full list of poetry features, do check out the official Poetry documentation.

Installing Poetry

On Linux/macOS/WSL


curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python -

On Windows


(Invoke-WebRequest -Uri https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py -UseBasicParsing).Content | python -

If you run into any problems using the above, try


pip install poetry

It should work on most machines.

To confirm your installation, run


poetry --version

If you see something like Poetry version 1.1.x, we're good to go!

If you face any challenges, you can refer to the installation guide.

Creating a new Poetry Project

To start a new Python project, run


poetry new <project_name>

That will create a new project with the following structure:


SERVUS
│ pyproject.toml
│ README.rst
│
├───servus
│         __init__.py
│
└───tests
        test_servus.py
        __init__.py

I used servus as my project name. I'll be writing more about that in a future article.

Sneak Peak: servus is a human-friendly wrapper for the aiohttp library for making asynchronous web requests.

What does each file do?

  • pyproject.toml : It's not specific to poetry. It serves a similar purpose as a setup.py, specifying a package's dependencies and properties. You can read more on that here

  • README.rst : reStructuredText for the package's documentation. I prefer working with markdown, so I would change that to README.md, but that's based on preference.

  • servus: The package source folder. It's where you'd put all the code and logic for your package.

  • tests: Houses all the tests for our package.

Installing dependencies

servus depends on the aiohttp library, so I'm going to install it as a requirement/dependency in my project.

In your terminal, from the same directory as your pyproject.toml, run


poetry add aiohttp

That will update our pyproject.toml and poetry.lock with a new dependency.

If a collaborator wanted to set up our project and contribute to it, they'd just clone our project folder and run


poetry install

Running code

First, we need to create some code to run.

In our package source folder (servus) , create a new file, async_api.py.


import aiohttp
import asyncio
import pprint

async def make_web_request(url):
    async with aiohttp.ClientSession() as session:
        response = await session.get(url)
        data = await response.json()
    return data

async def main():
    data = await make_web_request("https://restcountries.com/v3.1/name/nigeria")
    pprint.pprint(data)

# Uncomment for Windows :)
# asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())

asyncio.run(main())

That's just some basic code that makes an asynchronous web request to an API and prints out some data. If you are not familiar with asynchronous Python programming, you can check out my previous article Creating Asynchronous Web Requests with Python.

There are a number of ways to run our code.

  1. Using poetry shell:

  2. Run poetry shell from the same directory as pyproject.toml. This will create a new shell instance with a virtual environment activated. If that doesn't click immediately, that's fine. You just need to remember that to leave this isolated environment, type exit instead of the traditional deactivate. This will 'kill' the new shell process.

  3. Run python servus/async_api.py and you should get some pretty output (pun intended).

  4. Using poetry run:

  5. Run poetry run python servus/async_api.py. That's all. Short, concise, and beautiful. poetry handles activating our virtual environment and running the process. You can also use it with other programs like poetry run black . to run the black formatter.

  6. Activating the pre-existing poetry virtual environment:

  7. Run poetry env list --full-path. You'd get a list of virtual environments poetry has created for your project. You can then go ahead to activate it as you would any traditional virtual environment created by venv.

  8. I don't advise you to go down this path. You would encounter a lot of buggy behaviour.

Sharing your project

When you run poetry add or poetry install in a project, a poetry.lock file gets generated if it doesn't already exist. poetry.lock 'locks' down the exact version of Python packages used in a project, so it's easy to create reproducible and deterministic Python environments.

It's advisable you add it to your version control as you would a package-lock.json in JavaScript.

Collaborators only need to run poetry install to get up to speed.

Further Reading

Thanks for reading! Here are some resources you might find useful:

Have a project or need some advice? Get in touch on LinkedIn