DEV Community

Cover image for Releasing my Python Project
Amnish Singh Arora
Amnish Singh Arora

Posted on • Edited on

Releasing my Python Project

I have been working on til-page-builder for this whole semester, and as the term approaches its end, I thought it was a good time to release the project.

I have published the package to Python Package Index, commonly called PyPi, and in this post, I'll be sharing the steps I had to follow in the process.

PyPi

Note: I will be using TestPyPi in this tutotal, which is a separate server for testing python packages, since the original Pypi has temporarily suspended new users registration.

Registration Suspended

Table of Contents

 1. Registering as a New User 🧑🏻
 2. Creating an API Key 🔑
       2.1. Enabling MFA 🔒
       2.2. Getting the Token 💳
 3. Adjusting Project Structure
 4. Configuring a Build Backend
 5. Generating Distribution Packages
 6. Publishing the Package
 7. Installing the Package 💻
       7.1. User Testing
 8. Conclusion 🎇
 9. Attributions

Registering as a New User 🧑🏻

The very first step is to create a new PyPi account that we will use to publish our packages.

Test PyPi

Once we have an account, we can login using those credentials

Login to PyPi

Creating an API Key 🔑

After creating and logging into your account, the next step is to create an API key that will be used to upload packages to PyPi under our account.

Enabling MFA 🔒

However, to be eligible to create an API key, you first need to go to Account Settings, and enable 2 factor authentication - which is again a 2-step process. You first generate and store recovery codes for your account, after which you can enable MFA.
Be advised that only one authentication application can be linked and in my case, I used Microsoft Authenticator - a pretty popular and standard option.

MFA

Getting the Token 💳

Getting an API token is pretty simple once you are eligible. All you have to do is go to the API Token section under Account Settings and click on Add Token.

Add Token

which will take you to the following screen

Create Token

Here, you need to name your token and set a scope for its validity, which can be a specific project or all projects like I have selected.

Now click on Create Token and you'll see your token in the following format.

Generated Token

Adjusting Project Structure

The most crucial step in the entire process is to reorganize the project into a structure expected by PyPi.

Package Structure

Let's discuss the role of each file in the figure.

1. LICENSE: This file contains information about the rights and permissions granted to users regarding the use, modification, distribution, and sharing of the software. I already had an MIT License in my project.
2. pyproject.toml: It is a configuration file typically used for specifying build requirements and backend build systems for Python projects. I was already using this file for Black code formatter configuration.
3. README.md: Used as a documentation file for your project, typically includes project overview, installation instructions and optionally, contribution instructions.
4. example_package_YOUR_USERNAME_HERE: One big change I had to face was restructuring my project, essentially packaging all files in this directory. The name of this directory should be what you want to name your package and shoud not conflict with any of the existing packages.
Of course, since its a Python Package, it needs to have an __init__.py.
5. tests/: This is where you put all your unit and integration tests, I think its optional as not all projects will have tests.
The rest of the project remains as is.

⚠️Important Note: Make sure you are using absolute imports throughout the project, as relative imports might not behave as you expect, when your package is installed on other machines.

I spent quite a while to figure it out.

Module Errors

and had to go through 3 patch fixes to finally get it to work.

Installing Latest Package

Configuring a Build Backend

From official documentation,

Tools like pip and build do not actually convert your sources into a distribution package (like a wheel); that job is performed by a build backend. The build backend determines how your project will specify its configuration, including metadata (information about the project, for example, the name and tags that are displayed on PyPI) and input files.

I used Hatchling for my purpose, but there are other options available as well.

To configure Hatchling as your build backend, add the following lines to pyproject.toml file.



[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"


Enter fullscreen mode Exit fullscreen mode

And the following metadata needs to be set



[project]
name = "til_page_builder"
version = "1.0.3"
authors = [
  { name="Amnish Singh Arora", email="amnishsingh04@gmail.com" },
]
description = "A command-line tool for authoring \"Today I Learned\" posts in Markdown, which can be converted to HTML for publishing on the web."
readme = "README.md"
requires-python = ">=3.8"
classifiers = [
    "Programming Language :: Python :: 3",
    "License :: OSI Approved :: MIT License",
    "Operating System :: OS Independent",
]


Enter fullscreen mode Exit fullscreen mode

I started out with version 1.0.0, but got to 1.0.3 while getting everything to work correctly.

Generating Distribution Packages

The next step is to generate distribution packages by building the project. These are the files that are uploaded to PyPi and installed as packages on systems.

First you need to make sure you have the latest package builder.



py -m pip install --upgrade build


Enter fullscreen mode Exit fullscreen mode

Now make sure you're at the root of your project (at the same level as pyproject.toml), and run



py -m build


Enter fullscreen mode Exit fullscreen mode

Build Package

Once it is successfull, you'll see a tarball and a whl file generated in the dist directory.

Dist

These are the files that need to be uploaded/published to PyPi.

Publishing the Package

Congratulation for making to the last step of the process.
We'll use twine to upload the distribution packages.



py -m pip install --upgrade twine


Enter fullscreen mode Exit fullscreen mode

Once installed, we can run



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


Enter fullscreen mode Exit fullscreen mode

Upload Package

And that's how I was able to publish my first python package to get it in the hands of users.

📌 Notice that we are using a --repository flag to upload the package to TestPyPi instead of the real thing due to the issue I described in the beginning. But we can omit this flag to upload to the real server if we have the credentials.

Installing the Package 💻

Now that we have the package published, its time to install and test if it works when installed.



py -m pip install --index-url https://test.pypi.org/simple/ --no-deps til-page-builder==<version_number_optional>


Enter fullscreen mode Exit fullscreen mode

Installing Latest Package

Let's try to use it now 🤞



py -m til_page_builder.til_builder_main -v


Enter fullscreen mode Exit fullscreen mode


py -m til_page_builder.til_builder_main -h


Enter fullscreen mode Exit fullscreen mode

Using Package

That works. Let's try the main functionality now.



py -m til_page_builder.til_builder_main examples --output voila


Enter fullscreen mode Exit fullscreen mode

And that works!

That works

User Testing

I also updated the README file of my project and asked Katie to help me with testing it locally.

And thanks to her, I was able to find a critical defect. In my distribution package, I wasn't specifying the dependencies that had to be installed which is why she couldn't run my tool on her system.
She asked me to refer to her blog and I was able to fix this problem by adding dependencies to pyproject.toml and creating a setup.py file.

pyproject.toml



...
...
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "til_page_builder"
version = "1.0.4"
...
...
dependencies = [
    "yattag==1.15.1",
    "tomli==2.0.1"
]
...
...


Enter fullscreen mode Exit fullscreen mode

setup.py



from setuptools import setup, find_packages
from src.til_page_builder.version import version as version

with open("requirements.txt") as f:
requirements = f.read().splitlines()

setup(
name="til_page_builder",
version=version,
packages=find_packages(),
install_requires=requirements,
entry_points={
"console_scripts": [
"til_page_builder=til_page_builder.til_builder_main:main", # Adjust 'module_name' and 'main' accordingly
],
},
python_requires=">=3.8",
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
author="Amnish Singh Arora",
author_email="amnishsingh04@gmail.com",
description="A command-line tool for authoring 'Today I Learned' posts in Markdown, which can be converted to HTML for publishing on the web.",
long_description=open("README.md").read(),
long_description_content_type="text/markdown",
url="https://github.com/pypa/sampleproject",
project_urls={
"Homepage": "https://github.com/pypa/sampleproject",
"Issues": "https://github.com/pypa/sampleproject/issues",
},
)

Enter fullscreen mode Exit fullscreen mode




Conclusion 🎇

In this post, I shared my experience uploading my first ever Python Package to PyPi, as I wrap up my open source class for this semester. I am really glad that I was able to carry my project to its 1.0 release, and will continue making improvements so it actually becomes a useful tool.

Release 1.0

Here's one to the 1.0 release 🍾

Latest Release

Attributions

Cover Photo by Hitesh Choudhary on Unsplash

Top comments (1)

Collapse
 
juanfrank77 profile image
Juan F Gonzalez

👏👏👏