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
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
def left_pad(input, length, fill_character=' '): return str(input).rjust(length, str(fill_character))
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
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
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!