omlish 0.0.0.dev1__py3-none-any.whl → 0.0.0.dev2__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 (102) hide show
  1. omlish/__about__.py +2 -2
  2. omlish/argparse.py +4 -4
  3. omlish/asyncs/anyio.py +62 -1
  4. omlish/asyncs/futures.py +6 -6
  5. omlish/c3.py +4 -4
  6. omlish/check.py +6 -6
  7. omlish/collections/__init__.py +98 -63
  8. omlish/collections/cache/descriptor.py +5 -5
  9. omlish/collections/cache/impl.py +4 -4
  10. omlish/collections/coerce.py +43 -43
  11. omlish/collections/frozen.py +3 -3
  12. omlish/collections/identity.py +1 -1
  13. omlish/collections/mappings.py +3 -3
  14. omlish/collections/ordered.py +1 -1
  15. omlish/collections/skiplist.py +6 -6
  16. omlish/collections/sorted.py +3 -3
  17. omlish/collections/treap.py +17 -17
  18. omlish/collections/treapmap.py +2 -2
  19. omlish/collections/unmodifiable.py +28 -27
  20. omlish/configs/flattening.py +1 -1
  21. omlish/configs/props.py +1 -1
  22. omlish/dataclasses/impl/__init__.py +2 -0
  23. omlish/dataclasses/impl/api.py +5 -13
  24. omlish/dataclasses/impl/fields.py +1 -1
  25. omlish/dataclasses/impl/init.py +1 -1
  26. omlish/dataclasses/impl/internals.py +15 -0
  27. omlish/dataclasses/impl/main.py +4 -4
  28. omlish/dataclasses/impl/metaclass.py +1 -1
  29. omlish/dataclasses/impl/metadata.py +1 -1
  30. omlish/dataclasses/impl/order.py +1 -1
  31. omlish/dataclasses/impl/params.py +4 -38
  32. omlish/dataclasses/impl/reflect.py +1 -7
  33. omlish/dataclasses/impl/repr.py +23 -5
  34. omlish/dataclasses/impl/simple.py +2 -2
  35. omlish/dataclasses/impl/slots.py +2 -2
  36. omlish/dataclasses/impl/utils.py +4 -4
  37. omlish/dispatch/dispatch.py +9 -8
  38. omlish/dispatch/methods.py +2 -2
  39. omlish/docker.py +8 -6
  40. omlish/dynamic.py +5 -5
  41. omlish/graphs/dot/items.py +1 -1
  42. omlish/graphs/trees.py +15 -21
  43. omlish/inject/elements.py +1 -1
  44. omlish/inject/exceptions.py +1 -1
  45. omlish/inject/impl/injector.py +1 -1
  46. omlish/inject/impl/inspect.py +1 -1
  47. omlish/inject/injector.py +1 -1
  48. omlish/inject/providers.py +2 -2
  49. omlish/iterators.py +43 -2
  50. omlish/lang/__init__.py +167 -112
  51. omlish/lang/cached.py +13 -5
  52. omlish/lang/classes/__init__.py +35 -24
  53. omlish/lang/classes/abstract.py +1 -1
  54. omlish/lang/classes/simple.py +1 -1
  55. omlish/lang/clsdct.py +1 -1
  56. omlish/lang/contextmanagers.py +23 -15
  57. omlish/lang/datetimes.py +1 -1
  58. omlish/lang/descriptors.py +35 -2
  59. omlish/lang/exceptions.py +2 -0
  60. omlish/lang/functions.py +43 -13
  61. omlish/lang/imports.py +8 -8
  62. omlish/lang/iterables.py +1 -1
  63. omlish/lang/maybes.py +1 -1
  64. omlish/lang/objects.py +2 -2
  65. omlish/lang/timeouts.py +53 -0
  66. omlish/lang/typing.py +2 -2
  67. omlish/libc.py +6 -6
  68. omlish/marshal/base.py +6 -6
  69. omlish/marshal/dataclasses.py +2 -2
  70. omlish/marshal/enums.py +2 -2
  71. omlish/marshal/factories.py +10 -10
  72. omlish/marshal/iterables.py +2 -2
  73. omlish/marshal/mappings.py +2 -2
  74. omlish/marshal/optionals.py +4 -4
  75. omlish/marshal/polymorphism.py +4 -4
  76. omlish/marshal/standard.py +6 -6
  77. omlish/marshal/utils.py +1 -1
  78. omlish/os.py +13 -4
  79. omlish/procfs.py +336 -0
  80. omlish/reflect.py +2 -12
  81. omlish/replserver/console.py +9 -9
  82. omlish/replserver/server.py +4 -4
  83. omlish/sql/__init__.py +0 -0
  84. omlish/sql/_abcs.py +65 -0
  85. omlish/sql/dbs.py +90 -0
  86. omlish/stats.py +3 -3
  87. omlish/testing/pydevd.py +4 -6
  88. omlish/testing/pytest/inject/__init__.py +7 -0
  89. omlish/testing/pytest/inject/harness.py +23 -1
  90. omlish/testing/pytest/plugins/__init__.py +1 -1
  91. omlish/testing/pytest/plugins/pydevd.py +12 -0
  92. omlish/testing/pytest/plugins/switches.py +2 -2
  93. omlish/testing/testing.py +5 -5
  94. omlish/text/parts.py +3 -3
  95. omlish-0.0.0.dev2.dist-info/METADATA +31 -0
  96. omlish-0.0.0.dev2.dist-info/RECORD +193 -0
  97. {omlish-0.0.0.dev1.dist-info → omlish-0.0.0.dev2.dist-info}/WHEEL +1 -1
  98. omlish/testing/pytest/plugins/pycharm.py +0 -54
  99. omlish-0.0.0.dev1.dist-info/METADATA +0 -17
  100. omlish-0.0.0.dev1.dist-info/RECORD +0 -187
  101. {omlish-0.0.0.dev1.dist-info → omlish-0.0.0.dev2.dist-info}/LICENSE +0 -0
  102. {omlish-0.0.0.dev1.dist-info → omlish-0.0.0.dev2.dist-info}/top_level.txt +0 -0
@@ -53,7 +53,7 @@ class FnProvider(Provider):
53
53
  return self.cls
54
54
 
55
55
 
56
- def fn(fn: ta.Any, cls: ta.Optional[Cls] = _Missing) -> Provider:
56
+ def fn(fn: ta.Any, cls: Cls | None = _Missing) -> Provider:
57
57
  check.not_isinstance(fn, type)
58
58
  check.callable(fn)
59
59
  if cls is _Missing:
@@ -90,7 +90,7 @@ class ConstProvider(Provider):
90
90
  return self.cls
91
91
 
92
92
 
93
- def const(v: ta.Any, cls: ta.Optional[Cls] = _Missing) -> Provider:
93
+ def const(v: ta.Any, cls: Cls | None = _Missing) -> Provider:
94
94
  if cls is _Missing:
95
95
  cls = type(v)
96
96
  return ConstProvider(v, cls)
omlish/iterators.py CHANGED
@@ -1,10 +1,12 @@
1
1
  import collections
2
2
  import functools
3
+ import heapq
3
4
  import itertools
4
5
  import typing as ta
5
6
 
6
7
 
7
8
  T = ta.TypeVar('T')
9
+ U = ta.TypeVar('U')
8
10
 
9
11
  _MISSING = object()
10
12
 
@@ -97,7 +99,7 @@ class ProxyIterator(ta.Iterator[T]):
97
99
 
98
100
  class PrefetchIterator(ta.Iterator[T]):
99
101
 
100
- def __init__(self, fn: ta.Optional[ta.Callable[[], T]] = None) -> None:
102
+ def __init__(self, fn: ta.Callable[[], T] | None = None) -> None:
101
103
  super().__init__()
102
104
 
103
105
  self._fn = fn
@@ -138,7 +140,7 @@ class RetainIterator(ta.Iterator[T]):
138
140
  return item
139
141
 
140
142
 
141
- def unzip(it: ta.Iterable[T], width: ta.Optional[int] = None) -> list:
143
+ def unzip(it: ta.Iterable[T], width: int | None = None) -> list:
142
144
  if width is None:
143
145
  if not isinstance(it, PeekIterator):
144
146
  it = PeekIterator(iter(it))
@@ -182,3 +184,42 @@ def chunk(n: int, iterable: ta.Iterable[T], strict: bool = False) -> ta.Iterator
182
184
  return iter(ret())
183
185
  else:
184
186
  return iterator
187
+
188
+
189
+ def merge_on(
190
+ function: ta.Callable[[T], U],
191
+ *its: ta.Iterable[T],
192
+ ) -> ta.Iterator[tuple[U, list[tuple[int, T]]]]:
193
+ indexed_its = [
194
+ (
195
+ (function(item), it_idx, item)
196
+ for it_idx, item in zip(itertools.repeat(it_idx), it)
197
+ )
198
+ for it_idx, it in enumerate(its)
199
+ ]
200
+
201
+ grouped_indexed_its = itertools.groupby(
202
+ heapq.merge(*indexed_its),
203
+ key=lambda item_tuple: item_tuple[0],
204
+ )
205
+
206
+ return (
207
+ (fn_item, [(it_idx, item) for _, it_idx, item in grp])
208
+ for fn_item, grp in grouped_indexed_its
209
+ )
210
+
211
+
212
+ def expand_indexed_pairs(
213
+ seq: ta.Iterable[tuple[int, T]],
214
+ default: T,
215
+ *,
216
+ width: int | None = None,
217
+ ) -> list[T]:
218
+ width_ = width
219
+ if width_ is None:
220
+ width_ = (max(idx for idx, _ in seq) + 1) if seq else 0
221
+ result = [default] * width_
222
+ for idx, value in seq:
223
+ if idx < width_:
224
+ result[idx] = value
225
+ return result
omlish/lang/__init__.py CHANGED
@@ -1,112 +1,167 @@
1
- from .cached import cached_function # noqa
2
- from .cached import cached_property # noqa
3
- from .classes import Abstract # noqa
4
- from .classes import Callable # noqa
5
- from .classes import Descriptor # noqa
6
- from .classes import Final # noqa
7
- from .classes import FinalException # noqa
8
- from .classes import LazySingleton # noqa
9
- from .classes import Marker # noqa
10
- from .classes import Namespace # noqa
11
- from .classes import NoBool # noqa
12
- from .classes import NotInstantiable # noqa
13
- from .classes import NotPicklable # noqa
14
- from .classes import PackageSealed # noqa
15
- from .classes import Picklable # noqa
16
- from .classes import Sealed # noqa
17
- from .classes import SealedException # noqa
18
- from .classes import SimpleMetaDict # noqa
19
- from .classes import Singleton # noqa
20
- from .classes import Virtual # noqa
21
- from .classes import is_abstract # noqa
22
- from .classes import is_abstract_class # noqa
23
- from .classes import is_abstract_method # noqa
24
- from .classes import make_abstract # noqa
25
- from .classes import no_bool # noqa
26
- from .classes import virtual_check # noqa
27
- from .clsdct import ClassDctFn # noqa
28
- from .clsdct import cls_dct_fn # noqa
29
- from .clsdct import get_caller_cls_dct # noqa
30
- from .clsdct import is_possibly_cls_dct # noqa
31
- from .cmp import Infinity # noqa
32
- from .cmp import InfinityType # noqa
33
- from .cmp import NegativeInfinity # noqa
34
- from .cmp import NegativeInfinityType # noqa
35
- from .cmp import cmp # noqa
36
- from .contextmanagers import ContextManaged # noqa
37
- from .contextmanagers import ContextWrapped # noqa
38
- from .contextmanagers import DefaultLockable # noqa
39
- from .contextmanagers import ExitStacked # noqa
40
- from .contextmanagers import Lockable # noqa
41
- from .contextmanagers import NOP_CONTEXT_MANAGED # noqa
42
- from .contextmanagers import NOP_CONTEXT_MANAGER # noqa
43
- from .contextmanagers import NopContextManaged # noqa
44
- from .contextmanagers import NopContextManager # noqa
45
- from .contextmanagers import a_defer # noqa
46
- from .contextmanagers import attr_setting # noqa
47
- from .contextmanagers import breakpoint_on_exception # noqa
48
- from .contextmanagers import context_var_setting # noqa
49
- from .contextmanagers import context_wrapped # noqa
50
- from .contextmanagers import default_lock # noqa
51
- from .contextmanagers import defer # noqa
52
- from .contextmanagers import disposing # noqa
53
- from .contextmanagers import maybe_managing # noqa
54
- from .datetimes import months_ago # noqa
55
- from .datetimes import parse_date # noqa
56
- from .datetimes import parse_timedelta # noqa
57
- from .datetimes import to_seconds # noqa
58
- from .descriptors import AccessForbiddenException # noqa
59
- from .descriptors import access_forbidden # noqa
60
- from .descriptors import is_method_descriptor # noqa
61
- from .descriptors import unwrap_method_descriptors # noqa
62
- from .functions import VoidException # noqa
63
- from .functions import constant # noqa
64
- from .functions import identity # noqa
65
- from .functions import is_lambda # noqa
66
- from .functions import is_none # noqa
67
- from .functions import is_not_none # noqa
68
- from .functions import maybe_call # noqa
69
- from .functions import raise_ # noqa
70
- from .functions import recurse # noqa
71
- from .functions import ticking_timeout # noqa
72
- from .functions import try_ # noqa
73
- from .functions import unwrap_func # noqa
74
- from .functions import unwrap_func_with_partials # noqa
75
- from .functions import void # noqa
76
- from .imports import import_all # noqa
77
- from .imports import import_module # noqa
78
- from .imports import import_module_attr # noqa
79
- from .imports import lazy_import # noqa
80
- from .imports import proxy_import # noqa
81
- from .imports import try_import # noqa
82
- from .imports import yield_import_all # noqa
83
- from .imports import yield_importable # noqa
84
- from .iterables import BUILTIN_SCALAR_ITERABLE_TYPES # noqa
85
- from .iterables import asrange # noqa
86
- from .iterables import exhaust # noqa
87
- from .iterables import ilen # noqa
88
- from .iterables import peek # noqa
89
- from .iterables import prodrange # noqa
90
- from .iterables import take # noqa
91
- from .maybes import Maybe # noqa
92
- from .maybes import empty # noqa
93
- from .maybes import just # noqa
94
- from .maybes import maybe # noqa
95
- from .objects import SimpleProxy # noqa
96
- from .objects import arg_repr # noqa
97
- from .objects import attr_repr # noqa
98
- from .objects import new_type # noqa
99
- from .objects import super_meta # noqa
100
- from .strings import camel_case # noqa
101
- from .strings import indent_lines # noqa
102
- from .strings import is_dunder # noqa
103
- from .strings import is_ident # noqa
104
- from .strings import is_ident_cont # noqa
105
- from .strings import is_ident_start # noqa
106
- from .strings import is_sunder # noqa
107
- from .strings import prefix_lines # noqa
108
- from .strings import snake_case # noqa
109
- from .typing import BytesLike # noqa
110
- from .typing import protocol_check # noqa
111
- from .typing import typed_lambda # noqa
112
- from .typing import typed_partial # noqa
1
+ from .cached import ( # noqa
2
+ cached_function,
3
+ cached_property,
4
+ )
5
+
6
+ from .classes import ( # noqa
7
+ Abstract,
8
+ Callable,
9
+ Descriptor,
10
+ Final,
11
+ FinalException,
12
+ LazySingleton,
13
+ Marker,
14
+ Namespace,
15
+ NoBool,
16
+ NotInstantiable,
17
+ NotPicklable,
18
+ PackageSealed,
19
+ Picklable,
20
+ Sealed,
21
+ SealedException,
22
+ SimpleMetaDict,
23
+ Singleton,
24
+ Virtual,
25
+ is_abstract,
26
+ is_abstract_class,
27
+ is_abstract_method,
28
+ make_abstract,
29
+ no_bool,
30
+ virtual_check,
31
+ )
32
+
33
+ from .clsdct import ( # noqa
34
+ ClassDctFn,
35
+ cls_dct_fn,
36
+ get_caller_cls_dct,
37
+ is_possibly_cls_dct,
38
+ )
39
+
40
+ from .cmp import ( # noqa
41
+ Infinity,
42
+ InfinityType,
43
+ NegativeInfinity,
44
+ NegativeInfinityType,
45
+ cmp,
46
+ )
47
+
48
+ from .contextmanagers import ( # noqa
49
+ ContextManaged,
50
+ ContextWrapped,
51
+ DefaultLockable,
52
+ ExitStacked,
53
+ Lockable,
54
+ NOP_CONTEXT_MANAGED,
55
+ NOP_CONTEXT_MANAGER,
56
+ NopContextManaged,
57
+ NopContextManager,
58
+ a_defer,
59
+ attr_setting,
60
+ breakpoint_on_exception,
61
+ context_var_setting,
62
+ context_wrapped,
63
+ default_lock,
64
+ defer,
65
+ disposing,
66
+ maybe_managing,
67
+ )
68
+
69
+ from .datetimes import ( # noqa
70
+ months_ago,
71
+ parse_date,
72
+ parse_timedelta,
73
+ to_seconds,
74
+ )
75
+
76
+ from .descriptors import ( # noqa
77
+ AccessForbiddenException,
78
+ access_forbidden,
79
+ classonly,
80
+ is_method_descriptor,
81
+ unwrap_method_descriptors,
82
+ )
83
+
84
+ from .exceptions import ( # noqa
85
+ Unreachable,
86
+ )
87
+
88
+ from .functions import ( # noqa
89
+ Args,
90
+ VoidException,
91
+ constant,
92
+ identity,
93
+ is_lambda,
94
+ is_none,
95
+ is_not_none,
96
+ maybe_call,
97
+ periodically,
98
+ raise_,
99
+ recurse,
100
+ try_,
101
+ unwrap_func,
102
+ unwrap_func_with_partials,
103
+ void,
104
+ )
105
+
106
+ from .imports import ( # noqa
107
+ import_all,
108
+ import_module,
109
+ import_module_attr,
110
+ lazy_import,
111
+ proxy_import,
112
+ try_import,
113
+ yield_import_all,
114
+ yield_importable,
115
+ )
116
+
117
+ from .iterables import ( # noqa
118
+ BUILTIN_SCALAR_ITERABLE_TYPES,
119
+ asrange,
120
+ exhaust,
121
+ ilen,
122
+ peek,
123
+ prodrange,
124
+ take,
125
+ )
126
+
127
+ from .maybes import ( # noqa
128
+ Maybe,
129
+ empty,
130
+ just,
131
+ maybe,
132
+ )
133
+
134
+ from .objects import ( # noqa
135
+ SimpleProxy,
136
+ arg_repr,
137
+ attr_repr,
138
+ new_type,
139
+ super_meta,
140
+ )
141
+
142
+ from .strings import ( # noqa
143
+ camel_case,
144
+ indent_lines,
145
+ is_dunder,
146
+ is_ident,
147
+ is_ident_cont,
148
+ is_ident_start,
149
+ is_sunder,
150
+ prefix_lines,
151
+ snake_case,
152
+ )
153
+
154
+ from .timeouts import ( # noqa
155
+ DeadlineTimeout,
156
+ InfiniteTimeout,
157
+ Timeout,
158
+ TimeoutLike,
159
+ timeout,
160
+ )
161
+
162
+ from .typing import ( # noqa
163
+ BytesLike,
164
+ protocol_check,
165
+ typed_lambda,
166
+ typed_partial,
167
+ )
omlish/lang/cached.py CHANGED
@@ -105,11 +105,11 @@ class _CachedFunction(ta.Generic[T]):
105
105
  opts: Opts = Opts(),
106
106
  keyer: ta.Callable[..., tuple] | None = None,
107
107
  values: ta.MutableMapping | None = None,
108
- value_fn: ta.Optional[ta.Callable[P, T]] = None,
108
+ value_fn: ta.Callable[P, T] | None = None,
109
109
  ) -> None:
110
110
  super().__init__()
111
111
 
112
- self._fn = fn
112
+ self._fn = (fn,)
113
113
  self._opts = opts
114
114
  self._keyer = keyer if keyer is not None else _make_cache_keyer(fn, simple=opts.simple_key)
115
115
 
@@ -118,6 +118,14 @@ class _CachedFunction(ta.Generic[T]):
118
118
  self._value_fn = value_fn if value_fn is not None else fn
119
119
  functools.update_wrapper(self, fn)
120
120
 
121
+ @property
122
+ def _fn(self):
123
+ return self.__fn
124
+
125
+ @_fn.setter
126
+ def _fn(self, x):
127
+ self.__fn = x
128
+
121
129
  def reset(self) -> None:
122
130
  self._values = {}
123
131
 
@@ -157,8 +165,8 @@ class _CachedFunctionDescriptor(_CachedFunction[T]):
157
165
  *,
158
166
  instance: ta.Any = None,
159
167
  owner: ta.Any = None,
160
- name: ta.Optional[str] = None,
161
- **kwargs
168
+ name: str | None = None,
169
+ **kwargs,
162
170
  ) -> None:
163
171
  super().__init__(fn, **kwargs)
164
172
 
@@ -173,7 +181,7 @@ class _CachedFunctionDescriptor(_CachedFunction[T]):
173
181
  if owner is self._owner and (instance is self._instance or scope is classmethod):
174
182
  return self
175
183
 
176
- fn = self._fn
184
+ fn, = self._fn
177
185
  name = self._name
178
186
  bound_fn = fn.__get__(instance, owner)
179
187
  if self._bound_keyer is None:
@@ -1,24 +1,35 @@
1
- from .abstract import Abstract # noqa
2
- from .abstract import is_abstract # noqa
3
- from .abstract import is_abstract_class # noqa
4
- from .abstract import is_abstract_method # noqa
5
- from .abstract import make_abstract # noqa
6
- from .restrict import Final # noqa
7
- from .restrict import FinalException # noqa
8
- from .restrict import NoBool # noqa
9
- from .restrict import NotInstantiable # noqa
10
- from .restrict import NotPicklable # noqa
11
- from .restrict import PackageSealed # noqa
12
- from .restrict import Sealed # noqa
13
- from .restrict import SealedException # noqa
14
- from .restrict import no_bool # noqa
15
- from .simple import LazySingleton # noqa
16
- from .simple import Marker # noqa
17
- from .simple import Namespace # noqa
18
- from .simple import SimpleMetaDict # noqa
19
- from .simple import Singleton # noqa
20
- from .virtual import Callable # noqa
21
- from .virtual import Descriptor # noqa
22
- from .virtual import Picklable # noqa
23
- from .virtual import Virtual # noqa
24
- from .virtual import virtual_check # noqa
1
+ from .abstract import ( # noqa
2
+ Abstract,
3
+ is_abstract,
4
+ is_abstract_class,
5
+ is_abstract_method,
6
+ make_abstract,
7
+ )
8
+
9
+ from .restrict import ( # noqa
10
+ Final,
11
+ FinalException,
12
+ NoBool,
13
+ NotInstantiable,
14
+ NotPicklable,
15
+ PackageSealed,
16
+ Sealed,
17
+ SealedException,
18
+ no_bool,
19
+ )
20
+
21
+ from .simple import ( # noqa
22
+ LazySingleton,
23
+ Marker,
24
+ Namespace,
25
+ SimpleMetaDict,
26
+ Singleton,
27
+ )
28
+
29
+ from .virtual import ( # noqa
30
+ Callable,
31
+ Descriptor,
32
+ Picklable,
33
+ Virtual,
34
+ virtual_check,
35
+ )
@@ -48,7 +48,7 @@ class Abstract(abc.ABC):
48
48
  if ams:
49
49
  raise TypeError(
50
50
  f'Cannot subclass abstract class {cls.__name__} with abstract methods'
51
- f'{", ".join(map(str, sorted(ams)))}'
51
+ f'{", ".join(map(str, sorted(ams)))}',
52
52
  )
53
53
 
54
54
 
@@ -26,7 +26,7 @@ Namespace: type = _Namespace() # type: ignore
26
26
  ##
27
27
 
28
28
 
29
- _MARKER_NAMESPACE_KEYS: ta.Optional[set[str]] = None
29
+ _MARKER_NAMESPACE_KEYS: set[str] | None = None
30
30
 
31
31
 
32
32
  class _MarkerMeta(abc.ABCMeta):
omlish/lang/clsdct.py CHANGED
@@ -37,7 +37,7 @@ def get_caller_cls_dct(offset: int = 0) -> ta.MutableMapping[str, ta.Any]:
37
37
 
38
38
  class ClassDctFn:
39
39
 
40
- def __init__(self, fn: ta.Callable, offset: ta.Optional[int] = None, *, wrap=True) -> None:
40
+ def __init__(self, fn: ta.Callable, offset: int | None = None, *, wrap=True) -> None:
41
41
  super().__init__()
42
42
 
43
43
  self._fn = fn
@@ -19,10 +19,10 @@ class ContextManaged:
19
19
 
20
20
  def __exit__(
21
21
  self,
22
- exc_type: ta.Optional[ta.Type[Exception]],
23
- exc_val: ta.Optional[Exception],
24
- exc_tb: ta.Optional[types.TracebackType]
25
- ) -> ta.Optional[bool]:
22
+ exc_type: ta.Type[Exception] | None,
23
+ exc_val: Exception | None,
24
+ exc_tb: types.TracebackType | None,
25
+ ) -> bool | None:
26
26
  return None
27
27
 
28
28
 
@@ -51,7 +51,7 @@ NOP_CONTEXT_MANAGER = NopContextManager()
51
51
 
52
52
 
53
53
  @contextlib.contextmanager
54
- def defer(fn: ta.Callable) -> ta.Iterator[ta.Callable]:
54
+ def defer(fn: ta.Callable) -> ta.Generator[ta.Callable, None, None]:
55
55
  try:
56
56
  yield fn
57
57
  finally:
@@ -59,7 +59,7 @@ def defer(fn: ta.Callable) -> ta.Iterator[ta.Callable]:
59
59
 
60
60
 
61
61
  @contextlib.asynccontextmanager
62
- async def a_defer(fn: ta.Awaitable) -> ta.AsyncIterator[ta.Awaitable]:
62
+ async def a_defer(fn: ta.Awaitable) -> ta.AsyncGenerator[ta.Awaitable, None]:
63
63
  try:
64
64
  yield fn
65
65
  finally:
@@ -146,10 +146,10 @@ class ExitStacked:
146
146
 
147
147
  def __exit__(
148
148
  self,
149
- exc_type: ta.Optional[ta.Type[Exception]],
150
- exc_val: ta.Optional[Exception],
151
- exc_tb: ta.Optional[types.TracebackType]
152
- ) -> ta.Optional[bool]:
149
+ exc_type: ta.Type[Exception] | None,
150
+ exc_val: Exception | None,
151
+ exc_tb: types.TracebackType | None,
152
+ ) -> bool | None:
153
153
  self._exit_stack.__exit__(exc_type, exc_val, exc_tb)
154
154
  try:
155
155
  superfn = super().__exit__ # type: ignore
@@ -162,20 +162,28 @@ class ExitStacked:
162
162
  ##
163
163
 
164
164
 
165
- ContextWrappable: ta.TypeAlias = ta.Union[ta.ContextManager, str, ta.Callable[..., ta.ContextManager]]
165
+ ContextWrappable: ta.TypeAlias = ta.ContextManager | str | ta.Callable[..., ta.ContextManager]
166
166
 
167
167
 
168
168
  class ContextWrapped:
169
169
 
170
- def __init__(self, fn: ta.Callable, cm: ta.Union[str, ContextWrappable]) -> None:
170
+ def __init__(self, fn: ta.Callable, cm: str | ContextWrappable) -> None:
171
171
  super().__init__()
172
172
 
173
- self._fn = fn
173
+ self._fn = (fn,)
174
174
  self._cm = cm
175
175
  self._name: str | None = None
176
176
 
177
177
  functools.update_wrapper(self, fn)
178
178
 
179
+ @property
180
+ def _fn(self):
181
+ return self.__fn
182
+
183
+ @_fn.setter
184
+ def _fn(self, x):
185
+ self.__fn = x
186
+
179
187
  def __set_name__(self, owner, name):
180
188
  if name is not None:
181
189
  if self._name is not None:
@@ -187,7 +195,7 @@ class ContextWrapped:
187
195
  def __get__(self, instance, owner=None):
188
196
  if instance is None and owner is None:
189
197
  return self
190
- fn = self._fn.__get__(instance, owner) # noqa
198
+ fn = self._fn[0].__get__(instance, owner) # noqa
191
199
  cm: ta.Any = self._cm
192
200
  if isinstance(self._cm, str):
193
201
  if instance is not None:
@@ -217,7 +225,7 @@ class ContextWrapped:
217
225
  if not hasattr(cm, '__enter__') and callable(cm):
218
226
  cm = cm(*args, **kwargs)
219
227
  with cm: # type: ignore
220
- return self._fn(*args, **kwargs)
228
+ return self._fn[0](*args, **kwargs)
221
229
 
222
230
 
223
231
  def context_wrapped(cm): # ContextWrappable -> ta.Callable[[CallableT], CallableT]:
omlish/lang/datetimes.py CHANGED
@@ -62,6 +62,6 @@ def parse_timedelta(s: str) -> datetime.timedelta:
62
62
  for k, v in match.groupdict().items()
63
63
  if k != 'negative' and v is not None}
64
64
  if not timedelta_kwargs:
65
- raise ValueError()
65
+ raise ValueError
66
66
  sign = -1 if match.groupdict().get('negative') else 1
67
67
  return sign * datetime.timedelta(**timedelta_kwargs)
@@ -1,6 +1,10 @@
1
+ import functools
1
2
  import typing as ta
2
3
 
3
4
 
5
+ T = ta.TypeVar('T')
6
+
7
+
4
8
  ##
5
9
 
6
10
 
@@ -26,14 +30,14 @@ def unwrap_method_descriptors(fn: ta.Callable) -> ta.Callable:
26
30
 
27
31
  class AccessForbiddenException(Exception):
28
32
 
29
- def __init__(self, name: ta.Optional[str] = None, *args: ta.Any, **kwargs: ta.Any) -> None:
33
+ def __init__(self, name: str | None = None, *args: ta.Any, **kwargs: ta.Any) -> None:
30
34
  super().__init__(*((name,) if name is not None else ()), *args, **kwargs) # noqa
31
35
  self.name = name
32
36
 
33
37
 
34
38
  class AccessForbiddenDescriptor:
35
39
 
36
- def __init__(self, name: ta.Optional[str] = None) -> None:
40
+ def __init__(self, name: str | None = None) -> None:
37
41
  super().__init__()
38
42
 
39
43
  self._name = name
@@ -50,3 +54,32 @@ class AccessForbiddenDescriptor:
50
54
 
51
55
  def access_forbidden():
52
56
  return AccessForbiddenDescriptor()
57
+
58
+
59
+ ##
60
+
61
+
62
+ class _ClassOnly:
63
+ def __init__(self, mth):
64
+ if not isinstance(mth, classmethod):
65
+ raise TypeError(f'must be classmethod: {mth}')
66
+ super().__init__()
67
+ self._mth = (mth,)
68
+ functools.update_wrapper(self, mth) # type: ignore
69
+
70
+ @property
71
+ def _mth(self):
72
+ return self.__mth
73
+
74
+ @_mth.setter
75
+ def _mth(self, x):
76
+ self.__mth = x
77
+
78
+ def __get__(self, instance, owner):
79
+ if instance is not None:
80
+ raise TypeError(f'method must not be used on instance: {self._mth}')
81
+ return self._mth[0].__get__(instance, owner)
82
+
83
+
84
+ def classonly(obj: T) -> T: # noqa
85
+ return _ClassOnly(obj) # type: ignore
@@ -0,0 +1,2 @@
1
+ class Unreachable(Exception):
2
+ pass