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

oir / startle / 21696400393

05 Feb 2026 02:27AM UTC coverage: 98.682% (+0.006%) from 98.676%
21696400393

Pull #134

github

web-flow
Merge 12cee47e8 into a5d20b7fa
Pull Request #134: Untitled refactor PR

250 of 250 branches covered (100.0%)

Branch coverage included in aggregate %.

1247 of 1267 relevant lines covered (98.42%)

0.98 hits per line

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

98.59
startle/_value_parser.py
1
"""
2
String-to-type conversion functions.
3
"""
4

5
import typing
1✔
6
from collections.abc import Callable
1✔
7
from enum import Enum
1✔
8
from inspect import isclass
1✔
9
from pathlib import Path
1✔
10
from typing import Any, Literal, cast
1✔
11

12
from ._type_utils import strip_optional
1✔
13
from .error import UnsupportedValueTypeError, ValueParsingError
1✔
14

15

16
def _to_str(value: str) -> str:
1✔
17
    return value
1✔
18

19

20
def _to_int(value: str) -> int:
1✔
21
    try:
1✔
22
        return int(value)
1✔
23
    except ValueError as err:
1✔
24
        raise ValueParsingError(value, "integer") from err
1✔
25

26

27
def _to_float(value: str) -> float:
1✔
28
    try:
1✔
29
        return float(value)
1✔
30
    except ValueError as err:
1✔
31
        raise ValueParsingError(value, "float") from err
1✔
32

33

34
def _to_bool(value: str) -> bool:
1✔
35
    if value.lower() in {"true", "t", "yes", "y", "1"}:
1✔
36
        return True
1✔
37
    if value.lower() in {"false", "f", "no", "n", "0"}:
1✔
38
        return False
1✔
39
    raise ValueParsingError(value, "boolean")
1✔
40

41

42
def _to_path(value: str) -> Path:
1✔
43
    return Path(value)  # can this raise?
1✔
44

45

46
def _to_enum(value: str, enum_type: type) -> Enum:
1✔
47
    try:
1✔
48
        # for StringEnum and (str, Enum) types, use enum value
49
        # otherwise use the name of the member
50
        member_type: type = getattr(enum_type, "_member_type_", object)
1✔
51
        if member_type is str or (member_type is object and issubclass(enum_type, str)):
1✔
52
            return cast(Enum, enum_type(value))
1✔
53
        try:
1✔
54
            enum_type_ = cast(type[Enum], enum_type)
1✔
55
            return enum_type_[value.upper().replace("-", "_")]
1✔
56
        except KeyError as err:
1✔
57
            raise ValueParsingError(value, f"enum {enum_type.__name__}") from err
1✔
58
    except ValueError as err:
1✔
59
        raise ValueParsingError(value, f"enum {enum_type.__name__}") from err
1✔
60

61

62
PARSERS: dict[Any, Callable[[str], Any]] = {
1✔
63
    str: _to_str,
64
    Any: _to_str,
65
    int: _to_int,
66
    float: _to_float,
67
    bool: _to_bool,
68
    Path: _to_path,
69
}
70

71

72
def _get_parser(type_: Any) -> Callable[[str], Any] | None:
1✔
73
    """
74
    Get the parser function for a given type.
75
    """
76

77
    # if type is Optional[T], convert to T
78
    type_ = strip_optional(type_)
1✔
79

80
    if typing.get_origin(type_) is Literal:
1✔
81
        type_args = typing.get_args(type_)
1✔
82
        if all(isinstance(arg, str) for arg in type_args):
1✔
83

84
            def parser(value: str) -> str:
1✔
85
                if value in type_args:
1✔
86
                    return value
1✔
87
                raise ValueParsingError(value, f"literal {type_args}")
1✔
88

89
            return parser
1✔
90

91
    # check if type_ is an Enum
92
    if isclass(type_) and issubclass(type_, Enum):
1✔
93
        return lambda value: _to_enum(value, type_)
1✔
94

95
    if fp := PARSERS.get(type_):
1✔
96
        return fp
1✔
97

98
    return None
1✔
99

100

101
def parse(value: str, type_: Any) -> Any:
1✔
102
    """
103
    Parse or convert a string value to a given type.
104
    """
105
    if parser := _get_parser(type_):
1✔
106
        return parser(value)
1✔
107

108
    # otherwise it is unsupported
109
    raise UnsupportedValueTypeError(f"{type_.__module__}.{type_.__qualname__}")
×
110

111

112
def is_parsable(type_: Any) -> bool:
1✔
113
    """
114
    Check if a type is parsable (supported).
115
    """
116
    return _get_parser(type_) is not None
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

© 2026 Coveralls, Inc