omlish 0.0.0.dev237__py3-none-any.whl → 0.0.0.dev238__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.dev237'
2
- __revision__ = 'e8c58292f1ec88727fd832f6496545435d992e9d'
1
+ __version__ = '0.0.0.dev238'
2
+ __revision__ = '0ab60b1d75e5b0b298707ba55797958e528c69b5'
3
3
 
4
4
 
5
5
  #
@@ -57,11 +57,6 @@ from .identity import ( # noqa
57
57
  IdentityWeakSet,
58
58
  )
59
59
 
60
- from .indexed import ( # noqa
61
- IndexedSeq,
62
- IndexedSetSeq,
63
- )
64
-
65
60
  from .mappings import ( # noqa
66
61
  MissingDict,
67
62
  TypeMap,
@@ -91,6 +86,11 @@ else:
91
86
  'new_treap_map',
92
87
  ])
93
88
 
89
+ from .ranked import ( # noqa
90
+ RankedSeq,
91
+ RankedSetSeq,
92
+ )
93
+
94
94
  if _ta.TYPE_CHECKING:
95
95
  from .sorted.skiplist import ( # noqa
96
96
  SkipList,
@@ -0,0 +1,79 @@
1
+ import typing as ta
2
+
3
+ from .identity import IdentityKeyDict
4
+ from .identity import IdentitySet
5
+
6
+
7
+ T = ta.TypeVar('T')
8
+
9
+
10
+ ##
11
+
12
+
13
+ class RankedSeq(ta.Sequence[T]):
14
+ def __init__(self, it: ta.Iterable[T], *, identity: bool = False) -> None:
15
+ super().__init__()
16
+
17
+ self._lst = list(it)
18
+ self._ranks: ta.Mapping[T, int] = (IdentityKeyDict if identity else dict)((e, i) for i, e in enumerate(self._lst)) # noqa
19
+ if len(self._ranks) != len(self._lst):
20
+ raise ValueError(f'{len(self._ranks)} != {len(self._lst)}')
21
+
22
+ @property
23
+ def debug(self) -> ta.Sequence[T]:
24
+ return self._lst
25
+
26
+ def __iter__(self) -> ta.Iterator[T]:
27
+ return iter(self._lst)
28
+
29
+ def __getitem__(self, rank: int) -> T: # type: ignore
30
+ return self._lst[rank]
31
+
32
+ def __len__(self) -> int:
33
+ return len(self._lst)
34
+
35
+ def __contains__(self, obj: T) -> bool: # type: ignore
36
+ return obj in self._ranks
37
+
38
+ @property
39
+ def ranks(self) -> ta.Mapping[T, int]:
40
+ return self._ranks
41
+
42
+ def rank(self, obj: T) -> int:
43
+ return self._ranks[obj]
44
+
45
+
46
+ ##
47
+
48
+
49
+ class RankedSetSeq(ta.Sequence[ta.AbstractSet[T]]):
50
+ def __init__(self, it: ta.Iterable[ta.Iterable[T]], *, identity: bool = False) -> None:
51
+ super().__init__()
52
+
53
+ self._lst = [(IdentitySet if identity else set)(e) for e in it]
54
+ self._ranks: ta.Mapping[T, int] = (IdentityKeyDict if identity else dict)((e, i) for i, es in enumerate(self._lst) for e in es) # noqa
55
+ if len(self._ranks) != sum(map(len, self._lst)):
56
+ raise ValueError(f'{len(self._ranks)} != {sum(map(len, self._lst))}')
57
+
58
+ @property
59
+ def debug(self) -> ta.Sequence[ta.AbstractSet[T]]:
60
+ return self._lst
61
+
62
+ def __iter__(self) -> ta.Iterator[ta.AbstractSet[T]]:
63
+ return iter(self._lst)
64
+
65
+ def __getitem__(self, rank: int) -> ta.AbstractSet[T]: # type: ignore
66
+ return self._lst[rank]
67
+
68
+ def __len__(self) -> int:
69
+ return len(self._lst)
70
+
71
+ def __contains__(self, obj: T) -> bool: # type: ignore
72
+ return obj in self._ranks
73
+
74
+ @property
75
+ def ranks(self) -> ta.Mapping[T, int]:
76
+ return self._ranks
77
+
78
+ def rank(self, obj: T) -> int:
79
+ return self._ranks[obj]
omlish/configs/classes.py CHANGED
@@ -29,3 +29,7 @@ class Configurable(ta.Generic[ConfigurableConfigT], lang.Abstract):
29
29
  super().__init__()
30
30
 
31
31
  self._config: ConfigurableConfigT = check.isinstance(config, self.Config) # type: ignore[assignment]
32
+
33
+ @property
34
+ def config(self) -> ConfigurableConfigT:
35
+ return self._config
@@ -1,9 +1,15 @@
1
1
  import abc
2
2
  import typing as ta
3
3
 
4
+ from .. import cached
4
5
  from .. import check
6
+ from .. import dataclasses as dc
5
7
  from .. import lang
6
8
  from ..configs.classes import Configurable
9
+ from .daemon import Daemon
10
+ from .targets import Target
11
+ from .targets import TargetRunner
12
+ from .targets import target_runner_for
7
13
 
8
14
 
9
15
  ServiceConfigT = ta.TypeVar('ServiceConfigT', bound='Service.Config')
@@ -32,3 +38,71 @@ class Service(Configurable[ServiceConfigT], lang.Abstract):
32
38
  @classmethod
33
39
  def run_config(cls, config: Config) -> None:
34
40
  return cls.from_config(config).run()
41
+
42
+
43
+ ##
44
+
45
+
46
+ class ServiceTarget(Target):
47
+ svc: Service
48
+
49
+
50
+ class ServiceTargetRunner(TargetRunner, dc.Frozen):
51
+ target: ServiceTarget
52
+
53
+ def run(self) -> None:
54
+ self.target.svc.run()
55
+
56
+
57
+ @target_runner_for.register
58
+ def _(target: ServiceTarget) -> ServiceTargetRunner:
59
+ return ServiceTargetRunner(target)
60
+
61
+
62
+ #
63
+
64
+
65
+ class ServiceConfigTarget(Target):
66
+ cfg: Service.Config
67
+
68
+
69
+ class ServiceConfigTargetRunner(TargetRunner, dc.Frozen):
70
+ target: ServiceConfigTarget
71
+
72
+ def run(self) -> None:
73
+ Service.run_config(self.target.cfg)
74
+
75
+
76
+ @target_runner_for.register
77
+ def _(target: ServiceConfigTarget) -> ServiceConfigTargetRunner:
78
+ return ServiceConfigTargetRunner(target)
79
+
80
+
81
+ ##
82
+
83
+
84
+ @dc.dataclass(frozen=True)
85
+ class ServiceDaemon(lang.Final):
86
+ service: Service | Service.Config
87
+
88
+ @cached.function
89
+ def service_(self) -> Service:
90
+ if isinstance(self.service, Service):
91
+ return self.service
92
+ elif isinstance(self.service, Service.Config):
93
+ return Service.from_config(self.service)
94
+ else:
95
+ raise TypeError(self.service)
96
+
97
+ #
98
+
99
+ daemon: Daemon | Daemon.Config = Daemon.Config()
100
+
101
+ @cached.function
102
+ def daemon_(self) -> Daemon:
103
+ if isinstance(self.daemon, Daemon):
104
+ return self.daemon
105
+ elif isinstance(self.daemon, Daemon.Config):
106
+ return Daemon(Target.of(self.service_()), self.daemon)
107
+ else:
108
+ raise TypeError(self.daemon)
omlish/daemons/targets.py CHANGED
@@ -6,14 +6,18 @@ import typing as ta
6
6
  from .. import check
7
7
  from .. import dataclasses as dc
8
8
  from .. import lang
9
- from .services import Service
10
9
 
11
10
 
12
11
  if ta.TYPE_CHECKING:
13
12
  import runpy
13
+
14
+ from . import services
15
+
14
16
  else:
15
17
  runpy = lang.proxy_import('runpy')
16
18
 
19
+ services = lang.proxy_import('.services', __package__)
20
+
17
21
 
18
22
  ##
19
23
 
@@ -30,8 +34,11 @@ class Target(dc.Case):
30
34
  elif callable(obj):
31
35
  return FnTarget(obj)
32
36
 
33
- elif isinstance(obj, Service.Config):
34
- return ServiceConfigTarget(obj)
37
+ elif isinstance(obj, services.Service):
38
+ return services.ServiceTarget(obj)
39
+
40
+ elif isinstance(obj, services.Service.Config):
41
+ return services.ServiceConfigTarget(obj)
35
42
 
36
43
  else:
37
44
  raise TypeError(obj)
@@ -136,22 +143,3 @@ class ExecTargetRunner(TargetRunner, dc.Frozen):
136
143
  @target_runner_for.register
137
144
  def _(target: ExecTarget) -> ExecTargetRunner:
138
145
  return ExecTargetRunner(target)
139
-
140
-
141
- ##
142
-
143
-
144
- class ServiceConfigTarget(Target):
145
- cfg: Service.Config
146
-
147
-
148
- class ServiceConfigTargetRunner(TargetRunner, dc.Frozen):
149
- target: ServiceConfigTarget
150
-
151
- def run(self) -> None:
152
- Service.run_config(self.target.cfg)
153
-
154
-
155
- @target_runner_for.register
156
- def _(target: ServiceConfigTarget) -> ServiceConfigTargetRunner:
157
- return ServiceConfigTargetRunner(target)
@@ -91,9 +91,11 @@ from .impl.reflect import ( # noqa
91
91
  reflect,
92
92
  )
93
93
 
94
- from .utils import ( # noqa
95
- is_immediate_dataclass,
94
+ from .static import ( # noqa
95
+ Static,
96
+ )
96
97
 
98
+ from .utils import ( # noqa
97
99
  opt_repr,
98
100
  truthy_repr,
99
101
 
@@ -116,5 +118,7 @@ from .utils import ( # noqa
116
118
  ##
117
119
 
118
120
  from ..lite.dataclasses import ( # noqa
121
+ is_immediate_dataclass,
122
+
119
123
  dataclass_maybe_post_init as maybe_post_init,
120
124
  )
@@ -0,0 +1,176 @@
1
+ import abc
2
+ import copy
3
+ import dataclasses as dc
4
+ import typing as ta
5
+
6
+ from .. import lang
7
+ from ..lite.dataclasses import is_immediate_dataclass
8
+ from .impl.api import dataclass
9
+
10
+
11
+ ##
12
+
13
+
14
+ class Static(lang.Abstract):
15
+ __static_dataclass_class__: ta.ClassVar[type]
16
+ __static_dataclass_instance__: ta.ClassVar[ta.Any]
17
+
18
+ def __init_subclass__(cls, **kwargs: ta.Any) -> None:
19
+ super().__init_subclass__(**kwargs)
20
+
21
+ for a in ('__new__', '__init__'):
22
+ if a in cls.__dict__ and not (cls.__dict__[a] == getattr(Static, a)):
23
+ raise TypeError(f'Static base class {cls} must not implement {a}')
24
+
25
+ if cls.__init__ is not Static.__init__:
26
+ # This is necessary to make type-checking work (by allowing it to accept zero). This isn't strictly
27
+ # necessary, but since it's useful to do sometimes it might as well be done everywhere to prevent clashing.
28
+ raise TypeError(f'Static.__init__ should be first in mro of {cls}')
29
+
30
+ #
31
+
32
+ b_dc_lst = []
33
+
34
+ def b_dc_rec(b_cls: type) -> None: # noqa
35
+ if issubclass(b_cls, Static):
36
+ return
37
+ elif is_immediate_dataclass(b_cls):
38
+ b_dc_lst.append(b_cls)
39
+ elif dc.is_dataclass(b_cls):
40
+ for sb_cls in b_cls.__bases__:
41
+ b_dc_rec(sb_cls)
42
+
43
+ for b_cls in cls.__bases__:
44
+ b_dc_rec(b_cls)
45
+
46
+ b_sdc_dc_lst = [
47
+ b_cls.__static_dataclass_class__
48
+ for b_cls in cls.__bases__
49
+ if issubclass(b_cls, Static)
50
+ and b_cls is not Static
51
+ ]
52
+
53
+ sdc_dc_set = {*b_dc_lst, *b_sdc_dc_lst}
54
+ if not sdc_dc_set:
55
+ raise TypeError(f'Static dataclass {cls} inherits from no dataclass')
56
+
57
+ # Base static dataclasses of various types are allowed as long as there is exactly one final subclass involved.
58
+ # For example, a ModAttrManifest dataclass with an abstract StaticModAttrManifest subclass which sets a default
59
+ # mod_name may be mixed in with a further down use-case specific Manifest subclass.
60
+ sdc_dc_set -= {
61
+ m_cls
62
+ for s_cls in sdc_dc_set
63
+ for m_cls in s_cls.__mro__
64
+ if m_cls is not s_cls
65
+ }
66
+
67
+ if len(sdc_dc_set) > 1:
68
+ raise TypeError(f'Static dataclass {cls} inherits from multiple dataclasses: {sdc_dc_set!r}')
69
+ [sdc_cls] = sdc_dc_set
70
+
71
+ if '__static_dataclass_class__' in cls.__dict__:
72
+ raise AttributeError
73
+ setattr(cls, '__static_dataclass_class__', sdc_cls)
74
+
75
+ #
76
+
77
+ expected_fld_order: ta.Sequence[str] | None = None
78
+ is_abstract = lang.is_abstract_class(cls) or abc.ABC in cls.__bases__
79
+ if not is_abstract:
80
+ if is_immediate_dataclass(cls):
81
+ raise TypeError(cls)
82
+
83
+ flds_dct = {}
84
+ for b_cls in cls.__mro__:
85
+ if not dc.is_dataclass(b_cls):
86
+ continue
87
+ b_flds = dc.fields(b_cls) # noqa
88
+ for fld in b_flds:
89
+ if fld.name in flds_dct:
90
+ continue
91
+ flds_dct[fld.name] = fld
92
+
93
+ # Annotations are the authoritative source of field order.
94
+ new_anns = {}
95
+
96
+ for fld in flds_dct.values():
97
+ new_fld = copy.copy(fld)
98
+
99
+ try:
100
+ v = cls.__dict__[fld.name]
101
+ except KeyError:
102
+ if fld.default is dc.MISSING and fld.default_factory is dc.MISSING:
103
+ raise TypeError(f'Field {fld.name!r} of class {cls} is not set and has no default') from None
104
+ else:
105
+ if isinstance(v, dc.Field):
106
+ raise TypeError(f'Static dataclass {cls} may not introduce new fields: {fld.name}: {v}')
107
+
108
+ new_fld.default = dc.MISSING
109
+ # Use a default_factory to allow unsafe (mutable) values.
110
+ new_fld.default_factory = (lambda v2: lambda: v2)(v) # noqa
111
+
112
+ setattr(cls, fld.name, new_fld)
113
+ new_anns[fld.name] = fld.type
114
+
115
+ # Non-abstract static dataclasses may not introduce new fields.
116
+ expected_fld_order = list(flds_dct)
117
+
118
+ new_anns.update({
119
+ k: v
120
+ for k, v in getattr(cls, '__annotations__', {}).items()
121
+ if k not in new_anns
122
+ })
123
+
124
+ cls.__annotations__ = new_anns
125
+
126
+ else:
127
+ for b_cls in cls.__bases__:
128
+ if hasattr(b_cls, '__static_dataclass_instance__'):
129
+ raise TypeError(
130
+ f'Abstract static dataclass {cls} may not inherit from non-abstract static dataclass {b_cls}',
131
+ )
132
+
133
+ # Explicitly forbid dc transforms that rebuild the class, such as slots.
134
+ if (dc_cls := dataclass(cls, frozen=True)) is not cls:
135
+ raise TypeError(dc_cls)
136
+
137
+ dc_flds = dc.fields(cls) # type: ignore[arg-type] # noqa
138
+
139
+ if expected_fld_order is not None:
140
+ dc_fld_order = [f.name for f in dc_flds]
141
+ if dc_fld_order != expected_fld_order:
142
+ raise TypeError(
143
+ f'Static dataclass field order {dc_fld_order!r} != expected field order {expected_fld_order!r}',
144
+ )
145
+
146
+ if not is_abstract:
147
+ # This is the only time the Statices are ever actually instantiated, and it's only to produce the
148
+ # kwargs passed to the underlying dataclass.
149
+ tmp_inst = cls()
150
+ inst_kw = dc.asdict(tmp_inst) # type: ignore[call-overload] # noqa
151
+ inst = sdc_cls(**inst_kw)
152
+
153
+ cls.__static_dataclass_instance__ = inst
154
+
155
+ # Make all field values available via static `Class.field` access, even those created via a factory. Note
156
+ # that further inheritance of this non-abstract Static will continue to inherit dc.Field instances
157
+ # (including things like their metadata) via dc.fields() access, which does not reference `cls.__dict__`.
158
+ for fld in dc_flds:
159
+ v = getattr(inst, fld.name)
160
+ setattr(cls, fld.name, v)
161
+
162
+ def __new__(new_cls, *new_args, **new_kwargs): # noqa
163
+ try:
164
+ return new_cls.__dict__['__static_dataclass_instance__']
165
+ except KeyError:
166
+ return super().__new__(new_cls)
167
+
168
+ cls.__new__ = __new__ # type: ignore
169
+
170
+ cls.__init__ = Static.__init__ # type: ignore
171
+
172
+ @ta.final
173
+ def __init__(self) -> None:
174
+ # This stub serves to allow `StaticSubclass()` to typecheck by allowing it to accept only zero arguments. Note
175
+ # that this is only the case when `Static` is first in mro.
176
+ raise TypeError('May not instantiate static dataclasses')
@@ -4,7 +4,6 @@ import types
4
4
  import typing as ta
5
5
 
6
6
  from .. import check
7
- from .impl.internals import FIELDS_ATTR
8
7
  from .impl.metadata import METADATA_ATTR
9
8
  from .impl.metadata import UserMetadata
10
9
  from .impl.params import DEFAULT_FIELD_EXTRAS
@@ -18,14 +17,6 @@ T = ta.TypeVar('T')
18
17
  ##
19
18
 
20
19
 
21
- def is_immediate_dataclass(cls: type) -> bool:
22
- check.isinstance(cls, type)
23
- return FIELDS_ATTR in cls.__dict__
24
-
25
-
26
- ##
27
-
28
-
29
20
  def opt_repr(o: ta.Any) -> str | None:
30
21
  return repr(o) if o is not None else None
31
22
 
omlish/graphs/trees.py CHANGED
@@ -56,7 +56,7 @@ class BasicTreeAnalysis(ta.Generic[NodeT]):
56
56
 
57
57
  self._set_fac: ta.Callable[..., ta.MutableSet[NodeT]] = col.IdentitySet if identity else set
58
58
  self._dict_fac: ta.Callable[..., ta.MutableMapping[NodeT, ta.Any]] = col.IdentityKeyDict if identity else dict
59
- self._idx_seq_fac: ta.Callable[..., col.IndexedSeq[NodeT]] = functools.partial(col.IndexedSeq, identity=identity) # type: ignore # noqa
59
+ self._rank_seq_fac: ta.Callable[..., col.RankedSeq[NodeT]] = functools.partial(col.RankedSeq, identity=identity) # type: ignore # noqa
60
60
 
61
61
  def walk(cur: NodeT, parent: NodeT | None) -> None:
62
62
  check.not_none(cur)
@@ -88,10 +88,10 @@ class BasicTreeAnalysis(ta.Generic[NodeT]):
88
88
 
89
89
  walk(root, None)
90
90
 
91
- self._nodes = self._idx_seq_fac(nodes)
91
+ self._nodes = self._rank_seq_fac(nodes)
92
92
  self._node_set: ta.AbstractSet[NodeT] = node_set
93
- self._children_by_node: ta.Mapping[NodeT | None, col.IndexedSeq[NodeT]] = self._dict_fac(
94
- [(n, self._idx_seq_fac(cs)) for n, cs in children_by_node.items()])
93
+ self._children_by_node: ta.Mapping[NodeT | None, col.RankedSeq[NodeT]] = self._dict_fac(
94
+ [(n, self._rank_seq_fac(cs)) for n, cs in children_by_node.items()])
95
95
  self._child_sets_by_node: ta.Mapping[NodeT | None, ta.AbstractSet[NodeT]] = child_sets_by_node
96
96
  self._parents_by_node: ta.Mapping[NodeT, NodeT | None] = parents_by_node
97
97
 
@@ -100,7 +100,7 @@ class BasicTreeAnalysis(ta.Generic[NodeT]):
100
100
  return self._root
101
101
 
102
102
  @property
103
- def nodes(self) -> col.IndexedSeq[NodeT]:
103
+ def nodes(self) -> col.RankedSeq[NodeT]:
104
104
  return self._nodes
105
105
 
106
106
  @property
@@ -116,7 +116,7 @@ class BasicTreeAnalysis(ta.Generic[NodeT]):
116
116
  return self._node_set
117
117
 
118
118
  @property
119
- def children_by_node(self) -> ta.Mapping[NodeT | None, col.IndexedSeq[NodeT]]:
119
+ def children_by_node(self) -> ta.Mapping[NodeT | None, col.RankedSeq[NodeT]]:
120
120
  return self._children_by_node
121
121
 
122
122
  @property
@@ -224,8 +224,8 @@ class BasicTreeAnalysis(ta.Generic[NodeT]):
224
224
  break
225
225
  yield cur
226
226
 
227
- def get_lineage(self, node: NodeT) -> col.IndexedSeq[NodeT]:
228
- return self._idx_seq_fac(reversed([node, *self.iter_ancestors(node)]))
227
+ def get_lineage(self, node: NodeT) -> col.RankedSeq[NodeT]:
228
+ return self._rank_seq_fac(reversed([node, *self.iter_ancestors(node)]))
229
229
 
230
230
  def get_first_parent_of_type(self, node: NodeT, ty: type[T]) -> T | None:
231
231
  for cur in self.iter_ancestors(node):
@@ -48,25 +48,26 @@ def _has_method_descriptor(obj: ta.Any) -> bool:
48
48
  return False
49
49
 
50
50
 
51
- def unwrap_method_descriptors(fn: ta.Callable) -> ta.Callable:
51
+ def unwrap_method_descriptors(fn: ta.Any) -> ta.Any:
52
52
  while is_method_descriptor(fn):
53
- fn = fn.__func__ # type: ignore # noqa
53
+ fn = fn.__func__
54
54
  return fn
55
55
 
56
56
 
57
57
  ##
58
58
 
59
59
 
60
- def unwrap_func_with_partials(fn: ta.Callable) -> tuple[ta.Callable, list[functools.partial]]:
60
+ def unwrap_func_with_partials(fn: ta.Any) -> tuple[ta.Any, list[functools.partial]]:
61
61
  ps = []
62
62
  while True:
63
63
  if is_method_descriptor(fn) or isinstance(fn, types.MethodType):
64
- fn = fn.__func__ # type: ignore
64
+ fn = fn.__func__
65
65
 
66
66
  elif hasattr(fn, '__wrapped__'):
67
67
  nxt = fn.__wrapped__
68
- if not callable(nxt):
69
- raise TypeError(nxt)
68
+ # FIXME: ?
69
+ # if not callable(nxt):
70
+ # raise TypeError(nxt)
70
71
  if nxt is fn:
71
72
  raise TypeError(fn)
72
73
  fn = nxt
@@ -83,7 +84,7 @@ def unwrap_func_with_partials(fn: ta.Callable) -> tuple[ta.Callable, list[functo
83
84
  return fn, ps
84
85
 
85
86
 
86
- def unwrap_func(fn: ta.Callable) -> ta.Callable:
87
+ def unwrap_func(fn: ta.Any) -> ta.Any:
87
88
  uw, _ = unwrap_func_with_partials(fn)
88
89
  return uw
89
90
 
@@ -3,6 +3,18 @@ import dataclasses as dc
3
3
  import typing as ta
4
4
 
5
5
 
6
+ ##
7
+
8
+
9
+ def is_immediate_dataclass(cls: type) -> bool:
10
+ if not isinstance(cls, type):
11
+ raise TypeError(cls)
12
+ return dc._FIELDS in cls.__dict__ # type: ignore[attr-defined] # noqa
13
+
14
+
15
+ ##
16
+
17
+
6
18
  def dataclass_cache_hash(
7
19
  *,
8
20
  cached_hash_attr: str = '__dataclass_hash__',
@@ -33,6 +45,9 @@ def dataclass_cache_hash(
33
45
  return inner
34
46
 
35
47
 
48
+ ##
49
+
50
+
36
51
  def dataclass_maybe_post_init(sup: ta.Any) -> bool:
37
52
  if not isinstance(sup, super):
38
53
  raise TypeError(sup)
@@ -44,6 +59,9 @@ def dataclass_maybe_post_init(sup: ta.Any) -> bool:
44
59
  return True
45
60
 
46
61
 
62
+ ##
63
+
64
+
47
65
  def dataclass_repr_filtered(
48
66
  obj: ta.Any,
49
67
  fn: ta.Callable[[ta.Any, dc.Field, ta.Any], bool],
@@ -1,2 +0,0 @@
1
- # @omlish-lite
2
- from .types import Manifest # noqa
omlish/manifests/base.py CHANGED
@@ -1,4 +1,5 @@
1
1
  # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
2
3
  import dataclasses as dc
3
4
  import typing as ta
4
5
 
omlish/manifests/load.py CHANGED
@@ -1,4 +1,5 @@
1
1
  # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
2
3
  """
3
4
  Should be kept somewhat lightweight - used in cli entrypoints.
4
5
 
@@ -0,0 +1,20 @@
1
+ import abc
2
+ import typing as ta
3
+
4
+ from .. import dataclasses as dc
5
+ from .. import lang
6
+ from .base import ModAttrManifest
7
+
8
+
9
+ ##
10
+
11
+
12
+ class StaticModAttrManifest(dc.Static, ModAttrManifest, abc.ABC):
13
+ def __init_subclass__(cls, **kwargs: ta.Any) -> None:
14
+ if (
15
+ not (lang.is_abstract_class(cls) or abc.ABC in cls.__bases__) and
16
+ 'mod_name' not in cls.__dict__
17
+ ):
18
+ setattr(cls, 'mod_name', cls.__module__)
19
+
20
+ super().__init_subclass__(**kwargs)
omlish/manifests/types.py CHANGED
@@ -1,4 +1,5 @@
1
1
  # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
2
3
  import dataclasses as dc
3
4
  import typing as ta
4
5
 
omlish/metadata.py ADDED
@@ -0,0 +1,153 @@
1
+ """
2
+ These attempt to punch through *all* wrappers. The the usecases involve having things like bound methods, classmethods,
3
+ functools.partial instances, and needing to get the metadata of the underlying thing the end-user wrote.
4
+
5
+ TODO:
6
+ - re type targets:
7
+ - unwrap instances of objects to their types?
8
+ - merge mro?
9
+ - are these better left up to callers? too usecase-specific to favor either way?
10
+ """
11
+ import types
12
+ import typing as ta
13
+
14
+ from . import check
15
+ from . import lang
16
+
17
+
18
+ T = ta.TypeVar('T')
19
+
20
+
21
+ ##
22
+
23
+
24
+ class ObjectMetadata(lang.Abstract):
25
+ pass
26
+
27
+
28
+ class ObjectMetadataTarget(lang.Abstract):
29
+ pass
30
+
31
+
32
+ ##
33
+
34
+
35
+ _VALID_OBJECT_METADATA_TARGET_TYPES: tuple[type, ...] = (
36
+ type,
37
+
38
+ types.FunctionType,
39
+ # *not* types.MethodType - must unwrap to unbound class func
40
+ # *not* functools.partial - must unwrap to underlying func
41
+
42
+ ObjectMetadataTarget,
43
+ )
44
+
45
+
46
+ class ObjectMetadataTargetTypeError(TypeError):
47
+ pass
48
+
49
+
50
+ def _unwrap_object_metadata_target(obj: ta.Any) -> ta.Any:
51
+ tgt: ta.Any = obj
52
+ tgt = lang.unwrap_func(tgt)
53
+
54
+ if not isinstance(tgt, _VALID_OBJECT_METADATA_TARGET_TYPES):
55
+ raise ObjectMetadataTargetTypeError(tgt)
56
+
57
+ return tgt
58
+
59
+
60
+ ##
61
+
62
+
63
+ _OBJECT_METADATA_ATTR = '__' + __name__.replace('.', '_') + '__metadata__'
64
+
65
+
66
+ def append_object_metadata(obj: T, *mds: ObjectMetadata) -> T:
67
+ for md in mds:
68
+ check.isinstance(md, ObjectMetadata)
69
+
70
+ tgt = _unwrap_object_metadata_target(obj)
71
+ dct = tgt.__dict__
72
+
73
+ if isinstance(dct, types.MappingProxyType):
74
+ for _ in range(2):
75
+ try:
76
+ lst = dct[_OBJECT_METADATA_ATTR]
77
+ except KeyError:
78
+ setattr(tgt, _OBJECT_METADATA_ATTR, [])
79
+ else:
80
+ break
81
+ else:
82
+ raise RuntimeError
83
+
84
+ else:
85
+ lst = dct.setdefault(_OBJECT_METADATA_ATTR, [])
86
+
87
+ lst.extend(mds)
88
+ return obj
89
+
90
+
91
+ def get_object_metadata(obj: ta.Any, *, strict: bool = False) -> ta.Sequence[ObjectMetadata]:
92
+ try:
93
+ tgt = _unwrap_object_metadata_target(obj)
94
+ except ObjectMetadataTargetTypeError:
95
+ if not strict:
96
+ return ()
97
+ raise
98
+
99
+ try:
100
+ dct = tgt.__dict__
101
+ except AttributeError:
102
+ return ()
103
+
104
+ return dct.get(_OBJECT_METADATA_ATTR, ())
105
+
106
+
107
+ ##
108
+
109
+
110
+ class DecoratorObjectMetadata(ObjectMetadata, lang.Abstract):
111
+ _OBJECT_METADATA_TARGET_TYPES: ta.ClassVar[tuple[type, ...] | None] = None
112
+
113
+ def __init_subclass__(
114
+ cls,
115
+ *,
116
+ object_metadata_target_types: ta.Iterable[type] | None = None,
117
+ **kwargs: ta.Any,
118
+ ) -> None:
119
+ super().__init_subclass__(**kwargs)
120
+
121
+ if object_metadata_target_types is not None:
122
+ tts = tuple(object_metadata_target_types)
123
+ for tt in tts:
124
+ check.issubclass(tt, _VALID_OBJECT_METADATA_TARGET_TYPES)
125
+ setattr(cls, '_OBJECT_METADATA_TARGET_TYPES', tts)
126
+
127
+ def __call__(self, obj: T) -> T:
128
+ tgt: ta.Any = obj
129
+ if (tts := type(self)._OBJECT_METADATA_TARGET_TYPES) is not None: # noqa
130
+ tgt = _unwrap_object_metadata_target(tgt)
131
+ check.isinstance(tgt, tts)
132
+
133
+ append_object_metadata(tgt, self)
134
+ return obj
135
+
136
+
137
+ #
138
+
139
+
140
+ class ClassDecoratorObjectMetadata(
141
+ DecoratorObjectMetadata,
142
+ lang.Abstract,
143
+ object_metadata_target_types=[type],
144
+ ):
145
+ pass
146
+
147
+
148
+ class FunctionDecoratorObjectMetadata(
149
+ DecoratorObjectMetadata,
150
+ lang.Abstract,
151
+ object_metadata_target_types=[types.FunctionType],
152
+ ):
153
+ pass
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: omlish
3
- Version: 0.0.0.dev237
3
+ Version: 0.0.0.dev238
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -1,5 +1,5 @@
1
1
  omlish/.manifests.json,sha256=vQTAIvR8OblSq-uP2GUfnbei0RnmAnM5j0T1-OToh9E,8253
2
- omlish/__about__.py,sha256=0tS5CFbCYIp6LwAIjSNK3lhW-DW7VWodegiD0bAa7U8,3380
2
+ omlish/__about__.py,sha256=-JHhiSxa1m9XW-39IA3EWqH7y7ZB6GG03v7p93wDeA0,3380
3
3
  omlish/__init__.py,sha256=SsyiITTuK0v74XpKV8dqNaCmjOlan1JZKrHQv5rWKPA,253
4
4
  omlish/c3.py,sha256=ubu7lHwss5V4UznbejAI0qXhXahrU01MysuHOZI9C4U,8116
5
5
  omlish/cached.py,sha256=UI-XTFBwA6YXWJJJeBn-WkwBkfzDjLBBaZf4nIJA9y0,510
@@ -8,6 +8,7 @@ omlish/datetimes.py,sha256=HajeM1kBvwlTa-uR1TTZHmZ3zTPnnUr1uGGQhiO1XQ0,2152
8
8
  omlish/defs.py,sha256=9uUjJuVIbCBL3g14fyzAp-9gH935MFofvlfOGwcBIaM,4913
9
9
  omlish/dynamic.py,sha256=kIZokHHid8a0pIAPXMNiXrVJvJJyBnY49WP1a2m-HUQ,6525
10
10
  omlish/libc.py,sha256=8K4c66YV1ziJerl5poAAYCmsV-VSsHkT3EHhPW04ufg,15639
11
+ omlish/metadata.py,sha256=IJFczp-bkFk_lCYTUt5UmM_MvCbKICjJunEi2MqnC1w,3495
11
12
  omlish/outcome.py,sha256=ABIE0zjjTyTNtn-ZqQ_9_mUzLiBQ3sDAyqc9JVD8N2k,7852
12
13
  omlish/runmodule.py,sha256=PWvuAaJ9wQQn6bx9ftEL3_d04DyotNn8dR_twm2pgw0,700
13
14
  omlish/shlex.py,sha256=bsW2XUD8GiMTUTDefJejZ5AyqT1pTgWMPD0BMoF02jE,248
@@ -134,16 +135,16 @@ omlish/codecs/funcs.py,sha256=p4imNt7TobyZVXWC-WhntHVu9KfJrO4QwdtPRh-cVOk,850
134
135
  omlish/codecs/registry.py,sha256=2FnO5YP7ui1LzkguwESY0MP3WIdwgPTIJTM_4RyTOEg,3896
135
136
  omlish/codecs/standard.py,sha256=eiZ4u9ep0XrA4Z_D1zJI0vmWyuN8HLrX4Se_r_Cq_ZM,60
136
137
  omlish/codecs/text.py,sha256=JzrdwMpQPo2NBBg3K1EZszzQy5vEWmd82SIerJd4yeQ,5723
137
- omlish/collections/__init__.py,sha256=ddzZS3C2rvDo65hspO9KlFsrinElxPWvYEgVyBUZdb0,2164
138
+ omlish/collections/__init__.py,sha256=umpclbTE3wsSflMrKmYEiGmWFhiukfJxvBWgtYMZ8mk,2161
138
139
  omlish/collections/abc.py,sha256=sP7BpTVhx6s6C59mTFeosBi4rHOWC6tbFBYbxdZmvh0,2365
139
140
  omlish/collections/coerce.py,sha256=g68ROb_-5HgH-vI8612mU2S0FZ8-wp2ZHK5_Zy_kVC0,7037
140
141
  omlish/collections/exceptions.py,sha256=shcS-NCnEUudF8qC_SmO2TQyjivKlS4TDjaz_faqQ0c,44
141
142
  omlish/collections/frozen.py,sha256=mxhd8pw5zIXUiRHiBVZWYCYT7wYDVG3tAY5PNU-WH-I,4150
142
143
  omlish/collections/hasheq.py,sha256=XcOCE6f2lXizDCOXxSX6vJv-rLcpDo2OWCYIKGSWuic,3697
143
144
  omlish/collections/identity.py,sha256=SwnUE5D3v9RBjATDE1LUr_vO3Rb2NHcmTK64GZIcsO8,2720
144
- omlish/collections/indexed.py,sha256=tLa88qgWGzTZGssMFgvhgraIEkNEUvcIk5p4yjNEquQ,2201
145
145
  omlish/collections/mappings.py,sha256=YunNPyADrpitZGTJcXV0k4bmJddj1avDvEavz0coJWU,3203
146
146
  omlish/collections/ordered.py,sha256=tUAl99XHbSbzn7Hdh99jUBl27NcC2J7ZTI67slTMe5M,2333
147
+ omlish/collections/ranked.py,sha256=rg6DL36oOUiG5JQEAkGnT8b6f9mSndQlIovtt8GQj_w,2229
147
148
  omlish/collections/unmodifiable.py,sha256=-zys__n6L7liWzhmHAIvfxprq7cUE5HoR3foGvXc_7I,4748
148
149
  omlish/collections/utils.py,sha256=Q0lHhNDokVxdOvApmu1QX5fABYwbn1ATiIwp194Ur_E,2889
149
150
  omlish/collections/cache/__init__.py,sha256=D1gO71VcwxFTZP9gAc9isHfg_TEdalwhsJcgGLvS9hg,233
@@ -163,7 +164,7 @@ omlish/concurrent/futures.py,sha256=J2s9wYURUskqRJiBbAR0PNEAp1pXbIMYldOVBTQduQY,
163
164
  omlish/concurrent/threadlets.py,sha256=JfirbTDJgy9Ouokz_VmHeAAPS7cih8qMUJrN-owwXD4,2423
164
165
  omlish/configs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
165
166
  omlish/configs/all.py,sha256=kziwjzUBkf8AT0w7Pq7JX2jtkQVOQ5R1wJyn6hfTN5k,1055
166
- omlish/configs/classes.py,sha256=oCCkGzokn807mAlpRVe9F_JKZo8x6JcIVmo2sBsm7T8,1080
167
+ omlish/configs/classes.py,sha256=9uelgi9gS5Sf8ZbtydNXhMxjBs7xBxGZgfuK0Vbc2cg,1168
167
168
  omlish/configs/formats.py,sha256=RJw4Rzp7vlTd5YyAvpAoruQnk45v8dGPtPWwqH7aYyE,5301
168
169
  omlish/configs/nginx.py,sha256=XuX9yyb0_MwkJ8esKiMS9gFkqHUPza_uCprhnWykNy8,2051
169
170
  omlish/configs/shadow.py,sha256=-R5nbevC4pFgqDPYOCCIqNcusgXsMWlRIUOEG0HBoJg,2228
@@ -181,12 +182,13 @@ omlish/daemons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
181
182
  omlish/daemons/daemon.py,sha256=ykdbCPbpxKrdZVZc892SnedTdftTAYt_YdDpYchKcUE,3410
182
183
  omlish/daemons/launching.py,sha256=mhtkuAO16STcznUl3rrX9pacfrKbPQRCP2AllKL4B70,3664
183
184
  omlish/daemons/reparent.py,sha256=UaG2X6VJHJPOlUwHPNRH3aWGgF0Fg771jjO9IRPLlyY,280
184
- omlish/daemons/services.py,sha256=XRmYBYNLUumnxaXCr2B7ScNEUlM8oM5FSS0bdWheDNs,719
185
+ omlish/daemons/services.py,sha256=UAzzdP4jG0-piVzz6CsSTPIjTGt4VFXtbzP7KczMCho,2354
185
186
  omlish/daemons/spawning.py,sha256=cx00xeqSrfhlFbjCtKqaBHvMuHwB9hdjuKNHzAAo_dw,4030
186
- omlish/daemons/targets.py,sha256=L2BRWsv473X7dE4H7afA8TgTiaevCuZPab9Olh-AKUc,3248
187
+ omlish/daemons/targets.py,sha256=00KmtlknMhQ5PyyVAhWl3rpeTMPym0GxvHHq6mYPZ7c,3051
187
188
  omlish/daemons/waiting.py,sha256=RfgD1L33QQVbD2431dkKZGE4w6DUcGvYeRXXi8puAP4,1676
188
- omlish/dataclasses/__init__.py,sha256=D7I6ZJjEFeLN2re8oOZ_7JKWiG2plrPnaUFq3iEXYmQ,1553
189
- omlish/dataclasses/utils.py,sha256=N2seT8cJtfOv-41D7F3E-q4us-FCTQmnxxPv3dt1OcI,3796
189
+ omlish/dataclasses/__init__.py,sha256=b7EZCIfHnEHCHWwgD3YXxkdsU-uYd9iD4hM36RgpI1g,1598
190
+ omlish/dataclasses/static.py,sha256=35tPuneXUXZztFTzjNkW6DnQbZgKJUf68GmjzXV-WkQ,6903
191
+ omlish/dataclasses/utils.py,sha256=QWsHxVisS-MUCqh89JQsRdCLgdBVeC6EYK6jRwO9akU,3631
190
192
  omlish/dataclasses/impl/LICENSE,sha256=Oy-B_iHRgcSZxZolbI4ZaEVdZonSaaqFNzv7avQdo78,13936
191
193
  omlish/dataclasses/impl/__init__.py,sha256=zqGBC5gSbjJxaqG_zS1LL1PX-zAfhIua8UqOE4IwO2k,789
192
194
  omlish/dataclasses/impl/api.py,sha256=RhU4f50GVdn-dxilia8NA3F7VIm2R5z78pFfpIVXPRQ,6635
@@ -302,7 +304,7 @@ omlish/funcs/pipes.py,sha256=E7Sz8Aj8ke_vCs5AMNwg1I36kRdHVGTnzxVQaDyn43U,2490
302
304
  omlish/graphs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
303
305
  omlish/graphs/dags.py,sha256=zp55lYgUdRCxmADwiGDHeehMJczZFA_tzdWqy77icOk,3047
304
306
  omlish/graphs/domination.py,sha256=oCGoWzWTxLwow0LDyGjjEf2AjFiOiDz4WaBtczwSbsQ,7576
305
- omlish/graphs/trees.py,sha256=zvfjDN8R7J6wStNJEUO6OCioGXJrLGhU8KtcqlWVRPI,8191
307
+ omlish/graphs/trees.py,sha256=OgGDnCJKfpOeWgDJPSkuVEoeYp72o06jpm0jwUB96Xc,8189
306
308
  omlish/graphs/dot/__init__.py,sha256=Y1MZRQBZkcYyG1Tn7K2FhL8aYbm4v4tk6f5g9AqEkUw,359
307
309
  omlish/graphs/dot/items.py,sha256=OWPf0-hjBgS1uyy2QgAEn4IgFHJcEg7sHVWeTx1ghZc,4083
308
310
  omlish/graphs/dot/make.py,sha256=RN30gHfJPiXx5Q51kbDdhVJYf59Fr84Lz9J-mXRt9sI,360
@@ -401,7 +403,7 @@ omlish/lang/clsdct.py,sha256=sJYadm-fwzti-gsi98knR5qQUxriBmOqQE_qz3RopNk,1743
401
403
  omlish/lang/cmp.py,sha256=5vbzWWbqdzDmNKAGL19z6ZfUKe5Ci49e-Oegf9f4BsE,1346
402
404
  omlish/lang/contextmanagers.py,sha256=Mrn8NJ3pP0Zxi-IoGqSjZDdWUctsyee2vrZ2FtZvNmo,10529
403
405
  omlish/lang/datetimes.py,sha256=ehI_DhQRM-bDxAavnp470XcekbbXc4Gdw9y1KpHDJT0,223
404
- omlish/lang/descriptors.py,sha256=njkYDS1gn5p4-3v1jr-s_srauC7tvvt571RjE7Q4LXE,6616
406
+ omlish/lang/descriptors.py,sha256=mZ2h9zJ__MMpw8hByjRbAiONcwfVb6GD0btNnVi8C5w,6573
405
407
  omlish/lang/exceptions.py,sha256=qJBo3NU1mOWWm-NhQUHCY5feYXR3arZVyEHinLsmRH4,47
406
408
  omlish/lang/functions.py,sha256=0ql9EXA_gEEhvUVzMJCjVhEnVtHecsLKmfmAXuQqeGY,4388
407
409
  omlish/lang/generators.py,sha256=5LX17j-Ej3QXhwBgZvRTm_dq3n9veC4IOUcVmvSu2vU,5243
@@ -432,7 +434,7 @@ omlish/lite/cached.py,sha256=O7ozcoDNFm1Hg2wtpHEqYSp_i_nCLNOP6Ueq_Uk-7mU,1300
432
434
  omlish/lite/check.py,sha256=OLwtE2x6nlbGx4vS3Rda7zMHpgqzDSLJminTAX2lqLA,13529
433
435
  omlish/lite/configs.py,sha256=Ev_19sbII67pTWzInYjYqa9VyTiZBvyjhZqyG8TtufE,908
434
436
  omlish/lite/contextmanagers.py,sha256=ciaMl0D3QDHToM7M28-kwZ-Q48LtwgCxiud3nekgutA,2863
435
- omlish/lite/dataclasses.py,sha256=sjJnZ4tZXMzKRkr-gymMbhuMxJAY8parJ_sopEqBc6M,1704
437
+ omlish/lite/dataclasses.py,sha256=t1G5-xOuvE6o6w9RyqHzLT9wHD0HkqBh5P8HUZWxGzs,1912
436
438
  omlish/lite/inject.py,sha256=qBUftFeXMiRgANYbNS2e7TePMYyFAcuLgsJiLyMTW5o,28769
437
439
  omlish/lite/json.py,sha256=7-02Ny4fq-6YAu5ynvqoijhuYXWpLmfCI19GUeZnb1c,740
438
440
  omlish/lite/logs.py,sha256=CWFG0NKGhqNeEgryF5atN2gkPYbUdTINEw_s1phbINM,51
@@ -463,10 +465,11 @@ omlish/logs/proxy.py,sha256=A-ROPUUAlF397qTbEqhel6YhQMstNuXL3Xmts7w9dAo,2347
463
465
  omlish/logs/standard.py,sha256=FbKdF2Z4Na5i2TNwKn0avLJXyICe2JKsPufjvKCHGn0,3162
464
466
  omlish/logs/timing.py,sha256=XrFUHIPT4EHDujLKbGs9fGFMmoM3NEP8xPRaESJr7bQ,1513
465
467
  omlish/logs/utils.py,sha256=mzHrZ9ji75p5A8qR29eUr05CBAHMb8J753MSkID_VaQ,393
466
- omlish/manifests/__init__.py,sha256=P2B0dpT8D7l5lJwRGPA92IcQj6oeXfd90X5-q9BJrKg,51
467
- omlish/manifests/base.py,sha256=1LGglMh7UUU7JWIqPH_JfIm6czGETibpScEqKI5mSMg,920
468
- omlish/manifests/load.py,sha256=0ZjtsYL2EIKYd_MF3brKTPYdRZmtWdwomx2cFjjFV2M,6640
469
- omlish/manifests/types.py,sha256=d8bv5tknCJqclRfxCpao_8XxHo2yofhLpVHQTB-MfNw,260
468
+ omlish/manifests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
469
+ omlish/manifests/base.py,sha256=D1WvJYcBR_njkc0gpALpFCWh1h3agb9qgqphnbbPlm4,935
470
+ omlish/manifests/load.py,sha256=9mdsS3egmSX9pymO-m-y2Fhs4p6ruOdbsYaKT1-1Hwg,6655
471
+ omlish/manifests/static.py,sha256=7YwOVh_Ek9_aTrWsWNO8kWS10_j4K7yv3TpXZSHsvDY,501
472
+ omlish/manifests/types.py,sha256=mxL6N44mu06995YF8qzmg6V94EmfRiryzIUQcXVSCbI,275
470
473
  omlish/marshal/__init__.py,sha256=00D3S6qwUld1TUWd67hVHuNcrj3c_FAFSkCVXgGWT-s,2607
471
474
  omlish/marshal/base.py,sha256=tJ4iNuD7cW2GpGMznOhkAf2hugqp2pF2em0FaQcekrk,6740
472
475
  omlish/marshal/exceptions.py,sha256=jwQWn4LcPnadT2KRI_1JJCOSkwWh0yHnYK9BmSkNN4U,302
@@ -711,9 +714,9 @@ omlish/text/indent.py,sha256=YjtJEBYWuk8--b9JU_T6q4yxV85_TR7VEVr5ViRCFwk,1336
711
714
  omlish/text/minja.py,sha256=jZC-fp3Xuhx48ppqsf2Sf1pHbC0t8XBB7UpUUoOk2Qw,5751
712
715
  omlish/text/parts.py,sha256=JkNZpyR2tv2CNcTaWJJhpQ9E4F0yPR8P_YfDbZfMtwQ,6182
713
716
  omlish/text/random.py,sha256=jNWpqiaKjKyTdMXC-pWAsSC10AAP-cmRRPVhm59ZWLk,194
714
- omlish-0.0.0.dev237.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
715
- omlish-0.0.0.dev237.dist-info/METADATA,sha256=xNNscWsZ6ZOLDE0vOj3YCOrR50thYq82_KawDOui9OA,4176
716
- omlish-0.0.0.dev237.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
717
- omlish-0.0.0.dev237.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
718
- omlish-0.0.0.dev237.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
719
- omlish-0.0.0.dev237.dist-info/RECORD,,
717
+ omlish-0.0.0.dev238.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
718
+ omlish-0.0.0.dev238.dist-info/METADATA,sha256=Fzwpe0Ssmu0yFpCL5MUoWK0b3rF72OFhaG7rCK_duxU,4176
719
+ omlish-0.0.0.dev238.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
720
+ omlish-0.0.0.dev238.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
721
+ omlish-0.0.0.dev238.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
722
+ omlish-0.0.0.dev238.dist-info/RECORD,,
@@ -1,73 +0,0 @@
1
- import typing as ta
2
-
3
- from .identity import IdentityKeyDict
4
- from .identity import IdentitySet
5
-
6
-
7
- T = ta.TypeVar('T')
8
-
9
-
10
- class IndexedSeq(ta.Sequence[T]):
11
- def __init__(self, it: ta.Iterable[T], *, identity: bool = False) -> None:
12
- super().__init__()
13
-
14
- self._lst = list(it)
15
- self._idxs: ta.Mapping[T, int] = (IdentityKeyDict if identity else dict)((e, i) for i, e in enumerate(self._lst)) # noqa
16
- if len(self._idxs) != len(self._lst):
17
- raise ValueError(f'{len(self._idxs)} != {len(self._lst)}')
18
-
19
- @property
20
- def debug(self) -> ta.Sequence[T]:
21
- return self._lst
22
-
23
- def __iter__(self) -> ta.Iterator[T]:
24
- return iter(self._lst)
25
-
26
- def __getitem__(self, idx: int) -> T: # type: ignore
27
- return self._lst[idx]
28
-
29
- def __len__(self) -> int:
30
- return len(self._lst)
31
-
32
- def __contains__(self, obj: T) -> bool: # type: ignore
33
- return obj in self._idxs
34
-
35
- @property
36
- def idxs(self) -> ta.Mapping[T, int]:
37
- return self._idxs
38
-
39
- def idx(self, obj: T) -> int:
40
- return self._idxs[obj]
41
-
42
-
43
- class IndexedSetSeq(ta.Sequence[ta.AbstractSet[T]]):
44
- def __init__(self, it: ta.Iterable[ta.Iterable[T]], *, identity: bool = False) -> None:
45
- super().__init__()
46
-
47
- self._lst = [(IdentitySet if identity else set)(e) for e in it]
48
- self._idxs: ta.Mapping[T, int] = (IdentityKeyDict if identity else dict)((e, i) for i, es in enumerate(self._lst) for e in es) # noqa
49
- if len(self._idxs) != sum(map(len, self._lst)):
50
- raise ValueError(f'{len(self._idxs)} != {sum(map(len, self._lst))}')
51
-
52
- @property
53
- def debug(self) -> ta.Sequence[ta.AbstractSet[T]]:
54
- return self._lst
55
-
56
- def __iter__(self) -> ta.Iterator[ta.AbstractSet[T]]:
57
- return iter(self._lst)
58
-
59
- def __getitem__(self, idx: int) -> ta.AbstractSet[T]: # type: ignore
60
- return self._lst[idx]
61
-
62
- def __len__(self) -> int:
63
- return len(self._lst)
64
-
65
- def __contains__(self, obj: T) -> bool: # type: ignore
66
- return obj in self._idxs
67
-
68
- @property
69
- def idxs(self) -> ta.Mapping[T, int]:
70
- return self._idxs
71
-
72
- def idx(self, obj: T) -> int:
73
- return self._idxs[obj]