Recently, I decided to create my first Python package and publish it to PyPI. After a month of writing and testing code, I finally prepared everything for publication. Because this was new for me, I encountered several pitfalls along the way, so I decided to share the steps on how you can do the same.
You can check my package on GitHub or Pypi.
Note: In this article, I will discuss how to create and prepare a package for publication using Poetry. Poetry automates many tasks for you. If you prefer to manually prepare the package, you can refer to the guide.
First things first. You need an account. Go to https://pypi.org/ to create the account and finish its setup.
To publish a package on PyPI, you will need to generate a token for your account.
Once you are registered on PyPI, go to your account page, scroll down to the API tokens section, and click the Generate API token button. Choose a name and the scope for the token.
If you don't have any projects on PyPI, you will only be able to create an account-scoped API token, which will be used to publish new packages. Save the API token. We will need it later.
First, create a folder where the package files will be stored. Next, create a Python virtual environment. I prefer to create the virtual environment in the project's folder, but poetry
provides the option to create it in {cache-dir}/virtualenvs
.
python3 -m venv .venv
source .venv/bin/activate
After creating the virtual environment, we need to install and initialize poetry
.
pip install poetry
poetry init
Poetry
will ask you to set several settings during the initialization, which you can change later manually. As a result, a file called pyproject.toml
will be generated.
This is the most important file, responsible for the project's operation and dependency management.
It should look something like this:
[tool.poetry]
name = "pypi-poetry-publish-example"
version = "0.1.0"
description = ""
authors = ["Author <[email protected]>"]
readme = "README.md"
packages = [{include = "pypi_poetry_publish_example"}]
[tool.poetry.dependencies]
python = "^3.10"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
Let's explain some fields in the file:
name
- is the name of the project. By default, it is the name of the folder where poetry was initialized.
version
- project's version. It will be used for versioning when the package will be published.
python
- python version required for the project.
build-system
- the system that is used for building source distributions or wheels from them.
readme
- a filename that will be used for package description. If it is set here, you need to create it in the root.
After we have prepared poetry,
we will create a new folder called pypi_poetry_publish_example
where package files will be stored. Inside the folder, we will create a file core.py
.
Important: The name of the folder where the package files are stored should be the same as the name set in pyproject.toml
, written in camel case.
In our case: pypi-poetry-publish-example(pyproject.toml
) -> pypi_poetry_publish_example (folder name
)
# core.py
PREPEND_STR = 'prepend_'
def modify_str(string: str) -> str:
return f'{PREPEND_STR}{string}'
Additionally, it is a good idea to add a LICENSE
file. The MIT license is commonly used.
Finally, we need to save what versions of packages have been installed:
poetry lock
As a result, the project structure should look like this:
pypi-poetry-publish-example/
├── LICENSE
├── poetry.lock
├── pyproject.toml
├── README.md
├── pypi_poetry_publish_example/
├── __init__.py
└── core.py
Our project is ready to be published, but before that, we need to build the source and wheel archives.
To do this, we use the following command:
poetry build
Before we publish the package, we need to set the API token:
poetry config pypi-token.pypi pypi-XXXXXXXX
where pypi-XXXXXXXX
is the API token generated in your account.
This will create the required files to be published; to upload them to Pypi, use:
poetry publish
Congratulations! Your package has been uploaded, and it can be verified by visiting the projects page.
Now, it can be installed using:
pip install pypi-poetry-publish-example
There were no dependencies added in the example.
Dependencies can be added using Poetry if needed.
After installation, they will be added to tool.poetry.dependencies
and will be required by the package.
You might have seen commands like pip install somepackage[extra]
. This parameter will install the extra
optional features which won't be automatically added if only the command pip install somepackage
is applied.
To do this in your project, you need to add the optional
flag to the dependency you want to make optional, and add it to [tool.poetry.extras]
. The pyproject.toml
with the optional package pydantic
will look like this:
[tool.poetry]
name = "pypi-poetry-publish-example"
version = "0.1.0"
description = ""
authors = ["Author <[email protected]>"]
readme = "README.md"
packages = [{include = "pypi_poetry_publish_example"}]
[tool.poetry.dependencies]
python = "^3.10"
pydantic = {version=">=1.9", optional = true}
[tool.poetry.extras]
pydantic = ["pydantic"]
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"