DEV Community

Kalob Taulien
Kalob Taulien

Posted on

How to create a PyPi (Python) package

Have you ever wanted to create a Python package so you can type the following?

pip install my-awesome-package
Enter fullscreen mode Exit fullscreen mode

If so, this tutorial is for you.

1. Getting Poetry

Poetry is a system package you can use to very easily manage your Python Packages.

It makes handling your packages super easy. I have 9 Python packages under my name, and this is by far the best solution.

First, you need to install Poetry on your system.

osx / linux / bashonwindows install instructions

curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python -
Enter fullscreen mode Exit fullscreen mode

windows powershell install instructions

(Invoke-WebRequest -Uri https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py -UseBasicParsing).Content | python -
Enter fullscreen mode Exit fullscreen mode

More details about installation here

Now you can type poetry --version to see the version you're running. If this doesn't work for you, try closing and re-opening your terminal.

2. Creating a Poetry project

In this tutorial we're going to create a new package from scratch.

Go ahead and type:

poetry new test-package
Enter fullscreen mode Exit fullscreen mode

As the docs mention, it'll create a new folder with a bunch of files for you that are structured like this:

test-package
├── pyproject.toml
├── README.rst
├── test_package
│   └── __init__.py
└── tests
    ├── __init__.py
    └── test_test_package.py
Enter fullscreen mode Exit fullscreen mode

3. Adding your code

Create a new file in test-package/test_package/ called myfile.py.

Your file structure should look like this now:

test-package
├── pyproject.toml
├── README.rst
├── test_package
│   ├── __init__.py
│   └── myfile.py  # <- This is new
└── tests
    ├── __init__.py
    └── test_test_package.py
Enter fullscreen mode Exit fullscreen mode

All of your code will go in the test_package/ folder.

Note: This folder name will be different if you used a different package name during step 2.

You can add any files you want in this folder. This is what get's bundled in your package.

Now in your myfile.py file, add this function:

def custom_function(name):
    print(f"Hello {name}!")
Enter fullscreen mode Exit fullscreen mode

Later we can use this code like so:

from test_package.myfile import custom_function
Enter fullscreen mode Exit fullscreen mode

👆 We'll get to that later, first we need to build the package.

4. Building your package

So far we just have a bunch of code sitting on our computer and if someone else wants to use our code, they need to copy all the files and folders.

Let's "build" the project.

poetry build
Enter fullscreen mode Exit fullscreen mode

This will take all your code, bundle it, and put it in a versioned file inside of a /dist/ folder. The file should look something like this: test-package-0.1.0.tar.gz.

It will also create a wheel file for you that looks something like this: test_package-0.1.0-py3-none-any.whl

5. Testing your code in other virtual environments

Now what I like to do is test my package in a brand new virtual environment.

Create a new virtual env in a new folder somewhere else on your computer.

mkdir testenv && cd testenv 
python3 -m venv .venv/ 
source .venv/bin/activate 
Enter fullscreen mode Exit fullscreen mode

Note: Your virtual env will be created differently if you're on Windows. You can use virtualenv, pipenv, Docker, etc. It just needs to be a fresh environment.

Now that you're in a new Python environment, copy that .tar.gz from from earlier into this folder. (I usually use the operating systems OS for this, but there's nothing wrong with using cp to copy the file). The only file in this virtual environment should be your .tar.gz file.

Now install this file with:

pip install test-package-0.1.0.tar.gz
Enter fullscreen mode Exit fullscreen mode

Assuming everything went well, let's test this out.

Open a new Python shell (REPL) with:
python (on non-Windows) or py on Windows. And type this out:

from test_package.myfile import custom_function

custom_function("Kalob")
Enter fullscreen mode Exit fullscreen mode

It should print out Hello Kalob!.

And just like that, you have create a bundled package. But it's not available for everybody just yet.

6. Push it to GitHub

At this stage I like to push my code up to GitHub.

Because we're making a public package, I tend to make my repo's public as well. No use hiding the source code when it will be easily downloaded from PyPi.org anyway.

Dont forget to add /dist/ and other files to your .gitignore file. The /dist/ folder is where your bundled code goes when it's built by Poetry.

7. Publish the package

Now let's publish this code on PyPi.org.

First, you need a free PyPi.org account. You'll need your username and password handy because Poetry will ask for it so it can upload your file to PyPi and associate it with your account.

Once you have a free PyPi account, go ahead and run this in your terminal:

poetry publish
Enter fullscreen mode Exit fullscreen mode

It will ask for your username and password. Go ahead and type those in.

And now your package will be on PyPi.org.

Note: If the package of test-package already exists, or at one point existed, on PyPi.org you cannot use the same name. Making your Python packages have unique names is the best way to avoid this problem.

If you didn't run into a naming problem, you'll have successfully published a package to PyPi.org!

Congrats!

8. Install your package using pip

Assuming your package is now on PyPi, let's install your package in another project and test it out.

pip install test-package
Enter fullscreen mode Exit fullscreen mode

Everything should work as expected now. And your code is now easily accessible to every Python developer. 🎉

Example repo

If you'd like to see a simple package I recently created for Arbington.com take a look at python-vimeo on GitHub and feel free to use any part of that repo. That's why we open sourced it! :)

Discussion (0)