Tips & Tricks Tutorials

How to Publish Your Package on PyPI

When you’ve written some great code, you might want to make this available for others to use as well. The pythonic way of sharing a package is making it available on PyPI. Let’s create a simple package and go through the process of publishing it!

Today’s Package: Left Pad

JavaScript developers are great at sharing code: if someone writes functionality, they share it so that others don’t have to reinvent the wheel (it doesn’t stop them from doing so however). A great example of this dedication to reuse is the excellent ‘left-pad’ library, and today we will write a clone of this library to bring this greatness to the Python community!

Someone has already been helpful and released a left-pad package on PyPI. However, his package has neither unit tests nor a GitHub repository so we can do better! We’ll make a drop-in replacement which we’ll name ‘pad-on-left’.

It is important to check if the intended name of your package is free on PyPI before you start. To do so, just use the search box on the top right of the PyPI page.

Structure of the Package

To make our package work with PyPI (which really means, to make it work with distutils), our package needs to have several files:

--- Root directory (name doesn't matter)
 |- your_library
 |  |- __init__.py
 |  |- actual_code_goes_here.py
 |- setup.py
 |- README.rst
 |- LICENSE.txt

We’ll need to write a README file, the default for Python is to use ReStructuredText for these. You can read more about ReStructuredText in the Sphinx documentation. If you’d prefer to use Markdown or another file format, you need to add a setup.cfg file where you specify the name of the file.

Furthermore, you need to pick a license for your code. People can’t use your code without a license. In this case, we’ll pick a permissive open source license, I’ll use the Apache 2.0 license, but for your own project, you can use the MIT license or something else.

We’ll create the setup.py file later using PyCharm. Let’s start by creating a new Pure Python project, and writing the application.

Writing the Application

The function we need to write is simple: we get a string or a number, and if it is smaller than the specified length, we should add fill characters on the left side until we reach that length. Unlike JavaScript, the Python standard library has a method for this, and our ‘business logic’ is a single line of code:

def left_pad(input, length, fill_character=' '):
    return str(input).rjust(length, str(fill_character))

Now let’s add some tests. If you go to the npm (Node package manager, pip for JavaScript) page for left-pad, there are several examples listed there. Let’s make sure that our code correctly executes these examples.

A great way to unit test Python is by using doctests. They allow you to write examples in the docstrings of your code, and then doctest will execute the examples and verify that the actual code matches your documentation:

def left_pad(input, length, fill_character=' '):
    """
    Returns a string, which will be padded on the left with characters if necessary. If the input string is longer
    than the specified length, it will be returned unchanged.

    >>> left_pad('foo', 5)
    '  foo'

    >>> left_pad('foobar', 6)
    'foobar'

    >>> left_pad('toolong', 2)
    'toolong'

    >>> left_pad(1, 2, '0')
    '01'

    >>> left_pad(17, 5, 0)
    '00017'

    :param input: 
    :param length: The return string's desired length.
    :param fill_character: 
    :rtype str:
    """

    return str(input).rjust(length, str(fill_character))

To run the test, add a doctest run configuration: go to Run Configuration, and add a Python Tests | Doctests configuration. Then you can specify the path in several ways, I’ve chosen to configure it to look in my package’s folder. Afterwards you can run the tests and verify that the unit tests pass.

Let’s now generate a setup.py file, choose Tools | Create setup.py:

  • Package name should already be filled, and is the name of our project. This is the name that users will later use to pip install this package
  • Version: you need to provide the initial version of your package. This should be updated every time you want to push an update to PyPI. You should use semantic versioning if you can, otherwise, PEP 440 describes several ways of versioning packages.
  • URL: this should be the homepage URL of your project. In most cases you can use the GitHub repo URL here.
  • License: the license you’re using for your code, I’ll use ‘Apache 2.0’
  • Author: Your name and surname
  • Author Email: Your email address
  • Description: A short description of what your package is for

Publishing the Code on GitHub

Let’s now create a git repo, and push the code to GitHub. Use Ctrl+Shift+A (Cmd+Shift+A on Mac) to open the Find Action window, and run "Create Git Repository". Add a .gitignore file, select all your files, and then add them to git with Ctrl+Alt+A (Cmd+Alt+A). Then, commit (Ctrl+K / Cmd+K) your files to create the initial commit.

Now publish to GitHub: open Find Action again (Ctrl+Shift+A), and find ‘Share Project on GitHub’.

As we’re going to package and release this code as version 1.0.0, we can also tag this commit as version 1.0.0. We can do this by going to VCS | Git | Tag, I’ll use ‘v1.0.0’ as both the tag name, and the message. It’s recommended to use a message as well to create a full tag.

Tags are pushed separately, so we need to go to VCS | Git | Push, enable the ‘Push Tags’ checkbox, and Push.

Register for PyPI

At this point, we should register for both the real PyPI, and test PyPI. You can register here for test PyPI, and find the same form for production PyPI here.

To use these credentials, we need to create a .pypirc file. This is an ini-style configuration file, so let’s create a scratch file which we can then save in the correct place. Use Shift+Ctrl+Alt+Insert to start creating the scratch file, and then select ‘ini’ as the language.

[distutils]
index-servers=
    testpypi
    pypi

[testpypi]
repository = https://testpypi.python.org/pypi
username = name_of_the_user
password = hunter2

[pypi]
repository = https://pypi.python.org/pypi
username = name_of_the_user
password = hunter2

After writing the contents of the file, use File | Save As, and then save it as .pypirc in your home directory (/home/yourname/.pypirc on Mac and Linux, C:\Users\YourName\.pypirc on Windows). Afterward, you may want to restrict the file to be only readable from your account: chmod 600 ~/.pypirc on Mac and Linux, on Windows right click the file, Properties | Security, and then make sure only your account has Full Control, and other accounts don’t have any rights.

Push to PyPI

We need to build our distribution package first. For this there is a setup.py command: setup.py sdist. The s in sdist is for ‘source’. You can also create pre-built wheels by using bdist, for more information about those, see PyPA’s page on packaging.

We’ll only build a source distribution today. We can run the setup.py task by choosing Tools | Run Setup.py task, and then choosing ‘sdist’. As we don’t need any additional command-line options, we can dismiss the dialog for those. We can see in the run output that our package has been built.

Now that we have our built package, we can proceed to upload our code. PyPA recommends using Twine rather than setup.py commands, as setup.py may transmit your passwords in plaintext. So we will need to install Twine: Settings | Project | Project Interpreter, and add Twine.

After Twine is installed, we can open the Terminal (Alt+F12) and run twine register dist/pad-on-left-1.0.0.tar.gz -r testpypi and then twine upload dist/* -r testpypi. If these commands executed correctly, you should be able to find your package on testpypi.

If everything looks good on testpypi, you can run the same commands without -r testpypi:

twine register dist/pad-on-left-1.0.0.tar.gz twine upload dist/*

And after those commands completed successfully, you’ve uploaded your package to PyPI! Congratulations!

image description