Content from Why Python Packages?
Last updated on 2025-08-25 | Edit this page
Estimated time: 25 minutes
Overview
Questions
- Why do you need to package your python code?
- What can you actually package?
- What is Python Package Index (PyPI) and its purpose?
- What is a build?
Objectives
- benefits of python packaging
- does it fit your use case
- understand some componets of python packaing like PyPi
- understand the build process
Introduction
We all love to write code, to solve interesting problems. What if we have our code ready and we want to share it across the world. Well there are many ways to do that ofcourse ! By doing this course we will learn to distribute our code via Python Packaging using a tool call Pixi. You can think of the package as setup.exe from yester years.
When we make a package, we solve some key challenges like reproducibility, making it platform independent and also make it multi- environment. Distributing our code as package is better than sharing the souce code via for instance in a Github repository for many reasons :
Dependency management : A Package can explicityl declare its deepndencies. Tools like ‘pip’ or ‘uv’ can be then used to automatically install them for a user.
Versioning : You version your package and can make and distribute several versions of your code for backwards compatability.
Standerdisation : Packaging is an accepted way to distribute the code via repositories like PyPI
-
Metadata : A package has project specific metadata which are important for the end users.
What can you package ?
Any .py files (modules) or directories with init.py (packages).
What is PyPI
PyPi is the repository where all the Python packages which are released are available for end users to use. You can visit it here to have a look : https://pypi.org/ There is also a repository called https://test.pypi.org/, which allows us to try distribution tools and processes without affecting the real PyPi. In this course , we will publish our package to TestPyPI.
What is a build ?
It can be defined as a process of creation of distribution of your project from source code. This distribution can then be installed using tools like ‘pip’ or ‘uv’ etc. You can create a build for your project using the following command in the terminal : python -m build.
The end product of a successful build process in a .whl or .tar.gz file. These can then be installed via pip or uploaded to PyPI. It is important to version your build and provide necessary metadata.
- The code needs to be versioned.
- The dependencies of the projects needs to be managed.
- The metadata for the project needs to be managed.
- To make our python code installable, reusable and shareable via PyPi or TestPyPI, we need to package our code.
Content from Why choose Pixi for Python Packaging ?
Last updated on 2025-08-25 | Edit this page
Estimated time: 5 minutes
Overview
Questions
- Why Pixi ?
- What are the benefits of Pixi ?
Objectives
- To understand the benefits offered by Pixi
- What is
pixi.toml
andpyproject.toml
- What is
pixi.lock
- What do we mean by multi-environment support
Introduction
Pixi is a fast and reproducible package management tool. It has lots of features which are not all present in a single tool at this point in time. Hence we choose this tool. It comes with following features :
- Native supprt for both PyPI packages and conda
- Modern
- Support for multi-language dependency ( E.g. RUST + Python, or Python + C++)
- Uses
uv
under the hood. - Helps with reproducibility via
pixi.lock
Configuration files (pixi.toml
and
pyproject.toml
)
pixi.toml
is the file used by Pixi for defining the
environment , dependencies and tasks. pyproject.toml
is the
file in Python ecosystem (PEP 518/621) for configuring the build,
distribution and configration of python projects. It is required in
build tools like Poetry, Hatch, Flit , setuptools. It specifies metadata
(name, version, author). you can also specifiy dependencies here.
Multi-environment support
You can specify the installation of certain tools and packages specific to a particular OS or environmentsl like ( dev, test prod) etc.
Content from Set up a project directory
Last updated on 2025-08-25 | Edit this page
Estimated time: 5 minutes
Overview
Questions
- How should we structure our project ?
- What is init.py ?
- How should be name our packages ?
Objectives
- To understand how to structure your project to be able to package it well.
- Understand the importance of init.py and where to place it.
- Giving unique but understandable names to our packages.
Introduction
It is important to structure your project properly and include the necessary files, while giving unique yet understandable package names.
Packages are a way to organize modules in a Python project. A project can contain several modules, and grouping them into packages helps keep the code organized and maintainable.
Every package should have a special file called init.py in its folder. The presence of this file signals to Python that the folder is a package, allowing it to be imported later in your code.
Project Structure
A typical project would look like :
└── my_package/
├── __init__.py
├── happy.py
└── sad.py
Lets create the same structure for our project in the codespace.
OUTPUT
✔ Created ...greet_me/pixi.toml
This create a following structure for us.
Please note, if you want to use a pyproject.toml
, you
need to use the syntax mentioned below. This is also our preferance and
we will use this file in the next lesson.
pixi.toml
: Lets view and edit the pixi.toml file
generated for us.
TOML
[workspace]
authors = ["Priyanka O"]
channels = ["conda-forge"]
name = "greet_me"
version = "0.1.0"
platforms = ["linux-64"]
description = "A simple greeting package."
[dependencies]
python = ">=3.10"
[tasks]
Lets go inside the project directory:
To add libraries via pixi command use this syntax :
OUTPUT
✔ Added requests >=2.32.5,<3
Let us see that gets added to the pixi.toml
You can also generate/ update pixi.lock
file via this
command :
OUTPUT
✔ Lock-file was already up-to-date
Alternatively, Lets install the dependencies now, which wiil generate
the pixi.lock
file. This is also useful when you clone
someone else repo, the dependencies are installed via the
pixi.lock
file
OUTPUT
✔ The default environment has been installed.
There is also a command to update your dependencies to newer versions where possible with latest compatible versions.
OUTPUT
▪ solving [━━━━━━━━━━━━━━━━━━━━] 0/1
▪ updating lock-files [━━━━━━━━━━━━━━━━━━━━] 0/2
OUTPUT
✔ Lock-file was already up-to-date
Let us now create a folder named my_package
and add 3
files inside it namely happy.py
, sad.py
and
__init__.py
Ultimately, our project structure should look like this :
greet_me/
├── LICENSE
├── pyproject.toml
├── README.md
├── pixi.toml
├── pixi.lock # auto-generated, do not edit
├── tests/
│ └── test_greetings.py
└── my_package/
├── __init__.py
├── happy.py
└── sad.py
Add the following task to the pixi.toml file and then run via pixi
OUTPUT
Yay! happy day! 😀
- Follow the folder structure
- dont forget to add the init.py file.
- Sequence of pixi commands : init -> add -> run -> lock ->install -> update
Content from Metadata for Python packging
Last updated on 2025-08-25 | Edit this page
Estimated time: 15 minutes
Overview
Questions
- What is
pyproject.toml
?
Objectives
- To understand the structure of
pyproject.toml
Introduction
In the previos lesson, we touched upon pixi.toml
briefly. In this lesson, we will learn about
pyproject.toml
. pyproject.toml
is the most
common format for Python projects. Please not, for a project maintained
using pixi, either of the 2 i.e. pyproject.toml
or
pixi.toml
are fine. You just need to take care of some
specific syntaxes.
To add pyproject.toml
file, we give the following
command :
OUTPUT
✔ Created .../greet_me/pyproject.toml
Whats inside pyproject.toml
- Manifest metadata
TOML
[project]
name = "greet_me"
version = "0.1.0"
description = "greet_me Pixi-managed package"
authors = [{ name = "Priyanka", email = "" }]
readme = "README.md"
license = { text = "MIT" }
requires-python = ">=3.11"
dependencies = []
The [build-system]
table in a pyproject.toml file tells
packaging tools like pip what software is needed to build your Python
project. It specifies the build backend that will be used to create
distributable packages, like wheels (.whl) or source distributions
(.sdist).
This section was introduced by PEP 518 and is essential for modern
Python packaging. The [build-system]
table has two main
keys:
-
requires
: This is a list of strings specifying the packages needed to build your project. These packages will be downloaded and installed into a temporary, isolated environment before the build process begins. You must include the build backend itself here. -
build-backend
: This is a string that points to the specific Python object (the “backend”) that packaging tools will use to execute the build. It’s the entry point for creating your project’s packages.
- Editable project install
This means that the package is installed in editable mode, so you can
make changes to the package and see the changes reflected in the
environment, without having to re-install the environment. The
greet_me
package itself is added as an editable
dependency.
-
Dependency handling For dependency management, following lines are necessary in your
pyproject.toml
file.requires_python
tag is used to specify the version of Python.[tool.pixi.workspace]
: This section controls where packages come from and what platforms Pixi should resolve for. It is also used to define project-wide settings.[tool.pixi.pypi-dependencies]
: This section is used to delare the dependencies of our project that will be installed via Pip or similar tools from Python Package Index. In short they are libraries necessary for our project and will be installed via pip.
TOML
[project]
name = "greet_me"
requires-python = ">=3.11"
[tool.pixi.workspace]
channels = ["conda-forge"]
platforms = ["linux-64", "win-64"]
[tool.pixi.pypi-dependencies]
requests = ">=2.31.0,<3"
You can specify a range or multiple supported Python versions using the syntax below.
If you were using pixi.toml
file, the equivalent syntax
would be
TOML
[tool.pixi.workspace]
name = "greet_me"
channels = ["conda-forge"]
platforms = ["linux-64", "win-64"]
[tool.pixi.pypi-dependencies]
python = ">=3.11"
[tool.pixi.tasks]
- Tasks
Here you can specify various steps that you would want to run before making your package. It ususally lets you define and run custom cammands or scripts for your project.
TOML
[tool.pixi.tasks]
# This command will only be defined on Windows
greet = { cmd = "echo 'Happy Python Packaging!'" }
Final pyproject.toml
should look like this below, for
reference.
TOML
[project]
authors = [{name = "Priyanka O"}]
dependencies = []
name = "po_greet_me"
requires-python = ">= 3.11"
version = "0.1.2"
description = "greet_me Pixi-managed package"
[build-system]
build-backend = "hatchling.build"
requires = ["hatchling"]
[tool.hatch.build.targets.wheel]
packages = ["my_package"]
[tool.pixi.workspace]
channels = ["conda-forge"]
platforms = ["linux-64"]
[tool.pixi.pypi-dependencies]
greet_me = { path = ".", editable = true }
requests = ">=2.32.5,<3"
[tool.pixi.tasks]
greet = { cmd = "echo 'Happy Python Packaging!'" }
- Need to have a
pyproject.toml
file - Need to have
[build-system]
section withrequires
andbuild-backend
specfied. - Need to have
[project]
section with atleastname
andversion
specified. - Nice to have
dependencies
specified in[project]
section.
Content from How to publish your Python project
Last updated on 2025-08-25 | Edit this page
Estimated time: 25 minutes
Overview
Questions
- What is Twine and why is it needed
- What is build command and what does it do ?
- How to create and upload the Python package ?
- How to test/ use the uploaded Python package?
Objectives
- Learn the usage for tools like build and twine
- How to upload the Python Package to repositories like TestPyPi
- How to use the uploaded package.
Introduction
Once we have created our project, defined all the necessary metadata in the toml file, its time to publish our project. Let see the tools and steps we need to acheive this.
We need to install the following tools i.e. build
and
twine
Before proceeding with the steps mentioned below, kindly rename
or delete the pixi.toml
file as we will mainly focus on
pyproject.toml
for the steps mentioned below. You can also
try the build with pixi.toml
at a later point in time by
deleting or renaming the pyproject.toml
file.
Create your build
build
:A tool to read the pyproject.toml
file and build the package files
OUTPUT
Collecting build
Downloading build-1.3.0-py3-none-any.whl.metadata (5.6 kB)
Requirement already satisfied: packaging>=19.1 in /home/codespace/.local/lib/python3.12/site-packages (from build) (25.0)
Collecting pyproject_hooks (from build)
Downloading pyproject_hooks-1.2.0-py3-none-any.whl.metadata (1.3 kB)
Downloading build-1.3.0-py3-none-any.whl (23 kB)
Downloading pyproject_hooks-1.2.0-py3-none-any.whl (10 kB)
Installing collected packages: pyproject_hooks, build
Successfully installed build-1.3.0 pyproject_hooks-1.2.0
OUTPUT
* Creating isolated environment: venv+pip...
* Installing packages in isolated environment:
- hatchling
* Getting build dependencies for sdist...
* Building sdist...
* Building wheel from sdist
* Creating isolated environment: venv+pip...
* Installing packages in isolated environment:
- hatchling
* Getting build dependencies for wheel...
* Building wheel...
Successfully built greet_me-0.1.0.tar.gz and greet_me-0.1.0-py3-none-any.whl
This command creates a dist
directory containing two
files: - A wheel file (greet_me-0.1.0-py3-none-any.whl
). -
A source archive (greet_me-0.1.0.tar.gz
).
## Create an account on TestPyPI
Visit this URL and crete an account to generate the API keys, to be able to upload your package to TestPyPI in the next step.
Once you create your account, you can visit this link to generate the API key. Please copy the same in a notepad and paste it when prompted for it in the next step below.
Upload your build
twine
:A tool for securely uploading packages to PyPI
and TestPyPI. ```bash pip install build twine
twine upload –repository testpypi dist/* ``` You’ll be prompted to enter your TestPyPI username and password. It’s recommended to use an API token instead of your password. When prompted for your password, paste the token in.
OUTPUT
Uploading distributions to https://test.pypi.org/legacy/
INFO dist/po_greet_me-0.1.1-py3-none-any.whl (0.8 KB)
INFO dist/po_greet_me-0.1.1.tar.gz (5.0 KB)
INFO username set by command options
INFO Querying keyring for password
INFO No keyring backend found
Enter your API token:
INFO username: __token__
INFO password: <hidden>
Uploading po_greet_me-0.1.1-py3-none-any.whl
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2.5/2.5 kB • 00:00 • ?
INFO Response from https://test.pypi.org/legacy/:
200 OK
INFO <html>
<head>
<title>200 OK</title>
</head>
<body>
<h1>200 OK</h1>
<br/><br/>
</body>
</html>
Uploading po_greet_me-0.1.1.tar.gz
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 6.7/6.7 kB • 00:00 • ?
INFO Response from https://test.pypi.org/legacy/:
200 OK
INFO <html>
<head>
<title>200 OK</title>
</head>
<body>
<h1>200 OK</h1>
<br/><br/>
</body>
</html>
View at:
https://test.pypi.org/project/po-greet-me/0.1.1/
That’s it! After the upload is successful, your package will be available on TestPyPI. E.g. : https://test.pypi.org/project/po-greet-me/0.1.1/
It is possible that the name of your project already exists or is simialr to an existing project. In that case you may end up in an error like this :
OUTPUT
twine upload --repository testpypi dist/*
Uploading distributions to https://test.pypi.org/legacy/
Enter your API token:
Uploading greet_me-0.1.1-py3-none-any.whl
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2.6/2.6 kB • 00:00 • ?
WARNING Error during upload. Retry with the --verbose option for more details.
ERROR HTTPError: 403 Forbidden from https://test.pypi.org/legacy/
Forbidden
This isnt always helpful and you should try this command as tipped in the error message above to know more.
OUTPUT
Uploading distributions to https://test.pypi.org/legacy/
INFO dist/greet_me-0.1.1-py3-none-any.whl (0.9 KB)
INFO dist/greet_me-0.1.1.tar.gz (4.9 KB)
INFO username set by command options
INFO Querying keyring for password
INFO No keyring backend found
Enter your API token:
INFO username: __token__
INFO password: <hidden>
Uploading greet_me-0.1.1-py3-none-any.whl
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2.6/2.6 kB • 00:00 • ?
INFO Response from https://test.pypi.org/legacy/:
400 Bad Request
INFO <html>
<head>
<title>400 The name 'greet-me' is too similar to an existing project. See https://test.pypi.org/help/#project-name for more information.</title>
</head>
<body>
<h1>400 The name 'greet-me' is too similar to an existing project. See https://test.pypi.org/help/#project-name for more information.</h1>
The server could not comply with the request since it is either malformed or otherwise incorrect.<br/><br/>
The name 'greet-me' is too similar to an existing project. See https://test.pypi.org/help/#project-name for more information.
</body>
</html>
ERROR HTTPError: 400 Bad Request from https://test.pypi.org/legacy/
Bad Request
To fix this, rename you project e.g. to po_greet_me
,
and add the following in pyproject.toml
file. and try the
steps below to upload it again.
Test your package
Install your package via this command :
BASH
pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple po-greet-me==0.1.1
OUTPUT
Looking in indexes: https://test.pypi.org/simple/, https://pypi.org/simple
Collecting po-greet-me==0.1.1
Downloading https://test-files.pythonhosted.org/packages/52/85/dd6ebf4ee0a6ff76699a4c4f134059e6615b75c50e30cd40cd424370b81e/po_greet_me-0.1.1-py3-none-any.whl.metadata (137 bytes)
Downloading https://test-files.pythonhosted.org/packages/52/85/dd6ebf4ee0a6ff76699a4c4f134059e6615b75c50e30cd40cd424370b81e/po_greet_me-0.1.1-py3-none-any.whl (815 bytes)
Installing collected packages: po-greet-me
Successfully installed po-greet-me-0.1.1
Create a Python file named test_package.py
OUTPUT
Yay! happy day! 😀
- Fill all the metadata and give your project a unique name
- Build your Project
- Create a TestPyPI account and generate the API token
- Upload your package via twine to TestPyPI
- Check your package via pip install