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

pantsbuild / pants / 18517631058

15 Oct 2025 04:18AM UTC coverage: 69.207% (-11.1%) from 80.267%
18517631058

Pull #22745

github

web-flow
Merge 642a76ca1 into 99919310e
Pull Request #22745: [windows] Add windows support in the stdio crate.

53815 of 77759 relevant lines covered (69.21%)

2.42 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
5✔
4

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

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

14

15
class InvalidScalaVersion(ValueError):
5✔
16
    def __init__(self, scala_version: str) -> None:
5✔
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):
5✔
26
    BINARY = "binary"
5✔
27
    FULL = "full"
5✔
28

29

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

32

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

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

46
        return cls(
5✔
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:
5✔
54
        if mode == ScalaCrossVersionMode.FULL:
4✔
55
            return str(self)
×
56
        if self.major >= 3:
4✔
57
            return str(self.major)
×
58
        return f"{self.major}.{self.minor}"
4✔
59

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

64
    def __eq__(self, other: Any) -> bool:
5✔
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:
5✔
74
        if isinstance(other, ScalaVersion):
×
75
            if self.major > other.major:
×
76
                return True
×
77
            elif (self.major == other.major) and (self.minor > other.minor):
×
78
                return True
×
79
            elif (self.major == other.major) and (self.minor == other.minor):
×
80
                return self.patch > other.patch
×
81
            return False
×
82
        return False
×
83

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

90

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

95

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

104
    @property
5✔
105
    def all_coordinates(self) -> tuple[Coordinate, ...]:
5✔
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(
5✔
113
    scala_version: ScalaVersion,
114
) -> ScalaArtifactsForVersionResult:
115
    if scala_version.major == 3:
4✔
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(
4✔
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
5✔
154
async def resolve_scala_artifacts_for_version(
5✔
155
    request: ScalaArtifactsForVersionRequest,
156
) -> ScalaArtifactsForVersionResult:
157
    return _resolve_scala_artifacts_for_version(request.scala_version)
×
158

159

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