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

pantsbuild / pants / 23074067894

13 Mar 2026 11:06PM UTC coverage: 64.165% (-28.8%) from 92.932%
23074067894

Pull #23171

github

web-flow
Merge 17d8ea7d8 into f07276df6
Pull Request #23171: Debug reapi test cache misses

42163 of 65710 relevant lines covered (64.17%)

0.99 hits per line

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

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

5
from collections import defaultdict
1✔
6
from collections.abc import Mapping
1✔
7

8
from pants.backend.scala.dependency_inference.scala_parser import (
1✔
9
    resolve_fallible_result_to_analysis,
10
)
11
from pants.backend.scala.target_types import ScalaSourceField
1✔
12
from pants.core.util_rules.source_files import SourceFilesRequest
1✔
13
from pants.engine.addresses import Address
1✔
14
from pants.engine.internals.selectors import concurrently
1✔
15
from pants.engine.rules import collect_rules, implicitly, rule
1✔
16
from pants.engine.target import AllTargets, Targets
1✔
17
from pants.engine.unions import UnionRule
1✔
18
from pants.jvm.dependency_inference import symbol_mapper
1✔
19
from pants.jvm.dependency_inference.artifact_mapper import (
1✔
20
    DEFAULT_SYMBOL_NAMESPACE,
21
    MutableTrieNode,
22
    SymbolNamespace,
23
)
24
from pants.jvm.dependency_inference.symbol_mapper import FirstPartyMappingRequest, SymbolMap
1✔
25
from pants.jvm.subsystems import JvmSubsystem
1✔
26
from pants.jvm.target_types import JvmResolveField
1✔
27
from pants.util.logging import LogLevel
1✔
28

29

30
# TODO: add third-party targets here? That would allow us to avoid iterating over AllTargets twice.
31
#  See `backend/python/dependency_inference/module_mapper.py` for an example.
32
class AllScalaTargets(Targets):
1✔
33
    pass
1✔
34

35

36
class FirstPartyScalaTargetsMappingRequest(FirstPartyMappingRequest):
1✔
37
    pass
1✔
38

39

40
@rule(desc="Find all Scala targets in project", level=LogLevel.DEBUG)
1✔
41
async def find_all_scala_targets(targets: AllTargets) -> AllScalaTargets:
1✔
42
    return AllScalaTargets(tgt for tgt in targets if tgt.has_field(ScalaSourceField))
1✔
43

44

45
SCALA_PACKAGE_OBJECT_NAMESPACE: SymbolNamespace = "package object"
1✔
46

47

48
def _symbol_namespace(address: Address) -> SymbolNamespace:
1✔
49
    # NB: Although it is not required that `package object`s be declared in files
50
    # named `package.scala`, it is a very common (and reasonable) convention. Additionally,
51
    # we could technically mark only symbols which were declared _inside_ a `package object`,
52
    # rather than using the filename as a heuristic like this.
53
    if address.is_file_target and address.filename.endswith("package.scala"):
1✔
54
        return SCALA_PACKAGE_OBJECT_NAMESPACE
×
55
    else:
56
        return DEFAULT_SYMBOL_NAMESPACE
1✔
57

58

59
@rule(desc="Map all first party Scala targets to their symbols", level=LogLevel.DEBUG)
1✔
60
async def map_first_party_scala_targets_to_symbols(
1✔
61
    _: FirstPartyScalaTargetsMappingRequest,
62
    scala_targets: AllScalaTargets,
63
    jvm: JvmSubsystem,
64
) -> SymbolMap:
65
    source_analysis = await concurrently(
1✔
66
        resolve_fallible_result_to_analysis(
67
            **implicitly(SourceFilesRequest([target[ScalaSourceField]]))
68
        )
69
        for target in scala_targets
70
    )
71
    address_and_analysis = zip(
1✔
72
        [(tgt.address, tgt[JvmResolveField].normalized_value(jvm)) for tgt in scala_targets],
73
        source_analysis,
74
    )
75

76
    mapping: Mapping[str, MutableTrieNode] = defaultdict(MutableTrieNode)
1✔
77
    for (address, resolve), analysis in address_and_analysis:
1✔
78
        namespace = _symbol_namespace(address)
1✔
79
        for symbol in analysis.provided_symbols:
1✔
80
            mapping[resolve].insert(
1✔
81
                symbol.name,
82
                [address],
83
                first_party=True,
84
                namespace=namespace,
85
                recursive=symbol.recursive,
86
            )
87
        for symbol in analysis.provided_symbols_encoded:
1✔
88
            mapping[resolve].insert(
1✔
89
                symbol.name,
90
                [address],
91
                first_party=True,
92
                namespace=namespace,
93
                recursive=symbol.recursive,
94
            )
95

96
    return SymbolMap((resolve, node.frozen()) for resolve, node in mapping.items())
1✔
97

98

99
def rules():
1✔
100
    return (
1✔
101
        *collect_rules(),
102
        *symbol_mapper.rules(),
103
        UnionRule(FirstPartyMappingRequest, FirstPartyScalaTargetsMappingRequest),
104
    )
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