~/post/package-pypa
Published on

Building a package as per the PyPA Guidelines

4 mins read
Authors
  • Name
    Twitter

Python is definitely the language you MUST learn in 2022. Originally developed by Guido van Rossum in 1991, it is used in a wide variety of industries, ranging from education to medicine.

There are various tools and techniques for creating and distributing packages.

The Python Packaging Authority (PyPA) proposes guidelines for building and sharing python packages.

In this article, we will write a small python package implementing the LRU Cache.

For recall, The Least Recently Used (LRU) is a caching strategy consisting to evict elements from the cache to make room for new elements when the cache is full. In short, the least recently items are discarded first.

Here is the code of the LRU Cache:

from collections import OrderedDict

class LRUCache(OrderedDict):

    def __init__(self, capacity: int):
        self.capacity = capacity

    def put(self, key: str, value: str) -> None:
        if key in self:
            self.move_to_end(key)
        self[key] = value
        if len(self) > self.capacity:
            self.popitem(last=False)

    def get(self, key: str) -> int | str:
        if key not in self:
            return -1
        self.move_to_end(key)
        return self[key]

    def show_entries(self) -> None:
        print(self)
PyPA Sample Project

The most important files to remember are:

  • setup.py: script for building and installing the package. It contains a global setup() function.
  • setup.cfg: this is a configuration file that can be used by setup.py to define default.
  • setup(): you can pass many arguments to this function such as Name, Version, Description, URL, Author, License.
  • data: place to add data files if needed.
  • tests: placeholder to add unit tests for the modules.
  • src/<package>: top-level package containing all the modules and packages inside it.

Let’s clone the repo and modify it:

$ git clone https://github.com/pypa/sampleproject.git lru-cache

We updated setup.py with arguments as per our package project. Here is a snippet of our file:

setup(
    name="lrucache",
    version="0.1.0",
    description="LRU Cache for illustration purpose",
    long_description=long_description,
    long_description_content_type="text/markdown",
    url="https://github.com/abdelino17/lru-cache",
    author="Abdel FARE",
    author_email="fare.abdel@gmail.com",
    keywords="cache, lru, setuptools, development",
    package_dir={"": "src"},
    packages=find_packages(where="src"),
    python_requires=">=3.7, <4",
    project_urls={
        "Bug Reports": "https://github.com/abdelino17/lru-cache/issues",
        "Source": "https://github.com/abdelino17/lru-cache"
    }
)

With this setup.py file, we are ready to share our lru-cache package locally as well as to the world.

Structure of our package

For simplicity purpose, Let's add this to the __init__.py file:

from .lrucache import LRUCache

Here is the content of our test file:

import unittest

from lrucache import LRUCache

CACHE_CAPACITY = 3

class TestLRUCache(unittest.TestCase):

    def setUp(self) -> None:
        super().setUp()
        self.lruCache = LRUCache(CACHE_CAPACITY)

    def test_cache(self):
        self.lruCache.put("1", "1")
        self.lruCache.put("2", "2")
        self.lruCache.put("3", "3")

        self.assertEqual(self.lruCache.get("1"), "1")
        self.assertEqual(self.lruCache.get("3"), "3")

        self.lruCache.put("4", "4")
        self.assertEqual(self.lruCache.get("2"), -1)

        self.lruCache.put("5", "5")
        self.assertEqual(self.lruCache.get("1"), -1)


if __name__ == '__main__':
    unittest.main()

Installing from the local source

Let’s execute the following command to install the package from the local source:

$ pip install <path_to_package>

The following is the console output of the command:

Output of installation

Our package was installed successfully and we can now use it from the command line:

Usage of our module

Publishing a package to Test PyPI.

As a next step, we will add our sample package to the PyPI Test repository.

Before executing any command for publishing our package, we will need to create an account and get an API token on Test PyPI.

You could find all the information for creating and adding the token on the Test PyPI website.

To push the package, we will also need the Twine utility. You can install it with pip:

$ pip install twine

Now, we are ready to upload our package, For that, we will execute the following steps:

1.Create a distribution using the following command:

$ python setup.py sdist

2.Upload the distribution file to Test PyPI.

$ twine upload --repository testpypi dist/lrucache-0.1.0.tar.gz

This command will push the package file to our Test PyPI repository.

Pushing to Test PyPI

There we go! Our package is now available for the community.

Package Page