• 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

0.0
/src/python/pants/backend/terraform/hcl2_parser.py
1
# Copyright 2021 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3

UNCOV
4
import sys
×
UNCOV
5
from pathlib import PurePath
×
UNCOV
6
from typing import Set
×
7

8
#
9
# Note: This file is used as a pex entry point in the execution sandbox.
10
#
11

12

13
# PurePath does not have the Path.resolve method which resolves ".." components, thus we need to
14
# code our own version for PurePath's.
UNCOV
15
def resolve_pure_path(base: PurePath, relative_path: PurePath) -> PurePath:
×
UNCOV
16
    parts = list(base.parts)
×
UNCOV
17
    for component in relative_path.parts:
×
UNCOV
18
        if component == ".":
×
19
            pass
×
UNCOV
20
        elif component == "..":
×
UNCOV
21
            if not parts:
×
UNCOV
22
                raise ValueError(f"Relative path {relative_path} escapes from path {base}.")
×
UNCOV
23
            parts.pop()
×
24
        else:
UNCOV
25
            parts.append(component)
×
26

UNCOV
27
    return PurePath(*parts)
×
28

29

UNCOV
30
def extract_module_source_paths(path: PurePath, raw_content: bytes) -> Set[str]:
×
31
    # Import here so we can still test this file with pytest (since `hcl2` is not present in
32
    # normal Pants venv.)
33
    import hcl2  # type: ignore[import-not-found]  # pants: no-infer-dep
×
34

35
    content = raw_content.decode("utf-8")
×
36
    parsed_content = hcl2.loads(content)
×
37

38
    # Note: The `module` key is a list where each entry is a dict with a single entry where the key is the
39
    # module name and the values are a dict for that module's actual values.
40
    paths = set()
×
41
    for wrapped_module in parsed_content.get("module", []):
×
42
        values = list(wrapped_module.values())[
×
43
            0
44
        ]  # the module is the sole entry in `wrapped_module`
45
        source = values.get("source", "")
×
46

47
        # Local paths to modules must begin with "." or ".." as per
48
        # https://www.terraform.io/docs/language/modules/sources.html#local-paths.
49
        if source.startswith("./") or source.startswith("../"):
×
50
            try:
×
51
                resolved_path = resolve_pure_path(path, PurePath(source))
×
52
                paths.add(str(resolved_path))
×
53
            except ValueError:
×
54
                pass
×
55

56
    return paths
×
57

58

UNCOV
59
def main(args):
×
60
    paths = set()
×
61
    for filename in args:
×
62
        with open(filename, "rb") as f:
×
63
            content = f.read()
×
64
        paths |= extract_module_source_paths(PurePath(filename).parent, content)
×
65

66
    for path in paths:
×
67
        print(path)
×
68

69

UNCOV
70
if __name__ == "__main__":
×
71
    main(sys.argv[1:])
×
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