Install & Compatibility
Where this runs
tested against v0.12.1 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.95 runs
installs and imports cleanly · install 0.0s · import 0.260s · 18.9MB
glibcpy 3.10–3.95 runs
installs and imports cleanly · install 1.7s · import 0.238s · 19MB
17MB installed
● package 17MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
StandardMetadata
✓ from pyproject_metadata import StandardMetadata
✗ from pyproject_metadata.pyproject_metadata import StandardMetadata
The main class is directly importable from the top-level package.
ExtraKeyWarning
✓ from pyproject_metadata.errors import ExtraKeyWarning
Specific errors are available from the `errors` submodule.
This quickstart demonstrates how to use `pyproject-metadata` to validate a Python dictionary representing `pyproject.toml`'s `[project]` table and then generate a PEP 643-compliant PKG-INFO string. It highlights the use of `StandardMetadata.from_pyproject` for validation and `as_rfc822` for output. Note that `tomli` (or another TOML parser) is needed to initially parse a `pyproject.toml` file into a dictionary.
import tomli
from pyproject_metadata import StandardMetadata
# Example pyproject.toml [project] data as a Python dictionary
# In a real scenario, you'd load this from a pyproject.toml file using a TOML parser like 'tomli'
project_data = {
"name": "my-project",
"version": "0.1.0",
"description": "A short description",
"requires-python": ">=3.8",
"dependencies": [
"requests~=2.28",
"tomli>=1.1.0; python_version < \"3.11\""
],
"authors": [
{"name": "Your Name", "email": "your.email@example.com"}
],
"license": {"file": "LICENSE"},
"readme": "README.md",
"classifiers": [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License"
],
"urls": {
"Homepage": "https://github.com/my-project",
"Bug Tracker": "https://github.com/my-project/issues"
}
}
# Validate the project metadata
try:
metadata = StandardMetadata.from_pyproject(project_data, allow_extra_keys=False)
# Access validated fields
print(f"Project Name: {metadata.name}")
print(f"Project Version: {metadata.version}")
print(f"Requires Python: {metadata.requires_python}")
print(f"Dependencies: {metadata.dependencies}")
# Generate PEP 643-compliant Core Metadata (e.g., PKG-INFO content)
pkg_info = metadata.as_rfc822()
print("\n--- Generated PKG-INFO ---")
print(str(pkg_info))
except Exception as e:
print(f"Error validating metadata: {e}")
Debug
Known issues
gotchapyproject-metadata does NOT parse `pyproject.toml` files directly. It expects a pre-parsed Python dictionary corresponding to the `[project]` table. You must use a separate TOML parser (e.g., `tomli` for Python < 3.11 or `tomllib` for Python 3.11+) to read the `.toml` file first.fixAlways parse your `pyproject.toml` into a dictionary using a TOML parser before passing it to `StandardMetadata.from_pyproject`.
affects: All versions
gotchaBy default, extra (non-standard) fields in the `[project]` table will issue a `pyproject_metadata.errors.ExtraKeyWarning`. If unhandled, this might be unexpected. You can configure this behavior during instantiation.fixPass `allow_extra_keys=True` to ignore extra keys, or `allow_extra_keys=False` to raise a hard error for any extra keys, when calling `StandardMetadata.from_pyproject`.
affects: All versions
gotchaWhen using `project.license` as a string (representing an SPDX expression) or `project.license-files`, it's recommended to additionally validate and normalize the license expression using a dedicated tool, such as `packaging.licenses.canonicalize_license_expression` (requires `packaging` 24.2+), as `pyproject-metadata` itself does not perform full SPDX validation.fixIntegrate `packaging.licenses.canonicalize_license_expression` or a similar SPDX validation tool into your workflow for robust license field handling.
affects: All versions
breakingThe `project.dynamic` field requires careful handling by build backends. If a field is listed in `dynamic` but also specified statically, `pyproject-metadata` (following PEP 621) will raise an error. Also, build backends *must* provide data for dynamic fields and *must* raise an error if they fail to do so.fixEnsure that any fields listed in `dynamic` are *not* statically defined. Build backends must be prepared to dynamically provide the data for these fields or report an error if they cannot.
affects: All versions (by PEP 621 compliance)
Errors
Common errors & fixes
ValueError: Missing required fields: name
The input dictionary is missing the 'name' field, which is a mandatory requirement for project metadata according to PEP 621.
fixEnsure the dictionary passed to `Metadata.from_data()` includes a 'name' field (and 'version', as it is also required by PEP 621).
```python
from pyproject_metadata import Metadata
metadata_dict = {
"name": "my-package",
"version": "0.1.0",
# ... other valid fields
}
metadata = Metadata.from_data(metadata_dict)
``` TypeError: Field 'description' must be a string.
A field in the metadata dictionary, such as 'description', was provided with an incorrect data type, violating the PEP 621 specification for that field.
fixProvide the correct data type (e.g., a string) for the specified field according to PEP 621.
```python
from pyproject_metadata import Metadata
# Incorrect: description is an integer
# metadata_dict = {"name": "pkg", "version": "0.1.0", "description": 123}
# Correct: description is a string
metadata_dict = {"name": "pkg", "version": "0.1.0", "description": "A short description of the package."}
metadata = Metadata.from_data(metadata_dict)
``` ValueError: Field 'authors' list item email 'invalid-email' is not a valid email address.
An email address provided within a structured field like 'authors' or 'maintainers' does not conform to a valid email format.
fixEnsure all email addresses (and URLs, if applicable) provided in the metadata adhere to their respective valid formats.
```python
from pyproject_metadata import Metadata
# Incorrect: 'bad-email' is not a valid email format
# metadata_dict = {
# "name": "pkg", "version": "0.1.0",
# "authors": [{"name": "John Doe", "email": "bad-email"}]
# }
# Correct: 'john.doe@example.com' is a valid email
metadata_dict = {
"name": "pkg", "version": "0.1.0",
"authors": [{"name": "John Doe", "email": "john.doe@example.com"}]
}
metadata = Metadata.from_data(metadata_dict)
``` ModuleNotFoundError: No module named 'pyproject.metadata'
The user attempted to import the library using `pyproject.metadata` (with a dot), but the correct package name uses an underscore: `pyproject_metadata`.
fixUse an underscore (`_`) instead of a dot (`.`) in the package name when importing.
```python
# Incorrect:
# from pyproject.metadata import Metadata
# Correct:
from pyproject_metadata import Metadata
# Now you can use Metadata, e.g.:
# metadata = Metadata.from_data({"name": "my-package", "version": "0.1.0"})
``` Upgrade
Version history
0.12.1latest on PyPI · released Jul 4, 2026
Audit
Dependencies
packagingoptionalUsed for canonicalizing license expressions (METADATA 2.4+).