Creating and publishing a python lib with poetry and git
Tags: tutorial, python
Published: 2022-04-14 22:31:17

I've been using [Poetry](https://python-poetry.org/) for a couple months and it helps me a lot. There's no more worry with random sub dependncies on requirements.txt, setting up virtual environment or things like that

But the most innovative thing i see on poetry is the fast ability to create a python lib. It is helping to create simple helpers to integrate on other aplications for many purposes.

In this article i'll show how to create a poetry-python project, make it as a lib, publish and installing them, without [pypi](https://pypi.org/). Just you and your repository!


## Instaling poetry
```sh
pip install poetry
```
If you use vscode, Configure your poetry to create the python virtual environment into the project workspace for better integration with the IDE

```sh
poetry config virtualenvs.in-project true
```

## Create the project with poetry
```sh
# Create the project root folder and open vscode into it
poetry new my-hello-world-lib && code $_
# Or create the root folder and initialize the project after
mkdir my-hello-world-lib && cd $_ && poetry new . && code .
```

The workspace should look like this:

```
.
├── README.rst
├── my_hello_world_lib
│   └── __init__.py
├── pyproject.toml
└── tests
    ├── __init__.py
    └── test_my_hello_world_lib.py

```

You should take note of some things:

- All the exported code (the code acessible to other apps which will install the lib) shold be inside de folder with same name as the project (`my_hello_world_lib`)
- When writing a lib (or any python application) with mutiple modules, i highly recommend to use absolute static imports
    
    Ex: you have two files: `module_1.py` and `module_2.py`
    ```python
    # ./my_hello_world_lib/module_1.py
    def add(number_one: int, number_two: int):
        return number_one + number_two
    ```
    ---
    ```python

    # ./my_hello_world_lib/module_2.py
    from my_hello_world_lib.module_1 import add
    # insteas of 
    from . import import add
    import logging

    logger = logging.getLogger(__name__)

    def say_hello():
        logger.info('hello world!')

    add(2, 2)
    ```


Use the \_\_init__.py file to export the main functions or classes of your lib
```python
# ./my_hello_world_lib/__init__.py
from my_hello_world_lib.module_2 import say_hello

```

## *Publish* your first version

The source of truth of your applicaion remains in the file `pyproject.toml`, which is used by poetry to define the app production and development dependencies, project name, python version and others.

You may need to add some information to the file for a successfull lib installation

```toml
[tool.poetry]
name = "my-hello-world-lib"
version = "0.1.0"
description = ""
authors = ["Your Name <your@email.com.br>"]

[tool.poetry.dependencies]
python = "^3.8"

[tool.poetry.dev-dependencies]
pytest = "^5.2"

[build-system]
#                                 Add the setuptools to your build requirements
requires = ["poetry-core>=1.0.0", "setuptools>=40.8.0"]
build-backend = "poetry.core.masonry.api"

```

## Initialize the git repository

Now you can initialize your repository
```sh
git init
```

It's important to know that when it comes to a repository, you have to setup the same version information into distinct places: the `pyproject.toml` file and the tag of the commit. The both need to be syncronized.

Now your application is ready for its first version!

[Poetry](https://python-poetry.org/) can make life easier when versioning a project. you can use the cli command to upgrade the version.

```sh
    poetry version patch #or minor, major, prerelease and some others
```

You can read more about poetry's version command [here](https://python-poetry.org/docs/cli/#version)

Now you need to make sure the version on the git history.

Add the pyproject.toml file on the commit and tag it

```sh
git add pyproject.toml
git commit -m v$(poetry version -s) # prints out the project version
git tag v$(poetry version -s)

# Push the version information
git push origin master # Or your current branch
git push origin --tags # Push the tags
```

Your can make it fast with `Makefile`
```Makefile
version:
	@poetry version $(v)
	@git add pyproject.toml
	@git commit -m "v$$(poetry version -s)"
	@git tag v$$(poetry version -s)
	@git push
	@git push --tags
	@poetry version

```

Then just use the command 

```sh
make version v=<the version upgrade>
```

And done! you published your library inside your own repository!

## Installation

Now, to install your lib, you just need to add the dependency just like any other lib but using you git url. 
You can specify the version to be installed inside the url
Example:

```sh
poetry add git+https://github.com/LuscasLeo/my-hello-world-lib.git#v0.1.1
```

## Bonus - Using private repositories

If you don't want your lib to be public, you can easily use a private repository to host your project. You just need to specify the credentials that have access to the repository on the project which will use the lib:

```toml
# pyproject.toml
[tool.poetry.dependencies]
python = "^3.8"
my-hello-world-lib = {git = "https://<your username>:<your password>@github.com/LuscasLeo/my-hello-world-lib.git", rev = "v0.1.7"}
```