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.
To ask questions or get involved, you can join the Python Packaging
Discourse forum, #pypa
or #pypa-dev
on IRC, or the
distutils-sig mailing list.
Everyone interacting in the Twine project’s codebases, issue trackers, chat rooms, and mailing lists is expected to follow the PSF Code of Conduct.
Getting started¶
We use tox to run tests, check code style, and build the documentation.
To install tox
, run:
python3 -m pip install tox
Clone the twine repository from GitHub, then run:
cd /path/to/your/local/twine
tox -e dev
This creates a virtual environment, so that twine and its
dependencies do not interfere with other packages installed on your
machine. In the virtual environment, twine
is pointing at your
local copy, so when you make changes, you can easily see their effect.
The virtual environment also contains the tools for running tests
and checking code style, so you can run them on single files directly or
in your code editor. However, we still encourage using the tox
commands
below on the whole codebase.
To use the virtual environment, run:
source venv/bin/activate
Building the documentation¶
Additions and edits to twine’s documentation are welcome and appreciated.
To preview the docs while you’re making changes, run:
tox -e watch-docs
Then open a web browser to http://127.0.0.1:8000.
When you’re done making changes, lint and build the docs locally before making a pull request. In your active virtual environment, run:
tox -e docs
The HTML of the docs will be written to docs/_build/html
.
Code style¶
To automatically reformat your changes with isort and black, run:
tox -e format
To detect any remaining code smells with flake8, run:
tox -e lint
To perform strict type-checking using mypy, run:
tox -e types
Any errors from lint
or types
need to be fixed manually.
Additionally, we prefer that import
statements be used for packages and
modules only, rather than individual classes or functions.
Testing¶
We use pytest for writing and running tests.
To run the tests in your virtual environment, run:
tox -e py
To pass options to pytest
, e.g. the name of a test, run:
tox -e py -- tests/test_upload.py::test_exception_for_http_status
Twine is continuously tested against supported versions of Python using GitHub Actions. To run the tests against a specific version, e.g. Python 3.8, you will need it installed on your machine. Then, run:
tox -e py38
To run the “integration” tests of uploading to real package indexes, run:
tox -e integration
To run the tests against all supported Python versions, check code style, and build the documentation, run:
tox
Submitting changes¶
Fork the GitHub repository.
Make a branch off of
main
and commit your changes to it.Run the tests, check code style, and build the docs as described above.
Optionally, add your name 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
main
branch on GitHub, referencing an open issue.Add a changelog entry.
Changelog entries¶
The docs/changelog.rst
file is built by towncrier from files in the
changelog/
directory. To add an entry, create a file in that directory
named {number}.{type}.rst
, where {number}
is the pull request number,
and {type}
is feature
, bugfix
, doc
, removal
, or misc
.
For example, if your PR number is 1234 and it’s fixing a bug, then you
would create changelog/1234.bugfix.rst
. PRs can span multiple categories by
creating multiple files: if you added a feature and deprecated/removed an old
feature in PR #5678, you would create changelog/5678.feature.rst
and
changelog/5678.removal.rst
.
A changelog entry is meant for end users and should only contain details relevant to them. In order to maintain a consistent style, please keep the entry to the point, in sentence case, shorter than 80 characters, and in an imperative tone. An entry should complete the sentence “This change will …”. If one line is not enough, use a summary line in an imperative tone, followed by a description of the change in one or more paragraphs, each wrapped at 80 characters and separated by blank lines.
You don’t need to reference the pull request or issue number in a changelog entry, since towncrier will add a link using the number in the file name, and the pull request should reference an issue number. Similarly, you don’t need to add your name to the entry, since that will be associated with the pull request.
Changelog entries are rendered using reStructuredText, but they should only
have minimal formatting (such as ``monospaced text``
).
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.
For more details, refer to the source documentation (currently a work in progress):
- twine package
- twine.commands package
- twine.auth module
CredentialInput
Resolver
Resolver.__init__()
Resolver.choose()
Resolver.username
Resolver.password
Resolver.make_trusted_publishing_token()
Resolver.system
Resolver.get_username_from_keyring()
Resolver.get_password_from_keyring()
Resolver.username_from_keyring_or_prompt()
Resolver.password_from_keyring_or_trusted_publishing_or_prompt()
Resolver.prompt()
Resolver.is_pypi()
Private
- twine.cli module
- twine.exceptions module
- twine.package module
_safe_name()
PackageMetadata
PackageMetadata.metadata_version
PackageMetadata.name
PackageMetadata.version
PackageMetadata.platform
PackageMetadata.summary
PackageMetadata.description
PackageMetadata.keywords
PackageMetadata.home_page
PackageMetadata.author
PackageMetadata.author_email
PackageMetadata.license
PackageMetadata.supported_platform
PackageMetadata.download_url
PackageMetadata.classifiers
PackageMetadata.requires
PackageMetadata.provides
PackageMetadata.obsoletes
PackageMetadata.maintainer
PackageMetadata.maintainer_email
PackageMetadata.requires_dist
PackageMetadata.provides_dist
PackageMetadata.obsoletes_dist
PackageMetadata.requires_python
PackageMetadata.requires_external
PackageMetadata.project_urls
PackageMetadata.description_content_type
PackageMetadata.provides_extra
PackageMetadata.dynamic
PackageMetadata.license_expression
PackageMetadata.license_file
PackageMetadata.comment
PackageMetadata.pyversion
PackageMetadata.filetype
PackageMetadata.gpg_signature
PackageMetadata.attestations
PackageMetadata.md5_digest
PackageMetadata.sha256_digest
PackageMetadata.blake2_256_digest
PackageFile
Hexdigest
HashManager
- twine.repository module
Repository
Repository.__init__()
Repository.close()
Repository._convert_metadata_to_list_of_tuples()
Repository.set_certificate_authority()
Repository.set_client_certificate()
Repository.register()
Repository._upload()
Repository.upload()
Repository.package_is_uploaded()
Repository.release_urls()
Repository.verify_package_integrity()
- twine.settings module
Settings
Settings.__init__()
Settings.username
Settings.password
Settings._allow_noninteractive()
Settings.verbose
Settings.register_argparse_arguments()
Settings.from_argparse()
Settings._handle_package_signing()
Settings._handle_repository_options()
Settings._handle_certificates()
Settings.check_repository_url()
Settings.create_repository()
- twine.utils module
- twine.wheel module
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 them as a Member in the GitHub repo settings.
Get them Test PyPI and canon PyPI usernames and add them 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, and create a new branch
VERSION=3.4.2 git switch -c release-$VERSION
Update
docs/changelog.rst
tox -e changelog -- --version $VERSION git commit -am "Update changelog for $VERSION"
Open a pull request for review
Merge the pull request, and ensure the GitHub Actions build passes
Create a new git tag for the version
git switch main git pull --ff-only upstream main git tag -m "Release v$VERSION" $VERSION
Push to start the release, and watch it in GitHub Actions
git push upstream $VERSION
View the new release on PyPI
Future development¶
See our open issues.
In the future, pip
and twine
may
merge into a single tool; see ongoing discussion.