ialdev-core 0.1.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.
Files changed (48) hide show
  1. iad/core/__init__.py +9 -0
  2. iad/core/array.py +1961 -0
  3. iad/core/binary.py +377 -0
  4. iad/core/cache.py +903 -0
  5. iad/core/codetools.py +203 -0
  6. iad/core/datatools.py +671 -0
  7. iad/core/docs/locators.ipynb +754 -0
  8. iad/core/dotstyle.py +99 -0
  9. iad/core/env.py +271 -0
  10. iad/core/events.py +650 -0
  11. iad/core/filesproc.py +1046 -0
  12. iad/core/fnctools.py +390 -0
  13. iad/core/label.py +240 -0
  14. iad/core/logs.py +182 -0
  15. iad/core/nptools.py +449 -0
  16. iad/core/one_dark.puml +881 -0
  17. iad/core/param/__init__.py +17 -0
  18. iad/core/param/confargparse.py +55 -0
  19. iad/core/param/paramaze.py +339 -0
  20. iad/core/param/tbox.py +277 -0
  21. iad/core/paths.py +563 -0
  22. iad/core/pdtools.py +2570 -0
  23. iad/core/pydantools/__init__.py +5 -0
  24. iad/core/pydantools/fixed_pydantic_yaml/__init__.py +32 -0
  25. iad/core/pydantools/fixed_pydantic_yaml/compat/__init__.py +0 -0
  26. iad/core/pydantools/fixed_pydantic_yaml/compat/hacks.py +76 -0
  27. iad/core/pydantools/fixed_pydantic_yaml/compat/old_enums.py +37 -0
  28. iad/core/pydantools/fixed_pydantic_yaml/compat/representers.py +92 -0
  29. iad/core/pydantools/fixed_pydantic_yaml/compat/types.py +122 -0
  30. iad/core/pydantools/fixed_pydantic_yaml/compat/yaml_lib.py +104 -0
  31. iad/core/pydantools/fixed_pydantic_yaml/ext/__init__.py +1 -0
  32. iad/core/pydantools/fixed_pydantic_yaml/ext/semver.py +152 -0
  33. iad/core/pydantools/fixed_pydantic_yaml/ext/versioned_model.py +113 -0
  34. iad/core/pydantools/fixed_pydantic_yaml/main.py +30 -0
  35. iad/core/pydantools/fixed_pydantic_yaml/mixin.py +281 -0
  36. iad/core/pydantools/fixed_pydantic_yaml/model.py +20 -0
  37. iad/core/pydantools/fixed_pydantic_yaml/py.typed +1 -0
  38. iad/core/pydantools/fixed_pydantic_yaml/version.py +1 -0
  39. iad/core/pydantools/models.py +560 -0
  40. iad/core/regexp.py +348 -0
  41. iad/core/short.py +308 -0
  42. iad/core/strings.py +635 -0
  43. iad/core/unc_panda.py +270 -0
  44. iad/core/units.py +58 -0
  45. iad/core/wrap.py +420 -0
  46. ialdev_core-0.1.0.dist-info/METADATA +73 -0
  47. ialdev_core-0.1.0.dist-info/RECORD +48 -0
  48. ialdev_core-0.1.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,113 @@
1
+ import warnings
2
+ from typing import Optional, Tuple, Type
3
+
4
+ from pydantic.v1 import validator
5
+
6
+ from .semver import SemVer
7
+ from ..model import YamlModel
8
+
9
+ __all__ = ["VersionedYamlModel"]
10
+
11
+
12
+ def _chk_between(v, lo=None, hi=None):
13
+ if v is None:
14
+ return
15
+ if (hi is not None) and (v > hi):
16
+ raise ValueError(f"Default version higher than maximum: {v} > {hi}")
17
+ if (lo is not None) and (v < lo):
18
+ raise ValueError(f"Default version lower than minimum: {v} < {lo}")
19
+
20
+
21
+ def _get_minmax_robust(
22
+ cls: Type["VersionedYamlModel"],
23
+ ) -> Tuple[Optional[SemVer], Optional[SemVer]]:
24
+ min_, max_ = None, None
25
+ for supcls in cls.mro():
26
+ Config = getattr(supcls, "Config", None)
27
+ if Config is not None:
28
+ if min_ is None:
29
+ min_ = getattr(Config, "min_version", None)
30
+ if max_ is None:
31
+ max_ = getattr(Config, "max_version", None)
32
+ return min_, max_
33
+
34
+
35
+ class VersionedYamlModel(YamlModel):
36
+ """YAML model with versioning support.
37
+
38
+ Usage
39
+ -----
40
+ Inherit from this class, and set a Config class with attributes
41
+ `min_version` and/or `max_version`:
42
+
43
+ ```python
44
+ class MyModel(VersionedYamlModel):
45
+ class Config:
46
+ min_version = "1.0.0"
47
+
48
+ foo: str = "bar"
49
+ ```
50
+
51
+ By default, the minimum version is "0.0.0" and the maximum is unset.
52
+ This pattern enables you to more easily version your YAML files and
53
+ protect against accidentally using older (or newer) configuration file formats.
54
+
55
+ Notes
56
+ -----
57
+ By default, a validator checks that the "version" field is between
58
+ `Config.min_version` and `Config.max_version`, if those are not None.
59
+
60
+ It's probably best not to even set the `version` field by hand, but rather
61
+ in your configuration.
62
+ """
63
+
64
+ version: SemVer
65
+
66
+ def __init_subclass__(cls) -> None:
67
+ # Check Config class types
68
+ Config = getattr(cls, "Config", None)
69
+ if Config is not None:
70
+ # check one field
71
+ minv = getattr(Config, "min_version", None)
72
+ if minv is not None:
73
+ if not isinstance(minv, SemVer):
74
+ setattr(Config, "min_version", SemVer(minv))
75
+ # check other field
76
+ maxv = getattr(Config, "max_version", None)
77
+ if maxv is not None:
78
+ if not isinstance(maxv, SemVer):
79
+ setattr(Config, "max_version", SemVer(maxv))
80
+
81
+ # Check ranges
82
+ min_, max_ = _get_minmax_robust(cls)
83
+ if (min_ is not None) and (max_ is not None) and (min_ > max_):
84
+ raise ValueError(
85
+ f"Minimum version higher than maximum: {min_!r} > {max_!r}"
86
+ )
87
+
88
+ # Check the default value of the "version" field
89
+ fld = cls.__fields__["version"]
90
+ d = fld.default
91
+ if d is None:
92
+ pass
93
+ else:
94
+ _chk_between(d, lo=min_, hi=max_)
95
+ warnings.warn(
96
+ f"Recommended to have `version` be required, but set default {d!r}",
97
+ UserWarning,
98
+ )
99
+
100
+ if not issubclass(fld.type_, SemVer):
101
+ raise TypeError(
102
+ f"Field type for `version` must be SemVer, got {fld.type_!r}"
103
+ )
104
+
105
+ @validator("version", always=True)
106
+ def _check_semver(cls, v):
107
+ min_, max_ = _get_minmax_robust(cls)
108
+ _chk_between(v, lo=min_, hi=max_)
109
+ return v
110
+
111
+ class Config:
112
+ min_version = SemVer("0.0.0")
113
+ max_version = None
@@ -0,0 +1,30 @@
1
+ """YAML-enabled Pydantic models."""
2
+
3
+ __all__ = [
4
+ "__version__",
5
+ "yaml",
6
+ "yaml_safe_dump",
7
+ "yaml_safe_load",
8
+ "YamlEnum",
9
+ "YamlInt",
10
+ "YamlIntEnum",
11
+ "YamlStr",
12
+ "YamlStrEnum",
13
+ "YamlModel",
14
+ "YamlModelMixin",
15
+ "YamlModelMixinConfig",
16
+ "SemVer",
17
+ "VersionedYamlModel",
18
+ ]
19
+
20
+ from .compat.old_enums import YamlEnum
21
+ from .compat.hacks import inject_all as _inject_yaml_hacks
22
+ from .compat.types import YamlInt, YamlIntEnum, YamlStr, YamlStrEnum
23
+ from .compat.yaml_lib import yaml, yaml_safe_dump, yaml_safe_load
24
+ from .ext.semver import SemVer
25
+ from .ext.versioned_model import VersionedYamlModel
26
+ from .mixin import YamlModelMixin, YamlModelMixinConfig
27
+ from .model import YamlModel
28
+ from .version import __version__
29
+
30
+ _inject_yaml_hacks()
@@ -0,0 +1,281 @@
1
+ """Module to define the YamlModelMixin."""
2
+
3
+ from typing_extensions import Literal
4
+ import warnings
5
+ from pathlib import Path
6
+ from typing import (
7
+ TYPE_CHECKING,
8
+ Any,
9
+ Callable,
10
+ ClassVar,
11
+ Optional,
12
+ Type,
13
+ TypeVar,
14
+ Union,
15
+ cast,
16
+ no_type_check,
17
+ )
18
+ from pydantic.v1 import BaseModel, ValidationError
19
+ from pydantic.v1.error_wrappers import ErrorWrapper
20
+ from pydantic.v1.parse import Protocol, load_file, load_str_bytes
21
+ from pydantic.v1.main import ROOT_KEY, ModelMetaclass, BaseConfig
22
+ from pydantic.v1.types import StrBytes
23
+
24
+ if TYPE_CHECKING:
25
+ from pydantic.v1.typing import DictStrAny, AbstractSetIntStr, MappingIntStrAny
26
+
27
+ Model = TypeVar("Model", bound="BaseModel")
28
+
29
+ from .compat.yaml_lib import yaml_safe_dump, yaml_safe_load
30
+
31
+ ExtendedProto = Union[Protocol, Literal["yaml"]]
32
+
33
+ YamlStyle = Union[
34
+ None,
35
+ Literal[""],
36
+ Literal['"'],
37
+ Literal["'"],
38
+ Literal["|"],
39
+ Literal[">"],
40
+ ]
41
+
42
+
43
+ def is_yaml_requested(
44
+ content_type: Optional[str] = None,
45
+ proto: Optional[ExtendedProto] = None,
46
+ path_suffix: Optional[str] = None,
47
+ ) -> bool:
48
+ """Checks whether YAML is requested by the user, depending on params."""
49
+ is_yaml = False
50
+ if content_type is not None:
51
+ is_yaml = ("yaml" in content_type) or ("yml" in content_type)
52
+ if proto is not None:
53
+ is_yaml = is_yaml or (proto == "yaml")
54
+ if path_suffix is not None:
55
+ is_yaml = is_yaml or (path_suffix in [".yaml", ".yml"])
56
+ return is_yaml
57
+
58
+
59
+ class YamlModelMixinConfig:
60
+ """Additional configuration for YamlModelMixin."""
61
+
62
+ yaml_loads: Callable[[str], Any] = yaml_safe_load # type: ignore
63
+ yaml_dumps: Callable[..., str] = yaml_safe_dump # type: ignore
64
+
65
+
66
+ class YamlModelMixin(metaclass=ModelMetaclass):
67
+ """Mixin to add YAML compatibility to your class.
68
+
69
+ Usage
70
+ -----
71
+ Inherit from this and a `pydantic.BaseModel` or a subclass, like this:
72
+
73
+ ```python
74
+ class MyBaseType(BaseModel):
75
+ my_field: str = "default"
76
+
77
+ class MyExtType(YamlModelMixin, MyBaseType):
78
+ other_field: int = 42
79
+ ```
80
+
81
+ `YamlModelMixin` *must* be *before* any class that inherits from
82
+ `pydantic.BaseModel` due to issues with the method resolution order.
83
+
84
+ You can now use `MyExtType().yaml()` to dump the class values (default here)
85
+ to a YAML string.
86
+ """
87
+
88
+ if TYPE_CHECKING:
89
+ __custom_root_type__: ClassVar[bool] = False
90
+ __config__: ClassVar[Type[BaseConfig]] = YamlModelMixinConfig # type: ignore
91
+
92
+ @no_type_check
93
+ def __init_subclass__(cls, **_) -> None:
94
+ super().__init_subclass__()
95
+
96
+ # Set the config class
97
+ cfg: Type[YamlModelMixinConfig] = cls.__config__
98
+ if not issubclass(cfg, YamlModelMixinConfig):
99
+ class T(cfg, YamlModelMixinConfig):
100
+ pass
101
+
102
+ T.__doc__ = cfg.__doc__
103
+ T.__name__ = cfg.__name__
104
+ T.__qualname__ = cfg.__qualname__
105
+
106
+ cls.__config__ = T
107
+
108
+ def yaml(
109
+ self,
110
+ *,
111
+ include: Union["AbstractSetIntStr", "MappingIntStrAny", None] = None,
112
+ exclude: Union["AbstractSetIntStr", "MappingIntStrAny", None] = None,
113
+ by_alias: bool = False,
114
+ skip_defaults: Optional[bool] = None,
115
+ exclude_unset: bool = False,
116
+ exclude_defaults: bool = False,
117
+ exclude_none: bool = False,
118
+ sort_keys: bool = False,
119
+ default_flow_style: Optional[bool] = False,
120
+ default_style: YamlStyle = None,
121
+ indent: Optional[bool] = None,
122
+ encoding: Optional[str] = None,
123
+ **kwargs,
124
+ ) -> str:
125
+ """Generate a YAML representation of the model.
126
+
127
+ Parameters
128
+ ----------
129
+ include, exclude
130
+ Fields to include or exclude. See `dict()`.
131
+ by_alias : bool
132
+ Whether to use aliases instead of declared names. Default is False.
133
+ skip_defaults, exclude_unset, exclude_defaults, exclude_none
134
+ Arguments as per `BaseModel.dict()`.
135
+ sort_keys : bool
136
+ If True, will sort the keys in alphanumeric order for dictionaries.
137
+ Default is False, which will dump in the field definition order.
138
+ default_flow_style : bool or None
139
+ Whether to use the "flow" style in the dumper. By default, this is False,
140
+ which uses the "block" style (probably the most familiar to users).
141
+ default_style : {None, "", "'", '"', "|", ">"}
142
+ This is the default style for quoting strings, used by `ruamel.yaml` dumper.
143
+ Default is None, which varies the style based on line length.
144
+ indent, encoding, kwargs
145
+ Additional arguments for the dumper.
146
+ """
147
+ data: "DictStrAny" = self.dict( # type: ignore
148
+ include=include,
149
+ exclude=exclude,
150
+ by_alias=by_alias,
151
+ skip_defaults=skip_defaults,
152
+ exclude_unset=exclude_unset,
153
+ exclude_defaults=exclude_defaults,
154
+ exclude_none=exclude_none,
155
+ )
156
+
157
+ if self.__custom_root_type__:
158
+ data = data[ROOT_KEY]
159
+ warnings.warn(
160
+ "Explicit custom root behavior not yet implemented for pydantic_yaml."
161
+ " This may not work as expected. If so, please create a GitHub issue:"
162
+ " https://github.com/NowanIlfideme/pydantic-yaml/issues/new"
163
+ )
164
+ cfg = cast(YamlModelMixinConfig, self.__config__)
165
+ return cfg.yaml_dumps(
166
+ data,
167
+ sort_keys=sort_keys,
168
+ default_flow_style=default_flow_style,
169
+ default_style=default_style,
170
+ encoding=encoding,
171
+ indent=indent,
172
+ **kwargs,
173
+ )
174
+
175
+ @no_type_check
176
+ @classmethod
177
+ def parse_raw(
178
+ cls: Type["Model"],
179
+ b: StrBytes,
180
+ *,
181
+ content_type: str = "application/yaml", # This is a reasonable default, right?
182
+ encoding: str = "utf-8",
183
+ proto: ExtendedProto = None,
184
+ allow_pickle: bool = False,
185
+ ) -> "Model":
186
+ # NOTE: Type checking this function is a PITA, because we're overriding
187
+ # BaseModel.parse_raw, but not inheriting it due to the MRO problem!
188
+
189
+ # Check whether we're specifically asked to parse YAML
190
+ is_yaml = is_yaml_requested(content_type=content_type, proto=proto)
191
+
192
+ # Note that JSON is a subset of the YAML 1.2 spec, so we should be OK
193
+ # even if JSON is passed. It will be slower, however.
194
+ if is_yaml:
195
+ try:
196
+ cfg = cast(YamlModelMixinConfig, cls.__config__)
197
+ obj = cfg.yaml_loads(b)
198
+ except RecursionError as e:
199
+ raise ValueError(
200
+ "YAML files with recursive references are unsupported."
201
+ ) from e
202
+ except ValidationError:
203
+ raise
204
+ except Exception as e:
205
+ raise ValidationError([ErrorWrapper(e, loc=ROOT_KEY)], cls) from e
206
+ else:
207
+ obj = load_str_bytes(
208
+ b,
209
+ proto=proto,
210
+ content_type=content_type,
211
+ encoding=encoding,
212
+ allow_pickle=allow_pickle,
213
+ json_loads=cls.__config__.json_loads,
214
+ )
215
+
216
+ return obj
217
+
218
+ @no_type_check
219
+ @classmethod
220
+ def parse_file(
221
+ cls: Type["Model"],
222
+ path: Union[str, Path],
223
+ *,
224
+ content_type: str = None,
225
+ encoding: str = "utf-8",
226
+ proto: ExtendedProto = None,
227
+ allow_pickle: bool = False,
228
+ ) -> "Model":
229
+ obj = cls.parse_file_to_dict(path, content_type=content_type, encoding=encoding,
230
+ proto=proto, allow_pickle=allow_pickle)
231
+ res = cls.parse_obj(obj) # type: ignore
232
+ return cast("Model", res)
233
+
234
+ @classmethod
235
+ def parse_file_to_dict(cls, path: Union[str, Path],
236
+ *,
237
+ content_type: str = None,
238
+ encoding: str = "utf-8",
239
+ proto: ExtendedProto = None,
240
+ allow_pickle: bool = False):
241
+ path = Path(path)
242
+ # Assume YAML based on the file name, so `parse_raw()` works well below
243
+ if (content_type is None) and (path.suffix in [".yml", ".yaml"]):
244
+ content_type = "application/yaml"
245
+ # Check whether we're specifically asked to parse YAML
246
+ is_yaml = is_yaml_requested(
247
+ content_type=content_type, proto=proto, path_suffix=path.suffix
248
+ )
249
+ # The first code path explicitly checks YAML compatibility.
250
+ # We offload the rest to Pydantic.
251
+ if is_yaml:
252
+ b = path.read_bytes()
253
+ obj = cls.parse_raw(
254
+ b,
255
+ content_type=content_type,
256
+ encoding=encoding,
257
+ proto=proto,
258
+ allow_pickle=allow_pickle,
259
+ )
260
+ else:
261
+ obj = load_file(
262
+ path,
263
+ proto=proto,
264
+ content_type=content_type,
265
+ encoding=encoding,
266
+ allow_pickle=allow_pickle,
267
+ json_loads=cls.__config__.json_loads,
268
+ )
269
+ return obj
270
+
271
+ @classmethod
272
+ def __try_update_forward_refs__(cls, **localns: Any) -> None:
273
+ """
274
+ Same as update_forward_refs but will not raise exception
275
+ when forward references are not defined.
276
+ """
277
+ try:
278
+ if issubclass(cls, BaseModel):
279
+ super().__try_update_forward_refs__(**localns) # type: ignore
280
+ except AttributeError:
281
+ pass
@@ -0,0 +1,20 @@
1
+ from pydantic.v1 import BaseModel
2
+
3
+ from .mixin import YamlModelMixin
4
+
5
+ _pre_doc = """`pydantic.BaseModel` class with built-in YAML support.
6
+
7
+ You can alternatively inherit from this to implement your model:
8
+ `(pydantic_yaml.YamlModelMixin, pydantic.BaseModel)`
9
+
10
+ See Also
11
+ --------
12
+ pydantic-yaml: https://github.com/NowanIlfideme/pydantic-yaml
13
+ pydantic: https://pydantic-docs.helpmanual.io/
14
+ pyyaml: https://pyyaml.org/
15
+ ruamel.yaml: https://yaml.readthedocs.io/en/latest/index.html
16
+ """
17
+
18
+
19
+ class YamlModel(YamlModelMixin, BaseModel):
20
+ __doc__ = _pre_doc + BaseModel.__doc__
@@ -0,0 +1 @@
1
+ # Marker file for PEP 561. This package uses inline types.
@@ -0,0 +1 @@
1
+ __version__ = "0.9.0"