Managing software dependencies is typically a short and straightforward topic to encompass; unless we're talking most Python, that is. Python has a myriad of options when it comes to virtual environments, which is arguably not a practiced thing. Virtualenv, Pipenv, Conda, and Verse all aim to continue Python libraries project-specific, and they each do an adequate chore of accomplishing this... but why do we need a vast catalog of solutions to solve the same trouble? If modern programming languages such equally NodeJS manage to sidestep environments entirely (via the /node_modules folder), why couldn't the Python community settle on a standard?

Python isn't exactly an "old" programming language (relatively speaking), only a lot has inverse in programming since 1991. This was an era before linguistic communication-specific package management systems had been conceived. Both Pip and Virtualenv were introduced to Python in 2011- that's 20 years where installing dependencies meant manually downloading packaged source code into a system folder. Using Virtualenv in 2020 feels archaic, just the concept of isolating packages on a per-project level was a somewhat novel concept at the time. Once this minimal implementation of package management became the norm, information technology didn't take long for developers to realize ways to meliorate this workflow. Early revelations resulted in the creation of virtual environment solutions, which seemed monumentally meliorate than the last. In retrospect, these improvements were incremental to reaching the state of virtual environments today. This is why nosotros discover Python bloated with environment managers accumulated over fourth dimension as the concept matured.

Poetry is arguably Python's nearly sophisticated dependency management option bachelor today. Poetry goes far beyond dependencies, with features like generating .lock files, generating project scaffolding, and a ton of configuration options, all of which are handled via a uncomplicated CLI. If you lot're unsure how to cleanly and effectively structure and manage your Python projects, practise yourself a favor and use Poetry.

More Than Just Dependencies

Proper dependency management is only 1 dimension of preparing a production-ready application. For a Python project to be considered a valid parcel to be listed on PyPi, the Python Packaging Authority has a list of guidelines outlining various other requirements involving licensing, setup configuration files, manifests, and so along. The attraction of Poetry is that it is the first tool that handles all of these things cleanly. The Poetry Github repository states its purpose equally follows:

Packaging systems and dependency management in Python are rather convoluted and difficult to understand for newcomers. Even for seasoned developers it might exist cumbersome at times to create all files needed in a Python project: setup.py, requirements.txt, setup.cfg, MANIFEST.in and the newly added Pipfile. So I wanted a tool that would limit everything to a single configuration file to practise: dependency management, packaging and publishing.

It sounds crazy, but Poetry makes covering all bases of a managing a Python project piece of cake via its CLI and a single configuration file.

Setting upwards Poetry On OSX/Unix

I don't typically reiterate installation instructions from official docs, I've run into issues following the existing install instructions give-and-take-for-word.

I'm assuming nosotros're all using Python3 here since we aren't absolute savages. Information technology'due south critically important that we install Poetry for python3 as opposed to Python, contrary to what the official docs would have you re-create-and-paste. Mistakenly installing Poesy for the wrong version of Python is a massive headache, and then please use this:

            $ coil -sSL https://raw.githubusercontent.com/python-poetry/poesy/chief/get-poetry.py | python3                      
Poetry install script

This script should install Poetry and automatically change your organisation PATH to include the installation, equally the success message states. Go ahead and confirm:

            $ poetry --version                      
Confirm Poesy was installed correctly.

If the in a higher place control returns an error, brand sure your .bash_profile (or .zshrc) was updated with the following, and restart your concluding:

            export PATH="$HOME/.poetry/bin:${PATH}"          
Add together poetry to system path

Create a Python Project with Poetry

Plenty with the foreplay, let's encounter how Poetry streamlines not only dependency management only nearly everything that goes into structuring a Python projection. Poetry has a robust CLI, which allows u.s.a. to create and configure Python projects easily. Here's what getting started fresh looks similar:

            $ poetry new poetry-tutorial-project                      
Create a Python project via Poetry CLI.

This is an absurdly user-friendly mode to generate a standard Python folder structure for our new project named poetry-tutorial-projection:

            /verse-tutorial-project ├── README.md ├── poetry_tutorial_project │   └── __init__.py ├── pyproject.toml └── tests     ├── __init__.py     └── test_poetry_tutorial_project.py          
Contents of our new project: /poetry-tutorial-project

This saves usa the problem of manually creating this standard binder construction ourselves. Nearly of the file contents are empty, with one exception: pyproject.toml.

One Configuration to Rule Them All

The surreptitious sauce of every Verse project is independent in a file called pyproject.toml. This is where nosotros define everything from our project'south metadata, dependencies, scripts, and more than. If you're familiar with Node, think of pyproject.toml as the Python equivalent of package.json.

Starting a new Poetry project automatically creates a minimal version of this file. Hither's what mine looks like:

            [tool.poetry] proper noun = "poetry-tutorial-project" version = "0.1.0" description = "" authors = ["Todd Birchard <todd@case.com>"]  [tool.poesy.dependencies] python = "^3.vii"  [tool.poetry.dev-dependencies] pytest = "^iv.vi"  [build-system] requires = ["poetry>=0.12"] build-backend = "verse.masonry.api"                      
pyproject.toml

The above config has some basic data, simply it isn't enough to exist useful just withal. A complete pyproject.toml file would expect something like this:

            [tool.poetry] name = "poetry_tutorial_project" version = "0.one.0" description = "Elementary Python project built with Poetry." authors = ["Todd Birchard <toddbirchard@gmail.com>"] maintainers = ["Todd Birchard <toddbirchard@gmail.com>"] license = "MIT" readme = "README.md" homepage = "" repository = "https://github.com/hackersandslackers/python-poesy-tutorial/" documentation = "https://hackersandslackers.com/python-poetry/" keywords = [     "Poetry",     "Virtual Environments",     "Tutorial",     "Packages",     "Packaging" ]  [tool.poesy.dependencies] python = "^three.8" loguru = "*" psutil = "*"  [tool.poetry.dev-dependencies] pytest = "*"  [build-system] requires = ["poetry>=0.12"] build-backend = "poetry.masonry.api"  [tool.poetry.scripts] run = "wsgi:main"  [tool.poetry.urls] problems = "https://github.com/hackersandslackers/python-poetry-tutorial/issues"                      
pyproject.toml

Now we're cookin' with gas! Our .toml file is now comprised of 6 "sections," where each section contains config values for our project:

  • [tool.poetry]: The first section of pyproject.toml is simply informational metadata about our package, such as the bundle name, description, author details, etc. Most of the config values here are optional unless y'all're planning on publishing this project equally an official PyPi parcel. Providing values for repository and keywords isn't going to matter if you're non distributing this package. Still, this sort of metadata would be critical if you e'er hope to distribute your package.
  • [tool.poetry.dependencies]: This is where we define dependencies our application absolutely must download to run. You may specify specific version numbers for required packages (such as Flask = "1.0.0"), or if you simply want to grab the latest version, setting the version to "*" will do just that. Y'all'll also discover that the version of Python nosotros're targeting for our project is provided hither also: this is specifying the minimum version required to run our app. In the example in a higher place, a user running Python three.6 volition not exist able to run this app, as we specify that Python 3.7 is the absolute lowest version required.
  • [tool.poetry.dev-dependencies]: Dev dependencies are packages that contributing developers should download to iterate on this project. Dev dependencies are not required to run the app, and won't be downloaded when the app is built by default.
  • [build-system]: This is rarely a section you'll need to touch unless you upgrade your version of Poetry.
  • [tool.poetry.scripts]: This is where we specify where our app entry point(s) is past assigning function inside modules to the name of a script to be run. The case run = "wsgi:main" is specifying that we want to create a command called "run," which will look in wsgi.py for a role called main(). With this set, we can so launch our app via the Poetry CLI by typing poetry run (more than on this in a bit).
  • [tool.poesy.urls]: This is a completely optional section where you can add any number of helpful links or resources that somebody downloading this bundle might find useful.

A config similar the one above is more than sufficient to have a make clean, functioning, packaged app. Poesy supports other types of config values likewise, although chances are you'll rarely need most of them. In instance you lot're curious, find the full list here:

The pyproject.toml file | Documentation | Verse - Python dependency management and packaging fabricated like shooting fish in a barrel.

Official documentation of Poesy

Poesy CLI

Poesy'due south command-line interface is impressively simplistic for the scope of what it achieves. The equivalent functionality of both Pipenv and setup.py are covered past Verse, likewise as numerous other features related to configuration management and parcel publishing. We'll showtime with installing and managing the dependencies we simply set in pyproject.toml.

Installing & Managing Dependencies

  • verse shell : The first time this command is run in your projection directory, Poetry creates a Python virtual surroundings which will forever exist associated with this projection. Instead of creating a folder containing your dependency libraries (equally virtualenv does), Poesy creates an surround on a global system path, therefore separating dependency source code from your projection. Once this virtual environment is created, it can exist activated again at whatsoever time by simply running poetry beat in your projection directory in the future. Try comparing the output which python before and after activating your project shell to come across how Poetry handles virtual environments.
  • poetry install : Installs the dependencies specified in pyproject.toml. The first fourth dimension a project's dependencies are installed, a .lock file is created, which contains the actual version numbers of each package that was installed (i.e.: if Flask = "*" resulted in downloading Flask version one.0.0, the actual version number would be stored in .lock). If a .lock file is present, the version numbers in .lock will always be prioritized over what is in pyproject.toml.
  • poetry update : Mimics the functionality of install, with the exception that version numbers in .lock will Not be respected. If newer versions exist for packages in pyproject.toml, newer versions volition be installed, and .lock will be updated accordingly.
  • poesy add [package-name] : A shortcut for calculation a dependency to pyproject.toml. The package is installed immediately upon beingness added.
  • verse remove [package-proper name] : The opposite of the in a higher place.
  • verse export -f requirements.txt > requirements.txt : Exports the contents of your project'south .lock file to requirements.txt. It comes in handy when handing work off to developers who even so employ requirements.txt for some reason.

Configuration

  • poetry config : "Config" refers to environment-level configuration, such as the paths of the electric current virtual environment, or environment variables. Passing the --list option volition return your environment's electric current config values.
  • poetry check : Checks pyproject.toml for errors.
  • poetry show : Returns a breakdown of all packages currently installed to the project, including dependencies of  dependencies.

Executing Applications

  • poetry run [script-name] : Executes a script defined in  the [tool.poetry.scripts] department of pyproject.toml.

Building and Publishing

  • verse build : Builds the source and wheels archives.
  • poetry publish : Publishes the output of the previous build to the project's external repository (likely PyPi).

Become a Poet

I'one thousand well aware that tooling/architectural decisions in software are subjective preferences. Developers are non defined by their tools, blah blah, simply look... at the gamble of coming off as an ignorant novice, Verse is objectively the best mode to create, manage, and package Python projects. I don't accept a horse in this race, but I'd go so far equally to say that not embracing Poetry is a waste product of your time.

It'due south not much, but I've posted the lawmaking from this tutorial on Github:

hackersandslackers/python-poesy-tutorial

:snake: :pencil2: Elementary Python project congenital with Poetry. - hackersandslackers/python-poetry-tutorial