• 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

72.0
/src/python/pants/backend/project_info/count_loc_test.py
1
# Copyright 2019 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3

4
import pytest
1✔
5

6
from pants.backend.project_info import count_loc
1✔
7
from pants.backend.project_info.count_loc import CountLinesOfCode
1✔
8
from pants.backend.python import target_types_rules
1✔
9
from pants.backend.python.target_types import PythonSourcesGeneratorTarget
1✔
10
from pants.core.util_rules import external_tool
1✔
11
from pants.engine.target import MultipleSourcesField, Target
1✔
12
from pants.testutil.rule_runner import GoalRuleResult, RuleRunner
1✔
13

14

15
class ElixirSources(MultipleSourcesField):
1✔
16
    default = ("*.ex",)
1✔
17

18

19
class ElixirTarget(Target):
1✔
20
    alias = "elixir"
1✔
21
    core_fields = (ElixirSources,)
1✔
22

23

24
@pytest.fixture
1✔
25
def rule_runner() -> RuleRunner:
1✔
26
    return RuleRunner(
1✔
27
        rules=[
28
            *count_loc.rules(),
29
            *external_tool.rules(),
30
            *target_types_rules.rules(),
31
        ],
32
        target_types=[PythonSourcesGeneratorTarget, ElixirTarget],
33
    )
34

35

36
def assert_counts(
1✔
37
    stdout: str, lang: str, *, num_files: int = 1, blank: int = 0, comment: int = 0, code: int = 0
38
) -> None:
39
    summary_line = next(
1✔
40
        (
41
            line
42
            for line in stdout.splitlines()
43
            if len(line.split()) in (6, 7) and line.split()[0] == lang
44
        ),
45
        None,
46
    )
47
    assert summary_line is not None, f"Found no output line for {lang} given stdout:\n {stdout}"
1✔
48
    fields = summary_line.split()
1✔
49
    assert num_files == int(fields[1])
1✔
50
    assert blank == int(fields[3])
1✔
51
    assert comment == int(fields[4])
1✔
52
    assert code == int(fields[5])
1✔
53

54

55
@pytest.mark.platform_specific_behavior
1✔
56
def test_count_loc(rule_runner: RuleRunner) -> None:
1✔
57
    py_dir = "src/py/foo"
1✔
58
    elixir_dir = "src/elixir/foo"
1✔
59
    rule_runner.write_files(
1✔
60
        {
61
            f"{py_dir}/foo.py": '# A comment.\n\nprint("some code")\n# Another comment.',
62
            f"{py_dir}/bar.py": '# A comment.\n\nprint("some more code")',
63
            f"{py_dir}/BUILD": "python_sources(name='lib')",
64
            f"{elixir_dir}/foo.ex": 'IO.puts("Some elixir")\n# A comment',
65
            f"{elixir_dir}/ignored.ex": "# We do not expect this file to appear in counts.",
66
            f"{elixir_dir}/BUILD": "elixir(name='lib', sources=['foo.ex'])",
67
        }
68
    )
69
    result = rule_runner.run_goal_rule(
1✔
70
        CountLinesOfCode, args=[f"{py_dir}:lib", f"{elixir_dir}:lib"]
71
    )
72
    assert result.exit_code == 0
1✔
73
    assert_counts(result.stdout, "Python", num_files=2, blank=2, comment=3, code=2)
1✔
74
    assert_counts(result.stdout, "Elixir", comment=1, code=1)
1✔
75

76

77
def test_passthrough_args(rule_runner: RuleRunner) -> None:
1✔
UNCOV
78
    rule_runner.write_files(
×
79
        {"foo.py": "print('hello world!')\n", "BUILD": "python_sources(name='foo')"}
80
    )
UNCOV
81
    result = rule_runner.run_goal_rule(CountLinesOfCode, args=["//:foo", "--", "--no-cocomo"])
×
UNCOV
82
    assert result.exit_code == 0
×
UNCOV
83
    assert_counts(result.stdout, "Python", code=1)
×
UNCOV
84
    assert "Estimated Cost to Develop" not in result.stdout
×
85

86

87
def test_files_without_owners(rule_runner: RuleRunner) -> None:
1✔
88
    """cloc works on any readable file in the build root, regardless of whether it's declared in a
89
    BUILD file."""
UNCOV
90
    rule_runner.write_files(
×
91
        {
92
            "test/foo.ex": 'IO.puts("im a free thinker!")',
93
            "test/foo.hs": 'main = putStrLn "Whats Pants, precious?"',
94
        }
95
    )
UNCOV
96
    result = rule_runner.run_goal_rule(CountLinesOfCode, args=["test/foo.*"])
×
UNCOV
97
    assert result.exit_code == 0
×
UNCOV
98
    assert_counts(result.stdout, "Elixir", code=1)
×
UNCOV
99
    assert_counts(result.stdout, "Haskell", code=1)
×
100

101

102
def test_no_sources_exits_gracefully(rule_runner: RuleRunner) -> None:
1✔
UNCOV
103
    py_dir = "src/py/foo"
×
UNCOV
104
    rule_runner.write_files({f"{py_dir}/BUILD": "python_sources(name='lib')"})
×
UNCOV
105
    result = rule_runner.run_goal_rule(CountLinesOfCode, args=[f"{py_dir}:lib"])
×
UNCOV
106
    assert result == GoalRuleResult.noop()
×
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