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

pantsbuild / pants / 20632486505

01 Jan 2026 04:21AM UTC coverage: 43.231% (-37.1%) from 80.281%
20632486505

Pull #22962

github

web-flow
Merge 08d5c63b0 into f52ab6675
Pull Request #22962: Bump the gha-deps group across 1 directory with 6 updates

26122 of 60424 relevant lines covered (43.23%)

0.86 hits per line

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

46.94
/src/python/pants/jvm/resolve/coordinate.py
1
# Copyright 2023 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3
from __future__ import annotations
2✔
4

5
import re
2✔
6
from dataclasses import dataclass
2✔
7

8
from pants.engine.collection import DeduplicatedCollection
2✔
9

10

11
class InvalidCoordinateString(Exception):
2✔
12
    """The coordinate string being passed is invalid or malformed."""
13

14
    def __init__(self, coords: str) -> None:
2✔
15
        super().__init__(f"Received invalid artifact coordinates: {coords}")
×
16

17

18
@dataclass(frozen=True, order=True)
2✔
19
class Coordinate:
2✔
20
    """A single Maven-style coordinate for a JVM dependency.
21

22
    Coursier uses at least two string serializations of coordinates:
23
    1. A format that is accepted by the Coursier CLI which uses trailing attributes to specify
24
       optional fields like `packaging`/`type`, `classifier`, `url`, etc. See `to_coord_arg_str`.
25
    2. A format in the JSON report, which uses token counts to specify optional fields. We
26
       additionally use this format in our own lockfile. See `to_coord_str` and `from_coord_str`.
27
    """
28

29
    REGEX = re.compile("([^: ]+):([^: ]+)(:([^: ]*)(:([^: ]+))?)?:([^: ]+)")
2✔
30

31
    group: str
2✔
32
    artifact: str
2✔
33
    version: str
2✔
34
    packaging: str = "jar"
2✔
35
    classifier: str | None = None
2✔
36

37
    # True to enforce that the exact declared version of a coordinate is fetched, rather than
38
    # allowing dependency resolution to adjust the version when conflicts occur.
39
    strict: bool = True
2✔
40

41
    @staticmethod
2✔
42
    def from_json_dict(data: dict) -> Coordinate:
2✔
43
        return Coordinate(
×
44
            group=data["group"],
45
            artifact=data["artifact"],
46
            version=data["version"],
47
            packaging=data.get("packaging", "jar"),
48
            classifier=data.get("classifier", None),
49
        )
50

51
    def to_json_dict(self) -> dict:
2✔
52
        ret = {
×
53
            "group": self.group,
54
            "artifact": self.artifact,
55
            "version": self.version,
56
            "packaging": self.packaging,
57
            "classifier": self.classifier,
58
        }
59
        return ret
×
60

61
    @classmethod
2✔
62
    def from_coord_str(cls, s: str) -> Coordinate:
2✔
63
        """Parses from a coordinate string with optional `packaging` and `classifier` coordinates.
64

65
        See the classdoc for more information on the format.
66

67
        Using Aether's implementation as reference
68
        http://www.javased.com/index.php?source_dir=aether-core/aether-api/src/main/java/org/eclipse/aether/artifact/DefaultArtifact.java
69

70
        ${organisation}:${artifact}[:${packaging}[:${classifier}]]:${version}
71

72
        See also: `to_coord_str`.
73
        """
74

75
        parts = Coordinate.REGEX.match(s)
×
76
        if parts is not None:
×
77
            packaging_part = parts.group(4)
×
78
            return cls(
×
79
                group=parts.group(1),
80
                artifact=parts.group(2),
81
                packaging=packaging_part if packaging_part is not None else "jar",
82
                classifier=parts.group(6),
83
                version=parts.group(7),
84
            )
85
        else:
86
            raise InvalidCoordinateString(s)
×
87

88
    def to_coord_str(self, versioned: bool = True) -> str:
2✔
89
        """Renders the coordinate in Coursier's JSON-report format, which does not use attributes.
90

91
        See also: `from_coord_str`.
92
        """
93
        unversioned = f"{self.group}:{self.artifact}"
×
94
        if self.classifier is not None:
×
95
            unversioned += f":{self.packaging}:{self.classifier}"
×
96
        elif self.packaging != "jar":
×
97
            unversioned += f":{self.packaging}"
×
98

99
        version_suffix = ""
×
100
        if versioned:
×
101
            version_suffix = f":{self.version}"
×
102
        return f"{unversioned}{version_suffix}"
×
103

104
    def to_coord_arg_str(self, extra_attrs: dict[str, str] | None = None) -> str:
2✔
105
        """Renders the coordinate in Coursier's CLI input format.
106

107
        The CLI input format uses trailing key-val attributes to specify `packaging`, `url`, etc.
108

109
        See https://github.com/coursier/coursier/blob/b5d5429a909426f4465a9599d25c678189a54549/modules/coursier/shared/src/test/scala/coursier/parse/DependencyParserTests.scala#L7
110
        """
111
        attrs = dict(extra_attrs or {})
×
112
        if self.packaging != "jar":
×
113
            # NB: Coursier refers to `packaging` as `type` internally.
114
            attrs["type"] = self.packaging
×
115
        if self.classifier:
×
116
            attrs["classifier"] = self.classifier
×
117
        attrs_sep_str = "," if attrs else ""
×
118
        attrs_str = ",".join((f"{k}={v}" for k, v in attrs.items()))
×
119
        return f"{self.group}:{self.artifact}:{self.version}{attrs_sep_str}{attrs_str}"
×
120

121

122
class Coordinates(DeduplicatedCollection[Coordinate]):
2✔
123
    """An ordered list of `Coordinate`s."""
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