omlish 0.0.0.dev1__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.

Potentially problematic release.


This version of omlish might be problematic. Click here for more details.

Files changed (187) hide show
  1. omlish/__about__.py +7 -0
  2. omlish/__init__.py +0 -0
  3. omlish/argparse.py +223 -0
  4. omlish/asyncs/__init__.py +17 -0
  5. omlish/asyncs/anyio.py +23 -0
  6. omlish/asyncs/asyncio.py +19 -0
  7. omlish/asyncs/asyncs.py +76 -0
  8. omlish/asyncs/futures.py +179 -0
  9. omlish/asyncs/trio.py +11 -0
  10. omlish/c3.py +173 -0
  11. omlish/cached.py +9 -0
  12. omlish/check.py +231 -0
  13. omlish/collections/__init__.py +63 -0
  14. omlish/collections/_abc.py +156 -0
  15. omlish/collections/_io_abc.py +78 -0
  16. omlish/collections/cache/__init__.py +11 -0
  17. omlish/collections/cache/descriptor.py +188 -0
  18. omlish/collections/cache/impl.py +485 -0
  19. omlish/collections/cache/types.py +37 -0
  20. omlish/collections/coerce.py +337 -0
  21. omlish/collections/frozen.py +148 -0
  22. omlish/collections/identity.py +106 -0
  23. omlish/collections/indexed.py +75 -0
  24. omlish/collections/mappings.py +127 -0
  25. omlish/collections/ordered.py +81 -0
  26. omlish/collections/persistent.py +36 -0
  27. omlish/collections/skiplist.py +193 -0
  28. omlish/collections/sorted.py +126 -0
  29. omlish/collections/treap.py +228 -0
  30. omlish/collections/treapmap.py +144 -0
  31. omlish/collections/unmodifiable.py +174 -0
  32. omlish/collections/utils.py +110 -0
  33. omlish/configs/__init__.py +0 -0
  34. omlish/configs/flattening.py +147 -0
  35. omlish/configs/props.py +64 -0
  36. omlish/dataclasses/__init__.py +83 -0
  37. omlish/dataclasses/impl/__init__.py +6 -0
  38. omlish/dataclasses/impl/api.py +260 -0
  39. omlish/dataclasses/impl/as_.py +76 -0
  40. omlish/dataclasses/impl/exceptions.py +2 -0
  41. omlish/dataclasses/impl/fields.py +148 -0
  42. omlish/dataclasses/impl/frozen.py +55 -0
  43. omlish/dataclasses/impl/hashing.py +85 -0
  44. omlish/dataclasses/impl/init.py +173 -0
  45. omlish/dataclasses/impl/internals.py +118 -0
  46. omlish/dataclasses/impl/main.py +150 -0
  47. omlish/dataclasses/impl/metaclass.py +126 -0
  48. omlish/dataclasses/impl/metadata.py +74 -0
  49. omlish/dataclasses/impl/order.py +47 -0
  50. omlish/dataclasses/impl/params.py +150 -0
  51. omlish/dataclasses/impl/processing.py +16 -0
  52. omlish/dataclasses/impl/reflect.py +173 -0
  53. omlish/dataclasses/impl/replace.py +40 -0
  54. omlish/dataclasses/impl/repr.py +34 -0
  55. omlish/dataclasses/impl/simple.py +92 -0
  56. omlish/dataclasses/impl/slots.py +80 -0
  57. omlish/dataclasses/impl/utils.py +167 -0
  58. omlish/defs.py +193 -0
  59. omlish/dispatch/__init__.py +3 -0
  60. omlish/dispatch/dispatch.py +137 -0
  61. omlish/dispatch/functions.py +52 -0
  62. omlish/dispatch/methods.py +162 -0
  63. omlish/docker.py +149 -0
  64. omlish/dynamic.py +220 -0
  65. omlish/graphs/__init__.py +0 -0
  66. omlish/graphs/dot/__init__.py +19 -0
  67. omlish/graphs/dot/items.py +162 -0
  68. omlish/graphs/dot/rendering.py +147 -0
  69. omlish/graphs/dot/utils.py +30 -0
  70. omlish/graphs/trees.py +249 -0
  71. omlish/http/__init__.py +0 -0
  72. omlish/http/consts.py +20 -0
  73. omlish/http/wsgi.py +34 -0
  74. omlish/inject/__init__.py +85 -0
  75. omlish/inject/binder.py +12 -0
  76. omlish/inject/bindings.py +49 -0
  77. omlish/inject/eagers.py +21 -0
  78. omlish/inject/elements.py +43 -0
  79. omlish/inject/exceptions.py +49 -0
  80. omlish/inject/impl/__init__.py +0 -0
  81. omlish/inject/impl/bindings.py +19 -0
  82. omlish/inject/impl/elements.py +154 -0
  83. omlish/inject/impl/injector.py +182 -0
  84. omlish/inject/impl/inspect.py +98 -0
  85. omlish/inject/impl/private.py +109 -0
  86. omlish/inject/impl/providers.py +132 -0
  87. omlish/inject/impl/scopes.py +198 -0
  88. omlish/inject/injector.py +40 -0
  89. omlish/inject/inspect.py +14 -0
  90. omlish/inject/keys.py +43 -0
  91. omlish/inject/managed.py +24 -0
  92. omlish/inject/overrides.py +18 -0
  93. omlish/inject/private.py +29 -0
  94. omlish/inject/providers.py +111 -0
  95. omlish/inject/proxy.py +48 -0
  96. omlish/inject/scopes.py +84 -0
  97. omlish/inject/types.py +21 -0
  98. omlish/iterators.py +184 -0
  99. omlish/json.py +194 -0
  100. omlish/lang/__init__.py +112 -0
  101. omlish/lang/cached.py +267 -0
  102. omlish/lang/classes/__init__.py +24 -0
  103. omlish/lang/classes/abstract.py +74 -0
  104. omlish/lang/classes/restrict.py +137 -0
  105. omlish/lang/classes/simple.py +120 -0
  106. omlish/lang/classes/test/__init__.py +0 -0
  107. omlish/lang/classes/test/test_abstract.py +89 -0
  108. omlish/lang/classes/test/test_restrict.py +71 -0
  109. omlish/lang/classes/test/test_simple.py +58 -0
  110. omlish/lang/classes/test/test_virtual.py +72 -0
  111. omlish/lang/classes/virtual.py +130 -0
  112. omlish/lang/clsdct.py +67 -0
  113. omlish/lang/cmp.py +63 -0
  114. omlish/lang/contextmanagers.py +249 -0
  115. omlish/lang/datetimes.py +67 -0
  116. omlish/lang/descriptors.py +52 -0
  117. omlish/lang/functions.py +126 -0
  118. omlish/lang/imports.py +153 -0
  119. omlish/lang/iterables.py +54 -0
  120. omlish/lang/maybes.py +136 -0
  121. omlish/lang/objects.py +103 -0
  122. omlish/lang/resolving.py +50 -0
  123. omlish/lang/strings.py +128 -0
  124. omlish/lang/typing.py +92 -0
  125. omlish/libc.py +532 -0
  126. omlish/logs/__init__.py +9 -0
  127. omlish/logs/_abc.py +247 -0
  128. omlish/logs/configs.py +62 -0
  129. omlish/logs/filters.py +9 -0
  130. omlish/logs/formatters.py +67 -0
  131. omlish/logs/utils.py +20 -0
  132. omlish/marshal/__init__.py +52 -0
  133. omlish/marshal/any.py +25 -0
  134. omlish/marshal/base.py +201 -0
  135. omlish/marshal/base64.py +25 -0
  136. omlish/marshal/dataclasses.py +115 -0
  137. omlish/marshal/datetimes.py +90 -0
  138. omlish/marshal/enums.py +43 -0
  139. omlish/marshal/exceptions.py +7 -0
  140. omlish/marshal/factories.py +129 -0
  141. omlish/marshal/global_.py +33 -0
  142. omlish/marshal/iterables.py +57 -0
  143. omlish/marshal/mappings.py +66 -0
  144. omlish/marshal/naming.py +17 -0
  145. omlish/marshal/objects.py +106 -0
  146. omlish/marshal/optionals.py +49 -0
  147. omlish/marshal/polymorphism.py +147 -0
  148. omlish/marshal/primitives.py +43 -0
  149. omlish/marshal/registries.py +57 -0
  150. omlish/marshal/standard.py +80 -0
  151. omlish/marshal/utils.py +23 -0
  152. omlish/marshal/uuids.py +29 -0
  153. omlish/marshal/values.py +30 -0
  154. omlish/math.py +184 -0
  155. omlish/os.py +32 -0
  156. omlish/reflect.py +359 -0
  157. omlish/replserver/__init__.py +5 -0
  158. omlish/replserver/__main__.py +4 -0
  159. omlish/replserver/console.py +247 -0
  160. omlish/replserver/server.py +146 -0
  161. omlish/runmodule.py +28 -0
  162. omlish/stats.py +342 -0
  163. omlish/term.py +222 -0
  164. omlish/testing/__init__.py +7 -0
  165. omlish/testing/pydevd.py +225 -0
  166. omlish/testing/pytest/__init__.py +8 -0
  167. omlish/testing/pytest/helpers.py +35 -0
  168. omlish/testing/pytest/inject/__init__.py +1 -0
  169. omlish/testing/pytest/inject/harness.py +159 -0
  170. omlish/testing/pytest/plugins/__init__.py +20 -0
  171. omlish/testing/pytest/plugins/_registry.py +6 -0
  172. omlish/testing/pytest/plugins/logging.py +13 -0
  173. omlish/testing/pytest/plugins/pycharm.py +54 -0
  174. omlish/testing/pytest/plugins/repeat.py +19 -0
  175. omlish/testing/pytest/plugins/skips.py +32 -0
  176. omlish/testing/pytest/plugins/spacing.py +19 -0
  177. omlish/testing/pytest/plugins/switches.py +70 -0
  178. omlish/testing/testing.py +102 -0
  179. omlish/text/__init__.py +0 -0
  180. omlish/text/delimit.py +171 -0
  181. omlish/text/indent.py +50 -0
  182. omlish/text/parts.py +265 -0
  183. omlish-0.0.0.dev1.dist-info/LICENSE +21 -0
  184. omlish-0.0.0.dev1.dist-info/METADATA +17 -0
  185. omlish-0.0.0.dev1.dist-info/RECORD +187 -0
  186. omlish-0.0.0.dev1.dist-info/WHEEL +5 -0
  187. omlish-0.0.0.dev1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,50 @@
1
+ import importlib
2
+ import string
3
+ import typing as ta
4
+
5
+
6
+ class ResolvableClassNameError(NameError):
7
+ pass
8
+
9
+
10
+ def get_cls_fqcn(cls: type, *, nocheck: bool = False) -> str:
11
+ if not isinstance(cls, type):
12
+ raise TypeError(cls)
13
+ mn = cls.__module__
14
+ if set(mn) - set(string.ascii_lowercase + string.digits + '_.'):
15
+ raise ResolvableClassNameError(cls)
16
+ qn = cls.__qualname__
17
+ if not all(qp[0].isupper() for qp in qn.split('.')) or (set(qn) - set(string.ascii_letters + string.digits + '.')):
18
+ raise ResolvableClassNameError(cls)
19
+ fqcn = '.'.join([cls.__module__, cls.__qualname__])
20
+ if not nocheck:
21
+ if get_fqcn_cls(fqcn, nocheck=True) is not cls:
22
+ raise ResolvableClassNameError(cls, fqcn)
23
+ return fqcn
24
+
25
+
26
+ def get_fqcn_cls(fqcn: str, *, nocheck: bool = False) -> type:
27
+ if not isinstance(fqcn, str) or not fqcn:
28
+ raise TypeError(fqcn)
29
+ parts = fqcn.split('.')
30
+ pos = next(i for i, p in enumerate(parts) if p[0].isupper())
31
+ mps, qps = parts[:pos], parts[pos:]
32
+ mod = importlib.import_module('.'.join(mps))
33
+ o: ta.Any = mod
34
+ for qp in qps:
35
+ o = getattr(o, qp)
36
+ if not isinstance(o, type):
37
+ raise TypeError(o)
38
+ cls = o
39
+ if not isinstance(cls, type):
40
+ raise TypeError(cls)
41
+ if not nocheck:
42
+ if not get_cls_fqcn(cls, nocheck=True) == fqcn:
43
+ raise ResolvableClassNameError(cls, fqcn)
44
+ return o
45
+
46
+
47
+ class Resolvable:
48
+ def __init_subclass__(cls, **kwargs):
49
+ super().__init_subclass__(**kwargs)
50
+ get_cls_fqcn(cls, nocheck=True)
omlish/lang/strings.py ADDED
@@ -0,0 +1,128 @@
1
+ import typing as ta
2
+ import unicodedata
3
+
4
+
5
+ ##
6
+
7
+
8
+ def prefix_lines(s: str, p: str) -> str:
9
+ return '\n'.join([p + l for l in s.split('\n')])
10
+
11
+
12
+ def indent_lines(s: str, num: int) -> str:
13
+ return prefix_lines(s, ' ' * num)
14
+
15
+
16
+ ##
17
+
18
+
19
+ def camel_case(name: str) -> str:
20
+ return ''.join(map(str.capitalize, name.split('_'))) # noqa
21
+
22
+
23
+ def snake_case(name: str) -> str:
24
+ uppers: list[int | None] = [i for i, c in enumerate(name) if c.isupper()]
25
+ return '_'.join([name[l:r].lower() for l, r in zip([None] + uppers, uppers + [None])]).strip('_')
26
+
27
+
28
+ def is_dunder(name: str) -> bool:
29
+ return (
30
+ name[:2] == name[-2:] == '__' and
31
+ name[2:3] != '_' and
32
+ name[-3:-2] != '_' and
33
+ len(name) > 4
34
+ )
35
+
36
+
37
+ def is_sunder(name: str) -> bool:
38
+ return (
39
+ name[0] == name[-1] == '_' and
40
+ name[1:2] != '_' and
41
+ name[-2:-1] != '_' and
42
+ len(name) > 2
43
+ )
44
+
45
+
46
+ ##
47
+
48
+
49
+ class _CharSpec(ta.NamedTuple):
50
+ cats: ta.AbstractSet[str]
51
+ chars: ta.AbstractSet[str]
52
+
53
+
54
+ _IDENT_START_CHAR_SPEC = _CharSpec(
55
+ {
56
+ 'Ll',
57
+ 'Lm',
58
+ 'Lo',
59
+ 'Lt',
60
+ 'Lu',
61
+ 'Nl',
62
+ },
63
+ {
64
+ '_',
65
+ '\u2118',
66
+ '\u212E',
67
+ '\u309B',
68
+ '\u309C',
69
+ },
70
+ )
71
+
72
+
73
+ _IDENT_CONT_CHAR_SPEC = _CharSpec(
74
+ {
75
+ 'Ll',
76
+ 'Lm',
77
+ 'Lo',
78
+ 'Lt',
79
+ 'Lu',
80
+ 'Mc',
81
+ 'Mn',
82
+ 'Nd',
83
+ 'Nl',
84
+ 'Pc',
85
+ },
86
+ {
87
+ '_',
88
+ '\u00B7',
89
+ '\u0387',
90
+ '\u1369',
91
+ '\u136A',
92
+ '\u136B',
93
+ '\u136C',
94
+ '\u136D',
95
+ '\u136E',
96
+ '\u136F',
97
+ '\u1370',
98
+ '\u1371',
99
+ '\u19DA',
100
+ '\u2118',
101
+ '\u212E',
102
+ '\u309B',
103
+ '\u309C',
104
+ },
105
+ )
106
+
107
+
108
+ def _is_char_in_spec(spec: _CharSpec, c: str) -> bool:
109
+ if len(c) != 1:
110
+ raise ValueError(c)
111
+ return (
112
+ unicodedata.category(c) in spec.cats or
113
+ c in spec.chars or
114
+ unicodedata.category(unicodedata.normalize('NFKC', c)) in spec.cats or
115
+ unicodedata.normalize('NFKC', c) in spec.chars
116
+ )
117
+
118
+
119
+ def is_ident_start(c: str) -> bool:
120
+ return _is_char_in_spec(_IDENT_START_CHAR_SPEC, c)
121
+
122
+
123
+ def is_ident_cont(c: str) -> bool:
124
+ return _is_char_in_spec(_IDENT_CONT_CHAR_SPEC, c)
125
+
126
+
127
+ def is_ident(name: str) -> bool:
128
+ return is_ident_start(name[0]) and all(is_ident_cont(c) for c in name[1:])
omlish/lang/typing.py ADDED
@@ -0,0 +1,92 @@
1
+ """
2
+ TODO:
3
+ - typed_lambda is really kinda just 'annotate'
4
+ - TypedLambda / TypedPartial classes, picklable, reprs
5
+ - probably need to gen types per inst
6
+ """
7
+ import functools
8
+ import inspect
9
+ import typing as ta
10
+
11
+
12
+ Ty = ta.TypeVar('Ty', bound=type)
13
+
14
+
15
+ BytesLike: ta.TypeAlias = ta.Union[bytes, bytearray]
16
+
17
+
18
+ ##
19
+
20
+
21
+ def protocol_check(proto: type) -> ta.Callable[[Ty], Ty]:
22
+ def inner(cls):
23
+ if not issubclass(cls, proto):
24
+ raise TypeError(cls)
25
+ return cls
26
+ return inner
27
+
28
+
29
+ ##
30
+
31
+
32
+ _MISSING = object()
33
+
34
+
35
+ def _update_wrapper_no_anns(wrapper, wrapped):
36
+ functools.update_wrapper(wrapper, wrapped, assigned=list(set(functools.WRAPPER_ASSIGNMENTS) - {'__annotations__'}))
37
+ return wrapper
38
+
39
+
40
+ def typed_lambda(ret=_MISSING, **kw):
41
+ def inner(fn):
42
+ ns = {}
43
+ ns['__fn'] = fn
44
+ proto = ['def __lam(']
45
+ call = ['return __fn(']
46
+ pkw = {k: v for k, v in kw.items()}
47
+ for i, (n, t) in enumerate(pkw.items()):
48
+ if i:
49
+ call.append(', ')
50
+ else:
51
+ proto.append('*')
52
+ ns['__ann_' + n] = t
53
+ proto.append(f', {n}: __ann_{n}')
54
+ call.append(f'{n}={n}')
55
+ proto.append(')')
56
+ if ret is not _MISSING:
57
+ ns['__ann_return'] = ret
58
+ proto.append(f' -> __ann_return')
59
+ proto.append(':')
60
+ call.append(')')
61
+ src = f'{"".join(proto)} {"".join(call)}'
62
+ exec(src, ns)
63
+ lam = _update_wrapper_no_anns(ns['__lam'], fn)
64
+ lam.__signature__ = inspect.signature(lam, follow_wrapped=False)
65
+ return lam
66
+ for k in kw:
67
+ if k.startswith('__'):
68
+ raise NameError(k)
69
+ return inner
70
+
71
+
72
+ def typed_partial(obj, **kw):
73
+ for k in kw:
74
+ if k.startswith('__'):
75
+ raise NameError(k)
76
+ sig = inspect.signature(obj)
77
+ inner = _update_wrapper_no_anns(lambda **lkw: obj(**lkw, **kw), obj)
78
+ ret = (
79
+ obj if isinstance(obj, type) else
80
+ sig.return_annotation if sig.return_annotation is not inspect.Signature.empty else
81
+ _MISSING
82
+ )
83
+ lam = typed_lambda(
84
+ ret,
85
+ **{
86
+ n: p.annotation
87
+ for n, p in sig.parameters.items()
88
+ if n not in kw
89
+ and p.annotation is not inspect.Signature.empty
90
+ }
91
+ )(inner)
92
+ return _update_wrapper_no_anns(lam, obj)