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

pantsbuild / pants / 21378504907

26 Jan 2026 11:48PM UTC coverage: 43.218% (-37.1%) from 80.269%
21378504907

Pull #23038

github

web-flow
Merge a9ec5051e into 09b8ecaa1
Pull Request #23038: remote cache logger - new plugin to help debug the remote cache

0 of 45 new or added lines in 1 file covered. (0.0%)

17212 existing lines in 540 files now uncovered.

26144 of 60493 relevant lines covered (43.22%)

0.86 hits per line

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

51.43
/src/python/pants/engine/internals/target_adaptor.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
2✔
5

6
import dataclasses
2✔
7
from dataclasses import dataclass
2✔
8
from typing import Any, final
2✔
9

10
from pants.build_graph.address import Address
2✔
11
from pants.engine.engine_aware import EngineAwareParameter
2✔
12
from pants.util.frozendict import FrozenDict
2✔
13
from pants.util.ordered_set import FrozenOrderedSet
2✔
14
from pants.vcs.hunk import TextBlock
2✔
15

16

17
@dataclass(frozen=True)
2✔
18
class SourceBlock:
2✔
19
    """Block of lines in a file.
20

21
    Lines are 1 indexed, `start` is inclusive, `end` is exclusive.
22

23
    SourceBlock is used to describe a set of source lines that are owned by a Target,
24
    thus it can't be empty, i.e. `start` must be less than `end`.
25
    """
26

27
    start: int
2✔
28
    end: int
2✔
29

30
    def __init__(self, start: int, end: int):
2✔
UNCOV
31
        object.__setattr__(self, "start", start)
×
UNCOV
32
        object.__setattr__(self, "end", end)
×
33

UNCOV
34
        self.__post_init__()
×
35

36
    def __post_init__(self):
2✔
UNCOV
37
        if self.start >= self.end:
×
38
            raise ValueError(f"{self.start=} must be less than {self.end=}")
×
39

40
    def __len__(self) -> int:
2✔
41
        return self.end - self.start
×
42

43
    def is_touched_by(self, o: TextBlock) -> bool:
2✔
44
        """Check if the TextBlock touches the SourceBlock.
45

46
        The function behaves similarly to range intersection check, but some edge cases are
47
        different. See test cases for details.
48
        """
49

UNCOV
50
        if o.count == 0:
×
UNCOV
51
            start = o.start + 1
×
UNCOV
52
            end = start
×
53
        else:
UNCOV
54
            start = o.start
×
UNCOV
55
            end = o.end
×
56

UNCOV
57
        if self.end < start:
×
UNCOV
58
            return False
×
UNCOV
59
        if end < self.start:
×
UNCOV
60
            return False
×
UNCOV
61
        return True
×
62

63
    @classmethod
2✔
64
    def from_text_block(cls, text_block: TextBlock) -> SourceBlock:
2✔
65
        """Convert (start, count) range to (start, end) range.
66

67
        Useful for unified diff conversion, see
68
        https://www.gnu.org/software/diffutils/manual/html_node/Detailed-Unified.html
69
        """
70
        return cls(start=text_block.start, end=text_block.start + text_block.count)
×
71

72

73
class SourceBlocks(FrozenOrderedSet[SourceBlock]):
2✔
74
    pass
2✔
75

76

77
@dataclass(frozen=True)
2✔
78
class TargetAdaptorRequest(EngineAwareParameter):
2✔
79
    """Lookup the TargetAdaptor for an Address."""
80

81
    address: Address
2✔
82
    description_of_origin: str = dataclasses.field(hash=False, compare=False)
2✔
83

84
    def debug_hint(self) -> str:
2✔
85
        return self.address.spec
×
86

87

88
@final
2✔
89
class TargetAdaptor:
2✔
90
    """A light-weight object to store target information before being converted into the Target
91
    API."""
92

93
    __slots__ = ("type_alias", "name", "kwargs", "description_of_origin", "origin_sources_blocks")
2✔
94

95
    def __init__(
2✔
96
        self,
97
        type_alias: str,
98
        name: str | None,
99
        __description_of_origin__: str,
100
        __origin_sources_blocks__: FrozenDict[str, SourceBlocks] = FrozenDict(),
101
        **kwargs: Any,
102
    ) -> None:
UNCOV
103
        self.type_alias = type_alias
×
UNCOV
104
        self.name = name
×
UNCOV
105
        try:
×
UNCOV
106
            self.kwargs = FrozenDict.deep_freeze(kwargs)
×
107
        except TypeError as e:
×
108
            # FrozenDict's ctor eagerly computes its hash. If some kwarg is unhashable it will
109
            # raise a TypeError, which we enhance with the description of origin.
110
            raise TypeError(f"In {__description_of_origin__}: {e}")
×
UNCOV
111
        self.description_of_origin = __description_of_origin__
×
UNCOV
112
        self.origin_sources_blocks = __origin_sources_blocks__
×
113

114
    def with_new_kwargs(self, **kwargs) -> TargetAdaptor:
2✔
UNCOV
115
        return TargetAdaptor(
×
116
            type_alias=self.type_alias,
117
            name=self.name,
118
            __description_of_origin__=self.description_of_origin,
119
            __origin_sources_blocks__=self.origin_sources_blocks,
120
            **kwargs,
121
        )
122

123
    def __repr__(self) -> str:
2✔
124
        maybe_blocks = f", {self.origin_sources_blocks}" if self.origin_sources_blocks else ""
×
125
        return f"TargetAdaptor(type_alias={self.type_alias}, name={self.name}, origin={self.description_of_origin}{maybe_blocks})"
×
126

127
    def __eq__(self, other: Any | TargetAdaptor) -> bool:
2✔
UNCOV
128
        if not isinstance(other, TargetAdaptor):
×
129
            return NotImplemented
×
UNCOV
130
        return (
×
131
            self.type_alias == other.type_alias
132
            and self.name == other.name
133
            and self.kwargs == other.kwargs
134
        )
135

136
    def __hash__(self) -> int:
2✔
UNCOV
137
        return hash((self.type_alias, self.name, self.kwargs))
×
138

139
    @property
2✔
140
    def name_explicitly_set(self) -> bool:
2✔
141
        return self.name is not None
×
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