omlish 0.0.0.dev471__py3-none-any.whl → 0.0.0.dev472__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.
omlish/__about__.py CHANGED
@@ -1,5 +1,5 @@
1
- __version__ = '0.0.0.dev471'
2
- __revision__ = '2a1fe39e9894efdf0e28923ddd0067f441d9d964'
1
+ __version__ = '0.0.0.dev472'
2
+ __revision__ = '78c62ff9afe49d9f0ae12b27ff595b2079e9c082'
3
3
 
4
4
 
5
5
  #
omlish/lite/abstract.py CHANGED
@@ -3,6 +3,9 @@ import abc
3
3
  import typing as ta
4
4
 
5
5
 
6
+ T = ta.TypeVar('T')
7
+
8
+
6
9
  ##
7
10
 
8
11
 
@@ -14,25 +17,49 @@ def is_abstract_method(obj: ta.Any) -> bool:
14
17
  return bool(getattr(obj, _IS_ABSTRACT_METHOD_ATTR, False))
15
18
 
16
19
 
17
- def update_abstracts(cls, *, force=False):
20
+ def compute_abstract_methods(cls: type) -> ta.FrozenSet[str]:
21
+ # ~> https://github.com/python/cpython/blob/f3476c6507381ca860eec0989f53647b13517423/Modules/_abc.c#L358
22
+
23
+ # Stage 1: direct abstract methods
24
+
25
+ abstracts = {
26
+ a
27
+ # Get items as a list to avoid mutation issues during iteration
28
+ for a, v in list(cls.__dict__.items())
29
+ if is_abstract_method(v)
30
+ }
31
+
32
+ # Stage 2: inherited abstract methods
33
+
34
+ for base in cls.__bases__:
35
+ # Get __abstractmethods__ from base if it exists
36
+ if (base_abstracts := getattr(base, _ABSTRACT_METHODS_ATTR, None)) is None:
37
+ continue
38
+
39
+ # Iterate over abstract methods in base
40
+ for key in base_abstracts:
41
+ # Check if this class has an attribute with this name
42
+ try:
43
+ value = getattr(cls, key)
44
+ except AttributeError:
45
+ # Attribute not found in this class, skip
46
+ continue
47
+
48
+ # Check if it's still abstract
49
+ if is_abstract_method(value):
50
+ abstracts.add(key)
51
+
52
+ return frozenset(abstracts)
53
+
54
+
55
+ def update_abstracts(cls: ta.Type[T], *, force: bool = False) -> ta.Type[T]:
18
56
  if not force and not hasattr(cls, _ABSTRACT_METHODS_ATTR):
19
57
  # Per stdlib: We check for __abstractmethods__ here because cls might by a C implementation or a python
20
58
  # implementation (especially during testing), and we want to handle both cases.
21
59
  return cls
22
60
 
23
- abstracts: ta.Set[str] = set()
24
-
25
- for scls in cls.__bases__:
26
- for name in getattr(scls, _ABSTRACT_METHODS_ATTR, ()):
27
- value = getattr(cls, name, None)
28
- if getattr(value, _IS_ABSTRACT_METHOD_ATTR, False):
29
- abstracts.add(name)
30
-
31
- for name, value in cls.__dict__.items():
32
- if getattr(value, _IS_ABSTRACT_METHOD_ATTR, False):
33
- abstracts.add(name)
34
-
35
- setattr(cls, _ABSTRACT_METHODS_ATTR, frozenset(abstracts))
61
+ abstracts = compute_abstract_methods(cls)
62
+ setattr(cls, _ABSTRACT_METHODS_ATTR, abstracts)
36
63
  return cls
37
64
 
38
65
 
@@ -86,23 +113,26 @@ class Abstract:
86
113
  super().__init_subclass__(**kwargs)
87
114
 
88
115
  if not (Abstract in cls.__bases__ or abc.ABC in cls.__bases__):
89
- ams = {a: cls for a, o in cls.__dict__.items() if is_abstract_method(o)}
90
-
91
- seen = set(cls.__dict__)
92
- for b in cls.__bases__:
93
- ams.update({a: b for a in set(getattr(b, _ABSTRACT_METHODS_ATTR, [])) - seen}) # noqa
94
- seen.update(dir(b))
116
+ if ams := compute_abstract_methods(cls):
117
+ amd = {
118
+ a: mcls
119
+ for mcls in cls.__mro__[::-1]
120
+ for a in ams
121
+ if a in mcls.__dict__
122
+ }
95
123
 
96
- if ams:
97
124
  raise AbstractTypeError(
98
125
  f'Cannot subclass abstract class {cls.__name__} with abstract methods: ' +
99
126
  ', '.join(sorted([
100
127
  '.'.join([
101
- *([m] if (m := getattr(c, '__module__')) else []),
102
- getattr(c, '__qualname__', getattr(c, '__name__')),
128
+ *([
129
+ *([m] if (m := getattr(c, '__module__')) else []),
130
+ getattr(c, '__qualname__', getattr(c, '__name__')),
131
+ ] if c is not None else '?'),
103
132
  a,
104
133
  ])
105
- for a, c in ams.items()
134
+ for a in ams
135
+ for c in [amd.get(a)]
106
136
  ])),
107
137
  )
108
138
 
@@ -191,3 +191,17 @@ def dataclass_kw_only_init():
191
191
  return cls
192
192
 
193
193
  return inner
194
+
195
+
196
+ ##
197
+
198
+
199
+ @dc.dataclass()
200
+ class DataclassFieldRequiredError(Exception):
201
+ name: str
202
+
203
+
204
+ def dataclass_field_required(name: str) -> ta.Callable[[], ta.Any]:
205
+ def inner() -> ta.NoReturn:
206
+ raise DataclassFieldRequiredError(name)
207
+ return inner
@@ -141,7 +141,10 @@ class AsyncsFixture:
141
141
  finally:
142
142
  nursery_fixture.cancel_scope.cancel()
143
143
 
144
- except BaseException as exc: # noqa
144
+ except* (Skipped, XFailed):
145
+ pass
146
+
147
+ except* BaseException as exc: # noqa
145
148
  test_ctx.crash(self, exc)
146
149
 
147
150
  finally:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: omlish
3
- Version: 0.0.0.dev471
3
+ Version: 0.0.0.dev472
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License-Expression: BSD-3-Clause
@@ -1,5 +1,5 @@
1
1
  omlish/.omlish-manifests.json,sha256=FLw7xkPiSXuImZgqSP8BwrEib2R1doSzUPLUkc-QUIA,8410
2
- omlish/__about__.py,sha256=4sQEInuSehuSq7HJGythCXkRTNTxwCyeWLUL8WDLMKU,3611
2
+ omlish/__about__.py,sha256=4-bUUNkRfpsKN_j34JrHTQA3yrraoqE3_gcf_eEzYFg,3611
3
3
  omlish/__init__.py,sha256=SsyiITTuK0v74XpKV8dqNaCmjOlan1JZKrHQv5rWKPA,253
4
4
  omlish/c3.py,sha256=ZNIMl1kwg3qdei4DiUrJPQe5M81S1e76N-GuNSwLBAE,8683
5
5
  omlish/cached.py,sha256=MLap_p0rdGoDIMVhXVHm1tsbcWobJF0OanoodV03Ju8,542
@@ -479,7 +479,7 @@ omlish/lifecycles/manager.py,sha256=92s1IH_gDP25PM5tFuPMP2hD_6s5fPi_VzZiDS5549g,
479
479
  omlish/lifecycles/states.py,sha256=6gTdY3hn7-1sJ60lA3GeMx5RVKvXtFBBXE4KEjoO1Hs,1297
480
480
  omlish/lifecycles/transitions.py,sha256=3IFdWGtAeoy3XRlIyW7yCKV4e4Iof9ytkqklGMRFYQs,1944
481
481
  omlish/lite/__init__.py,sha256=cyZEpGob7XjU8DohyNxVe5CQRk4CQ5vrHL42OdhQb8w,148
482
- omlish/lite/abstract.py,sha256=Z3kLviPNGLkmA8m8BZILzWxez_sP18OyzgMP3-c2-RI,4068
482
+ omlish/lite/abstract.py,sha256=uXKPgubjZmV3J_py2yZJRUyPtcYzlSGkZ5IqlT32_Dk,4926
483
483
  omlish/lite/args.py,sha256=ILJXAiN3KjIoJwY42aKpYPngUdxHIy9ssVIExFVz3fE,978
484
484
  omlish/lite/asyncs.py,sha256=ITnHvg1gq4Wl6PmhwK6DTKriNLBfxFfiVLE9QL6LEHk,3254
485
485
  omlish/lite/attrops.py,sha256=02DNBjOl27NjznkwolgPwtWpA1q3UPUuwOjHsgG4oLo,11381
@@ -487,7 +487,7 @@ omlish/lite/cached.py,sha256=AF0PdB2k4h2dyNc5tzrmnNrb9zKnoMPQU3WA8KrhS_o,3108
487
487
  omlish/lite/check.py,sha256=ytCkwZoKfOlJqylL-AGm8C2WfsWJd2q3kFbnZCzX3_M,13844
488
488
  omlish/lite/configs.py,sha256=4-1uVxo-aNV7vMKa7PVNhM610eejG1WepB42-Dw2xQI,914
489
489
  omlish/lite/contextmanagers.py,sha256=usDzBoNqJi98AccVlwgZoMvoBXOe9wyx2MreZtWhJy4,5863
490
- omlish/lite/dataclasses.py,sha256=sBsClTxr5nmoahgXzruyZS6GqEWYGmDs8YvAXOIMl74,4814
490
+ omlish/lite/dataclasses.py,sha256=Kxr68nTinRAkdWFGeu8C2qLul8iw6bxpbqqp20yxZfg,5064
491
491
  omlish/lite/imports.py,sha256=GyEDKL-WuHtdOKIL-cc8aFd0-bHwZFDEjAB52ItabX0,1341
492
492
  omlish/lite/inject.py,sha256=BQgjBj2mzJgMimLam-loSpQzcb31-8NYPVRQgHVv3cQ,29159
493
493
  omlish/lite/json.py,sha256=m0Ce9eqUZG23-H7-oOp8n1sf4fzno5vtK4AK_4Vc-Mg,706
@@ -800,7 +800,7 @@ omlish/testing/pytest/plugins/spacing.py,sha256=zgqJqH1EMFS--LmduSsatGhzaOK8bBGj
800
800
  omlish/testing/pytest/plugins/utils.py,sha256=7NZIe_AiblFEm7fIOL66up4k0sdBL3RZgjRV7yzPrDs,266
801
801
  omlish/testing/pytest/plugins/asyncs/__init__.py,sha256=TTNhFmP_krug1973sq_bpWBTIvg68-1nbuVLSs92Z6k,41
802
802
  omlish/testing/pytest/plugins/asyncs/consts.py,sha256=0NOCkzV43dOu3u97BqYMQ4mPG8JuFncpWibkOZpCqX4,55
803
- omlish/testing/pytest/plugins/asyncs/fixtures.py,sha256=O0gT4jVH-4t1WYpY2j51QgsbdK8LKt4R9hOxnf74eTg,11264
803
+ omlish/testing/pytest/plugins/asyncs/fixtures.py,sha256=2m0wdmvehLGI0JI1auNP1xxzjwlPrlsgGBlodMkxXOA,11319
804
804
  omlish/testing/pytest/plugins/asyncs/plugin.py,sha256=cQEdInjYxXswOMexTdZTkcNpM3RKeQiKxdS7fjwIsq0,6088
805
805
  omlish/testing/pytest/plugins/asyncs/utils.py,sha256=YYh6XW_WmHnQCWw1jUMi0HOX_PkRnM-u5_dlVth2tt8,299
806
806
  omlish/testing/pytest/plugins/asyncs/backends/__init__.py,sha256=DpJGt5KA2N2pNXy59raVyJH1969M1AP80pJAqIlNEAs,359
@@ -842,9 +842,9 @@ omlish/typedvalues/marshal.py,sha256=2xqX6JllhtGpmeYkU7C-qzgU__0x-vd6CzYbAsocQlc
842
842
  omlish/typedvalues/of_.py,sha256=UXkxSj504WI2UrFlqdZJbu2hyDwBhL7XVrc2qdR02GQ,1309
843
843
  omlish/typedvalues/reflect.py,sha256=PAvKW6T4cW7u--iX80w3HWwZUS3SmIZ2_lQjT65uAyk,1026
844
844
  omlish/typedvalues/values.py,sha256=ym46I-q2QJ_6l4UlERqv3yj87R-kp8nCKMRph0xQ3UA,1307
845
- omlish-0.0.0.dev471.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
846
- omlish-0.0.0.dev471.dist-info/METADATA,sha256=fgEVi5OFTSDL77Dkou_6_-zoRUUSFSxYotqYsemGQhc,18999
847
- omlish-0.0.0.dev471.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
848
- omlish-0.0.0.dev471.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
849
- omlish-0.0.0.dev471.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
850
- omlish-0.0.0.dev471.dist-info/RECORD,,
845
+ omlish-0.0.0.dev472.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
846
+ omlish-0.0.0.dev472.dist-info/METADATA,sha256=YdE7vkMrfcNoa_DIKW5K9O1_DbzdmLKAYEdiUS3kw2Y,18999
847
+ omlish-0.0.0.dev472.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
848
+ omlish-0.0.0.dev472.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
849
+ omlish-0.0.0.dev472.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
850
+ omlish-0.0.0.dev472.dist-info/RECORD,,