Building a python package as per the PyPA Guidelines
Tags: python, programming, cache, lru
Published: 2022-06-14 22:13:36

---
title: Building a python package as per the PyPA Guidelines
published: true
description: A sample illustration of building a modern python package
canonical_url: https://blog.abdelfare.me/post/package-pypa
tags: python, programming, cache, lru
//cover_image: https://direct_url_to_image.jpg
---
Python is definitely the language you *MUST* to 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](https://github.com/abdelino17/lru-cache.git).

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:

```python
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 recommends using a sample project for building reusable packages and is available at: https://github.com/pypa/sampleproject.
![PyPA Sample Project](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5qmdhydhkqfaniu5ukkg.png)

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:

```bash
$ 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:

```python
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.

Before building, here is the structure of our package:
![Structure of our package](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9jlci3fht3o6vdxus4ex.png)
  
For simplicity purpose, Let's add this to the `__init__.py` file:
```python
from .lrucache import LRUCache
```

Here is the content of our test file:
```python
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: 
```bash
$ pip install <path_to_package>
```

The following is the console output of the command:
![Output of installation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kvx0lkvu1jyod4fvltog.png)

Our package was installed successfully and we can now use it from the command line:
![Usage of our module](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/britnrdta2cs46qa6yun.png)


# 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](https://test.pypi.org).

To push the package, we will also need the [Twine utility](https://pypi.org/project/twine/). You can install it with pip: 
```bash
$ 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:

```bash
$ python setup.py sdist
```

2.Upload the distribution file to Test PyPI.

```bash
$ 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nks31muylfr58hbmh6ic.png)

There we go! Our package is now available for the community.
![Package Page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x6xiyvpg0cy9fpi7yuk9.png)