smhk

Convert a Python script into a Poetry package

Tl;DR: Run poetry init convert a Python script into a Poetry package, then edit the resulting pyproject.toml to define the package, entry points (scripts), dependencies and more.

A new Python project can easily begin as a single script.py, but there soon becomes a point where it’s worth packaging up the script. That way you can benefit from proper dependency management, entry points, installation and much more.

Here is how to go from a script.py to a Python package using Poetry.

Structure §

Initial §

To start out with, ensure your script.py is in its own directory:

.
└── my-project/
    └── script.py

If your script uses local imports for other scripts (e.g. from .util_1 import blah), then ensure they are included too:

.
└── my-project/
    ├── script.py
    ├── util_1.py
    └── util_2.py

Run Poetry init §

From inside my-project, run poetry init.

This will take you through a Poetry wizard for setting up your new project. It will try to infer some information, e.g. by default the my-project directory will be the name of the package, but you are free to change this.

Afterwards your project should now contain a pyproject.toml:

.
└── my-project/
    ├── script.py
    ├── util_1.py
    ├── util_2.py
    └── pyproject.toml

Set up your code as a package §

There are different ways to do this, but my preference is to move your Python code into a src/my_project/ subdirectory. This way there is the flexibility to add other “sub-packages” within your single package (e.g. src/something_else/) and keeping it all neatly contained. It also discourages other scripts/projects from importing your Python code directly, and instead they should take the proper route of installing your package before importing it.

So your new structure becomes:

.
└── my-project/
    ├── src/
    │   └── my_project/
    │       ├── script.py
    │       ├── util_1.py
    │       └── util_2.py
    └── pyproject.toml

Then you can add src/my_project/ as a package within pyproject.toml:

packages = [
    { include = "my_project", from = "src" },
]

Lock §

Create the lock file §

Run poetry lock to create the poetry.lock file.

Install the package §

Run poetry install to install the package.

Entry points §

Create entry points §

Entry points let you run poetry run <blah> and then a given function in your code executes. This is a well defined way to show how your package is used.

Define entry points in your pyproject.toml. For example, if you have a main() function in your script.py:

[tool.poetry.scripts]
frobnicate = "my_project.script:main"

Test the entry points §

Run poetry run frobnicate to run your script using your entry point.