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

pantsbuild / pants / 25443604553

06 May 2026 03:05PM UTC coverage: 92.879% (-0.04%) from 92.915%
25443604553

push

github

web-flow
[pants_ng] Scaffolding for a pants_ng mode. (#23319)

In this mode the command line is parsed as an
NG invocation, and dispatched appropriately.

Of course at the moment there are no
implementations to dispatch to. That will follow.

This does expose a new option, `pants_ng` to users. 
There is a big warning not to set it, but we're not trying
to hide that we're working on a new thing, so I am
comfortable with this.

25 of 76 new or added lines in 9 files covered. (32.89%)

1294 existing lines in 76 files now uncovered.

92234 of 99306 relevant lines covered (92.88%)

4.05 hits per line

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

93.88
/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
12✔
4

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

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

10

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

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

17

18
@dataclass(frozen=True, order=True)
12✔
19
class Coordinate:
12✔
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("([^: ]+):([^: ]+)(:([^: ]*)(:([^: ]+))?)?:([^: ]+)")
12✔
30

31
    group: str
12✔
32
    artifact: str
12✔
33
    version: str
12✔
34
    packaging: str = "jar"
12✔
35
    classifier: str | None = None
12✔
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
12✔
40

41
    @staticmethod
12✔
42
    def from_json_dict(data: dict) -> Coordinate:
12✔
43
        return Coordinate(
12✔
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:
12✔
UNCOV
52
        ret = {
1✔
53
            "group": self.group,
54
            "artifact": self.artifact,
55
            "version": self.version,
56
            "packaging": self.packaging,
57
            "classifier": self.classifier,
58
        }
UNCOV
59
        return ret
1✔
60

61
    @classmethod
12✔
62
    def from_coord_str(cls, s: str) -> Coordinate:
12✔
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)
12✔
76
        if parts is not None:
12✔
77
            packaging_part = parts.group(4)
12✔
78
            return cls(
12✔
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:
12✔
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}"
12✔
94
        if self.classifier is not None:
12✔
95
            unversioned += f":{self.packaging}:{self.classifier}"
3✔
96
        elif self.packaging != "jar":
12✔
97
            unversioned += f":{self.packaging}"
×
98

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

104
    def to_coord_arg_str(self, extra_attrs: dict[str, str] | None = None) -> str:
12✔
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 {})
12✔
112
        if self.packaging != "jar":
12✔
113
            # NB: Coursier refers to `packaging` as `type` internally.
114
            attrs["type"] = self.packaging
2✔
115
        if self.classifier:
12✔
116
            attrs["classifier"] = self.classifier
3✔
117
        attrs_sep_str = "," if attrs else ""
12✔
118
        attrs_str = ",".join((f"{k}={v}" for k, v in attrs.items()))
12✔
119
        return f"{self.group}:{self.artifact}:{self.version}{attrs_sep_str}{attrs_str}"
12✔
120

121

122
class Coordinates(DeduplicatedCollection[Coordinate]):
12✔
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