The essentials

Quick reference

One focused task per row. Jump to the related section for complete, working examples.

UseSyntaxExamples
Create a virtual environmentpython -m venv .venvView examples
Seed current packaging toolspython -m venv --upgrade-deps .venvView examples
Invoke the environment directly.venv/bin/python -m pip --versionView examples
Declare backend requirementsrequires = ['hatchling>=1.26'] # in [build-system]View examples
Select a build backendbuild-backend = 'hatchling.build'View examples
Declare Python compatibilityrequires-python = '>=3.11'View examples
Declare a runtime dependencydependencies = ['httpx>=0.27,<1']View examples
Publish a console commandacme = 'acme.cli:main' # in [project.scripts]View examples
Declare an optional featuretest = ['pytest>=8'] # in [project.optional-dependencies]View examples
Apply deployment constraintspython -m pip install -c constraints.txt -r requirements.txtView examples
Require artifact hashespython -m pip install --require-hashes -r requirements.txtView examples
Use a src package layoutsrc/acme/__init__.pyView examples
Open packaged texttext = resources.files('acme').joinpath('data.txt').read_text(encoding='utf-8')View examples
Build sdist and wheelpython -m buildView examples
Build only a wheelpython -m build --wheelView examples
Install the built wheelpython -m pip install --force-reinstall dist/acme_tools-1.2.0-py3-none-any.whlView examples
Validate distribution metadatapython -m twine check dist/*View examples
Upload to TestPyPIpython -m twine upload --repository testpypi dist/*View examples
Read installed metadataversion = importlib.metadata.version('acme-tools')View examples

Modern Python projects declare build requirements and core metadata in pyproject.toml, build isolated source and wheel distributions, and test installation artifacts rather than relying on a source checkout. Virtual environments isolate installed distributions, not operating-system libraries. Reproducibility additionally requires deliberate dependency constraints, hashes where appropriate, and controlled build inputs.

Step by step

Detailed examples

01

Create and operate an isolated environment

python -m venv creates an environment around a specific interpreter. Activation only adjusts shell variables; invoking the environment's Python directly is more explicit in automation. Environments are disposable and generally not portable because scripts embed absolute interpreter paths. Recreate them from declared inputs instead of copying or committing them.

Detect whether Python is running in a venv
import sys

inside_venv = sys.prefix != sys.base_prefix
print(type(inside_venv).__name__)
print(sys.base_prefix != "")
Output
bool
True
Back to quick reference ↑
02

Declare the build backend

The [build-system] table tells a frontend which packages to install into an isolated build environment and which backend object to call. Keep requires limited to actual build dependencies and use versions compatible with your supported frontend. A missing table invokes legacy defaults in some tools, so explicit configuration is easier to audit.

Read build-system configuration
import tomllib

document = tomllib.loads("""
[build-system]
requires = ["hatchling>=1.26"]
build-backend = "hatchling.build"
""")
print(document["build-system"]["build-backend"])
print(document["build-system"]["requires"])
Output
hatchling.build
['hatchling>=1.26']
Back to quick reference ↑
03

Express interoperable project metadata

The [project] table defined by the packaging metadata specification contains name, version or dynamic fields, Python compatibility, dependencies, scripts, classifiers, and URLs. Distribution names and import package names need not match. Declare requires-python honestly so installers reject incompatible interpreters before installation.

Validate core project metadata
import tomllib

project = tomllib.loads("""
[project]
name = "acme-tools"
version = "1.2.0"
requires-python = ">=3.11"
dependencies = ["httpx>=0.27,<1"]
""")["project"]
print(project["name"], project["version"])
print(project["requires-python"])
print(len(project["dependencies"]))
Output
acme-tools 1.2.0
>=3.11
1
Back to quick reference ↑
04

Separate abstract dependencies from locked environments

Project metadata should state compatible dependency ranges, while applications and deployments may use a fully resolved lock or constraints file. Do not copy an environment's complete freeze into a reusable library's runtime dependencies. Evaluate environment markers on every target platform, and treat direct URLs or alternate indexes as supply-chain decisions requiring review.

Evaluate a simple environment marker
import sys

minimum = (3, 11)
supported = sys.version_info[:2] >= minimum
print("supported" if supported else "unsupported")
print("target", ".".join(map(str, minimum)))
Output
supported
target 3.11
Back to quick reference ↑
05

Design import and distribution boundaries

A src layout keeps the repository root from silently satisfying imports and helps tests exercise an installed package. Include __init__.py for regular packages unless namespace-package behavior is intentional. Package data needs backend configuration and a runtime access API such as importlib.resources; paths beside the source tree may not exist in an installed wheel.

Traverse an importable package resource
from importlib import resources

root = resources.files("importlib")
print(root.name)
print(root.is_dir())
Output
importlib
True
Back to quick reference ↑
06

Build artifacts and test what users install

Use a standards-based frontend to build both an sdist and wheel in isolation. Inspect their contents, install the wheel into a fresh environment, and run tests from outside the repository so local files cannot mask missing package data. An sdist must contain enough source and configuration to reproduce the wheel without network access beyond declared build requirements.

Form an artifact name safely
name = "acme-tools".replace("-", "_")
version = "1.2.0"
wheel = f"{name}-{version}-py3-none-any.whl"
print(wheel)
Output
acme_tools-1.2.0-py3-none-any.whl
Back to quick reference ↑
07

Publish immutably and verify provenance

Upload a release once; distribution files on PyPI cannot be replaced under the same filename. Test against TestPyPI or a private staging index, verify metadata and installation, then publish with an API token or trusted publisher rather than a password. Never place credentials in pyproject.toml, command history, or a committed URL.

Select non-secret release metadata
metadata = {
    "name": "acme-tools",
    "version": "1.2.0",
    "requires_python": ">=3.11",
}
for key in sorted(metadata):
    print(f"{key}={metadata[key]}")
Output
name=acme-tools
requires_python=>=3.11
version=1.2.0
Back to quick reference ↑

Local code tester

Inspect pyproject metadata

Parse a compact pyproject.toml document with Python's standard-library TOML reader.

Runs in your browser
Output
Press Run to load Python locally.

Sources and further reading

References

Authoritative documentation used to verify and expand this cheat sheet.

  1. Python Software Foundationvenv — Creation of virtual environmentsdocs.python.org
  2. Python Packaging Authoritypyproject.toml specificationpackaging.python.org
  3. Python Packaging AuthorityDeclaring project metadatapackaging.python.org
  4. Python Packaging AuthorityPackaging Python Projectspackaging.python.org
  5. Python Packaging AuthorityThe Packaging Flowpackaging.python.org
  6. Python Packaging AuthorityRecording installed projectspackaging.python.org

Help us improve

Found a typo or missing example?

Tell us what would make this cheat sheet clearer, more complete, or more useful.

Share feedback