Distributing PyPI Packages using API Tokens in TravisCI
Tags: python, pypi, tutorial, travis
Published: 2019-08-11 18:06:29

The _PyPI_ package index is one of the tools that makes **Python** so powerful, with just a simple command, you get access to thousands of cool libraries, ready for you to use in your project.

Writing **Python** packages and deploying them to _PyPI_ is one way for sharing libraries to the open-source community. For beginners, submitting a package to _PyPI_ is not an easy task, but the community is working hard, for make this process more easier, you can read more about packaging, following the official [Python Packaging Guide](https://packaging.python.org/tutorials/packaging-projects/).

In this post, I'm going to skip some things/steps about packaging, and guide you through the process of using the newest [API Tokens](http://pyfound.blogspot.com/2019/07/pypi-now-supports-uploading-via-api.html) feature in _PyPI_, for your continuous integration and deployment (CI/CD).

For this we'll use the [PyPI Test](https://test.pypi.org/) instance, which is a better option for doing initial test in your packages, like: testing if the docs render correctly, or if the [classifiers](https://pypi.org/classifiers/) in your `setup.py` are correct, for example.

## Using Travis CI

_Travis CI_ can automatically release your **Python** packages to _PyPI_ after a successful build. For a minimal configuration, you can use the following code in your `.travis.yml` file:

```yaml
deploy:
  provider: pypi
  user: "Your username"
  password: "Your password"
```

However, as you may notice, this would expose your _PyPI_ password to the world, and that is a bad idea. What Travis recommend is to encrypt the password or save the credentials as Travis Environment Variables, you can read more about it on [Travis deployment docs](https://docs.travis-ci.com/user/deployment/pypi/).

### Get the PyPI tokens

So, the first thing to do, is go to https://test.pypi.org/ and create an account (if you don't have one) or login, after that, we're gonna need our _API Token_.  How to get it? Go to your _PyPI_ account settings and select "Add API token". When you create an API token, you choose its scope: you can create a token that can be used to upload to all the projects you maintain or own, or you can limit its scope to just one project.

![](https://thepracticaldev.s3.amazonaws.com/i/js4fdwiifbvbyvstc8zo.png)

### How to use the tokens

API tokens provide an alternative way (instead of username and password) to authenticate when uploading packages to _PyPI_.

These API tokens can only be used to upload packages to PyPI, and not to log in more generally, since a thief who copies the token won't also gain the ability to delete the project, delete old releases or add/removed collaborators.

As you can see on the following screenshot, I have successfully manually deployed the first version of the demo project on PyPI:

![](https://thepracticaldev.s3.amazonaws.com/i/xz68e9fukw7icfkui8a5.png)

Now we need to enable _Travis_ for this project, so go to **https://travis-ci.org/account/repositories** and enable it, after that we have to change the following things in our `.travis.yml` file:

- Set the username to `__token__`.
- Set the password to the token value, including the `pypi-` prefix.

For more extra security, we're going to store the token as an environment variable, go to **https://travis-ci.org/<owner>/<repository>/settings** and now our `.travis.yml` file will looks like this:

```yaml
deploy:
  provider: pypi
  user: __token__
  password: $TEST_PYPI_TOKEN
  server: https://test.pypi.org/legacy/
  distributions: "sdist bdist_wheel"
  on:
    branch: staging
    condition: $TRAVIS_PYTHON_VERSION = "3.6"
```

And now, every time we push code to the _staging_ branch, _Travis_ will trigger an automatic deploy to the _PyPI_ test instance. do a small changes in the codebase, and change the `setup.py` version number, then push to the _staging_ branch, _Travis_ will trigger a build and if everything works deploy the new version to _PyPI_.

![](https://thepracticaldev.s3.amazonaws.com/i/j0n1h21o1ulv7in5rl86.png)

We can inspect the build logs to see if the deploy process started correctly:

![](https://thepracticaldev.s3.amazonaws.com/i/hf1p4lgjx9aaqfsqf64y.png)

And voilà, on the line _271_ we see the deploy process started, if you expand the line you could see the following logs:

![](https://thepracticaldev.s3.amazonaws.com/i/in5rcm8ljalsyfk8zvpy.png)

That means that our new version was uploaded correctly and now we can see it available in _PyPI_, automatically deployed with _Travis_ using the new API tokens:

![](https://thepracticaldev.s3.amazonaws.com/i/ityi3uscghk93qsf7m98.png)

## Conclusion 

This is a big step forward for the Python Package Index, increasing the security with new multiple features, and reducing all the characteristics that make it hard to work on, for the **Python** community, thanks to the [Packaging Working Group](https://wiki.python.org/psf/PackagingWG) and the grant from the [Open Technology Fund](https://pyfound.blogspot.com/2019/03/commencing-security-accessibility-and.html).

You can read more about API tokens on the official [PSF Blog](http://pyfound.blogspot.com/2019/07/pypi-now-supports-uploading-via-api.html) or help to test this [beta feature](https://wiki.python.org/psf/WarehousePackageMaintainerTesting). If do you want to read the Spanish version of this post, you can find it on [my blog](https://oscarmcm.com/essays/2019/distributing-packages-via-pypi-tokens). Also the source code is available [on GitHub](https://github.com/oscarmcm/pypi-token-demo).

And that's it! From here you can automate the process for releasing new package versions, so let's go, publish something to _PyPI_ 🐍.

Thanks to [@Darwing1210](https://twitter.com/Darwing1210/) and [@guadamzjj](https://twitter.com/guadamzjj/) for reviewing this document.

With ❤️ from 🇳🇮.