Skip to content

Commit

Permalink
chore: add more checks and formatters (#191)
Browse files Browse the repository at this point in the history
Signed-off-by: Henry Schreiner <[email protected]>
  • Loading branch information
henryiii authored Oct 4, 2024
1 parent 82d1d8e commit c3c37e5
Show file tree
Hide file tree
Showing 10 changed files with 132 additions and 63 deletions.
23 changes: 11 additions & 12 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,21 @@ jobs:
fail-fast: false
matrix:
os:
- 'windows-latest'
- 'ubuntu-latest'
- "windows-latest"
- "ubuntu-latest"
python:
- '3.7'
- '3.8'
- '3.9'
- '3.10'
- '3.11'
- '3.12'
- '3.13'
- "3.7"
- "3.8"
- "3.9"
- "3.10"
- "3.11"
- "3.12"
- "3.13"
include:
- os: macos-13
python: '3.7'
python: "3.7"
- os: macos-14
python: '3.12'
python: "3.12"

steps:
- name: Checkout
Expand All @@ -56,7 +56,6 @@ jobs:
env_vars: PYTHON
name: ${{ matrix.python }}


# https:/marketplace/actions/alls-green#why
required-checks-pass: # This job does nothing and is only used for the branch protection
if: always()
Expand Down
98 changes: 78 additions & 20 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,24 +1,82 @@
ci:
autofix_prs: false
autoupdate_commit_msg: 'pre-commit: bump repositories'
autoupdate_commit_msg: "pre-commit: bump repositories"

repos:
- repo: https:/pre-commit/pre-commit-hooks
rev: v4.6.0
hooks:
- id: check-ast
- id: check-builtin-literals
- id: check-docstring-first
- id: check-merge-conflict
- id: check-yaml
- id: check-toml
- id: debug-statements
- id: end-of-file-fixer
- id: trailing-whitespace

- repo: https:/astral-sh/ruff-pre-commit
rev: "v0.6.8"
hooks:
- id: ruff
args: ["--fix", "--show-fixes"]
- id: ruff-format
- repo: https:/pre-commit/pre-commit-hooks
rev: v4.6.0
hooks:
- id: check-ast
- id: check-builtin-literals
- id: check-docstring-first
- id: check-merge-conflict
- id: check-yaml
- id: check-toml
- id: debug-statements
- id: end-of-file-fixer
- id: trailing-whitespace

- repo: https:/astral-sh/ruff-pre-commit
rev: "v0.6.8"
hooks:
- id: ruff
args: ["--fix", "--show-fixes"]
- id: ruff-format

- repo: https:/pre-commit/pygrep-hooks
rev: v1.10.0
hooks:
- id: rst-backticks
- id: rst-directive-colons
- id: rst-inline-touching-normal

- repo: https:/adamchainz/blacken-docs
rev: 1.18.0
hooks:
- id: blacken-docs
additional_dependencies: [black==24.*]

- repo: https:/rbubley/mirrors-prettier
rev: "v3.3.3"
hooks:
- id: prettier
types_or: [yaml, markdown, html, css, scss, javascript, json]
args: [--prose-wrap=always]

- repo: https:/henryiii/check-sdist
rev: "v1.0.0"
hooks:
- id: check-sdist
args: [--inject-junk]
additional_dependencies:
- flit-core

- repo: https:/codespell-project/codespell
rev: v2.3.0
hooks:
- id: codespell
exclude: ^(LICENSE$|src/scikit_build_core/resources/find_python|tests/test_skbuild_settings.py$)

- repo: https:/shellcheck-py/shellcheck-py
rev: v0.10.0.1
hooks:
- id: shellcheck

- repo: https:/henryiii/validate-pyproject-schema-store
rev: 2024.09.23
hooks:
- id: validate-pyproject

- repo: https:/python-jsonschema/check-jsonschema
rev: 0.29.3
hooks:
- id: check-dependabot
- id: check-github-workflows
- id: check-readthedocs
- id: check-metaschema
files: \.schema\.json

- repo: https:/scientific-python/cookie
rev: 2024.08.19
hooks:
- id: sp-repo-review
52 changes: 30 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,30 @@
[![Documentation Status][rtd-badge]][rtd-link]
[![PyPI version][pypi-version]][pypi-link]


> Dataclass for PEP 621 metadata with support for [core metadata] generation
This project does not implement the parsing of `pyproject.toml`
containing PEP 621 metadata.
This project does not implement the parsing of `pyproject.toml` containing PEP
621 metadata.

Instead, given a Python data structure representing PEP 621 metadata (already
parsed), it will validate this input and generate a PEP 643-compliant metadata
file (e.g. `PKG-INFO`).


## Usage

After [installing `pyproject-metadata`](https://pypi.org/project/pyproject-metadata/),
After
[installing `pyproject-metadata`](https://pypi.org/project/pyproject-metadata/),
you can use it as a library in your scripts and programs:

```python
from pyproject_metadata import StandardMetadata

parsed_pyproject = { ... } # you can use parsers like `tomli` to obtain this dict
metadata = StandardMetadata.from_pyproject(parsed_pyproject, allow_extra_keys = False)
parsed_pyproject = {...} # you can use parsers like `tomli` to obtain this dict
metadata = StandardMetadata.from_pyproject(parsed_pyproject, allow_extra_keys=False)
print(metadata.entrypoints) # same fields as defined in PEP 621

pkg_info = metadata.as_rfc822()
print(str(pkg_info))) # core metadata
print(str(pkg_info)) # core metadata
```

## SPDX licenses (METADATA 2.4+)
Expand All @@ -50,24 +49,25 @@ A backend is also expected to copy entries from `project.licence_files`, which
are paths relative to the project directory, into the `dist-info/licenses`
folder, preserving the original source structure.


## Modifying metadata

By default, `StandardMetadata` metadata fields are immutable unless a field is
listed in `dynaimc` (not to be confused with `dynamic_metadata`). If you want to
modify fields that are not dynamic, you can use the `dataclasses.replace` /
`copy.replace` (Python 3.13+) function.


## Dynamic Metadata (METADATA 2.2+)

Pyproject-metadata supports dynamic metadata. To use it, specify your METADATA fields in `dynamic_metadata`. If you want to convert `pyproject.toml` field names to METADATA field(s), use `pyproject_metadata.pyproject_to_metadata("field-name")`, which will return a frozenset of metadata names that are touched by that field.

Pyproject-metadata supports dynamic metadata. To use it, specify your METADATA
fields in `dynamic_metadata`. If you want to convert `pyproject.toml` field
names to METADATA field(s), use
`pyproject_metadata.pyproject_to_metadata("field-name")`, which will return a
frozenset of metadata names that are touched by that field.

## Adding extra fields

You can add extra fields to the Message returned by `to_rfc822()`, as long as they are valid metadata entries.

You can add extra fields to the Message returned by `to_rfc822()`, as long as
they are valid metadata entries.

## Collecting multiple errors

Expand All @@ -76,7 +76,6 @@ the metadata parse at once, instead of raising an exception on the first one.
The exception type will be `pyproject_metadata.errors.ExceptionGroup` (which is
just `ExceptionGroup` on Python 3.11+).


## Validating extra fields

By default, a warning (`pyproject_metadata.errors.ExtraKeyWarning`) will be
Expand All @@ -85,27 +84,35 @@ to either avoid the check (`True`) or hard error (`False`). If you want to
detect extra keys, you can get them with `pyproject_metadata.extra_top_level`
and `pyproject_metadata.extra_build_sytem`.


## Validating classifiers

If you want to validate classifiers, then install the `trove_classifiers` library (the canonical source for classifiers), and run:
If you want to validate classifiers, then install the `trove_classifiers`
library (the canonical source for classifiers), and run:

```python
import trove_classifiers

metadata_classifieres = {c for c in metadata.classifiers if not c.startswith("Private ::")}
metadata_classifieres = {
c for c in metadata.classifiers if not c.startswith("Private ::")
}
invalid_classifiers = set(metadata.classifiers) - trove_classifiers.classifiers

# Also the deprecated dict if you want it
dep_names = set(metadata.classifiers) & set(trove_classifiers.deprecated_classifiers)
deprecated_classifiers = {k: trove_classifiers.deprecated_classifiers[k] for k in dep_names}
deprecated_classifiers = {
k: trove_classifiers.deprecated_classifiers[k] for k in dep_names
}
```

If you are writing a build backend, you should not validate classifiers with a `Private ::` prefix; these are only restricted for upload to PyPI (such as `Private :: Do Not Upload`).

Since classifiers are a moving target, it is probably best for build backends (which may be shipped by third party distributors like Debian or Fedora) to either ignore or have optional classifier validation.
If you are writing a build backend, you should not validate classifiers with a
`Private ::` prefix; these are only restricted for upload to PyPI (such as
`Private :: Do Not Upload`).

Since classifiers are a moving target, it is probably best for build backends
(which may be shipped by third party distributors like Debian or Fedora) to
either ignore or have optional classifier validation.

<!-- prettier-ignore-start -->
[core metadata]: https://packaging.python.org/specifications/core-metadata/
[gha-checks-link]: https:/pypa/pyproject-metadata/actions/workflows/checks.yml
[gha-checks-badge]: https:/pypa/pyproject-metadata/actions/workflows/checks.yml/badge.svg
Expand All @@ -119,3 +126,4 @@ Since classifiers are a moving target, it is probably best for build backends (w
[pypi-version]: https://badge.fury.io/py/pyproject-metadata.svg
[rtd-link]: https://pep621.readthedocs.io/en/latest/?badge=latest
[rtd-badge]: https://readthedocs.org/projects/pep621/badge/?version=latest
<!-- prettier-ignore-end -->
2 changes: 1 addition & 1 deletion docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ Docs:

- Better API section


## 0.9.0 (WIP)

This release adds PEP 639 support (METADATA 2.4), refactors the RFC messages,
Expand Down Expand Up @@ -69,6 +68,7 @@ Internal and CI:
- Require 100% coverage

Docs:

- Include extra badge in readme
- Rework docs, include README and more classes
- Changelog is now in markdown
Expand Down
1 change: 0 additions & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
```


```{toctree}
:caption: Contents:
:maxdepth: 2
Expand Down
5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ testpaths = ["tests"]

[tool.mypy]
strict = true
warn_unreachable = false
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]


[tool.ruff.lint]
Expand Down Expand Up @@ -103,3 +105,6 @@ html.show_contexts = true
report.exclude_also = [
"if typing.TYPE_CHECKING:",
]

[tool.repo-review]
ignore = ["PC140"]
6 changes: 3 additions & 3 deletions pyproject_metadata/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,19 +242,19 @@ class StandardMetadata:

dynamic_metadata: list[str] = dataclasses.field(default_factory=list)
"""
This is a list of METADATA fields that can change inbetween SDist and wheel. Requires metadata_version 2.2+.
This is a list of METADATA fields that can change in between SDist and wheel. Requires metadata_version 2.2+.
"""
metadata_version: str | None = None
"""
Thi is the target metadata version. If None, it will be computed as a minimum based on the fields set.
This is the target metadata version. If None, it will be computed as a minimum based on the fields set.
"""
all_errors: bool = False
"""
If True, all errors will be collected and raised in an ExceptionGroup.
"""
_locked_metadata: bool = False
"""
Interal flag to prevent setting non-dynamic fields after initialization.
Internal flag to prevent setting non-dynamic fields after initialization.
"""

def __post_init__(self) -> None:
Expand Down
2 changes: 1 addition & 1 deletion pyproject_metadata/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

"""
This module defines exceptions and error handling utilities. It is the
recommened path to access ``ConfiguraitonError``, ``ConfigurationWarning``, and
recommend path to access ``ConfiguratonError``, ``ConfigurationWarning``, and
``ExceptionGroup``. For backward compatibility, ``ConfigurationError`` is
re-exported in the top-level package.
"""
Expand Down
2 changes: 1 addition & 1 deletion tests/test_rfc822.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@
],
)
def test_headers(
items: list[tuple[str, str]], data: str, monkeypatch: pytest.MonkeyPatch
items: list[tuple[str, None | str]], data: str, monkeypatch: pytest.MonkeyPatch
) -> None:
message = pyproject_metadata.RFC822Message()
smart_message = pyproject_metadata._SmartMessageSetter(message)
Expand Down
4 changes: 2 additions & 2 deletions tests/test_standard_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -749,7 +749,7 @@ def all_errors(request: pytest.FixtureRequest, monkeypatch: pytest.MonkeyPatch)
license-files = ['/LICENSE']
""",
"'/LICENSE' is an invalid \"project.license-files\" glob: the pattern must match files within the project directory",
id="Aboslute license-files glob",
id="Absolute license-files glob",
),
pytest.param(
"""
Expand Down Expand Up @@ -960,7 +960,7 @@ def test_load_with_metadata_version(
""",
"'License ::' classifiers are deprecated for metadata >= 2.4, use a SPDX license expression for \"project.license\" instead",
"2.4",
id="License trove classfiers with metadata 2.4",
id="License trove classifiers with metadata 2.4",
),
],
)
Expand Down

0 comments on commit c3c37e5

Please sign in to comment.