omlish 0.0.0.dev425__py3-none-any.whl → 0.0.0.dev426__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 (46) hide show
  1. omlish/__about__.py +2 -2
  2. omlish/c3.py +4 -1
  3. omlish/configs/processing/flattening.py +1 -1
  4. omlish/configs/processing/merging.py +8 -6
  5. omlish/dataclasses/impl/concerns/doc.py +1 -1
  6. omlish/diag/_pycharm/runhack.py +1 -1
  7. omlish/diag/procfs.py +2 -2
  8. omlish/formats/json/stream/lexing.py +63 -16
  9. omlish/formats/json/stream/parsing.py +1 -1
  10. omlish/formats/json/stream/utils.py +2 -2
  11. omlish/formats/logfmt.py +8 -2
  12. omlish/funcs/genmachine.py +1 -1
  13. omlish/http/sse.py +1 -1
  14. omlish/inject/impl/injector.py +1 -1
  15. omlish/inject/impl/multis.py +2 -2
  16. omlish/inject/impl/providers.py +0 -4
  17. omlish/inject/impl/proxy.py +0 -2
  18. omlish/inject/scopes.py +0 -4
  19. omlish/io/buffers.py +1 -1
  20. omlish/lang/__init__.py +23 -13
  21. omlish/lang/{attrs.py → attrstorage.py} +15 -15
  22. omlish/lang/cached/property.py +2 -2
  23. omlish/lang/classes/simple.py +26 -4
  24. omlish/lang/collections.py +1 -1
  25. omlish/lang/iterables.py +2 -2
  26. omlish/lifecycles/contextmanagers.py +1 -1
  27. omlish/lifecycles/controller.py +1 -1
  28. omlish/lite/asyncs.py +5 -0
  29. omlish/lite/attrops.py +332 -0
  30. omlish/lite/cached.py +1 -1
  31. omlish/lite/maybes.py +2 -0
  32. omlish/lite/strings.py +0 -7
  33. omlish/lite/timing.py +4 -1
  34. omlish/logs/all.py +4 -0
  35. omlish/logs/modules.py +10 -0
  36. omlish/logs/times.py +2 -5
  37. omlish/os/atomics.py +1 -1
  38. omlish/reflect/types.py +22 -0
  39. {omlish-0.0.0.dev425.dist-info → omlish-0.0.0.dev426.dist-info}/METADATA +2 -2
  40. {omlish-0.0.0.dev425.dist-info → omlish-0.0.0.dev426.dist-info}/RECORD +44 -44
  41. omlish/lite/logs.py +0 -4
  42. omlish/lite/reprs.py +0 -85
  43. {omlish-0.0.0.dev425.dist-info → omlish-0.0.0.dev426.dist-info}/WHEEL +0 -0
  44. {omlish-0.0.0.dev425.dist-info → omlish-0.0.0.dev426.dist-info}/entry_points.txt +0 -0
  45. {omlish-0.0.0.dev425.dist-info → omlish-0.0.0.dev426.dist-info}/licenses/LICENSE +0 -0
  46. {omlish-0.0.0.dev425.dist-info → omlish-0.0.0.dev426.dist-info}/top_level.txt +0 -0
omlish/lite/asyncs.py CHANGED
@@ -1,3 +1,4 @@
1
+ # ruff: noqa: UP045
1
2
  import functools
2
3
  import typing as ta
3
4
 
@@ -8,6 +9,10 @@ T = ta.TypeVar('T')
8
9
  ##
9
10
 
10
11
 
12
+ async def opt_await(aw: ta.Optional[ta.Awaitable[T]]) -> ta.Optional[T]:
13
+ return (await aw if aw is not None else None)
14
+
15
+
11
16
  def as_async(fn: ta.Callable[..., T], *, wrap: bool = False) -> ta.Callable[..., ta.Awaitable[T]]:
12
17
  async def inner(*args, **kwargs):
13
18
  return fn(*args, **kwargs)
omlish/lite/attrops.py ADDED
@@ -0,0 +1,332 @@
1
+ # ruff: noqa: UP006 UP007 UP045
2
+ # @omlish-lite
3
+ """
4
+ TODO:
5
+ - dotted paths!
6
+ - per-attr repr transform / filter
7
+ - __ne__ ? cases where it still matters
8
+ - ordering ?
9
+ """
10
+ import types # noqa
11
+ import typing as ta
12
+
13
+
14
+ T = ta.TypeVar('T')
15
+
16
+
17
+ ##
18
+
19
+
20
+ @ta.final
21
+ class AttrOps(ta.Generic[T]):
22
+ @ta.final
23
+ class Attr:
24
+ def __init__(
25
+ self,
26
+ name: str,
27
+ *,
28
+ display: ta.Optional[str] = None,
29
+
30
+ repr: bool = True, # noqa
31
+ hash: bool = True, # noqa
32
+ eq: bool = True,
33
+ ) -> None:
34
+ if '.' in name:
35
+ raise NotImplementedError('Dotted paths not yet supported')
36
+ if not name.isidentifier() or name.startswith('__'):
37
+ raise AttributeError(f'Invalid attr: {name!r}')
38
+ self._name = name
39
+
40
+ if display is None:
41
+ display = name[1:] if name.startswith('_') and len(name) > 1 else name
42
+ self._display = display
43
+
44
+ self._repr = repr
45
+ self._hash = hash
46
+ self._eq = eq
47
+
48
+ @classmethod
49
+ def of(
50
+ cls,
51
+ o: ta.Union[
52
+ str,
53
+ ta.Tuple[str, str],
54
+ 'AttrOps.Attr',
55
+ ],
56
+ ) -> 'AttrOps.Attr':
57
+ if isinstance(o, AttrOps.Attr):
58
+ return o
59
+ elif isinstance(o, str):
60
+ return cls(o)
61
+ else:
62
+ name, disp = o
63
+ return cls(
64
+ name,
65
+ display=disp,
66
+ )
67
+
68
+ @property
69
+ def name(self) -> str:
70
+ return self._name
71
+
72
+ @property
73
+ def display(self) -> str:
74
+ return self._display
75
+
76
+ @property
77
+ def hash(self) -> bool:
78
+ return self._hash
79
+
80
+ @property
81
+ def eq(self) -> bool:
82
+ return self._eq
83
+
84
+ @ta.overload
85
+ def __init__(
86
+ self,
87
+ *attrs: ta.Sequence[ta.Union[
88
+ str,
89
+ ta.Tuple[str, str],
90
+ Attr,
91
+ ]],
92
+ with_module: bool = False,
93
+ use_qualname: bool = False,
94
+ with_id: bool = False,
95
+ repr_filter: ta.Optional[ta.Callable[[ta.Any], bool]] = None,
96
+ recursive: bool = False,
97
+ subtypes_eq: bool = False,
98
+ ) -> None:
99
+ ...
100
+
101
+ @ta.overload
102
+ def __init__(
103
+ self,
104
+ attrs_fn: ta.Callable[[T], ta.Tuple[ta.Union[
105
+ ta.Any,
106
+ ta.Tuple[str, ta.Any],
107
+ Attr,
108
+ ], ...]],
109
+ /,
110
+ *,
111
+ with_module: bool = False,
112
+ use_qualname: bool = False,
113
+ with_id: bool = False,
114
+ repr_filter: ta.Optional[ta.Callable[[ta.Any], bool]] = None,
115
+ recursive: bool = False,
116
+ subtypes_eq: bool = False,
117
+ ) -> None:
118
+ ...
119
+
120
+ def __init__(
121
+ self,
122
+ *args,
123
+ with_module=False,
124
+ use_qualname=False,
125
+ with_id=False,
126
+ repr_filter=None,
127
+ recursive=False,
128
+ subtypes_eq=False,
129
+ ) -> None:
130
+ if args and len(args) == 1 and callable(args[0]):
131
+ self._attrs: ta.Sequence[AttrOps.Attr] = self._capture_attrs(args[0])
132
+ else:
133
+ self._attrs = list(map(AttrOps.Attr.of, args))
134
+
135
+ self._with_module: bool = with_module
136
+ self._use_qualname: bool = use_qualname
137
+ self._with_id: bool = with_id
138
+ self._repr_filter: ta.Optional[ta.Callable[[ta.Any], bool]] = repr_filter
139
+ self._recursive: bool = recursive
140
+ self._subtypes_eq: bool = subtypes_eq
141
+
142
+ @property
143
+ def attrs(self) -> ta.Sequence[Attr]:
144
+ return self._attrs
145
+
146
+ #
147
+
148
+ @ta.final
149
+ class _AttrCapturer:
150
+ def __init__(self, fn):
151
+ self.__fn = fn
152
+
153
+ def __getattr__(self, attr):
154
+ return self.__fn(self, attr)
155
+
156
+ @classmethod
157
+ def _capture_attrs(cls, fn: ta.Callable) -> ta.Sequence[Attr]:
158
+ def access(parent, attr):
159
+ dct[(ret := cls._AttrCapturer(access))] = (parent, attr)
160
+ return ret
161
+
162
+ dct: dict = {}
163
+ raw = fn(root := cls._AttrCapturer(access))
164
+
165
+ def rec(cap): # noqa
166
+ if cap is root:
167
+ return
168
+ parent, attr = dct[cap]
169
+ yield from rec(parent)
170
+ yield attr
171
+
172
+ attrs: ta.List[AttrOps.Attr] = []
173
+ for o in raw:
174
+ if isinstance(o, AttrOps.Attr):
175
+ attrs.append(o)
176
+ continue
177
+
178
+ if isinstance(o, tuple):
179
+ disp, cap, = o
180
+ else:
181
+ disp, cap = None, o
182
+
183
+ path = tuple(rec(cap))
184
+
185
+ attrs.append(AttrOps.Attr(
186
+ '.'.join(path),
187
+ display=disp,
188
+ ))
189
+
190
+ return attrs
191
+
192
+ #
193
+
194
+ _repr: ta.Callable[[T], str]
195
+
196
+ @property
197
+ def repr(self) -> ta.Callable[[T], str]:
198
+ try:
199
+ return self._repr
200
+ except AttributeError:
201
+ pass
202
+
203
+ def _repr(o: T) -> str:
204
+ vs = ', '.join(
205
+ f'{a._display}={v!r}' # noqa
206
+ for a in self._attrs
207
+ if a._repr # noqa
208
+ for v in [getattr(o, a._name)] # noqa
209
+ if self._repr_filter is None or self._repr_filter(v)
210
+ )
211
+
212
+ return (
213
+ f'{o.__class__.__module__ + "." if self._with_module else ""}'
214
+ f'{o.__class__.__qualname__ if self._use_qualname else o.__class__.__name__}'
215
+ f'{("@" + hex(id(o))[2:]) if self._with_id else ""}'
216
+ f'({vs})'
217
+ )
218
+
219
+ if self._recursive:
220
+ _repr = self._reprlib().recursive_repr()(_repr)
221
+
222
+ self._repr = _repr
223
+ return _repr
224
+
225
+ _reprlib_: ta.ClassVar[ta.Any]
226
+
227
+ @classmethod
228
+ def _reprlib(cls) -> ta.Any:
229
+ try:
230
+ return cls._reprlib_
231
+ except AttributeError:
232
+ pass
233
+
234
+ import reprlib # noqa
235
+
236
+ cls._reprlib_ = reprlib
237
+ return reprlib
238
+
239
+ #
240
+
241
+ _hash: ta.Callable[[T], int]
242
+
243
+ @property
244
+ def hash(self) -> ta.Callable[[T], int]:
245
+ try:
246
+ return self._hash
247
+ except AttributeError:
248
+ pass
249
+
250
+ def _hash(o: T) -> int:
251
+ return hash(tuple(
252
+ getattr(o, a._name) # noqa
253
+ for a in self._attrs
254
+ if a._hash # noqa
255
+ ))
256
+
257
+ self._hash = _hash
258
+ return _hash
259
+
260
+ #
261
+
262
+ _eq: ta.Callable[[T, ta.Any], ta.Union[bool, 'types.NotImplementedType']]
263
+
264
+ @property
265
+ def eq(self) -> ta.Callable[[T, ta.Any], ta.Union[bool, 'types.NotImplementedType']]:
266
+ try:
267
+ return self._eq
268
+ except AttributeError:
269
+ pass
270
+
271
+ def _eq(o: T, x: ta.Any) -> 'ta.Union[bool, types.NotImplementedType]':
272
+ if self._subtypes_eq:
273
+ if not isinstance(x, type(o)):
274
+ return NotImplemented
275
+ else:
276
+ if type(x) is not type(o):
277
+ return NotImplemented
278
+
279
+ return all(
280
+ getattr(o, a._name) == getattr(x, a._name) # noqa
281
+ for a in self._attrs
282
+ if a._eq # noqa
283
+ )
284
+
285
+ self._eq = _eq
286
+ return _eq
287
+
288
+ #
289
+
290
+ @property
291
+ def hash_eq(self) -> ta.Tuple[
292
+ ta.Callable[[T], int],
293
+ ta.Callable[[T, ta.Any], ta.Union[bool, 'types.NotImplementedType']],
294
+ ]:
295
+ return (self.hash, self.eq)
296
+
297
+ @property
298
+ def repr_hash_eq(self) -> ta.Tuple[
299
+ ta.Callable[[T], str],
300
+ ta.Callable[[T], int],
301
+ ta.Callable[[T, ta.Any], ta.Union[bool, 'types.NotImplementedType']],
302
+ ]:
303
+ return (self.repr, self.hash, self.eq)
304
+
305
+ #
306
+
307
+ def install(
308
+ self,
309
+ locals_dct: ta.MutableMapping[str, ta.Any],
310
+ *,
311
+ all: bool = False, # noqa
312
+ repr: bool = False, # noqa
313
+ hash: bool = False, # noqa
314
+ eq: bool = False,
315
+ ) -> 'AttrOps[T]':
316
+ if repr or all:
317
+ locals_dct.update(__repr__=self.repr)
318
+ if hash or all:
319
+ locals_dct.update(__hash__=self.hash)
320
+ if eq or all:
321
+ locals_dct.update(__eq__=self.eq)
322
+ return self
323
+
324
+
325
+ attr_ops = AttrOps[ta.Any]
326
+
327
+
328
+ ##
329
+
330
+
331
+ def attr_repr(obj: ta.Any, *attrs: str, **kwargs: ta.Any) -> str:
332
+ return AttrOps(*attrs, **kwargs).repr(obj)
omlish/lite/cached.py CHANGED
@@ -21,7 +21,7 @@ class _AbstractCachedNullary:
21
21
  def __call__(self, *args, **kwargs): # noqa
22
22
  raise TypeError
23
23
 
24
- def __get__(self, instance, owner): # noqa
24
+ def __get__(self, instance, owner=None): # noqa
25
25
  bound = instance.__dict__[self._fn.__name__] = self.__class__(self._fn.__get__(instance, owner))
26
26
  return bound
27
27
 
omlish/lite/maybes.py CHANGED
@@ -148,6 +148,7 @@ class _Maybe(Maybe[T], Abstract):
148
148
  return op and not sp
149
149
 
150
150
 
151
+ @ta.final
151
152
  class _JustMaybe(_Maybe[T]):
152
153
  __slots__ = ('_v', '_hash')
153
154
 
@@ -185,6 +186,7 @@ class _JustMaybe(_Maybe[T]):
185
186
  )
186
187
 
187
188
 
189
+ @ta.final
188
190
  class _EmptyMaybe(_Maybe[T]):
189
191
  __slots__ = ()
190
192
 
omlish/lite/strings.py CHANGED
@@ -73,13 +73,6 @@ def split_keep_delimiter(s, d):
73
73
  ##
74
74
 
75
75
 
76
- def attr_repr(obj: ta.Any, *attrs: str) -> str:
77
- return f'{type(obj).__name__}({", ".join(f"{attr}={getattr(obj, attr)!r}" for attr in attrs)})'
78
-
79
-
80
- ##
81
-
82
-
83
76
  FORMAT_NUM_BYTES_SUFFIXES: ta.Sequence[str] = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB']
84
77
 
85
78
 
omlish/lite/timing.py CHANGED
@@ -1,6 +1,9 @@
1
+ from ..logs.modules import get_module_logger
1
2
  from ..logs.utils import LogTimingContext
2
3
  from ..logs.utils import log_timing_context
3
- from .logs import log
4
+
5
+
6
+ log = get_module_logger(globals()) # noqa
4
7
 
5
8
 
6
9
  LogTimingContext.DEFAULT_LOG = log
omlish/logs/all.py CHANGED
@@ -36,6 +36,10 @@ with _lang.auto_proxy_init(globals()):
36
36
  NamedLogLevel,
37
37
  )
38
38
 
39
+ from .modules import ( # noqa
40
+ get_module_logger,
41
+ )
42
+
39
43
  from .protocols import ( # noqa
40
44
  LoggerLike,
41
45
  )
omlish/logs/modules.py ADDED
@@ -0,0 +1,10 @@
1
+ # @omlish-lite
2
+ import logging
3
+ import typing as ta
4
+
5
+
6
+ ##
7
+
8
+
9
+ def get_module_logger(mod_globals: ta.Mapping[str, ta.Any]) -> logging.Logger:
10
+ return logging.getLogger(mod_globals.get('__name__'))
omlish/logs/times.py CHANGED
@@ -72,16 +72,13 @@ class UnexpectedLoggingStartTimeWarning(LoggingSetupWarning):
72
72
 
73
73
 
74
74
  def _check_logging_start_time() -> None:
75
- x = LoggingTimeFields.get_std_start_time_ns()
76
- ns = time.time_ns()
77
-
78
- if x > ns:
75
+ if (x := LoggingTimeFields.get_std_start_time_ns()) < (t := time.time()):
79
76
  import warnings # noqa
80
77
 
81
78
  warnings.warn(
82
79
  f'Unexpected logging start time detected: '
83
80
  f'get_std_start_time_ns={x}, '
84
- f'time.time_ns()={ns}',
81
+ f'time.time()={t}',
85
82
  UnexpectedLoggingStartTimeWarning,
86
83
  )
87
84
 
omlish/os/atomics.py CHANGED
@@ -7,8 +7,8 @@ import tempfile
7
7
  import typing as ta
8
8
 
9
9
  from ..lite.abstract import Abstract
10
+ from ..lite.attrops import attr_repr
10
11
  from ..lite.check import check
11
- from ..lite.strings import attr_repr
12
12
 
13
13
 
14
14
  AtomicPathSwapKind = ta.Literal['dir', 'file']
omlish/reflect/types.py CHANGED
@@ -407,6 +407,16 @@ class ReflectTypeError(TypeError):
407
407
  pass
408
408
 
409
409
 
410
+ _TRIVIAL_TYPES: set[ta.Any] = {
411
+ bool,
412
+ int,
413
+ str,
414
+ float,
415
+ object,
416
+ type(None),
417
+ }
418
+
419
+
410
420
  class Reflector:
411
421
  def __init__(
412
422
  self,
@@ -448,12 +458,24 @@ class Reflector:
448
458
  if obj is ta.Any:
449
459
  return ANY
450
460
 
461
+ ##
462
+ # Trivial
463
+
464
+ try:
465
+ if obj in _TRIVIAL_TYPES:
466
+ return obj
467
+ except TypeError:
468
+ pass
469
+
451
470
  ##
452
471
  # Already a Type?
453
472
 
454
473
  if isinstance(obj, (ta.TypeVar, TypeInfo)): # noqa
455
474
  return obj
456
475
 
476
+ ##
477
+ # It's a type
478
+
457
479
  oty = type(obj)
458
480
 
459
481
  ##
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: omlish
3
- Version: 0.0.0.dev425
3
+ Version: 0.0.0.dev426
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License-Expression: BSD-3-Clause
@@ -296,7 +296,7 @@ examples are:
296
296
  - **wrapt** - For (optionally-enabled) injector circular proxies.
297
297
  - **greenlet** - For some gnarly stuff like the
298
298
  [sync<->async bridge](https://github.com/wrmsr/omlish/blob/master/omlish/asyncs/bridge.py) and the
299
- [io trampoline](https://github.com/wrmsr/omlish/blob/master/omlish/io/trampoline.py).
299
+ [io trampoline](https://github.com/wrmsr/omlish/blob/master/omextra/io/trampoline.py).
300
300
  - **sqlalchemy** - Parts of the codebase use SQLAlchemy for db stuff, but it is being migrated away from in favor of the
301
301
  internal api. It will however likely still remain as an optional dep for the api adapter.
302
302