Welcome to twine’s documentation!¶
Table of Contents
Twine user documentation¶
Twine is a utility for publishing Python packages on PyPI.
It provides build system independent uploads of source and binary distribution artifacts for both new and existing projects.
Why Should I Use This?¶
The goal of twine
is to improve PyPI interaction by improving
security and testability.
The biggest reason to use twine
is that it securely authenticates
you to PyPI over HTTPS using a verified connection regardless of
the underlying Python version, while whether or not
python setup.py upload
will work correctly and securely depends
on your build system, your Python version and the underlying operating
system.
Secondly, it allows you to precreate your distribution files.
python setup.py upload
only allows you to upload something that you’re
building with distutils
or setuptools
, and created in the same
command invocation. This means that you cannot test the
exact file you’re going to upload to PyPI to ensure that it works before
uploading it.
Finally, twine
allows you to pre-sign your files and pass the
.asc
files into the command line invocation (twine upload
myproject-1.0.1.tar.gz myproject-1.0.1.tar.gz.asc
). This enables you
to be assured that you’re typing your gpg
passphrase into gpg
itself and not anything else, since you will be the one directly
executing gpg --detach-sign -a <filename>
.
Features¶
- Verified HTTPS connections
- Uploading doesn’t require executing
setup.py
- Uploading files that have already been created, allowing testing of distributions before release
- Supports uploading any packaging format (including wheels)
Installation¶
$ pip install twine
Using Twine¶
Create some distributions in the normal way:
$ python setup.py sdist bdist_wheel
Upload with
twine
to Test PyPI and verify things look right. Twine will automatically prompt for your username and password:$ twine upload --repository-url https://test.pypi.org/legacy/ dist/* username: ... password: ...
Upload to PyPI:
$ twine upload dist/*
Done!
More documentation on using twine
to upload packages to PyPI is in
the Python Packaging User Guide.
Keyring Support¶
Instead of typing in your password every time you upload a distribution, Twine allows you to store your username and password securely using keyring.
To use the keyring, you must first install the keyring packages:
- On Windows and MacOS you just need to install
keyring
, for example,pip install --user keyring
. - On Linux, in addition to the
keyring
package you also need to ensure thepython3-dbus
system package is installed. For example,apt install python3-dbus
. See Keyring’s installation instructions for more details.
Once keyring is installed you can use the keyring
program to set your
username and password to use for each package index (repository) you want to
upload to using Twine.
To set your username and password for test PyPI run the following command.
keyring
will prompt you for your password:
$ keyring set https://test.pypi.org/legacy/ your-username
# or
$ python3 -m keyring set https://test.pypi.org/legacy/ your-username
To set your username and password for PyPI run this command, again, keyring
will prompt for the password:
$ keyring set https://upload.pypi.org/legacy/ your-username
# or
$ python3 -m keyring set https://upload.pypi.org/legacy/ your-username
The next time you run twine
it will prompt you for a username and will grab the appropriate password from the keyring.
Note
If you are using Linux in a headless environment (such as on a server) you’ll need to do some additional steps to ensure that Keyring can store secrets securely. See Using Keyring on headless systems.
Disabling Keyring¶
In some cases, the presence of keyring may be problematic. To disable
keyring and defer to a prompt for passwords, uninstall keyring
or if that’s not an option, you can also configure keyring to be disabled.
See twine 338 for a discussion on ways to do that.
Options¶
twine upload
¶
Uploads one or more distributions to a repository.
$ twine upload -h
usage: twine upload [-h] [-r REPOSITORY] [--repository-url REPOSITORY_URL]
[-s] [--sign-with SIGN_WITH] [-i IDENTITY] [-u USERNAME]
[-p PASSWORD] [-c COMMENT] [--config-file CONFIG_FILE]
[--skip-existing] [--cert path] [--client-cert path]
[--verbose] [--disable-progress-bar]
dist [dist ...]
positional arguments:
dist The distribution files to upload to the repository
(package index). Usually dist/* . May additionally
contain a .asc file to include an existing signature
with the file upload.
optional arguments:
-h, --help show this help message and exit
-r REPOSITORY, --repository REPOSITORY
The repository (package index) to upload the package
to. Should be a section in the config file (default:
pypi). (Can also be set via TWINE_REPOSITORY
environment variable.)
--repository-url REPOSITORY_URL
The repository (package index) URL to upload the
package to. This overrides --repository. (Can also be
set via TWINE_REPOSITORY_URL environment variable.)
-s, --sign Sign files to upload using GPG.
--sign-with SIGN_WITH
GPG program used to sign uploads (default: gpg).
-i IDENTITY, --identity IDENTITY
GPG identity used to sign files.
-u USERNAME, --username USERNAME
The username to authenticate to the repository
(package index) as. (Can also be set via
TWINE_USERNAME environment variable.)
-p PASSWORD, --password PASSWORD
The password to authenticate to the repository
(package index) with. (Can also be set via
TWINE_PASSWORD environment variable.)
-c COMMENT, --comment COMMENT
The comment to include with the distribution file.
--config-file CONFIG_FILE
The .pypirc config file to use.
--skip-existing Continue uploading files if one already exists. (Only
valid when uploading to PyPI. Other implementations
may not support this.)
--cert path Path to alternate CA bundle (can also be set via
TWINE_CERT environment variable).
--client-cert path Path to SSL client certificate, a single file
containing the private key and the certificate in PEM
format.
--verbose Show verbose output.
--disable-progress-bar
Disable the progress bar.
twine check
¶
Checks whether your distributions long description will render correctly on PyPI.
$ twine check -h
usage: twine check [-h] dist [dist ...]
positional arguments:
dist The distribution files to check, usually dist/*
optional arguments:
-h, --help show this help message and exit
twine register
¶
WARNING: The register
command is no longer necessary if you are uploading to
pypi.org. As such, it is no longer supported in Warehouse (the new
PyPI software running on pypi.org). However, you may need this if you are using
a different package index.
For completeness, its usage:
$ twine register -h
usage: twine register [-h] -r REPOSITORY [--repository-url REPOSITORY_URL]
[-u USERNAME] [-p PASSWORD] [-c COMMENT]
[--config-file CONFIG_FILE] [--cert path]
[--client-cert path]
package
positional arguments:
package File from which we read the package metadata.
optional arguments:
-h, --help show this help message and exit
-r REPOSITORY, --repository REPOSITORY
The repository (package index) to register the package
to. Should be a section in the config file. (Can also
be set via TWINE_REPOSITORY environment variable.)
Initial package registration no longer necessary on
pypi.org:
https://packaging.python.org/guides/migrating-to-pypi-
org/
--repository-url REPOSITORY_URL
The repository (package index) URL to register the
package to. This overrides --repository. (Can also be
set via TWINE_REPOSITORY_URL environment variable.)
-u USERNAME, --username USERNAME
The username to authenticate to the repository
(package index) as. (Can also be set via
TWINE_USERNAME environment variable.)
-p PASSWORD, --password PASSWORD
The password to authenticate to the repository
(package index) with. (Can also be set via
TWINE_PASSWORD environment variable.)
-c COMMENT, --comment COMMENT
The comment to include with the distribution file.
--config-file CONFIG_FILE
The .pypirc config file to use.
--cert path Path to alternate CA bundle (can also be set via
TWINE_CERT environment variable).
--client-cert path Path to SSL client certificate, a single file
containing the private key and the certificate in PEM
format.
Environment Variables¶
Twine also supports configuration via environment variables. Options passed on the command line will take precedence over options set via environment variables. Definition via environment variable is helpful in environments where it is not convenient to create a .pypirc file, such as a CI/build server, for example.
TWINE_USERNAME
- the username to use for authentication to the repository.TWINE_PASSWORD
- the password to use for authentication to the repository.TWINE_REPOSITORY
- the repository configuration, either defined as a section in .pypirc or provided as a full URL.TWINE_REPOSITORY_URL
- the repository URL to use.TWINE_CERT
- custom CA certificate to use for repositories with self-signed or untrusted certificates.
Resources¶
- IRC
(
#pypa
- irc.freenode.net) - GitHub repository
- User and developer documentation
- Python Packaging User Guide
Contributing¶
See our developer documentation for how to get started, an architectural overview, and our future development plans.
Code of Conduct¶
Everyone interacting in the twine
project’s codebases, issue
trackers, chat rooms, and mailing lists is expected to follow the
PyPA Code of Conduct.
Contributing¶
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/
.
Testing¶
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¶
- Fork the GitHub repository.
- Make a branch off of
master
and commit your changes to it. - Run the tests with
tox
and lint any docs changes withtox -e docs
. - Ensure that your name is added to the end of the
AUTHORS
file using the formatName <email@domain.com> (url)
, where the(url)
portion is optional. - 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:
- A user-facing tool for publishing on pypi.org
- A user-facing tool for publishing on other Python package indexes
(e.g.,
devpi
instances) - 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/cli.py
. The
code for registering new projects is in
twine/commands/register.py
, and the code for uploading is in
twine/commands/upload.py
. The file twine/package.py
contains a single class, PackageFile
, which hashes the project
files and extracts their metadata. The file
twine/repository.py
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.
- Add her as a Member in the GitHub repo settings. (This will also give her privileges on the Travis CI project.)
- 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.
Choose a version number, e.g., “1.15.”
Merge the last planned PR before the new release:
- Add new changes to
docs/changelog.rst
. - Update the
__version__
string intwine/__init__.py
, which is wheresetup.py
pulls it from, with{number}rc1
for “release candidate 1”. - Update copyright dates.
- Add new changes to
Run Twine tests:
tox -e py{27,34,35,36,py}
tox -e lint
for the lintertox -e docs
(this checks the Sphinx docs and usesreadme_renderer
to check that thelong_description
and other metadata will render fine on the PyPI description)
Run integration tests with downstreams:
Test
pypiserver
support:git clone git@github.com:pypiserver/pypiserver cd pypiserver tox -e pre_twine
Create a test package to upload to Test PyPI, version-control it with git, and test
zest.releaser
per directions in this comment.Test
devpi
support:pip install devpi-client devpi use https://m.devpi.net devpi user -c {username} password={password} devpi login {username} --password={password} devpi index -c testpypi type=mirror mirror_url=https://test.pypi.org/simple/ devpi use {username}/testpypi python setup.py sdist twine upload --repository-url https://m.devpi.net/{username}/testpypi/ dist/{testpackage}.tar.gz
Create a git tag with
git tag -sam 'Release v{number}' {number}
.{number}
, such as1.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
View your tag:
git tag -v {number}
Push your tag:
git push upstream {number}
.Delete old distributions:
rm dist/*
.Create distributions with
python setup.py sdist bdist_wheel
.Set your TestPyPI and canon PyPI credentials in your session with
keyring
(docs forthcoming).Upload to Test PyPI: twine upload --repository-url https://test.pypi.org/legacy/ --skip-existing dist/*
Verify that everything looks good, downloads ok, etc. Make needed fixes.
Merge the last PR before the new release:
- Add new changes and new release to
docs/changelog.rst
, with the new version{number}
, this time without therc1
suffix. - Update the
__version__
string intwine/__init__.py
with{number}
.
- Add new changes and new release to
Run tests again. Check the changelog to verify that it looks right.
Create a new git tag with
git tag -sam 'Release v{number}' {number}
.View your tag:
git tag -v {number}
Push your tag:
git push upstream {number}
.Delete old distributions:
rm dist/*
.Create distributions with
python setup.py sdist bdist_wheel
.On a Monday or Tuesday, upload to canon PyPI: twine upload --skip-existing dist/*
Note
Will be replaced by
tox -e release
at some point.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.
Changelog¶
Next bugfix release
- [Bug] #367: Avoid MD5 when Python is compiled in FIPS mode
- [Bug] #408: Fix keyring support.
- [Bug] #412: Don’t crash if there’s no package description.
- [Bug]: :feature:`` Add Python 3.7 to classifiers.
- [Bug] #421: Remove unnecessary usage of readme_render.markdown.
- [Bug] #428: Fix –skip-existing for Nexus Repos.
- [Bug] #432: Use https URLs everywhere.
- [Bug] #435: Specify python_requires in setup.py
- [Bug] #436: Use modern Python language features.
- [Bug] #444: Use io.StringIO instead of StringIO.
- [Bug] #441: Only install pyblake2 if needed.
- [Bug] #447: Avoid requests-toolbelt to 0.9.0 to prevent attempting to use openssl when it isn’t available.
- [Bug] #452: Restore prompts while retaining support for suppressing prompts.
1.13.0 2019-02-13
1.12.0 2018-09-24
1.11.0 2018-03-19
- [Feature] #319: Support Metadata 2.1 (PEP 566), including Markdown
for
description
fields. - [Feature] #320: Remove PyPI as default
register
package index. - [Bug] #322: Raise exception if attempting upload to deprecated legacy PyPI URLs.
- [Bug] #269: Avoid uploading to PyPI when given alternate
repository URL, and require
http://
orhttps://
inrepository_url
. - [Support] #318: Update PyPI URLs.
- [Support] #314: Add new maintainer, release checklists.
- [Support] #277: Add instructions on how to use keyring.
1.10.0 2018-03-07
- [Feature] #256: Improve progressbar
- [Feature] #257: Declare support for Python 3.6
- [Feature] #303: Revise docs predicting future of
twine
- [Feature] #296: Add architecture overview to docs
- [Feature] #295: Add doc building instructions
- [Feature] #46: Link to changelog from
README
- [Feature] #304: Reorganize & improve user & developer documentation.
- [Bug] #265: Fix
--repository[-url]
help text - [Bug] #268: Print progress to
stdout
, notstderr
- [Bug] #297: Fix Read the Docs, tox, Travis configuration
- [Bug] #286: Fix Travis CI and test configuration
- [Bug] #200: Remove obsolete registration guidance
- [Bug] #299: Fix changelog formatting
- [Bug] #298: Fix syntax highlighting in
README
- [Bug] #315: Degrade gracefully when keyring is unavailable
1.9.0 2017-05-22
[Support]: Check if a package exists if the URL is one of:
https://pypi.python.org/pypi/
https://upload.pypi.org/
https://upload.pypi.io/
This helps people with
https://upload.pypi.io
still in their.pypirc
file.[Support]: Fix precedence of
--repository-url
over--repository
. See also [Bug] #206:[Support]: Fix
--skip-existing
when used to upload a package for the first time. See also [Bug] #220:[Support]: Twine sends less information about the user’s system in the User-Agent string. See also [Bug] #229:
[Support]: Twine will use
hashlib.blake2b
on Python 3.6+ instead of using pyblake2 for Blake2 hashes 256 bit hashes.[Support]: Twine will now resolve passwords using the keyring if available. Module can be required with the
keyring
extra.
1.8.0 2016-08-08
[Feature] #171: Generate Blake2b 256 digests for packages if
pyblake2
is installed. Users can usepython -m pip install twine[with-blake2]
to havepyblake2
installed with Twine.[Feature] #166: Allow the Repository URL to be provided on the command-line (
--repository-url
) or via an environment variable (TWINE_REPOSITORY_URL
).[Feature] #144: Retrieve configuration from the environment as a default.
- Repository URL will default to
TWINE_REPOSITORY
- Username will default to
TWINE_USERNAME
- Password will default to
TWINE_PASSWORD
- Repository URL will default to
[Feature] #201: Switch from upload.pypi.io to upload.pypi.org.
[Support]: Do not generate traffic to Legacy PyPI unless we’re uploading to it or uploading to Warehouse (e.g., pypi.io). This avoids the attempt to upload a package to the index if we can find it on Legacy PyPI already.
[Support]: Warn users if they receive a 500 error when uploading to
*pypi.python.org
[Support]: Stop testing on Python 2.6. 2.6 support will be “best effort” until 2.0.0
[Support]: Generate SHA256 digest for all packages by default.
1.7.4 2016-07-09
- [Bug]: Correct a packaging error.
1.7.3 2016-07-08
- [Bug] #195: Fix uploads to instances of pypiserver using
--skip-existing
. We were not properly checking the return status code on the response after attempting an upload.
1.7.2 2016-07-05
1.7.0 2016-07-04
- [Feature] #177: Switch Twine to upload to pypi.io instead of pypi.python.org.
- [Feature] #167: Implement retries when the CDN in front of PyPI gives us a 5xx error.
- [Feature] #162: Allow
--skip-existing
to work for 409 status codes. - [Feature] #152: Add progress bar to uploads.
- [Feature] #142: Support
--cert
and--client-cert
command-line flags and config file options for feature parity with pip. This allows users to verify connections to servers other than PyPI (e.g., local package repositories) with different certificates. - [Bug] #186: Allow passwords to have
%
s in them.
1.6.4 2015-10-27
1.6.3 2015-10-05
1.6.2 2015-09-28
[Bug] #132: Upload signatures with packages appropriately
As part of the refactor for the 1.6.0 release, we were using the wrong name to find the signature file.
This also uncovered a bug where if you’re using twine in a situation where
*
is not expanded by your shell, we might also miss uploading signatures to PyPI. Both were fixed as part of this.
1.6.0 2015-09-14
- [Feature] #8: Support registering new packages with
twine register
- [Feature] #115: Add the
--skip-existing
flag totwine upload
to allow users to skip releases that already exist on PyPI. - [Feature] #97: Allow the user to specify the location of their
.pypirc
- [Feature] #104: Large file support via the
requests-toolbelt
- [Feature] #106: Upload wheels first to PyPI
- [Bug] #111: Provide more helpful messages if
.pypirc
is out of date. - [Bug] #116: Work around problems with Windows when using
getpass.getpass
- [Bug] #114: Warnings triggered by pkginfo searching for
PKG-INFO
files should no longer be user visible. - [Bug] #92: Raise an exception on redirects
1.5.0 2015-03-10
1.4.0 2014-12-12
- [Feature] #6: Switch to a git style dispatching for the commands to enable simpler commands and programmatic invocation.
- [Feature] #13: Parse
~/.pypirc
ourselves and usesubprocess
instead of thedistutils.spawn
module. - [Bug] #65: Expand globs and check for existence of dists to upload
- [Bug] #26: Add support for uploading Windows installers
- [Bug] #47: Fix issue uploading packages with
_
s in the name - [Bug] #32: Use
pkg_resources
to load registered commands - [Bug] #34: List registered commands in help text
- [Bug] #28: Prevent ResourceWarning from being shown
1.3.0 2014-03-31
- [Feature]: Additional functionality.
1.2.2 2013-10-03
- [Feature]: Basic functionality.