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

pantsbuild / pants / 20332790708

18 Dec 2025 09:48AM UTC coverage: 64.992% (-15.3%) from 80.295%
20332790708

Pull #22949

github

web-flow
Merge f730a56cd into 407284c67
Pull Request #22949: Add experimental uv resolver for Python lockfiles

54 of 97 new or added lines in 5 files covered. (55.67%)

8270 existing lines in 295 files now uncovered.

48990 of 75379 relevant lines covered (64.99%)

1.81 hits per line

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

73.08
/src/python/pants/backend/scala/util_rules/versions.py
1
# Copyright 2022 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3
from __future__ import annotations
4✔
4

5
import re
4✔
6
from dataclasses import dataclass
4✔
7
from enum import Enum
4✔
8
from typing import Any
4✔
9

10
from pants.engine.rules import collect_rules, rule
4✔
11
from pants.jvm.resolve.coordinate import Coordinate
4✔
12
from pants.util.strutil import softwrap
4✔
13

14

15
class InvalidScalaVersion(ValueError):
4✔
16
    def __init__(self, scala_version: str) -> None:
4✔
17
        super().__init__(
×
18
            softwrap(
19
                f"""Value '{scala_version}' is not a valid Scala version.
20
            It should be formed of [major].[minor].[patch]"""
21
            )
22
        )
23

24

25
class ScalaCrossVersionMode(Enum):
4✔
26
    BINARY = "binary"
4✔
27
    FULL = "full"
4✔
28

29

30
_SCALA_VERSION_PATTERN = re.compile(r"^([0-9]+)\.([0-9]+)\.([0-9]+)(\-(.+))?$")
4✔
31

32

33
@dataclass(frozen=True)
4✔
34
class ScalaVersion:
4✔
35
    major: int
4✔
36
    minor: int
4✔
37
    patch: int
4✔
38
    suffix: str | None = None
4✔
39

40
    @classmethod
4✔
41
    def parse(cls, scala_version: str) -> ScalaVersion:
4✔
42
        matched = _SCALA_VERSION_PATTERN.match(scala_version)
4✔
43
        if not matched:
4✔
44
            raise InvalidScalaVersion(scala_version)
×
45

46
        return cls(
4✔
47
            major=int(matched.groups()[0]),
48
            minor=int(matched.groups()[1]),
49
            patch=int(matched.groups()[2]),
50
            suffix=matched.groups()[4] if len(matched.groups()) == 5 else None,
51
        )
52

53
    def crossversion(self, mode: ScalaCrossVersionMode) -> str:
4✔
54
        if mode == ScalaCrossVersionMode.FULL:
3✔
UNCOV
55
            return str(self)
×
56
        if self.major >= 3:
3✔
UNCOV
57
            return str(self.major)
×
58
        return f"{self.major}.{self.minor}"
3✔
59

60
    @property
4✔
61
    def binary(self) -> str:
4✔
62
        return self.crossversion(ScalaCrossVersionMode.BINARY)
3✔
63

64
    def __eq__(self, other: Any) -> bool:
4✔
UNCOV
65
        return (
×
66
            isinstance(other, ScalaVersion)
67
            and other.major == self.major
68
            and other.minor == self.minor
69
            and other.patch == self.patch
70
            and other.suffix == self.suffix
71
        )
72

73
    def __gt__(self, other: Any) -> bool:
4✔
UNCOV
74
        if isinstance(other, ScalaVersion):
×
UNCOV
75
            if self.major > other.major:
×
UNCOV
76
                return True
×
UNCOV
77
            elif (self.major == other.major) and (self.minor > other.minor):
×
UNCOV
78
                return True
×
UNCOV
79
            elif (self.major == other.major) and (self.minor == other.minor):
×
UNCOV
80
                return self.patch > other.patch
×
UNCOV
81
            return False
×
82
        return False
×
83

84
    def __str__(self) -> str:
4✔
85
        version_str = f"{self.major}.{self.minor}.{self.patch}"
3✔
86
        if self.suffix:
3✔
UNCOV
87
            version_str += f"-{self.suffix}"
×
88
        return version_str
3✔
89

90

91
@dataclass(frozen=True)
4✔
92
class ScalaArtifactsForVersionRequest:
4✔
93
    scala_version: ScalaVersion
4✔
94

95

96
@dataclass(frozen=True)
4✔
97
class ScalaArtifactsForVersionResult:
4✔
98
    compiler_coordinate: Coordinate
4✔
99
    library_coordinate: Coordinate
4✔
100
    reflect_coordinate: Coordinate | None
4✔
101
    compiler_main: str
4✔
102
    repl_main: str
4✔
103

104
    @property
4✔
105
    def all_coordinates(self) -> tuple[Coordinate, ...]:
4✔
106
        coords = [self.compiler_coordinate, self.library_coordinate]
×
107
        if self.reflect_coordinate:
×
108
            coords.append(self.reflect_coordinate)
×
109
        return tuple(coords)
×
110

111

112
def _resolve_scala_artifacts_for_version(
4✔
113
    scala_version: ScalaVersion,
114
) -> ScalaArtifactsForVersionResult:
115
    if scala_version.major == 3:
3✔
116
        return ScalaArtifactsForVersionResult(
×
117
            compiler_coordinate=Coordinate(
118
                group="org.scala-lang",
119
                artifact="scala3-compiler_3",
120
                version=str(scala_version),
121
            ),
122
            library_coordinate=Coordinate(
123
                group="org.scala-lang",
124
                artifact="scala3-library_3",
125
                version=str(scala_version),
126
            ),
127
            reflect_coordinate=None,
128
            compiler_main="dotty.tools.dotc.Main",
129
            repl_main="dotty.tools.repl.Main",
130
        )
131

132
    return ScalaArtifactsForVersionResult(
3✔
133
        compiler_coordinate=Coordinate(
134
            group="org.scala-lang",
135
            artifact="scala-compiler",
136
            version=str(scala_version),
137
        ),
138
        library_coordinate=Coordinate(
139
            group="org.scala-lang",
140
            artifact="scala-library",
141
            version=str(scala_version),
142
        ),
143
        reflect_coordinate=Coordinate(
144
            group="org.scala-lang",
145
            artifact="scala-reflect",
146
            version=str(scala_version),
147
        ),
148
        compiler_main="scala.tools.nsc.Main",
149
        repl_main="scala.tools.nsc.MainGenericRunner",
150
    )
151

152

153
@rule
4✔
154
async def resolve_scala_artifacts_for_version(
4✔
155
    request: ScalaArtifactsForVersionRequest,
156
) -> ScalaArtifactsForVersionResult:
157
    return _resolve_scala_artifacts_for_version(request.scala_version)
×
158

159

160
def rules():
4✔
161
    return collect_rules()
4✔
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