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.
- iad/core/__init__.py +9 -0
- iad/core/array.py +1961 -0
- iad/core/binary.py +377 -0
- iad/core/cache.py +903 -0
- iad/core/codetools.py +203 -0
- iad/core/datatools.py +671 -0
- iad/core/docs/locators.ipynb +754 -0
- iad/core/dotstyle.py +99 -0
- iad/core/env.py +271 -0
- iad/core/events.py +650 -0
- iad/core/filesproc.py +1046 -0
- iad/core/fnctools.py +390 -0
- iad/core/label.py +240 -0
- iad/core/logs.py +182 -0
- iad/core/nptools.py +449 -0
- iad/core/one_dark.puml +881 -0
- iad/core/param/__init__.py +17 -0
- iad/core/param/confargparse.py +55 -0
- iad/core/param/paramaze.py +339 -0
- iad/core/param/tbox.py +277 -0
- iad/core/paths.py +563 -0
- iad/core/pdtools.py +2570 -0
- iad/core/pydantools/__init__.py +5 -0
- iad/core/pydantools/fixed_pydantic_yaml/__init__.py +32 -0
- iad/core/pydantools/fixed_pydantic_yaml/compat/__init__.py +0 -0
- iad/core/pydantools/fixed_pydantic_yaml/compat/hacks.py +76 -0
- iad/core/pydantools/fixed_pydantic_yaml/compat/old_enums.py +37 -0
- iad/core/pydantools/fixed_pydantic_yaml/compat/representers.py +92 -0
- iad/core/pydantools/fixed_pydantic_yaml/compat/types.py +122 -0
- iad/core/pydantools/fixed_pydantic_yaml/compat/yaml_lib.py +104 -0
- iad/core/pydantools/fixed_pydantic_yaml/ext/__init__.py +1 -0
- iad/core/pydantools/fixed_pydantic_yaml/ext/semver.py +152 -0
- iad/core/pydantools/fixed_pydantic_yaml/ext/versioned_model.py +113 -0
- iad/core/pydantools/fixed_pydantic_yaml/main.py +30 -0
- iad/core/pydantools/fixed_pydantic_yaml/mixin.py +281 -0
- iad/core/pydantools/fixed_pydantic_yaml/model.py +20 -0
- iad/core/pydantools/fixed_pydantic_yaml/py.typed +1 -0
- iad/core/pydantools/fixed_pydantic_yaml/version.py +1 -0
- iad/core/pydantools/models.py +560 -0
- iad/core/regexp.py +348 -0
- iad/core/short.py +308 -0
- iad/core/strings.py +635 -0
- iad/core/unc_panda.py +270 -0
- iad/core/units.py +58 -0
- iad/core/wrap.py +420 -0
- ialdev_core-0.1.0.dist-info/METADATA +73 -0
- ialdev_core-0.1.0.dist-info/RECORD +48 -0
- ialdev_core-0.1.0.dist-info/WHEEL +4 -0
iad/core/wrap.py
ADDED
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import collections
|
|
4
|
+
import enum
|
|
5
|
+
import re
|
|
6
|
+
import sys as _sys
|
|
7
|
+
from functools import wraps
|
|
8
|
+
from typing import Collection, Optional, Type, Callable, Sequence, Literal, Generic, TypeVar
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def name_func_outputs(func, names: Collection[str] = None, *,
|
|
12
|
+
out_type: str | Type[tuple | dict] = None,
|
|
13
|
+
adjust=False, nest=None):
|
|
14
|
+
"""Turns a function returning a tuple of items into one returning
|
|
15
|
+
a named tuple or a dict with items assigned with provided names.
|
|
16
|
+
|
|
17
|
+
- Converts into a tuple, if typename str or None (same as str=='<func_name>_out').
|
|
18
|
+
- Converts into dict if typename is ``dict``
|
|
19
|
+
|
|
20
|
+
If number of items in the output does not match that of names,
|
|
21
|
+
depending on the value of ``adjust`` argument:
|
|
22
|
+
|
|
23
|
+
- ``False`` - raise ``TypeError``
|
|
24
|
+
- ``True`` - uses first ``len(names)`` and raise only if ``len(output)`` is bigger
|
|
25
|
+
- ``None`` - returns output without change
|
|
26
|
+
|
|
27
|
+
Special checking is done for the case of nested wrapping attempts,
|
|
28
|
+
which are being tracked and depending on the argument ``nest``:
|
|
29
|
+
- ``False`` - raise ``RuntimeError``
|
|
30
|
+
- ``True`` - allow nested wrapping and return multi-wrapped function
|
|
31
|
+
- ``None`` - ignore nested wrapping request and return the input function
|
|
32
|
+
|
|
33
|
+
Example::
|
|
34
|
+
|
|
35
|
+
>>> f0 = lambda x: tuple(range(x)) if x > 1 else 0
|
|
36
|
+
>>> name_func_outputs(f0, list('xyz'))(3)
|
|
37
|
+
<lambda_out> x: 0, y: 1, z: 2
|
|
38
|
+
|
|
39
|
+
>>> name_func_outputs(f0, list('xyz'), out_type=dict, adjust=True)(2)
|
|
40
|
+
{'x': 0, 'y': 1}
|
|
41
|
+
|
|
42
|
+
:param func: the function to wrap
|
|
43
|
+
:param names: collection of names to match the function's outputs or named tuple
|
|
44
|
+
:param out_type: name of namedtuple or namedtuple class
|
|
45
|
+
:param adjust: adjust names length to the output length
|
|
46
|
+
:param nest: allow nested `name_outputs` wrappings
|
|
47
|
+
:return: new function with dict output
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
def out_len_error(n):
|
|
51
|
+
raise RuntimeError(f"Cant wrap a {n} outputs of {func_name} in {ln} names")
|
|
52
|
+
|
|
53
|
+
@wraps(func)
|
|
54
|
+
def wrapper(*args, **kwargs):
|
|
55
|
+
out = func(*args, **kwargs)
|
|
56
|
+
if not isinstance(out, tuple):
|
|
57
|
+
if len(names) == 0 or adjust is None: return out
|
|
58
|
+
if len(names) == 1 or adjust is True: out = (out,)
|
|
59
|
+
if adjust is False: out_len_error(1)
|
|
60
|
+
else:
|
|
61
|
+
if (lo := len(out)) > ln: out_len_error(lo)
|
|
62
|
+
if lo == ln or adjust is True: return construct(out)
|
|
63
|
+
if adjust is None: return out # from here its always lo < ln
|
|
64
|
+
out_len_error(lo)
|
|
65
|
+
return construct(out)
|
|
66
|
+
|
|
67
|
+
func_name = re.sub(r'\W', '', func.__name__)
|
|
68
|
+
if names is not None:
|
|
69
|
+
is_str = lambda x: isinstance(x, str)
|
|
70
|
+
if isinstance(names, str) or not all(map(is_str, names)):
|
|
71
|
+
raise TypeError("names must be a collection of strings")
|
|
72
|
+
if out_type is None:
|
|
73
|
+
out_type = f"{func_name}_out"
|
|
74
|
+
|
|
75
|
+
if isinstance(out_type, str):
|
|
76
|
+
construct = lambda out: namedtuple(
|
|
77
|
+
out_type, names[:(len(out) if adjust else None)]
|
|
78
|
+
)(*out)
|
|
79
|
+
elif issubclass(out_type, dict):
|
|
80
|
+
construct = lambda out: dict(zip(names, out))
|
|
81
|
+
else:
|
|
82
|
+
raise TypeError("Given names typename must be a dict class or str or None")
|
|
83
|
+
elif isinstance(out_type, tuple) and hasattr(out_type, '_fields'):
|
|
84
|
+
names = out_type._fields
|
|
85
|
+
construct = lambda out: out_type(*out)
|
|
86
|
+
else:
|
|
87
|
+
raise TypeError("typename must be namedtuple class if names are not provided")
|
|
88
|
+
ln = len(names)
|
|
89
|
+
|
|
90
|
+
# check if attempting re-wrap the function in the same way
|
|
91
|
+
attr = dict(names=names, out_type=out_type, prev=None, nest=0)
|
|
92
|
+
if prev_attr := getattr(func, '_name_outputs', None):
|
|
93
|
+
if prev_attr['out_type'] == out_type and prev_attr['names'] == names:
|
|
94
|
+
if nest is None: # function is already wrapped as requested
|
|
95
|
+
return func
|
|
96
|
+
elif nest is False:
|
|
97
|
+
raise RuntimeError(f'Re-wrapping name_outputs with {attr}')
|
|
98
|
+
attr['prev'] = prev_attr
|
|
99
|
+
attr['nest'] = prev_attr['nest'] + 1
|
|
100
|
+
setattr(wrapper, '_name_outputs', attr)
|
|
101
|
+
return wrapper
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def doc_from(src: type | Callable, merge: Literal['append', 'prepend', 'anchor', 'replace'] = 'append', cite=False):
|
|
105
|
+
|
|
106
|
+
def merger(obj):
|
|
107
|
+
doc = (f'Doc from {src.__qualname__}:\n' if cite else '') + (src.__doc__ or '')
|
|
108
|
+
if not obj.__doc__ or merge == 'replace':
|
|
109
|
+
obj.__doc__ = doc
|
|
110
|
+
if merge == 'append':
|
|
111
|
+
obj.__doc__ += doc
|
|
112
|
+
elif merge == 'prepend':
|
|
113
|
+
obj.__doc__ = doc + '\n' + obj.__doc__
|
|
114
|
+
elif merge == 'anchor':
|
|
115
|
+
obj.__doc__ = obj.__doc__.replace('<<anchor>>', f'{doc}')
|
|
116
|
+
else:
|
|
117
|
+
raise NameError(f'Unknown doc merging method {merge}')
|
|
118
|
+
return obj
|
|
119
|
+
|
|
120
|
+
return merger
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@doc_from(name_func_outputs)
|
|
124
|
+
def name_outputs(names: Optional[Collection[str]] = None, *,
|
|
125
|
+
out_type: str | Type[tuple | dict] | None = None,
|
|
126
|
+
adjust=False, nest=None):
|
|
127
|
+
f"""{name_func_outputs.__doc__}"""
|
|
128
|
+
|
|
129
|
+
def convert(func):
|
|
130
|
+
return name_func_outputs(func, names, out_type=out_type, adjust=adjust, nest=nest)
|
|
131
|
+
return convert
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
name_outputs.__doc__ = name_func_outputs.__doc__
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class NamedTupleI:
|
|
138
|
+
"""
|
|
139
|
+
Implements Interface of ``NamedTuple`` classes.
|
|
140
|
+
|
|
141
|
+
Don't subclass it directly, use instead:
|
|
142
|
+
- either ``namedtuple`` function in this module
|
|
143
|
+
- or ``NamedTupleMeta`` metaclass
|
|
144
|
+
|
|
145
|
+
It can be used for type checking though:
|
|
146
|
+
::
|
|
147
|
+
isinstance(obj, NamedTupleI)
|
|
148
|
+
|
|
149
|
+
instead of
|
|
150
|
+
::
|
|
151
|
+
isinstance(type(obj), NamedTupleMeta)
|
|
152
|
+
"""
|
|
153
|
+
from .nptools import array_info_str
|
|
154
|
+
|
|
155
|
+
_fields: list[str]
|
|
156
|
+
__iter__: Callable
|
|
157
|
+
|
|
158
|
+
def __init__(self, *args, **kws): ...
|
|
159
|
+
|
|
160
|
+
def __repr__(self):
|
|
161
|
+
val_str = lambda v: (NamedTupleI.array_info_str(v, stats=False)
|
|
162
|
+
if hasattr(v, 'shape') and hasattr(v, 'ndim') else str(v))
|
|
163
|
+
fields_str = (f'{k}: {val_str(v)}' for k, v in zip(self._fields, self))
|
|
164
|
+
|
|
165
|
+
end, sep = '<end>', '<sep>'
|
|
166
|
+
s = f"<{self.__class__.__name__}> {end}" + sep.join(fields_str)
|
|
167
|
+
end_str, sep_str = ['\n\t'] * 2 if len(s) > 50 else ['', ', ']
|
|
168
|
+
return s.replace(end, end_str).replace(sep, sep_str)
|
|
169
|
+
|
|
170
|
+
def _part(self, *items: str | int, name: Optional[str] = None):
|
|
171
|
+
"""Return a part of tuple items as a new namedtuple
|
|
172
|
+
|
|
173
|
+
:param name: name of the new namedtuple class
|
|
174
|
+
:param items: fields names to extract (in this order!)
|
|
175
|
+
"""
|
|
176
|
+
name = name or 'Part'
|
|
177
|
+
|
|
178
|
+
def extractor(elements):
|
|
179
|
+
for elm in elements:
|
|
180
|
+
if isinstance(elm, int):
|
|
181
|
+
yield self._fields[elm], tuple.__getitem__(self, elm)
|
|
182
|
+
elif isinstance(elm, str):
|
|
183
|
+
yield elm, getattr(self, elm)
|
|
184
|
+
elif isinstance(elm, slice):
|
|
185
|
+
for item in zip(self._fields[elm], tuple.__getitem__(self, elm)):
|
|
186
|
+
yield item
|
|
187
|
+
else:
|
|
188
|
+
raise TypeError("Invalid reference to tuple element")
|
|
189
|
+
|
|
190
|
+
_fields, _items = zip(*extractor(items))
|
|
191
|
+
return namedtuple(name, _fields)(*_items)
|
|
192
|
+
|
|
193
|
+
def apply(self, func):
|
|
194
|
+
return self.__class__(*(map(func, self)))
|
|
195
|
+
|
|
196
|
+
def __add__(self, other):
|
|
197
|
+
return namedtuple('Combined', [*self._fields, *other._fields])(*self, *other)
|
|
198
|
+
|
|
199
|
+
@staticmethod
|
|
200
|
+
def __build_reduced__(typename, fields, values, module):
|
|
201
|
+
return namedtuple(typename, fields, module=module)(*values)
|
|
202
|
+
|
|
203
|
+
def __reduce__(self):
|
|
204
|
+
"""Override pickle machinery to support dynamically defined or nested named tuples"""
|
|
205
|
+
cls = self.__class__
|
|
206
|
+
return (
|
|
207
|
+
NamedTupleI.__build_reduced__,
|
|
208
|
+
(cls.__name__, self._fields, [*self], cls.__module__), # passed to __build_reduced__
|
|
209
|
+
{}) # no other state information is used
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class NamedTupleMeta(type):
|
|
213
|
+
@staticmethod
|
|
214
|
+
def _find_module(level=1, module=None):
|
|
215
|
+
if module is None:
|
|
216
|
+
try:
|
|
217
|
+
module = _sys._getframe(level).f_globals.get('__name__', '__main__')
|
|
218
|
+
except (AttributeError, ValueError):
|
|
219
|
+
return None
|
|
220
|
+
return module
|
|
221
|
+
|
|
222
|
+
def __repr__(cls):
|
|
223
|
+
return f"{cls.__name__}({', '.join(cls._fields)})"
|
|
224
|
+
|
|
225
|
+
def __new__(mcs, name, bases, attrs, fields: Sequence[str], defaults: Sequence = None, module=None):
|
|
226
|
+
module = NamedTupleMeta._find_module(module=module)
|
|
227
|
+
if NamedTupleI not in bases:
|
|
228
|
+
bases = (*bases, NamedTupleI)
|
|
229
|
+
bases = (*bases, collections.namedtuple(name, fields, defaults=defaults, module=module))
|
|
230
|
+
cls = super().__new__(mcs, name, bases, attrs)
|
|
231
|
+
cls.__module__ = module
|
|
232
|
+
return cls
|
|
233
|
+
|
|
234
|
+
def __init__(cls, name, bases, attrs, **_):
|
|
235
|
+
super().__init__(name, bases, attrs)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def namedtuple(typename: str, fields: Sequence[str], defaults: Sequence = None, module=None):
|
|
239
|
+
"""Wraps ``collections.namedtuple`` to add custom __repr__ for some data types:
|
|
240
|
+
numpy arrays, ...
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
**Additional manipulation over tuple content**
|
|
244
|
+
|
|
245
|
+
Extraction of part of the fields as a new tuple:
|
|
246
|
+
|
|
247
|
+
>>> v3 = namedtuple('XYZ', ['x', 'y', 'z'])(10, 20, 30)
|
|
248
|
+
>>> v3._part('z', 'x', name='ZX') == (v3.z, v3.x)
|
|
249
|
+
True
|
|
250
|
+
>>> v3._part(slice(0,2)) == v3[:2]
|
|
251
|
+
True
|
|
252
|
+
>>> v3._part(slice(0,2), slice(2,3)) == v3
|
|
253
|
+
True
|
|
254
|
+
>>> v3._part('x', slice(1,2), 2) == v3
|
|
255
|
+
True
|
|
256
|
+
|
|
257
|
+
Concatenation of tuples:
|
|
258
|
+
|
|
259
|
+
>>> v3._part('x', 'y') + v3._part('z') == v3
|
|
260
|
+
True
|
|
261
|
+
|
|
262
|
+
:param typename: name of the new type
|
|
263
|
+
:param fields: names of tuple fields in this order
|
|
264
|
+
:param defaults: sequence of default valued of the fields in same order
|
|
265
|
+
:param module: module the new class to be associated with
|
|
266
|
+
"""
|
|
267
|
+
module = NamedTupleMeta._find_module(level=1, module=module)
|
|
268
|
+
return NamedTupleMeta(typename, bases=(), attrs={}, fields=fields, defaults=defaults, module=module)
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def name_tuple(typename='Tuple', **kws):
|
|
272
|
+
"""
|
|
273
|
+
Create namedtuple OBJECT from name: value pairs
|
|
274
|
+
|
|
275
|
+
:param typename: for the tuple type
|
|
276
|
+
:param kws: names-values pairs
|
|
277
|
+
:return: namedtuple
|
|
278
|
+
"""
|
|
279
|
+
return namedtuple(typename, tuple(kws.keys()))(*kws.values())
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def double_wrap(dec_func):
|
|
283
|
+
"""
|
|
284
|
+
a decorator of decorator, allowing the decorator to be used as:
|
|
285
|
+
@decorator(with, arguments, and=kwargs)
|
|
286
|
+
or
|
|
287
|
+
@decorator
|
|
288
|
+
"""
|
|
289
|
+
|
|
290
|
+
@wraps(dec_func)
|
|
291
|
+
def new_dec(*args, **kwargs):
|
|
292
|
+
if len(args) == 1 and len(kwargs) == 0 and callable(args[0]):
|
|
293
|
+
# actual decorated function
|
|
294
|
+
return dec_func(args[0])
|
|
295
|
+
else:
|
|
296
|
+
# decorator arguments
|
|
297
|
+
return lambda real_func: dec_func(real_func, *args, **kwargs)
|
|
298
|
+
|
|
299
|
+
return new_dec
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
class CaseInsEnum(str, enum.Enum):
|
|
303
|
+
"""
|
|
304
|
+
Enum of string values allowing to set it with case-insensitive names or values.
|
|
305
|
+
|
|
306
|
+
>>> class E(CaseInsEnum):
|
|
307
|
+
... min: 'minimal'
|
|
308
|
+
... max: 'maximal'
|
|
309
|
+
... assert E('Min') is E.min and E('MINIMAL') is E.min
|
|
310
|
+
|
|
311
|
+
Same can be also created functionally:
|
|
312
|
+
|
|
313
|
+
>>> E = CaseInsEnum('E', {'min': 'minimal', 'max': 'maximal'})
|
|
314
|
+
|
|
315
|
+
Or just list the keys if values are of no importance:
|
|
316
|
+
|
|
317
|
+
>>> En = CaseInsEnum('En', ['min', 'max'])
|
|
318
|
+
"""
|
|
319
|
+
@classmethod
|
|
320
|
+
def _missing_(cls, key: str):
|
|
321
|
+
key = key.lower()
|
|
322
|
+
for n, v in cls._member_map_.items():
|
|
323
|
+
if n.lower() == key or isinstance(v, str) and v.lower() == key:
|
|
324
|
+
return v
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def enum_str_type(*values, name):
|
|
328
|
+
"""
|
|
329
|
+
Create type enumerating provided strings as attributes AND values.
|
|
330
|
+
|
|
331
|
+
>>> Colors = enum_str_type('Colors', ['red', 'yellow'])
|
|
332
|
+
>>> assert Colors.yellow == Colors('yellow')
|
|
333
|
+
|
|
334
|
+
:param name:
|
|
335
|
+
:param values:
|
|
336
|
+
:return:
|
|
337
|
+
"""
|
|
338
|
+
return CaseInsEnum(name, dict(zip(values, values)))
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def enum_attr(attr: str, **kwargs):
|
|
342
|
+
"""Create ``CaseInsEnum`` class with an extra attribute for every member.
|
|
343
|
+
|
|
344
|
+
Examples
|
|
345
|
+
>>> AB = enum_attr('info', a='Member A', b='Member B')
|
|
346
|
+
>>> AB('a') is AB.a
|
|
347
|
+
True
|
|
348
|
+
>>> AB.b.info
|
|
349
|
+
'Member B'
|
|
350
|
+
|
|
351
|
+
Special attribute '__call__' is supported, to make the memebres callable by
|
|
352
|
+
providing each with its own function:
|
|
353
|
+
|
|
354
|
+
Examples
|
|
355
|
+
>>> Funcs = enum_attr('__call__', len=len, print=print)
|
|
356
|
+
>>> Funcs.len('Hi')
|
|
357
|
+
2
|
|
358
|
+
>>> Funcs.print('Hi')
|
|
359
|
+
Hi
|
|
360
|
+
|
|
361
|
+
:param attr: name of the attribute to add
|
|
362
|
+
:param kwargs: dict for all the members {name: attr_value}
|
|
363
|
+
"""
|
|
364
|
+
class _EnumNameMatcher:
|
|
365
|
+
if attr == '__call__':
|
|
366
|
+
def __call__(self, *args, **kws):
|
|
367
|
+
return kwargs[self.name](*args, **kws)
|
|
368
|
+
else:
|
|
369
|
+
def __init__(self, m):
|
|
370
|
+
setattr(self, attr, kwargs[self.name])
|
|
371
|
+
|
|
372
|
+
return CaseInsEnum('EnumMatch', [*kwargs], type=_EnumNameMatcher)
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
T = TypeVar("T")
|
|
376
|
+
RT = TypeVar("RT")
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
class classproperty(Generic[T, RT]):
|
|
380
|
+
"""
|
|
381
|
+
Class property attribute (read-only).
|
|
382
|
+
|
|
383
|
+
This works around deprecation from 3.13 of
|
|
384
|
+
::
|
|
385
|
+
class C:
|
|
386
|
+
@classmethod
|
|
387
|
+
@property
|
|
388
|
+
def some(cls,): ...
|
|
389
|
+
|
|
390
|
+
Same usage as @property, but taking the class as the first argument.
|
|
391
|
+
::
|
|
392
|
+
class C:
|
|
393
|
+
@classproperty
|
|
394
|
+
def x(cls):
|
|
395
|
+
return 0
|
|
396
|
+
|
|
397
|
+
print(C.x) # 0
|
|
398
|
+
print(C().x) # 0
|
|
399
|
+
"""
|
|
400
|
+
|
|
401
|
+
def __init__(self, func: Callable[[type[T]], RT]) -> None:
|
|
402
|
+
# For using `help(...)` on instances in Python >= 3.9.
|
|
403
|
+
self.__doc__ = func.__doc__
|
|
404
|
+
self.__module__ = func.__module__
|
|
405
|
+
self.__name__ = func.__name__
|
|
406
|
+
self.__qualname__ = func.__qualname__
|
|
407
|
+
# Consistent use of __wrapped__ for wrapping functions.
|
|
408
|
+
self.__wrapped__: Callable[[type[T]], RT] = func
|
|
409
|
+
|
|
410
|
+
def __set_name__(self, owner: type[T], name: str) -> None:
|
|
411
|
+
# Update based on class context.
|
|
412
|
+
self.__module__ = owner.__module__
|
|
413
|
+
self.__name__ = name
|
|
414
|
+
self.__qualname__ = owner.__qualname__ + "." + name
|
|
415
|
+
|
|
416
|
+
def __get__(self, instance: Optional[T], owner: Optional[type[T]] = None) -> RT:
|
|
417
|
+
if owner is None:
|
|
418
|
+
owner = type(instance)
|
|
419
|
+
return self.__wrapped__(owner)
|
|
420
|
+
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ialdev-core
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: iad.core — algorithmic utilities: data tools, parameters, paths, caching, and more
|
|
5
|
+
Author-email: Your Name <your.email@example.com>
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Intended Audience :: Science/Research
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Requires-Dist: ialdev-io
|
|
18
|
+
Requires-Dist: pydantic>=2.0
|
|
19
|
+
Requires-Dist: pandas>=1.3.0
|
|
20
|
+
Requires-Dist: numpy>=1.20.0
|
|
21
|
+
Requires-Dist: pyyaml>=5.4.0
|
|
22
|
+
Requires-Dist: ruamel.yaml>=0.15.0
|
|
23
|
+
Requires-Dist: regex>=2021.0.0
|
|
24
|
+
Requires-Dist: rapidfuzz>=3.0
|
|
25
|
+
Requires-Dist: tqdm>=4.60.0
|
|
26
|
+
Requires-Dist: frozendict>=2.0.0
|
|
27
|
+
Requires-Dist: python-box>=6.0.0
|
|
28
|
+
Requires-Dist: joblib>=1.0.0
|
|
29
|
+
Requires-Dist: configargparse>=1.0.0
|
|
30
|
+
Requires-Dist: deprecated>=1.2.0
|
|
31
|
+
Requires-Dist: semver>=2.13.0
|
|
32
|
+
Requires-Dist: uncertainties>=3.1.0
|
|
33
|
+
Requires-Dist: pint>=0.20.0
|
|
34
|
+
Requires-Dist: zfpy
|
|
35
|
+
Requires-Dist: xxhash>=3.0.0
|
|
36
|
+
Requires-Dist: toolz>=0.11.0
|
|
37
|
+
Requires-Dist: numba>=0.55.0
|
|
38
|
+
Requires-Dist: scikit-learn>=1.0.0
|
|
39
|
+
Requires-Dist: python-dotenv>=0.19.0
|
|
40
|
+
Project-URL: Homepage, https://github.com/yourusername/toolbox
|
|
41
|
+
Project-URL: Issues, https://github.com/yourusername/toolbox/issues
|
|
42
|
+
Project-URL: Repository, https://github.com/yourusername/toolbox
|
|
43
|
+
|
|
44
|
+
# algutils
|
|
45
|
+
|
|
46
|
+
Algorithmic utilities: data tools, I/O, parameters, paths, caching, image transforms, and math (hist, geom, regress).
|
|
47
|
+
|
|
48
|
+
Extracted from the toolbox project as a standalone, installable package.
|
|
49
|
+
|
|
50
|
+
## Installation
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# From this directory (editable)
|
|
54
|
+
pip install -e .
|
|
55
|
+
|
|
56
|
+
# With optional extras
|
|
57
|
+
pip install -e ".[io,units,dev]"
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Usage
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from algutils import logger, as_list
|
|
64
|
+
from algutils.param import TBox, YamlModel
|
|
65
|
+
from algutils.io.format import FileFormat
|
|
66
|
+
from algutils.io.imread import imread
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Development
|
|
70
|
+
|
|
71
|
+
- **pixi**: `pixi install` then `pixi run test` or `pixi run lint`
|
|
72
|
+
- **pip**: `pip install -e ".[dev]"` then `pytest src/algutils -v`
|
|
73
|
+
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
iad/core/__init__.py,sha256=4xggwbL5Zndz_oFrfs219c6P8efWRrEWnUDeP2bXhIA,149
|
|
2
|
+
iad/core/array.py,sha256=O_zxRbaucDW2Q7eEx5ARajw2lHJYpz1dvC1jxQ4RmlU,79170
|
|
3
|
+
iad/core/binary.py,sha256=vWVobeuAx7EHLqLM0RM04bWLJvZrVGTheEEYHd7N-Kc,13114
|
|
4
|
+
iad/core/cache.py,sha256=put1jCyjHa6T6ADYnJbtG4TBwe9atsH7dLO6pi1AD4k,32377
|
|
5
|
+
iad/core/codetools.py,sha256=Id9FKG8fCpaaueg3Jvc0p809BDVHBP5aW7QBeQs2fkg,6355
|
|
6
|
+
iad/core/datatools.py,sha256=CuTQs1C46wAipG9W0NtW2UztczQ2xNWjCv2nRPJnSuU,24314
|
|
7
|
+
iad/core/dotstyle.py,sha256=8gvL-whoezSmkHvDjfR9DofGHygsEhIQrNdSi_sCVCs,3226
|
|
8
|
+
iad/core/env.py,sha256=Kg84m5BDqvZG9me0xKgpnjJJV89TiAhErWXCuN4G6VQ,11259
|
|
9
|
+
iad/core/events.py,sha256=TWxAVKmUWae7EF3OdR1vQ2FksSzpBMWpxy8X7HPn-yQ,25296
|
|
10
|
+
iad/core/filesproc.py,sha256=l-vfMj4t6TyIVSmtU0bPWhsFYvnpxlL4YHHg18kpY8s,40292
|
|
11
|
+
iad/core/fnctools.py,sha256=xt6UX9O4cUlK7UdG3m7mmAgQXwpWF16zRbNLZ-yWKy4,13157
|
|
12
|
+
iad/core/label.py,sha256=WDB9syfugJ3WC4Xy42WeICi9lX9ADRradboqEn8Bhx8,8780
|
|
13
|
+
iad/core/logs.py,sha256=XO0jykx7ryr2VPX1pap_On3Da7hM9PzBGmayD_wHpK0,5973
|
|
14
|
+
iad/core/nptools.py,sha256=PoHzObTQ9JKRdgbZNeYJBSksu33tjG3A5f7o4fqk1D0,13435
|
|
15
|
+
iad/core/one_dark.puml,sha256=UPosFuJLYw460MLlYckuwUn79rZI1u6Uac7GsxPl_GA,17513
|
|
16
|
+
iad/core/paths.py,sha256=16cCCiUtRW4RLAY6RJVkOUDYNTNYwWKM4yv-bbx4sFc,22076
|
|
17
|
+
iad/core/pdtools.py,sha256=cRpEtzCQLbzTLmmmweJS77Gw820Hiluss_BqG1Ojyv0,104952
|
|
18
|
+
iad/core/regexp.py,sha256=I66EqUAZcKgy21uJY82w7oUsMII27MgGCZz6znVGKM4,12804
|
|
19
|
+
iad/core/short.py,sha256=NrSDmte61g_8qcsQV0x6hoWOqZcqTGcTrWW2_1449yM,9942
|
|
20
|
+
iad/core/strings.py,sha256=XhYgQZwS_aTbyUOHY--1XQPNHz_HPkLMuumj0t0bLoc,21743
|
|
21
|
+
iad/core/unc_panda.py,sha256=S5S5__BQb93b-tLOk9MAyxgCz0cqOtrL7FY8mvFFTpY,8916
|
|
22
|
+
iad/core/units.py,sha256=dKfP__EDbZUDaIL46u91t29JXlig74k09rJbMCyemZs,1842
|
|
23
|
+
iad/core/wrap.py,sha256=B3I0b6PxuXyE2JenIaoDCmXYocGuaFmUD4JfdlIvwco,14193
|
|
24
|
+
iad/core/docs/locators.ipynb,sha256=fCqTraIJU4tm52I6mLXgjs-piX6zf74XjTRCj-PEwoA,17402
|
|
25
|
+
iad/core/param/__init__.py,sha256=gXKFYSJx8q9AFc8X4W_S5cCPNAcIPmreN7sFuMo9uDM,623
|
|
26
|
+
iad/core/param/confargparse.py,sha256=OO-bnGgErJNvlZEPAj6_4jnR57edtw1FIJRd0ihWKi4,2326
|
|
27
|
+
iad/core/param/paramaze.py,sha256=iMuaoyRx8gOXI-kRASYsQnCN0bcHC9JWNJhLDEqVZLc,14411
|
|
28
|
+
iad/core/param/tbox.py,sha256=UzumsGhBK73itUqu9Hl-qhRAQwm8YT5dADapJxSh65M,10665
|
|
29
|
+
iad/core/pydantools/__init__.py,sha256=3tQHBGtqP460FHWMjWfT2HEIXbSVxZuxnVtvaVI5i1g,230
|
|
30
|
+
iad/core/pydantools/models.py,sha256=Oqk-Cd82vHa4FHsLbvOgP3Cupcf-Q8rVuPo25s40BMQ,21955
|
|
31
|
+
iad/core/pydantools/fixed_pydantic_yaml/__init__.py,sha256=7RZILZOdH_mHDQyIDC1bN1LmM1qNGTajVH1rp2_nKds,531
|
|
32
|
+
iad/core/pydantools/fixed_pydantic_yaml/main.py,sha256=NCRUz-MFYtiPx5RrZYJar4jig4ZZUnzMWrfZIx16uyo,774
|
|
33
|
+
iad/core/pydantools/fixed_pydantic_yaml/mixin.py,sha256=OmS05ME0JkzFx9eM39P04TlvruDHHme9jN2UyQnPIow,9741
|
|
34
|
+
iad/core/pydantools/fixed_pydantic_yaml/model.py,sha256=5soCAJQdwMec5OOSjU59mzMJHbbW7QGI6drYwNo0oRQ,569
|
|
35
|
+
iad/core/pydantools/fixed_pydantic_yaml/py.typed,sha256=DtCsIDq6KOv2NOEdQjTbeMWJKRh6ZEL2E-6Mf1RLeMA,59
|
|
36
|
+
iad/core/pydantools/fixed_pydantic_yaml/version.py,sha256=H9NWRZb7NbeRRPLP_V1fARmLNXranorVM-OOY-8_2ug,22
|
|
37
|
+
iad/core/pydantools/fixed_pydantic_yaml/compat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
38
|
+
iad/core/pydantools/fixed_pydantic_yaml/compat/hacks.py,sha256=0Bta3tgEsABwne7H0QdwN_d46wiMM25c83nAoE2YKxo,2087
|
|
39
|
+
iad/core/pydantools/fixed_pydantic_yaml/compat/old_enums.py,sha256=cjGmmS3sGHFMH0pHd82JsZHdZfmFhknnY1fq_EInIUU,963
|
|
40
|
+
iad/core/pydantools/fixed_pydantic_yaml/compat/representers.py,sha256=kWJtC5GUrrOGSMxNRtJkPWxVVu-dQX62zEQT1LeVor0,2480
|
|
41
|
+
iad/core/pydantools/fixed_pydantic_yaml/compat/types.py,sha256=knTZj52933YRhFtW69_hd4ubAlxe3njrdyOipr9Qp6o,3611
|
|
42
|
+
iad/core/pydantools/fixed_pydantic_yaml/compat/yaml_lib.py,sha256=RZoLqOh-p0qoVbIs8DdgGCc6HjDCKsTphnZG72f6nWA,3245
|
|
43
|
+
iad/core/pydantools/fixed_pydantic_yaml/ext/__init__.py,sha256=N3F4AH6kyPV8n40LKvteU1EvR5CC_gvbR92AGtaaAPs,81
|
|
44
|
+
iad/core/pydantools/fixed_pydantic_yaml/ext/semver.py,sha256=31jPcdu9A99_rMoEAKCWfzSW46ellcEhnO9Zj4h34Mc,4164
|
|
45
|
+
iad/core/pydantools/fixed_pydantic_yaml/ext/versioned_model.py,sha256=jdqMTs15XoiV8MTTFonPNB-dNuZ_bCsCKKeDFmKlPqI,3507
|
|
46
|
+
ialdev_core-0.1.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
47
|
+
ialdev_core-0.1.0.dist-info/METADATA,sha256=SWtY7F9cXXPzD8_aZ8dYgmMDYIrsmbZZTPYREUVXAQY,2278
|
|
48
|
+
ialdev_core-0.1.0.dist-info/RECORD,,
|