Skip to main content

An Example Python Package

This repo is a simple demonstration of how to create and publish a Python package to PyPI (the Python Package Index, pronounced "pie-pee-eye", but I prefer pie-pie, because who doesn't like pie).

PyPI Account Setup

Before getting started, please create an account at both test.pypi.org AND pypi.org.

Next, create a file called .pypirc. Add the following to it:

[pypi]
  username = __token__
  password = <the full pypi token string including the pypi- prefix>

[testpypi]
  username = __token__
  password = <the full testpypi token string including the pypi- prefix>

We will replace the passwords once we have generated each of the tokens. Save this file in your home directory, e.g. C:\Users\YourName for Windows. This will allow twine (the PyPI publishing tool) to automatically log you in whenever you upload a package.

After you have created and verified your account(s), navigate to the Account Settings page and find the API Tokens section. Click Add API Token, and then enter a name (e.g. pypi-global-api-token) and select Entire Account for the scope. Your token should now appear. Edit your .pypirc file in the appropriate location.

Create the Repo for your Package

If you do not yet have a repo for your package, create one!

  1. Create a repository on GitHub
  2. For your .gitignore, choose the Python option.
  3. Clone into your repo

Directory setup

Setup the following directory structure inside of your repository:

my-package/
├─ my_package/
│  ├─ __init__.py
│  ├─ module1.py
│  ├─ module2.py
│  ├─ sub_package/
│  │  ├─ __init__.py
│  │  ├─ module3.py
│  │  ├─ module4.py
├─ tests/
│  ├─ test_module1.py
│  ├─ test_module2.py
│  ├─ test_module3.py
│  ├─ test_module4.py
├─ LICENSE
├─ README.md
├─ .gitignore
├─ pyproject.toml

Your package files should be copied into the my_package subfolder (feel free to rename). For now, you can leave the tests folder empty. Your .gitignore should probably follow a standard Python .gitignore. Add your license text (e.g. MIT License) to the license file.

Populate pyproject.toml

Your pyproject.toml is a configuration file for packaging and building a Python package that is ready for distribution. If you are familiar with setup.py, you can think of it as a cleaner, more readable way of automating the configuration normally done there.

It is a table of key-value pairs, with sections defined by brackets, e.g. [section_name]. Some sections may have keys which may need their own tables, e.g. [section_name.sub_section].

Let's build it!

The Build System section

The first [build-system] section defines which packaging backend you will use. Stick to the defaults for now!

[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"

The Project Section

Next, the [project section] is where you enter the main project metadata, like the package name, the version, etc. Start with the following keys:

[project]
name = "your-package-name"
description = "An example package which does something"
version = "0.0.1"

Next let's add a few optional keys to the project section which identify some important files and additional metadata. Note that the value stored at a key can itself be a table (as in the license key), an array (as in the classifiers key), or even an array of tables (as in the authors key).

readme = "README.md"
license = {file = "LICENSE"}
authors = [
    {name = "Your Name", email = "you@email.com"},
    {name = "Another Name", email = "them@email.com"}
]
classifiers = [
    "Development Status :: 4 - Beta",
    "Intended Audience :: Science/Research",
    "License :: OSI Approved :: MIT License",
    "Programming Language :: Python :: 3.7",
    "Programming Language :: Python :: 3.8",
    "Programming Language :: Python :: 3.9",
]

Next, we will specify which dependencies your package needs. This example assumes that the package requires Python v3.7 or higher, as well as the requests package.

requires-python = ">=3.7"
dependencies = [
    "requests"
]

nb: if you already have a requirements.txt file, follow the instructions here for dynamically injecting your requirements into the dependencies key.

Finally, let's add some additional metadata by creating a subsection for the urls key:

[project.urls]
Documentation = "https://somesite.com"
Repository = "https://github.com/username/repository"

There's a lot more advanced configuration we can do, plugins that can be installed, etc etc, but that should be enough for now!

Build and Publish the Package

Install the pip packages build (for creating the disribution files) and twine (for publishing the package to PyPI):

pip install build twine

From the root directory of your project, run the following command to build your dist and wheel files!

python -m build

When build is complete, you should now see a dist file in your package directory.

That was easy! Next, let's publish it. We will start by publishing to test.pypi.org in order to make sure everything is working.

python -m twine upload --repository testpypi dist/*

When it completes, head over to test.pypi.org and check it out! It's now ready to be installed (though the testpypi index is pruned regularly). You can install it via pip as you would any other package, but you will need to specify that it is coming from testpypi with the --index-url flag.

pip install --index-url https://test.pypi.org/simple/ your-package-name

Finally, let's publish it to the real Python PI:

twine upload dist/*

Additional Resources

Metadata

Release files for sdl-example-package 0.0.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sdl-example-package 0.0.2
File Size Uploaded Provenance
sdl-example-package-0.0.2.tar.gz 6.2 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for sdl-example-package 0.0.2
File Interpreter ABI Platform
sdl_example_package-0.0.2-py3-none-any.whl Python 3 none any Details

Total release size: 13.4 kB

Release files / sdl-example-package-0.0.2.tar.gz

Download URL sdl-example-package-0.0.2.tar.gz
Size 6.2 kB
Tags Source
SHA-256 checksum
How to use checksums
f5980d8d5aad8f91b791497495ba1ef2ee859c7c5dbe83dbd613ff9e785e3b8c
BLAKE2b-256 checksum
How to use checksums
5180b0e121913a40a8702c6e5cf692b7b9f94ac13013f12248376cb300fac6cd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.9.6

Release files / sdl_example_package-0.0.2-py3-none-any.whl

Download URL sdl_example_package-0.0.2-py3-none-any.whl
Size 7.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
478b4b124f6a00c2ebd7344a5d5812d447a1acdaa970b91cd1c55291b7a9ecf7
BLAKE2b-256 checksum
How to use checksums
0851fd70a146bd2502c107556715db7b876b9e92f46e48c73b67384975d00173
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.9.6

Security for sdl-example-package 0.0.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.0.2 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page