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

pantsbuild / pants / 18252174847

05 Oct 2025 01:36AM UTC coverage: 43.382% (-36.9%) from 80.261%
18252174847

push

github

web-flow
run tests on mac arm (#22717)

Just doing the minimal to pull forward the x86_64 pattern.

ref #20993

25776 of 59416 relevant lines covered (43.38%)

1.3 hits per line

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

45.83
/src/python/pants/backend/python/typecheck/pytype/rules_integration_test.py
1
# Copyright 2020 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3

4
from __future__ import annotations
3✔
5

6
from collections.abc import Iterable
3✔
7
from textwrap import dedent
3✔
8

9
import pytest
3✔
10

11
from pants.backend.python import target_types_rules
3✔
12
from pants.backend.python.target_types import (
3✔
13
    PythonRequirementTarget,
14
    PythonSourcesGeneratorTarget,
15
    PythonSourceTarget,
16
)
17
from pants.backend.python.typecheck.pytype.rules import (
3✔
18
    PytypeFieldSet,
19
    PytypePartition,
20
    PytypePartitions,
21
    PytypeRequest,
22
)
23
from pants.backend.python.typecheck.pytype.rules import rules as pytype_rules
3✔
24
from pants.backend.python.util_rules.interpreter_constraints import InterpreterConstraints
3✔
25
from pants.core.goals.check import CheckResult, CheckResults
3✔
26
from pants.engine.addresses import Address
3✔
27
from pants.engine.fs import EMPTY_DIGEST
3✔
28
from pants.engine.rules import QueryRule
3✔
29
from pants.engine.target import Target
3✔
30
from pants.testutil.python_rule_runner import PythonRuleRunner
3✔
31

32

33
@pytest.fixture
3✔
34
def rule_runner() -> PythonRuleRunner:
3✔
35
    return PythonRuleRunner(
3✔
36
        rules=[
37
            *pytype_rules(),
38
            *target_types_rules.rules(),
39
            QueryRule(CheckResults, (PytypeRequest,)),
40
            QueryRule(PytypePartitions, (PytypeRequest,)),
41
        ],
42
        target_types=[
43
            PythonRequirementTarget,
44
            PythonSourcesGeneratorTarget,
45
            PythonSourceTarget,
46
        ],
47
    )
48

49

50
PACKAGE = "src/py/project"
3✔
51
GOOD_FILE = dedent(
3✔
52
    """\
53
    def add(x: int, y: int) -> int:
54
        return x + y
55

56
    result = add(3, 3)
57
    """
58
)
59
BAD_FILE = dedent(
3✔
60
    """\
61
    def add(x: int, y: int) -> int:
62
        return x + y
63

64
    result = add(2.0, 3.0)
65
    """
66
)
67
# This will fail if `name-error` is enabled (default).
68
NAME_ERROR_FILE = dedent(
3✔
69
    """\
70
    print(foo)
71
    """
72
)
73

74
NAME_ERROR_PYTYPE_CONFIG = dedent(
3✔
75
    """\
76
    [tool.pytype]
77

78
    disable = [
79
        'name-error',
80
    ]
81
    """
82
)
83

84

85
def run_pytype(
3✔
86
    rule_runner: PythonRuleRunner, targets: list[Target], *, extra_args: Iterable[str] | None = None
87
) -> tuple[CheckResult, ...]:
88
    rule_runner.set_options(extra_args or (), env_inherit={"PATH", "PYENV_ROOT", "HOME"})
3✔
89
    result = rule_runner.request(
3✔
90
        CheckResults, [PytypeRequest(PytypeFieldSet.create(tgt) for tgt in targets)]
91
    )
92

93
    return result.results
3✔
94

95

96
def test_passing(rule_runner: PythonRuleRunner) -> None:
3✔
97
    rule_runner.write_files({f"{PACKAGE}/f.py": GOOD_FILE, f"{PACKAGE}/BUILD": "python_sources()"})
×
98
    tgt = rule_runner.get_target(Address(PACKAGE, relative_file_path="f.py"))
×
99
    result = run_pytype(rule_runner, [tgt])
×
100

101
    assert len(result) == 1
×
102
    assert result[0].exit_code == 0
×
103
    assert "no errors found" in result[0].stdout
×
104
    assert result[0].report == EMPTY_DIGEST
×
105

106

107
@pytest.mark.platform_specific_behavior
3✔
108
def test_failing(rule_runner: PythonRuleRunner) -> None:
3✔
109
    rule_runner.write_files({f"{PACKAGE}/f.py": BAD_FILE, f"{PACKAGE}/BUILD": "python_sources()"})
3✔
110
    tgt = rule_runner.get_target(Address(PACKAGE, relative_file_path="f.py"))
3✔
111
    result = run_pytype(rule_runner, [tgt])
3✔
112

113
    assert len(result) == 1
3✔
114
    assert result[0].exit_code == 1
3✔
115
    assert "FAILED:" in result[0].stdout
3✔
116
    assert f"{PACKAGE}/f.py:4:1" in result[0].stdout
3✔
117
    assert "[wrong-arg-types]" in result[0].stdout
3✔
118
    assert result[0].report == EMPTY_DIGEST
3✔
119

120

121
def test_multiple_targets(rule_runner: PythonRuleRunner) -> None:
3✔
122
    rule_runner.write_files(
×
123
        {
124
            f"{PACKAGE}/good.py": GOOD_FILE,
125
            f"{PACKAGE}/bad.py": BAD_FILE,
126
            f"{PACKAGE}/BUILD": "python_sources()",
127
        }
128
    )
129
    tgts = [
×
130
        rule_runner.get_target(Address(PACKAGE, relative_file_path="good.py")),
131
        rule_runner.get_target(Address(PACKAGE, relative_file_path="bad.py")),
132
    ]
133
    result = run_pytype(rule_runner, tgts)
×
134

135
    assert len(result) == 1
×
136
    assert result[0].exit_code == 1
×
137
    assert f"{PACKAGE}/good.py" not in result[0].stdout
×
138
    assert f"{PACKAGE}/bad.py:4:1" in result[0].stdout
×
139
    assert "[wrong-arg-types]" in result[0].stdout
×
140
    assert "Analyzing 2 sources" in result[0].stdout
×
141
    assert result[0].report == EMPTY_DIGEST
×
142

143

144
@pytest.mark.parametrize(
3✔
145
    "config_filename,exit_code,extra_args",
146
    (
147
        ("pytype.toml", 0, ["--pytype-config=pytype.toml"]),
148
        ("pyproject.toml", 0, None),
149
        ("noconfig", 1, None),
150
    ),
151
)
152
def test_config_file(
3✔
153
    rule_runner: PythonRuleRunner,
154
    config_filename: str,
155
    exit_code: int,
156
    extra_args: Iterable[str] | None,
157
) -> None:
158
    rule_runner.write_files(
×
159
        {
160
            f"{PACKAGE}/f.py": NAME_ERROR_FILE,
161
            f"{PACKAGE}/BUILD": "python_sources()",
162
            f"{config_filename}": NAME_ERROR_PYTYPE_CONFIG,
163
        }
164
    )
165
    tgt = rule_runner.get_target(Address(PACKAGE, relative_file_path="f.py"))
×
166
    result = run_pytype(rule_runner, [tgt], extra_args=extra_args)
×
167

168
    assert len(result) == 1
×
169
    assert result[0].exit_code == exit_code
×
170

171

172
def test_skip(rule_runner: PythonRuleRunner) -> None:
3✔
173
    rule_runner.write_files({f"{PACKAGE}/f.py": BAD_FILE, f"{PACKAGE}/BUILD": "python_sources()"})
×
174
    tgt = rule_runner.get_target(Address(PACKAGE, relative_file_path="f.py"))
×
175
    result = run_pytype(rule_runner, [tgt], extra_args=["--pytype-skip"])
×
176

177
    assert not result
×
178

179

180
def test_partition_targets(rule_runner: PythonRuleRunner) -> None:
3✔
181
    def create_folder(folder: str, resolve: str, interpreter: str) -> dict[str, str]:
×
182
        return {
×
183
            f"{folder}/dep.py": "",
184
            f"{folder}/root.py": "",
185
            f"{folder}/BUILD": dedent(
186
                f"""\
187
                python_source(
188
                    name='dep',
189
                    source='dep.py',
190
                    resolve='{resolve}',
191
                    interpreter_constraints=['=={interpreter}.*'],
192
                )
193
                python_source(
194
                    name='root',
195
                    source='root.py',
196
                    resolve='{resolve}',
197
                    interpreter_constraints=['=={interpreter}.*'],
198
                    dependencies=[':dep'],
199
                )
200
                """
201
            ),
202
        }
203

204
    files = {
×
205
        **create_folder("resolveA_py38", "a", "3.8"),
206
        **create_folder("resolveA_py39", "a", "3.9"),
207
        **create_folder("resolveB_1", "b", "3.9"),
208
        **create_folder("resolveB_2", "b", "3.9"),
209
    }
210
    rule_runner.write_files(files)
×
211
    rule_runner.set_options(
×
212
        ["--python-resolves={'a': '', 'b': ''}", "--python-enable-resolves"],
213
        env_inherit={"PATH", "PYENV_ROOT", "HOME"},
214
    )
215

216
    resolve_a_py38_dep = rule_runner.get_target(Address("resolveA_py38", target_name="dep"))
×
217
    resolve_a_py38_root = rule_runner.get_target(Address("resolveA_py38", target_name="root"))
×
218
    resolve_a_py39_dep = rule_runner.get_target(Address("resolveA_py39", target_name="dep"))
×
219
    resolve_a_py39_root = rule_runner.get_target(Address("resolveA_py39", target_name="root"))
×
220
    resolve_b_dep1 = rule_runner.get_target(Address("resolveB_1", target_name="dep"))
×
221
    resolve_b_root1 = rule_runner.get_target(Address("resolveB_1", target_name="root"))
×
222
    resolve_b_dep2 = rule_runner.get_target(Address("resolveB_2", target_name="dep"))
×
223
    resolve_b_root2 = rule_runner.get_target(Address("resolveB_2", target_name="root"))
×
224
    request = PytypeRequest(
×
225
        PytypeFieldSet.create(t)
226
        for t in (
227
            resolve_a_py38_root,
228
            resolve_a_py39_root,
229
            resolve_b_root1,
230
            resolve_b_root2,
231
        )
232
    )
233

234
    partitions = rule_runner.request(PytypePartitions, [request])
×
235
    assert len(partitions) == 3
×
236

237
    def assert_partition(
×
238
        partition: PytypePartition,
239
        roots: list[Target],
240
        deps: list[Target],
241
        interpreter: str,
242
        resolve: str,
243
    ) -> None:
244
        root_addresses = {t.address for t in roots}
×
245
        assert {fs.address for fs in partition.field_sets} == root_addresses
×
246
        assert {t.address for t in partition.root_targets.closure()} == {
×
247
            *root_addresses,
248
            *(t.address for t in deps),
249
        }
250
        ics = [f"CPython=={interpreter}.*"]
×
251
        assert partition.interpreter_constraints == InterpreterConstraints(ics)
×
252
        assert partition.description() == f"{resolve}, {ics}"
×
253

254
    assert_partition(partitions[0], [resolve_a_py38_root], [resolve_a_py38_dep], "3.8", "a")
×
255
    assert_partition(partitions[1], [resolve_a_py39_root], [resolve_a_py39_dep], "3.9", "a")
×
256
    assert_partition(
×
257
        partitions[2],
258
        [resolve_b_root1, resolve_b_root2],
259
        [resolve_b_dep1, resolve_b_dep2],
260
        "3.9",
261
        "b",
262
    )
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

© 2025 Coveralls, Inc