Third party cookies may be stored when visiting this site. Please see the cookie information.

PenguinTutor YouTube Channel

How to Create and Publish Your Own Python Library to PyPI

This video is a guide on creating and publishing your very own Python library to PyPI. PyPI is the definitive and most popular way to distribute Python libraries, allowing users to easily install your code using the pip command.

This guide, uses the PyVLCB library (a tool for communicating with CBUS and VLCB model railway systems) as a case study to demonstrate the process.

The Mindset Shift

The first step is shifting your mindset. You are moving from writing code just for yourself to creating a reliable toolkit that others can use in their own software.

Structuring Your Library

Start by separating your core logic into reusable modules placed in a dedicated folder.

You must rename one of your files to __init__.py.

Note: That is two double underscores on either side of the word "init".

This file designs the folder as a package.

Best Practices for Stability and Safety

Consistency in naming is crucial for user experience, and you must maintain stability so user programs don't break when you add features.

Type Hinting

While Python variables are dynamically typed (meaning you can put any data into any variable), adding type hints improves code readability.

Hints are particularly useful for IDEs, which can warn you if you try to pass the wrong data to a method.



class VLCBFormat :

    """ Handles a single VLCB packet



    Attributes:

        priority: CAN priority

        can_id: CAN ID

        data: Remaining data as a hex str

    

    """ 

    def __init__ (self, priority: int, can_id: int, data: str) -> None:

    	self.priority = priority # Priority is actually high and low priority (2bit high / 2bit low) but just treated as single value

        self.can_id = can_id

        self.data = data # Data is left as hex string



Extract from vlcbformat.py

In the VLCBFormat class shown above, the priority argument is typed as an integer, as is can_id. The __init__ constructor returns None.

Error Handling

It is crucial to implement robust error handling so your library can be used safely.

Avoid Print Statements: While useful for personal debugging, when implemented in a library print statements can confuse command-line output or be hidden entirely in GUI applications.

Use Exceptions: Instead of printing errors, use robust exception handling to manage unexpected inputs or situations gracefully.

For example the following snippet from the __init.py file raises a ValueError exception if the string is missing the mandatory start charactor ':'.



        if (input_string[0] != ":"):

            raise ValueError(f"No start frame in '{input_string}'")

Managing Dependencies

Where possible, reduce the number of external dependencies. This makes installation easier and minimizes conflicts for your users. If dependencies are required, include them in the package details so they install automatically.

The PyVLCB library needs pyserial for the USB communications. The following extract from pyproject.html will cause pip to install pyserial, if it's not already included.



# 'install_requires' becomes 'dependencies'

dependencies = [

    "pyserial>=3.4",

]

Testing (including regression testing)

You should create and run unit tests for critical functions. This ensures your code works as expected and maintains stability over time.

Documentation

Good documentation is an essential part of a library; it is how others learn to use your toolkit.

Docstrings

Adding comprehensive docstrings to classes and methods allows for automatic documentation generation.

The following example shows the docstring for the parse_input method in the __init.py file.



        """Parse a log entry and return as a list of string values



        Args:

            input_string (string): String consisting of of num, date, direction, message as a single string

        

        Returns (list[str]): List of strings

This docstring includes the argument and return types, but if using Python type hints then the argument types can be generated based on those instead.

Automated documentation

If using GitHub, you can set up a document workflow to update documentation every time new code is pushed.

Below is my file .github/workflows/docs.yml file, used to generate the documents.



name: Deploy Documentation



# Trigger the workflow on push to the main branch

on:

  push:

    branches:

      - main



# Grant GITHUB_TOKEN the permissions to write to the gh-pages branch

permissions:

  contents: write



jobs:

  deploy:

    runs-on: ubuntu-latest

    steps:

      - name: Checkout code

        uses: actions/checkout@v4



      - name: Set up Python

        uses: actions/setup-python@v5

        with:

          python-version: '3.x'



      - name: Install dependencies

        run: |

          pip install -r docs/requirements.txt

          # If your library is needed for the docs to build (to read docstrings), install it too:

          pip install . 



      - name: Configure Git User

        run: |

          git config --global user.name "github-actions[bot]"

          git config --global user.email "github-actions[bot]@users.noreply.github.com" 



      - name: Build and Deploy

        run: mkdocs gh-deploy --force

README

Include a detailed README file. These are often written using markdown and include information on installing and getting started.

Also consider adding guides or tutorials, which may be on a separate website to the auto-generated library.

Packaging and Publishing

Once your code is ready, follow these final steps to publish to PyPI.

Configure Metadata: Create or update your pyproject.toml file to include all necessary metadata and configuration details.

PyPI Account: Create a login on the PyPI website and enable multi-factor authentication.

GitHub Actions: Create a new publisher project and add a publish.yml file to your Git repository. This is stored in .github/workflows/publish.yml

Publishing: Update the version number in the pyproject.toml file; the lbrary will be published from your GitHub repository automatically.

Tip: You may want to test this workflow first using TestPyPI.

Verification

The process isn't complete until you have verified everything works as intended.

Install the package locally using pip to confirm the installation is successful.

Depending on your system, you may need to create a virtual environment first.

More information

See my other programming guides at:

Blog links and videos on programming

Previous is a popular programming language used throughout education and industry.
is a popular programming language used throughout education and industry.
Next Beginners tutorial for Pygame Zero
Beginners tutorial for Pygame Zero