We are happy you have decided to contribute to twine.

Please see the GitHub repository for code and more documentation, and the official Python Packaging User Guide for user documentation. You can also join #pypa or #pypa-dev on Freenode, or the pypa-dev mailing list, to ask questions or get involved.

Getting started

We recommend you use a development environment. Using a virtualenv keeps your development environment isolated, so twine and its dependencies do not interfere with other packages installed on your machine. You can use virtualenv or pipenv to isolate your development environment.

Clone the twine repository from GitHub, and then make and activate a virtual environment that uses Python 3.6 as the default Python. Example:

mkvirtualenv -p /usr/bin/python3.6 twine

Then, run the following command:

pip install -e /path/to/your/local/twine

Now, in your virtual environment, twine is pointing at your local copy, so when you make changes, you can easily see their effect.

Building the documentation

Additions and edits to twine’s documentation are welcome and appreciated.

We use tox to build docs. Activate your virtual environment, then install tox.

pip install tox

If you are using pipenv to manage your virtual environment, you may need the tox-pipenv plugin so that tox can use pipenv environments instead of virtualenvs.

After making docs changes, lint and build the docs locally, using tox, before making a pull request. Activate your virtual environment, then, in the root directory, run:

tox -e docs

The HTML of the docs will be visible in twine/docs/_build/.


Tests with twine are run using tox, and tested against the following Python versions: 2.7, 3.4, 3,5, and 3.6. To run these tests locally, you will need to have these versions of Python installed on your machine.

Either use tox to build against all supported Python versions (if you have them installed) or use tox -e py{version} to test against a specific version, e.g., tox -e py27 or tox -e py34.

Also, always run tox -e lint before submitting a pull request.

Submitting changes

  1. Fork the GitHub repository.
  2. Make a branch off of master and commit your changes to it.
  3. Run the tests with tox and lint any docs changes with tox -e docs.
  4. Ensure that your name is added to the end of the AUTHORS file using the format Name <> (url), where the (url) portion is optional.
  5. Submit a pull request to the master branch on GitHub.

Architectural overview

Twine is a command-line tool for interacting with PyPI securely over HTTPS. Its three purposes are to be:

  1. A user-facing tool for publishing on
  2. A user-facing tool for publishing on other Python package indexes (e.g., devpi instances)
  3. A useful API for other programs (e.g., zest.releaser) to call for publishing on any Python package index

Currently, twine has two principal functions: uploading new packages and registering new projects (register is no longer supported on PyPI, and is in Twine for use with other package indexes).

Its command line arguments are parsed in twine/ The code for registering new projects is in twine/commands/, and the code for uploading is in twine/commands/ The file twine/ contains a single class, PackageFile, which hashes the project files and extracts their metadata. The file twine/ contains the Repository class, whose methods control the URL the package is uploaded to (which the user can specify either as a default, in the .pypirc file, or pass on the command line), and the methods that upload the package securely to a URL.

Where Twine gets configuration and credentials

A user can set the repository URL, username, and/or password via command line, .pypirc files, environment variables, and keyring.

Adding a maintainer

A checklist for adding a new maintainer to the project.

  1. Add her as a Member in the GitHub repo settings. (This will also give her privileges on the Travis CI project.)
  2. Get her Test PyPI and canon PyPI usernames and add her as a Maintainer on our Test PyPI project and canon PyPI.

Making a new release

A checklist for creating, testing, and distributing a new version.

  1. Choose a version number, e.g., “1.15.”

  2. Merge the last planned PR before the new release:

    1. Add new changes to docs/changelog.rst.
    2. Update the __version__ string in twine/, which is where pulls it from, with {number}rc1 for “release candidate 1”.
    3. Update copyright dates.
  3. Run Twine tests:

    1. tox -e py{27,34,35,36,py}
    2. tox -e lint for the linter
    3. tox -e docs (this checks the Sphinx docs and uses readme_renderer to check that the long_description and other metadata will render fine on the PyPI description)
  4. Run integration tests with downstreams:

    1. Test pypiserver support:

      git clone
      cd pypiserver
      tox -e pre_twine
    2. Create a test package to upload to Test PyPI, version-control it with git, and test zest.releaser per directions in this comment.

    3. Test devpi support:

      pip install devpi-client
      devpi use
      devpi user -c {username} password={password}
      devpi login {username} --password={password}
      devpi index -c testpypi type=mirror mirror_url=
      devpi use {username}/testpypi
      python sdist
      twine upload --repository-url{username}/testpypi/ dist/{testpackage}.tar.gz
  5. Create a git tag with git tag -sam 'Release v{number}' {number}.

    • {number}, such as 1.15.1rc1
    • -s signs it with your PGP key
    • -a creates an annotated tag for GitHub
    • -m adds the message; optional if you want to compose a longer message
  6. View your tag: git tag -v {number}

  7. Push your tag: git push upstream {number}.

  8. Delete old distributions: rm dist/*.

  9. Create distributions with python sdist bdist_wheel.

  10. Set your TestPyPI and canon PyPI credentials in your session with keyring (docs forthcoming).

  11. Upload to Test PyPI: twine upload --repository-url --skip-existing dist/*

  12. Verify that everything looks good, downloads ok, etc. Make needed fixes.

  13. Merge the last PR before the new release:

    1. Add new changes and new release to docs/changelog.rst, with the new version {number}, this time without the rc1 suffix.
    2. Update the __version__ string in twine/ with {number}.
  14. Run tests again. Check the changelog to verify that it looks right.

  15. Create a new git tag with git tag -sam 'Release v{number}' {number}.

  16. View your tag: git tag -v {number}

  17. Push your tag: git push upstream {number}.

  18. Delete old distributions: rm dist/*.

  19. Create distributions with python sdist bdist_wheel.

  20. On a Monday or Tuesday, upload to canon PyPI: twine upload --skip-existing dist/*


    Will be replaced by tox -e release at some point.

  21. Send announcement email to pypa-dev mailing list and celebrate.

Future development

See our open issues.

In the future, pip and twine may merge into a single tool; see ongoing discussion.