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

pantsbuild / pants / 18812500213

26 Oct 2025 03:42AM UTC coverage: 80.284% (+0.005%) from 80.279%
18812500213

Pull #22804

github

web-flow
Merge 2a56fdb46 into 4834308dc
Pull Request #22804: test_shell_command: use correct default cache scope for a test's environment

29 of 31 new or added lines in 2 files covered. (93.55%)

1314 existing lines in 64 files now uncovered.

77900 of 97030 relevant lines covered (80.28%)

3.35 hits per line

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

76.67
/src/python/pants/util/eval.py
1
# Copyright 2015 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3

4
from __future__ import annotations
12✔
5

6
from typing import Any
12✔
7

8
from pants.util.strutil import softwrap
12✔
9

10

11
def parse_expression(
12✔
12
    val: str, acceptable_types: type | tuple[type, ...], name: str | None = None
13
) -> Any:
14
    """Attempts to parse the given `val` as a python expression of the specified `acceptable_types`.
15

16
    :param val: A string containing a python expression.
17
    :param acceptable_types: The acceptable types of the parsed object.
18
    :param name: An optional logical name for the value being parsed; ie if the literal val
19
                        represents a person's age, 'age'.
20
    :raises: If `val` is not a valid python literal expression or it is but evaluates to an object
21
             that is not a an instance of one of the `acceptable_types`.
22
    """
23

24
    def format_type(typ):
3✔
UNCOV
25
        return typ.__name__
1✔
26

27
    if not isinstance(val, str):
3✔
28
        raise ValueError(
×
29
            f"The raw `val` is not a str.  Given {val} of type {format_type(type(val))}."
30
        )
31

32
    def get_name():
3✔
UNCOV
33
        return repr(name) if name else "value"
1✔
34

35
    def format_raw_value():
3✔
UNCOV
36
        lines = val.splitlines()
1✔
UNCOV
37
        for line_number in range(0, len(lines)):
1✔
UNCOV
38
            lines[line_number] = "{line_number:{width}}: {line}".format(
1✔
39
                line_number=line_number + 1, line=lines[line_number], width=len(str(len(lines)))
40
            )
UNCOV
41
        return "\n".join(lines)
1✔
42

43
    try:
3✔
44
        parsed_value = eval(val)
3✔
45
    except Exception as e:
×
46
        raise ValueError(
×
47
            softwrap(
48
                f"""
49
                The {get_name()} cannot be evaluated as a literal expression: {e!r}
50
                Given raw value:
51
                  {format_raw_value()}
52
                """
53
            )
54
        )
55

56
    if not isinstance(parsed_value, acceptable_types):
3✔
57

UNCOV
58
        def iter_types(types):
1✔
UNCOV
59
            if isinstance(types, type):
1✔
UNCOV
60
                yield types
1✔
61
            elif isinstance(types, tuple):
×
62
                for item in types:
×
63
                    yield from iter_types(item)
×
64
            else:
65
                raise ValueError(
×
66
                    f"The given acceptable_types is not a valid type (tuple): {acceptable_types}"
67
                )
68

UNCOV
69
        expected_types = ", ".join(format_type(t) for t in iter_types(acceptable_types))
1✔
UNCOV
70
        raise ValueError(
1✔
71
            softwrap(
72
                f"""
73
                The {get_name()} is not of the expected type(s): {expected_types}:
74
                Given the following raw value that evaluated to type {format_type(type(parsed_value))}:
75
                  {format_raw_value()}
76
                """
77
            )
78
        )
79
    return parsed_value
3✔
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