• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

abravalheri / validate-pyproject / 5541151060525056

12 Mar 2025 09:10PM UTC coverage: 98.033%. Remained the same
5541151060525056

Pull #227

cirrus-ci

henryiii
chore: use tox-uv

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Pull Request #227: chore: move to using dependency-groups

296 of 308 branches covered (96.1%)

Branch coverage included in aggregate %.

950 of 963 relevant lines covered (98.65%)

6.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.74
/src/validate_pyproject/extra_validations.py
1
"""The purpose of this module is implement PEP 621 validations that are
2
difficult to express as a JSON Schema (or that are not supported by the current
3
JSON Schema library).
4
"""
5

6
from inspect import cleandoc
7✔
7
from typing import Mapping, TypeVar
7✔
8

9
from .error_reporting import ValidationError
7✔
10

11
T = TypeVar("T", bound=Mapping)
7✔
12

13

14
class RedefiningStaticFieldAsDynamic(ValidationError):
7✔
15
    _DESC = """According to PEP 621:
7✔
16

17
    Build back-ends MUST raise an error if the metadata specifies a field
18
    statically as well as being listed in dynamic.
19
    """
20
    __doc__ = _DESC
7✔
21
    _URL = (
7✔
22
        "https://packaging.python.org/en/latest/specifications/"
23
        "pyproject-toml/#dynamic"
24
    )
25

26

27
class IncludedDependencyGroupMustExist(ValidationError):
7✔
28
    _DESC = """An included dependency group must exist and must not be cyclic.
7✔
29
    """
30
    __doc__ = _DESC
7✔
31
    _URL = "https://peps.python.org/pep-0735/"
7✔
32

33

34
def validate_project_dynamic(pyproject: T) -> T:
7✔
35
    project_table = pyproject.get("project", {})
7✔
36
    dynamic = project_table.get("dynamic", [])
7✔
37

38
    for field in dynamic:
7✔
39
        if field in project_table:
7✔
40
            raise RedefiningStaticFieldAsDynamic(
7✔
41
                message=f"You cannot provide a value for `project.{field}` and "
42
                "list it under `project.dynamic` at the same time",
43
                value={
44
                    field: project_table[field],
45
                    "...": " # ...",
46
                    "dynamic": dynamic,
47
                },
48
                name=f"data.project.{field}",
49
                definition={
50
                    "description": cleandoc(RedefiningStaticFieldAsDynamic._DESC),
51
                    "see": RedefiningStaticFieldAsDynamic._URL,
52
                },
53
                rule="PEP 621",
54
            )
55

56
    return pyproject
7✔
57

58

59
def validate_include_depenency(pyproject: T) -> T:
7✔
60
    dependency_groups = pyproject.get("dependency-groups", {})
7✔
61
    for key, value in dependency_groups.items():
7✔
62
        for each in value:
7✔
63
            if (
7!
64
                isinstance(each, dict)
65
                and (include_group := each.get("include-group"))
66
                and include_group not in dependency_groups
67
            ):
68
                raise IncludedDependencyGroupMustExist(
×
69
                    message=f"The included dependency group {include_group} doesn't exist",
70
                    value=each,
71
                    name=f"data.dependency_groups.{key}",
72
                    definition={
73
                        "description": cleandoc(IncludedDependencyGroupMustExist._DESC),
74
                        "see": IncludedDependencyGroupMustExist._URL,
75
                    },
76
                    rule="PEP 735",
77
                )
78
    # TODO: check for `include-group` cycles (can be conditional to graphlib)
79
    return pyproject
7✔
80

81

82
EXTRA_VALIDATIONS = (validate_project_dynamic, validate_include_depenency)
7✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc