Skip to content

Part 2: Publishing your package to PyPI

Run poetry build (at the level where a valid pyproject.toml is present). From this point on, you have two options:

  • Publish to pypi
  • Publish to a private repository

We will cover both options. But before that, you need to adapt your project so that you can publish it.

Set up a private pypi repository

You can set up a local pypi server using docker compose. This is recommended for testing purposes.

Creating the project greeter

You will need to create the following files:

mkdir -p services/part-2
cd services/part-2
mkdir -p src/greeter
touch src/greeter/__init__.py
touch src/greeter/cli.py
touch README.md
touch pyproject.toml

Generate a lock file with poetry:

cd services/part-2
poetry lock

The whole project for this part should look like this:

$ tree services/part-2
services/part-2/
├── poetry.lock
├── pyproject.toml
├── README.md
└── src
    └── greeter
        ├── cli.py
        └── __init__.py

2 directories, 5 files

And add the following to the files

# service/part-2/pyproject.toml
[tool.poetry]
name = "greeter-test-<random_string>"
version = "0.1.0"
description = ""
authors = ["your name <your.name@email.coop>"]
readme = "README.md"
packages = [
    { include = "greeter", from = "src" },
]

[tool.poetry.scripts]
greeter-cli = "greeter.cli:cli"

[tool.poetry.dependencies]
python = "^3.10"
cowsay = "^6.1"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

and finally, update the README.md like

# Greeter

A dummy wrapper for `cowsay` written for the workshop at <https://github.com/Som-Energia/somenergia-poetry-docker-workshop>.

Where random-string is some random string we will append to the name of the module so that it wont collide with other pypi libraries.

Get random names

For the examples from now on, the name of the library will be is greeter-test-elated_swanson. You can get a random name here.

Now, from services/part-2 directory run poetry build. This should generate a dist directory with a .tar.gz file and a .whl file.

$ poetry build
Building greeter-test-ilhUggIkhxjxB (0.1.0)
  - Building sdist
  - Built greeter_test_ilhuggikhxjxb-0.1.0.tar.gz
  - Building wheel
  - Built greeter_test_ilhuggikhxjxb-0.1.0-py3-none-any.whl

Publish to pypi.org

Set up a pypi account

Make sure you have a valid account at pypi. You can create one here.

Set up pypi credentials with poetry by setting a pypi token

pypi token

poetry config pypi-token.pypi pypi-averylongtoken

Now you can just do

poetry publish

Version already exists

If you get an error like HTTPError: 400 Client Error: File already exists. See https://pypi.org/help/#file-name-reuse for url: https://upload.pypi.org/legacy/, you need to bump the version of your package. You can do this by changing the version field in pyproject.toml and running poetry build again.

Publish to a private repository

if you wish to publish to a private repository, say, pypi.docker.localhost, start it with

docker compose -f docker-compose.pypi-local.yml up -d

from the root of the repository, and then visit http://pypi.docker.localhost to see your local pypi server instance. You should see something like this

Alt text

You can now add repository to the config in poetry, from services/part-2 directory run

poetry config --local repositories.myprivaterepo https://pypi.docker.localhost/

Now your private pypi repository is aliased with myprivaterepo

Use --local

Use --local to avoid modifying your global configuration. This will add a config.toml file to your services/part-2 directory.

Don't pass /simple

Careful to not add the /simple bit if your privare repo is using pypiserver, see https://github.com/pypiserver/pypiserver/issues/329#issuecomment-688883871

Set up credentials for your private repository with

# username:password are set at the local pypi server
poetry config http-basic.myprivaterepo username password

Since our local pypi server is using a self-signed certificate, we need to disable certificate verification with

poetry config certificates.myprivaterepo.cert false

And finally, publish your package with

poetry publish --repository myprivaterepo

See https://python-poetry.org/docs/libraries#publishing-to-pypi for more documentation. You should see something like this at https://pypi.docker.localhost/packages/

Alt text

Adding dependencies from private repositories to pyproject.toml

You may also want to add dependencies from private repositories. These repos normally need keys to access them. Make sure to follow the instructions from your private repository to add credentials to your pyproject.toml file. Generally, the process is as follows:

That means, for example, for any other project that uses poetry, you can add a source to its pyproject.toml file like

poetry source add myprivaterepo --priority supplemental https://pypi.docker.localhost

This should add something like this

[[tool.poetry.source]]
name = "myprivaterepo"
url = "https://pypi.docker.localhost"
priority = "supplemental"

Add credentials for that repository

poetry config http-basic.myprivaterepo <user> <password>

Now you can add dependencies from myprivaterepo using the --source argument

poetry add --source myprivaterepo greeter-test-elated-swanson

Last update: November 6, 2023