extended-data-types 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- extended_data_types/__init__.py +90 -0
- extended_data_types/base64_utils.py +53 -0
- extended_data_types/export_utils.py +98 -0
- extended_data_types/hcl2_utils.py +52 -0
- extended_data_types/import_utils.py +26 -0
- extended_data_types/json_utils.py +35 -0
- extended_data_types/list_data_type.py +78 -0
- extended_data_types/map_data_type.py +226 -0
- extended_data_types/matcher_utils.py +68 -0
- extended_data_types/py.typed +0 -0
- extended_data_types/splitter_utils.py +54 -0
- extended_data_types/stack_utils.py +87 -0
- extended_data_types/state_utils.py +169 -0
- extended_data_types/string_data_type.py +161 -0
- extended_data_types/type_utils.py +67 -0
- extended_data_types/yaml_utils/__init__.py +31 -0
- extended_data_types/yaml_utils/constructors.py +58 -0
- extended_data_types/yaml_utils/dumpers.py +69 -0
- extended_data_types/yaml_utils/loaders.py +28 -0
- extended_data_types/yaml_utils/representers.py +65 -0
- extended_data_types/yaml_utils/tag_classes.py +53 -0
- extended_data_types/yaml_utils/utils.py +61 -0
- extended_data_types-1.0.0.dist-info/METADATA +123 -0
- extended_data_types-1.0.0.dist-info/RECORD +26 -0
- extended_data_types-1.0.0.dist-info/WHEEL +4 -0
- extended_data_types-1.0.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""This module provides utilities for string and value matching.
|
|
2
|
+
|
|
3
|
+
It includes functions to partially match strings and to compare non-empty values
|
|
4
|
+
for equality, handling different data types including strings, mappings, and lists.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Any, Mapping
|
|
10
|
+
|
|
11
|
+
from .json_utils import encode_json
|
|
12
|
+
from .state_utils import is_nothing
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def is_partial_match(
|
|
16
|
+
a: str | None,
|
|
17
|
+
b: str | None,
|
|
18
|
+
check_prefix_only: bool = False,
|
|
19
|
+
) -> bool:
|
|
20
|
+
"""Checks if two strings partially match.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
a (str | None): The first string.
|
|
24
|
+
b (str | None): The second string.
|
|
25
|
+
check_prefix_only (bool): Whether to check only the prefix.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
bool: True if there is a partial match, False otherwise.
|
|
29
|
+
"""
|
|
30
|
+
if is_nothing(a) or is_nothing(b):
|
|
31
|
+
return False
|
|
32
|
+
|
|
33
|
+
a = a.casefold() if a is not None else ""
|
|
34
|
+
b = b.casefold() if b is not None else ""
|
|
35
|
+
|
|
36
|
+
if check_prefix_only:
|
|
37
|
+
return a.startswith(b) or b.startswith(a)
|
|
38
|
+
|
|
39
|
+
return a in b or b in a
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def is_non_empty_match(a: Any, b: Any) -> bool:
|
|
43
|
+
"""Checks if two non-empty values match.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
a (Any): The first value.
|
|
47
|
+
b (Any): The second value.
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
bool: True if the values match, False otherwise.
|
|
51
|
+
"""
|
|
52
|
+
if is_nothing(a) or is_nothing(b):
|
|
53
|
+
return False
|
|
54
|
+
|
|
55
|
+
if not isinstance(a, type(b)):
|
|
56
|
+
return False
|
|
57
|
+
|
|
58
|
+
if isinstance(a, str):
|
|
59
|
+
a = a.casefold()
|
|
60
|
+
b = b.casefold()
|
|
61
|
+
elif isinstance(a, Mapping):
|
|
62
|
+
a = encode_json(a, sort_keys=True)
|
|
63
|
+
b = encode_json(b, sort_keys=True)
|
|
64
|
+
elif isinstance(a, list):
|
|
65
|
+
a.sort()
|
|
66
|
+
b.sort()
|
|
67
|
+
|
|
68
|
+
return bool(a == b)
|
|
File without changes
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""This module contains utility functions for splitting lists and dictionaries by the type of their items.
|
|
2
|
+
|
|
3
|
+
It includes functions `split_list_by_type` and `split_dict_by_type` which categorize elements
|
|
4
|
+
based on their type and return defaultdict of type list or dict respectively.
|
|
5
|
+
|
|
6
|
+
Functions:
|
|
7
|
+
- split_list_by_type: Splits a list by the type of its items.
|
|
8
|
+
- split_dict_by_type: Splits a dictionary by the type of its values.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from collections import defaultdict
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
from .type_utils import typeof
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def split_list_by_type(
|
|
20
|
+
input_list: list[Any], primitive_only: bool = False
|
|
21
|
+
) -> defaultdict[type, list[Any]]:
|
|
22
|
+
"""Split a list by the type of its items, with an option to categorize by primitive types only.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
input_list (List[Any]): The list to split.
|
|
26
|
+
primitive_only (bool): If True, categorize items based on primitive types (int, float, str, etc.)
|
|
27
|
+
rather than their exact type.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
DefaultDict[type, List[Any]]: A defaultdict storing lists of elements categorized by their type.
|
|
31
|
+
"""
|
|
32
|
+
result: defaultdict[type, list[Any]] = defaultdict(list)
|
|
33
|
+
for item in input_list:
|
|
34
|
+
result[typeof(item, primitive_only=primitive_only)].append(item)
|
|
35
|
+
return result
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def split_dict_by_type(
|
|
39
|
+
input_dict: dict[Any, Any], primitive_only: bool = False
|
|
40
|
+
) -> defaultdict[type, dict[Any, Any]]:
|
|
41
|
+
"""Split a dictionary by the type of its values, with an option to categorize by primitive types only.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
input_dict (Dict[Any, Any]): The dictionary to split.
|
|
45
|
+
primitive_only (bool): If True, categorize values based on primitive types (int, float, str, etc.)
|
|
46
|
+
rather than their exact type.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
DefaultDict[type, Dict[Any, Any]]: A defaultdict storing dictionaries of elements categorized by their type.
|
|
50
|
+
"""
|
|
51
|
+
result: defaultdict[type, dict[Any, Any]] = defaultdict(dict)
|
|
52
|
+
for key, value in input_dict.items():
|
|
53
|
+
result[typeof(value, primitive_only=primitive_only)][key] = value
|
|
54
|
+
return result
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""This module provides utilities for inspecting the call stack and methods of classes.
|
|
2
|
+
|
|
3
|
+
It includes functions to get the caller's name, filter methods, and retrieve available
|
|
4
|
+
methods and their docstrings for a class.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
from inspect import getmembers, ismethod
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def get_caller() -> str:
|
|
16
|
+
"""Gets the name of the caller function.
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
str: The name of the caller function.
|
|
20
|
+
"""
|
|
21
|
+
return sys._getframe(2).f_code.co_name # noqa: SLF001
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def get_unique_signature(obj: Any, delim: str = "/") -> str:
|
|
25
|
+
"""Generate a unique signature for an object based on its class and module.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
obj (Any): The object to generate a signature for.
|
|
29
|
+
delim (str): The delimiter to use between the module and class names. Defaults to "/".
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
str: A unique signature string for the object.
|
|
33
|
+
"""
|
|
34
|
+
return str(obj.__class__.__module__) + delim + str(obj.__class__.__name__)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def filter_methods(methods: list[str]) -> list[str]:
|
|
38
|
+
"""Filters out private methods from a list of method names.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
methods (list[str]): The list of method names to filter.
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
list[str]: The filtered list of method names.
|
|
45
|
+
"""
|
|
46
|
+
return [method for method in methods if not method.startswith("_")]
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def get_available_methods(cls: type[Any]) -> dict[str, str | None]:
|
|
50
|
+
"""Gets available methods and their docstrings for a class.
|
|
51
|
+
|
|
52
|
+
An "available method" is a public method that:
|
|
53
|
+
- Does not contain '__' in its name.
|
|
54
|
+
- Belongs to the same module as the class.
|
|
55
|
+
- Does not have 'NOPARSE' in its docstring.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
cls (type[Any]): The class to inspect.
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
dict[str, str | None]: A dictionary of method names and their docstrings.
|
|
62
|
+
"""
|
|
63
|
+
module_name = cls.__class__.__module__
|
|
64
|
+
methods = getmembers(cls, ismethod)
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
method_name: method_signature.__doc__
|
|
68
|
+
for method_name, method_signature in methods
|
|
69
|
+
if "__" not in method_name
|
|
70
|
+
and method_signature.__self__.__class__.__module__ == module_name
|
|
71
|
+
and "NOPARSE" not in (method_signature.__doc__ or "")
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def current_python_version_is_at_least(minor: int, major: int = 3) -> bool:
|
|
76
|
+
"""Checks if the current Python version is at least the specified version.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
minor (int): The minimum minor version.
|
|
80
|
+
major (int, optional): The minimum major version. Defaults to 3.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
bool: True if the current Python version is at least the specified version, False otherwise.
|
|
84
|
+
"""
|
|
85
|
+
return (sys.version_info.major > major) or (
|
|
86
|
+
sys.version_info.major == major and sys.version_info.minor >= minor
|
|
87
|
+
)
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"""The `state_utils` module provides utility functions for handling and evaluating data structure "emptiness".
|
|
2
|
+
|
|
3
|
+
It includes functions to determine whether a value is considered "nothing", to extract
|
|
4
|
+
non-empty values, and to assess the state of provided arguments and keyword arguments.
|
|
5
|
+
|
|
6
|
+
Functions:
|
|
7
|
+
- is_nothing: Determines if a value is considered "nothing" (e.g., None, empty string, empty list, empty dict).
|
|
8
|
+
- are_nothing: Checks if all provided values (both positional and keyword arguments) are "nothing".
|
|
9
|
+
- all_non_empty: Returns all non-empty values from provided arguments and keyword arguments.
|
|
10
|
+
- all_non_empty_in_list: Returns a list of non-empty values from the provided list.
|
|
11
|
+
- all_non_empty_in_dict: Returns a dictionary of non-empty values from the provided dictionary.
|
|
12
|
+
- first_non_empty: Retrieves the first non-empty value from a set of provided values.
|
|
13
|
+
- any_non_empty: Retrieves the first non-empty value from a mapping for a given set of keys.
|
|
14
|
+
- yield_non_empty: Yields non-empty values from a mapping for a given set of keys.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from typing import Any, Generator
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def is_nothing(v: Any) -> bool:
|
|
23
|
+
"""Checks if a value is considered 'nothing'.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
v (Any): The value to check.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
bool: True if the value is considered 'nothing', False otherwise.
|
|
30
|
+
"""
|
|
31
|
+
if v in [None, "", {}, []]:
|
|
32
|
+
return True
|
|
33
|
+
|
|
34
|
+
if str(v) == "" or str(v).isspace():
|
|
35
|
+
return True
|
|
36
|
+
|
|
37
|
+
if isinstance(v, (list, set)):
|
|
38
|
+
v = [vv for vv in v if vv not in [None, "", {}, []]]
|
|
39
|
+
if len(v) == 0:
|
|
40
|
+
return True
|
|
41
|
+
|
|
42
|
+
return False
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def are_nothing(*args: Any, **kwargs: Any) -> bool:
|
|
46
|
+
"""Checks if all provided values (both args and kwargs) are considered 'nothing'.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
args (Any): Positional arguments to check.
|
|
50
|
+
kwargs (Any): Keyword arguments to check.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
bool: True if all values are considered 'nothing', False otherwise.
|
|
54
|
+
"""
|
|
55
|
+
non_empty = all_non_empty(*args, **kwargs)
|
|
56
|
+
|
|
57
|
+
if non_empty is None:
|
|
58
|
+
return True
|
|
59
|
+
|
|
60
|
+
if isinstance(non_empty, (list, dict)):
|
|
61
|
+
return len(non_empty) == 0
|
|
62
|
+
|
|
63
|
+
if isinstance(non_empty, tuple):
|
|
64
|
+
list_part, dict_part = non_empty
|
|
65
|
+
return len(list_part) == 0 and len(dict_part) == 0
|
|
66
|
+
|
|
67
|
+
return False
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def all_non_empty(
|
|
71
|
+
*args: Any, **kwargs: Any
|
|
72
|
+
) -> list[Any] | dict[str, Any] | tuple[list[Any], dict[str, Any]] | None:
|
|
73
|
+
"""Returns all non-empty values from the provided args and kwargs.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
args (Any): Positional arguments to check.
|
|
77
|
+
kwargs (Any): Keyword arguments to check.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
Union[List[Any], Dict[str, Any], Tuple[List[Any], Dict[str, Any]], None]:
|
|
81
|
+
A list, dict, tuple of list
|
|
82
|
+
"""
|
|
83
|
+
if len(args) == 0 and len(kwargs) == 0:
|
|
84
|
+
return None
|
|
85
|
+
|
|
86
|
+
if len(args) == 0:
|
|
87
|
+
return all_non_empty_in_dict(dict(kwargs))
|
|
88
|
+
|
|
89
|
+
results = all_non_empty_in_list(list(args))
|
|
90
|
+
if len(kwargs) == 0:
|
|
91
|
+
return results
|
|
92
|
+
|
|
93
|
+
return results, all_non_empty_in_dict(dict(kwargs))
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def all_non_empty_in_list(input_list: list[Any]) -> list[Any]:
|
|
97
|
+
"""Returns a list of all non-empty values from the input list.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
input_list (List[Any]): A list of items to check for emptiness.
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
List: A list of non-empty values.
|
|
104
|
+
"""
|
|
105
|
+
return [item for item in input_list if not is_nothing(item)]
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def all_non_empty_in_dict(input_dict: dict[Any, Any]) -> dict[Any, Any]:
|
|
109
|
+
"""Returns a dictionary of all non-empty values from the input dictionary.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
input_dict (Dict[Any, Any]): A dictionary of items to check for emptiness.
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
Dict: A dictionary of non-empty values.
|
|
116
|
+
"""
|
|
117
|
+
return {key: value for key, value in input_dict.items() if not is_nothing(value)}
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def first_non_empty(*vals: Any) -> Any:
|
|
121
|
+
"""Returns the first non-empty value.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
vals (Any): The values to check.
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
Any: The first non-empty value, or None if all are 'nothing'.
|
|
128
|
+
"""
|
|
129
|
+
non_empty_vals = all_non_empty(*vals)
|
|
130
|
+
return (
|
|
131
|
+
non_empty_vals[0]
|
|
132
|
+
if isinstance(non_empty_vals, list) and non_empty_vals
|
|
133
|
+
else None
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def any_non_empty(m: dict[Any, Any], *keys: Any) -> dict[Any, Any]:
|
|
138
|
+
"""Returns the first non-empty value from a mapping for the given keys.
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
m (Dict): The mapping to check.
|
|
142
|
+
keys (Any): The keys to check.
|
|
143
|
+
|
|
144
|
+
Returns:
|
|
145
|
+
Dict[Any, Any]: A mapping containing the first non-empty value.
|
|
146
|
+
"""
|
|
147
|
+
for k in keys:
|
|
148
|
+
v = m.get(k)
|
|
149
|
+
if not is_nothing(v):
|
|
150
|
+
return {k: v}
|
|
151
|
+
return {}
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def yield_non_empty(
|
|
155
|
+
m: dict[Any, Any], *keys: Any
|
|
156
|
+
) -> Generator[dict[Any, Any], None, None]:
|
|
157
|
+
"""Yields non-empty values from a mapping for the given keys.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
m (Dict): The mapping to check.
|
|
161
|
+
keys (Any): The keys to check.
|
|
162
|
+
|
|
163
|
+
Yields:
|
|
164
|
+
Generator[Dict[Any, Any], None, None]: A generator yielding non-empty values.
|
|
165
|
+
"""
|
|
166
|
+
for k in keys:
|
|
167
|
+
v = m.get(k)
|
|
168
|
+
if not is_nothing(v):
|
|
169
|
+
yield {k: v}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"""This module provides utilities for string manipulation and validation.
|
|
2
|
+
|
|
3
|
+
It includes functions to sanitize keys, truncate messages, manipulate character
|
|
4
|
+
cases, validate URLs, convert camelCase to TitleCase, and convert string representations
|
|
5
|
+
of truth to boolean values.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import inflection
|
|
11
|
+
import validators
|
|
12
|
+
|
|
13
|
+
from .stack_utils import current_python_version_is_at_least
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def sanitize_key(key: str, delim: str = "_") -> str:
|
|
17
|
+
"""Sanitizes a key by replacing non-alphanumeric characters with a delimiter.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
key (str): The key to sanitize.
|
|
21
|
+
delim (str): The delimiter to replace non-alphanumeric characters with. Defaults to "_".
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
str: The sanitized key.
|
|
25
|
+
"""
|
|
26
|
+
return "".join(x if (x.isalnum() or x == delim) else delim for x in key)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def truncate(msg: str, max_length: int, ender: str = "...") -> str:
|
|
30
|
+
"""Truncates a message to a maximum length, appending an ender if truncated.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
msg (str): The message to truncate.
|
|
34
|
+
max_length (int): The maximum length of the truncated message.
|
|
35
|
+
ender (str): The string to append to the truncated message. Defaults to "...".
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
str: The truncated message.
|
|
39
|
+
"""
|
|
40
|
+
if len(msg) <= max_length:
|
|
41
|
+
return msg
|
|
42
|
+
return msg[: max_length - len(ender)] + ender
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def lower_first_char(inp: str) -> str:
|
|
46
|
+
"""Converts the first character of a string to lowercase.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
inp (str): The input string.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
str: The string with the first character in lowercase.
|
|
53
|
+
"""
|
|
54
|
+
return inp[:1].lower() + inp[1:] if inp else ""
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def upper_first_char(inp: str) -> str:
|
|
58
|
+
"""Converts the first character of a string to uppercase.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
inp (str): The input string.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
str: The string with the first character in uppercase.
|
|
65
|
+
"""
|
|
66
|
+
return inp[:1].upper() + inp[1:] if inp else ""
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def is_url(url: str) -> bool:
|
|
70
|
+
"""Checks if the given string is a valid URL.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
url (str): The string to check.
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
bool: True if the file path is a valid URL, False otherwise.
|
|
77
|
+
"""
|
|
78
|
+
return validators.url(url.strip()) is True
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def titleize_name(name: str) -> str:
|
|
82
|
+
"""Converts a camelCase name to a TitleCase name.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
name (str): The camelCase name.
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
str: The TitleCase name.
|
|
89
|
+
"""
|
|
90
|
+
return inflection.titleize(inflection.underscore(name))
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def strtobool(val: str | bool | None, raise_on_error: bool = False) -> bool | None:
|
|
94
|
+
"""Converts a string representation of truth to boolean.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
val (str | bool | None): The value to convert.
|
|
98
|
+
raise_on_error (bool): Whether to raise an error on invalid value. Defaults to False.
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
bool | None: The converted boolean value, or None if invalid and raise_on_error is False.
|
|
102
|
+
"""
|
|
103
|
+
if isinstance(val, bool) or val is None:
|
|
104
|
+
return val
|
|
105
|
+
|
|
106
|
+
if isinstance(val, str):
|
|
107
|
+
val = val.lower()
|
|
108
|
+
if val in ("y", "yes", "t", "true", "on", "1"):
|
|
109
|
+
return True
|
|
110
|
+
if val in ("n", "no", "f", "false", "off", "0"):
|
|
111
|
+
return False
|
|
112
|
+
|
|
113
|
+
if raise_on_error:
|
|
114
|
+
error_msg = f"invalid truth value {val!r}"
|
|
115
|
+
raise ValueError(error_msg)
|
|
116
|
+
|
|
117
|
+
return None
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def removeprefix(string: str, prefix: str) -> str:
|
|
121
|
+
"""Removes the specified prefix from the string if present.
|
|
122
|
+
|
|
123
|
+
For Python versions less than 3.9, the function mimics the behavior of
|
|
124
|
+
str.removeprefix.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
string (str): The string from which to remove the prefix.
|
|
128
|
+
prefix (str): The prefix to remove.
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
str: The string with the prefix removed if it was present, otherwise the original string.
|
|
132
|
+
"""
|
|
133
|
+
if current_python_version_is_at_least(9):
|
|
134
|
+
return string.removeprefix(prefix)
|
|
135
|
+
|
|
136
|
+
if prefix and string.startswith(prefix):
|
|
137
|
+
string = string[len(prefix) :]
|
|
138
|
+
|
|
139
|
+
return string
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def removesuffix(string: str, suffix: str) -> str:
|
|
143
|
+
"""Removes the specified suffix from the string if present.
|
|
144
|
+
|
|
145
|
+
For Python versions less than 3.9, the function mimics the behavior of
|
|
146
|
+
str.removesuffix.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
string (str): The string from which to remove the suffix.
|
|
150
|
+
suffix (str): The suffix to remove.
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
str: The string with the suffix removed if it was present, otherwise the original string.
|
|
154
|
+
"""
|
|
155
|
+
if current_python_version_is_at_least(9):
|
|
156
|
+
return string.removesuffix(suffix)
|
|
157
|
+
|
|
158
|
+
if suffix and string.endswith(suffix):
|
|
159
|
+
string = string[: -len(suffix)]
|
|
160
|
+
|
|
161
|
+
return string
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Type Utilities.
|
|
2
|
+
|
|
3
|
+
This module provides utility functions related to Python types, specifically for retrieving
|
|
4
|
+
default values based on the type. It includes functions for getting default values for common
|
|
5
|
+
types like lists, dictionaries, and strings, and for determining whether to return primitive
|
|
6
|
+
or exact types of a given value.
|
|
7
|
+
|
|
8
|
+
Functions:
|
|
9
|
+
- get_default_value_for_type: Returns the default value for a given type.
|
|
10
|
+
- get_primitive_type_for_instance_type: Returns the primitive type for a given value.
|
|
11
|
+
- typeof: Returns the type (or primitive type) of a given value.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from typing import Any
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def get_default_value_for_type(input_type: type) -> Any:
|
|
20
|
+
"""Returns the default value for a given type.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
input_type (type): The type to get the default value for.
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
Any: The default value for the given type.
|
|
27
|
+
"""
|
|
28
|
+
if input_type is list:
|
|
29
|
+
return []
|
|
30
|
+
if input_type is dict:
|
|
31
|
+
return {}
|
|
32
|
+
if input_type is str:
|
|
33
|
+
return ""
|
|
34
|
+
return None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def get_primitive_type_for_instance_type(value: Any) -> type:
|
|
38
|
+
"""Gets the primitive type for a given value.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
value (Any): The value to match.
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
type: The primitive type for the given value.
|
|
45
|
+
"""
|
|
46
|
+
if isinstance(value, (bool, int, float, str, bytes, bytearray)):
|
|
47
|
+
return type(value)
|
|
48
|
+
if isinstance(value, (list, tuple)):
|
|
49
|
+
return list
|
|
50
|
+
if isinstance(value, dict):
|
|
51
|
+
return dict
|
|
52
|
+
if isinstance(value, (set, frozenset)):
|
|
53
|
+
return set
|
|
54
|
+
return type(None) if value is None else object
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def typeof(item: Any, primitive_only: bool = False) -> type:
|
|
58
|
+
"""Determines either the primitive or exact type of a given value.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
item (Any): The value to determine the type of.
|
|
62
|
+
primitive_only (bool): Whether to return the primitive type.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
type: The type (or primitive type) of the value.
|
|
66
|
+
"""
|
|
67
|
+
return get_primitive_type_for_instance_type(item) if primitive_only else type(item)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""This module provides utilities for handling YAML data.
|
|
2
|
+
|
|
3
|
+
It includes custom loaders, dumpers, and utility functions for working with YAML.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .constructors import yaml_construct_pairs, yaml_construct_undefined
|
|
7
|
+
from .dumpers import PureDumper
|
|
8
|
+
from .loaders import PureLoader
|
|
9
|
+
from .representers import (
|
|
10
|
+
yaml_represent_pairs,
|
|
11
|
+
yaml_represent_tagged,
|
|
12
|
+
yaml_str_representer,
|
|
13
|
+
)
|
|
14
|
+
from .tag_classes import YamlPairs, YamlTagged
|
|
15
|
+
from .utils import decode_yaml, encode_yaml, is_yaml_data
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"YamlTagged",
|
|
20
|
+
"YamlPairs",
|
|
21
|
+
"PureLoader",
|
|
22
|
+
"PureDumper",
|
|
23
|
+
"decode_yaml",
|
|
24
|
+
"encode_yaml",
|
|
25
|
+
"is_yaml_data",
|
|
26
|
+
"yaml_construct_undefined",
|
|
27
|
+
"yaml_construct_pairs",
|
|
28
|
+
"yaml_represent_tagged",
|
|
29
|
+
"yaml_represent_pairs",
|
|
30
|
+
"yaml_str_representer",
|
|
31
|
+
]
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""This module provides constructors for custom YAML tags and types.
|
|
2
|
+
|
|
3
|
+
It includes functions to construct undefined YAML tags and YAML pairs.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from yaml import MappingNode, SafeLoader, ScalarNode, SequenceNode
|
|
11
|
+
|
|
12
|
+
from .tag_classes import YamlPairs, YamlTagged
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def yaml_construct_undefined(
|
|
16
|
+
loader: SafeLoader,
|
|
17
|
+
node: ScalarNode | SequenceNode | MappingNode,
|
|
18
|
+
) -> YamlTagged:
|
|
19
|
+
"""Construct a YAML tagged object for undefined tags.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
loader (SafeLoader): The YAML loader.
|
|
23
|
+
node (ScalarNode | SequenceNode | MappingNode): The YAML node.
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
YamlTagged: The constructed YAML tagged object.
|
|
27
|
+
"""
|
|
28
|
+
value: Any
|
|
29
|
+
if isinstance(node, ScalarNode):
|
|
30
|
+
value = loader.construct_scalar(node)
|
|
31
|
+
elif isinstance(node, SequenceNode):
|
|
32
|
+
value = loader.construct_sequence(node)
|
|
33
|
+
elif isinstance(node, MappingNode):
|
|
34
|
+
value = loader.construct_mapping(node)
|
|
35
|
+
else:
|
|
36
|
+
node_type = type(node).__name__
|
|
37
|
+
raise TypeError(f"Unexpected node type: {node_type}") # noqa: TRY003, EM102
|
|
38
|
+
return YamlTagged(node.tag, value)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def yaml_construct_pairs(
|
|
42
|
+
loader: SafeLoader,
|
|
43
|
+
node: MappingNode,
|
|
44
|
+
) -> dict[Any, Any] | YamlPairs:
|
|
45
|
+
"""Construct YAML pairs.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
loader (SafeLoader): The YAML loader.
|
|
49
|
+
node (MappingNode): The YAML mapping node.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
Union[Dict[Any, Any], YamlPairs]: The constructed YAML pairs.
|
|
53
|
+
"""
|
|
54
|
+
value: list[tuple[Any, Any]] = loader.construct_pairs(node) # type: ignore[no-untyped-call]
|
|
55
|
+
try:
|
|
56
|
+
return dict(value)
|
|
57
|
+
except TypeError:
|
|
58
|
+
return YamlPairs(value)
|