omlish 0.0.0.dev51__py3-none-any.whl → 0.0.0.dev53__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/.manifests.json CHANGED
@@ -42,7 +42,10 @@
42
42
  "line": 1,
43
43
  "value": {
44
44
  "$omdev.cli.types.CliModule": {
45
- "cmd_name": "jp",
45
+ "cmd_name": [
46
+ "jmespath",
47
+ "jp"
48
+ ],
46
49
  "mod_name": "omlish.specs.jmespath.__main__"
47
50
  }
48
51
  }
omlish/__about__.py CHANGED
@@ -1,5 +1,5 @@
1
- __version__ = '0.0.0.dev51'
2
- __revision__ = 'a9d714d2c1bc65f8d907b3e3bc7ad7d71f942d29'
1
+ __version__ = '0.0.0.dev53'
2
+ __revision__ = 'b933fe4d493e86c4f8b6531c82d6510916625619'
3
3
 
4
4
 
5
5
  #
@@ -28,6 +28,8 @@ class Project(ProjectBase):
28
28
  name = 'omlish'
29
29
  description = 'omlish'
30
30
 
31
+ #
32
+
31
33
  optional_dependencies = {
32
34
  'async': [
33
35
  'anyio ~= 4.6',
@@ -61,7 +63,7 @@ class Project(ProjectBase):
61
63
 
62
64
  'json5 ~= 0.9',
63
65
 
64
- 'pyyaml ~= 5.0',
66
+ 'pyyaml ~= 6.0',
65
67
 
66
68
  'cbor2 ~= 5.6',
67
69
 
@@ -109,6 +111,32 @@ class Project(ProjectBase):
109
111
  ],
110
112
  }
111
113
 
114
+ #
115
+
116
+ _plus_dependencies = [
117
+ 'anyio',
118
+ 'sniffio',
119
+
120
+ 'asttokens',
121
+ 'executing',
122
+
123
+ 'orjson',
124
+ 'pyyaml',
125
+
126
+ 'wrapt',
127
+ ]
128
+
129
+ _dependency_specs_by_name = (lambda od: { # noqa
130
+ s.split()[0]: s
131
+ for l in od.values() for s in l
132
+ })(optional_dependencies)
133
+
134
+ optional_dependencies['plus'] = (lambda ds, pd: [ # noqa
135
+ ds[n] for n in pd
136
+ ])(_dependency_specs_by_name, _plus_dependencies)
137
+
138
+ #
139
+
112
140
  entry_points = {
113
141
  'omlish.manifests': {name: name},
114
142
  }
@@ -134,6 +162,7 @@ class SetuptoolsBase:
134
162
  '*.c',
135
163
  '*.cc',
136
164
  '*.cu',
165
+ '*.g4',
137
166
  '*.h',
138
167
 
139
168
  '.manifests.json',
omlish/bootstrap/sys.py CHANGED
@@ -29,7 +29,7 @@ else:
29
29
  libc = lang.proxy_import('..libc', __package__)
30
30
  logs = lang.proxy_import('..logs', __package__)
31
31
  osu = lang.proxy_import('..os', __package__)
32
- dotenv = lang.proxy_import('.formats.dotenv', __package__)
32
+ dotenv = lang.proxy_import('..formats.dotenv', __package__)
33
33
 
34
34
 
35
35
  ##
@@ -89,15 +89,19 @@ from .impl.reflect import ( # noqa
89
89
  )
90
90
 
91
91
  from .utils import ( # noqa
92
- chain_metadata,
93
- deep_replace,
94
- field_modifier,
95
- fields_dict,
96
92
  maybe_post_init,
93
+
97
94
  opt_repr,
95
+ truthy_repr,
96
+
97
+ fields_dict,
98
+ field_modifier,
99
+ chain_metadata,
98
100
  update_class_metadata,
99
- update_field_extras,
100
101
  update_field_metadata,
102
+ update_field_extras,
101
103
  update_fields,
102
104
  update_fields_metadata,
105
+
106
+ deep_replace,
103
107
  )
@@ -33,7 +33,7 @@ def field( # noqa
33
33
  derive: ta.Callable[..., ta.Any] | None = None,
34
34
  coerce: bool | ta.Callable[[ta.Any], ta.Any] | None = None,
35
35
  validate: ta.Callable[[ta.Any], bool] | None = None,
36
- check_type: bool | type | None = None,
36
+ check_type: bool | type | tuple[type | None, ...] | None = None,
37
37
  override: bool = False,
38
38
  repr_fn: ta.Callable[[ta.Any], str | None] | None = None,
39
39
  frozen: bool | None = None,
@@ -193,7 +193,10 @@ def field_init(
193
193
 
194
194
  if fx.check_type:
195
195
  cn = f'__dataclass_check_type__{f.name}__'
196
- if isinstance(fx.check_type, type):
196
+ ct: ta.Any
197
+ if isinstance(fx.check_type, tuple):
198
+ ct = tuple(type(None) if e is None else check_.isinstance(e, type) for e in fx.check_type)
199
+ elif isinstance(fx.check_type, (type, tuple)):
197
200
  ct = fx.check_type
198
201
  # FIXME:
199
202
  # elif info.params_extras.generic_init:
@@ -45,7 +45,7 @@ class FieldExtras(lang.Final):
45
45
  derive: ta.Callable[..., ta.Any] | None = None # TODO
46
46
  coerce: bool | ta.Callable[[ta.Any], ta.Any] | None = None
47
47
  validate: ta.Callable[[ta.Any], bool] | None = None
48
- check_type: bool | type | None = None
48
+ check_type: bool | type | tuple[type | None, ...] | None = None
49
49
  override: bool = False
50
50
  repr_fn: ta.Callable[[ta.Any], str | None] | None = None
51
51
  frozen: bool | None = None # TODO
@@ -33,6 +33,10 @@ def opt_repr(o: ta.Any) -> str | None:
33
33
  return repr(o) if o is not None else None
34
34
 
35
35
 
36
+ def truthy_repr(o: ta.Any) -> str | None:
37
+ return repr(o) if o else None
38
+
39
+
36
40
  #
37
41
 
38
42
 
@@ -24,7 +24,8 @@ from .base import ( # noqa
24
24
  RecursiveMarshalerFactory,
25
25
  RecursiveUnmarshalerFactory,
26
26
 
27
- SetType,
27
+ Override,
28
+ ReflectOverride,
28
29
  )
29
30
 
30
31
  from .exceptions import ( # noqa
@@ -44,6 +45,8 @@ from .naming import ( # noqa
44
45
  )
45
46
 
46
47
  from .global_ import ( # noqa
48
+ GLOBAL_REGISTRY,
49
+
47
50
  marshal,
48
51
  unmarshal,
49
52
  )
@@ -56,10 +59,12 @@ from .helpers import ( # noqa
56
59
 
57
60
  from .objects import ( # noqa
58
61
  FieldInfo,
62
+ FieldInfos,
59
63
  FieldMetadata,
60
64
  FieldOptions,
61
65
  ObjectMarshaler,
62
66
  ObjectMetadata,
67
+ ObjectSpecials,
63
68
  ObjectUnmarshaler,
64
69
  SimpleObjectMarshalerFactory,
65
70
  SimpleObjectUnmarshalerFactory,
omlish/marshal/base.py CHANGED
@@ -81,11 +81,11 @@ https://github.com/yukinarit/pyserde
81
81
  - Flatten
82
82
  """
83
83
  import abc
84
- import dataclasses as dc
85
84
  import typing as ta
86
85
 
87
86
  from .. import check
88
87
  from .. import collections as col
88
+ from .. import dataclasses as dc
89
89
  from .. import lang
90
90
  from .. import matchfns as mfs
91
91
  from .. import reflect as rfl
@@ -163,13 +163,18 @@ class BaseContext(lang.Abstract):
163
163
  registry: Registry
164
164
  options: col.TypeMap[Option] = col.TypeMap()
165
165
 
166
+ def _reflect(self, o: ta.Any) -> rfl.Type:
167
+ if (ovr := self.registry.get_of(o, ReflectOverride)):
168
+ return ovr[-1].rty
169
+ return rfl.type_(o)
170
+
166
171
 
167
172
  @dc.dataclass(frozen=True)
168
173
  class MarshalContext(BaseContext, lang.Final):
169
174
  factory: MarshalerFactory | None = None
170
175
 
171
176
  def make(self, o: ta.Any) -> Marshaler:
172
- rty = rfl.type_(o)
177
+ rty = self._reflect(o)
173
178
  try:
174
179
  return check.not_none(self.factory)(self, rty) # type: ignore
175
180
  except mfs.MatchGuardError:
@@ -181,7 +186,7 @@ class UnmarshalContext(BaseContext, lang.Final):
181
186
  factory: UnmarshalerFactory | None = None
182
187
 
183
188
  def make(self, o: ta.Any) -> Unmarshaler:
184
- rty = rfl.type_(o)
189
+ rty = self._reflect(o)
185
190
  try:
186
191
  return check.not_none(self.factory)(self, rty) # type: ignore
187
192
  except mfs.MatchGuardError:
@@ -214,10 +219,15 @@ class RecursiveUnmarshalerFactory(RecursiveTypeFactory[UnmarshalContext, Unmarsh
214
219
  ##
215
220
 
216
221
 
217
- @dc.dataclass(frozen=True)
218
- class SetType(RegistryItem, lang.Final):
219
- marshaler: Marshaler | None = None
222
+ @dc.dataclass(frozen=True, kw_only=True)
223
+ class Override(RegistryItem, lang.Final):
224
+ marshaler: Marshaler | None = dc.xfield(None, check_type=(Marshaler, None))
220
225
  marshaler_factory: MarshalerFactory | None = None
221
226
 
222
- unmarshaler: Unmarshaler | None = None
227
+ unmarshaler: Unmarshaler | None = dc.xfield(None, check_type=(Unmarshaler, None))
223
228
  unmarshaler_factory: UnmarshalerFactory | None = None
229
+
230
+
231
+ @dc.dataclass(frozen=True)
232
+ class ReflectOverride(RegistryItem, lang.Final):
233
+ rty: rfl.Type
@@ -1,8 +1,13 @@
1
+ """
2
+ TODO:
3
+ - tangled with objects - Field/ObjectMetadata defined over there but unused
4
+ """
1
5
  import typing as ta
2
6
 
3
7
  from .. import check
4
8
  from .. import collections as col
5
9
  from .. import dataclasses as dc
10
+ from .. import lang
6
11
  from .. import reflect as rfl
7
12
  from .base import MarshalContext
8
13
  from .base import Marshaler
@@ -16,6 +21,7 @@ from .naming import translate_name
16
21
  from .objects import DEFAULT_FIELD_OPTIONS
17
22
  from .objects import FIELD_OPTIONS_KWARGS
18
23
  from .objects import FieldInfo
24
+ from .objects import FieldInfos
19
25
  from .objects import FieldMetadata
20
26
  from .objects import FieldOptions
21
27
  from .objects import ObjectMarshaler
@@ -37,7 +43,7 @@ def get_dataclass_metadata(ty: type) -> ObjectMetadata:
37
43
  def get_field_infos(
38
44
  ty: type,
39
45
  opts: col.TypeMap[Option] = col.TypeMap(),
40
- ) -> ta.Sequence[FieldInfo]:
46
+ ) -> FieldInfos:
41
47
  dc_md = get_dataclass_metadata(ty)
42
48
  dc_naming = dc_md.field_naming or opts.get(Naming)
43
49
 
@@ -96,6 +102,15 @@ def get_field_infos(
96
102
  unmarshal_names=[n + '_' for n in fi_kw['unmarshal_names']],
97
103
  )
98
104
 
105
+ if fo_kw.get('no_marshal'):
106
+ fi_kw.update(
107
+ marshal_name=None,
108
+ )
109
+ if fo_kw.get('no_unmarshal'):
110
+ fi_kw.update(
111
+ unmarshal_names=(),
112
+ )
113
+
99
114
  ret.append(
100
115
  FieldInfo(
101
116
  options=FieldOptions(**fo_kw),
@@ -103,7 +118,7 @@ def get_field_infos(
103
118
  ),
104
119
  )
105
120
 
106
- return ret
121
+ return FieldInfos(ret)
107
122
 
108
123
 
109
124
  def _make_field_obj(ctx, ty, obj, fac):
@@ -119,22 +134,25 @@ def _make_field_obj(ctx, ty, obj, fac):
119
134
 
120
135
  class DataclassMarshalerFactory(MarshalerFactory):
121
136
  def guard(self, ctx: MarshalContext, rty: rfl.Type) -> bool:
122
- return isinstance(rty, type) and dc.is_dataclass(rty)
137
+ return isinstance(rty, type) and dc.is_dataclass(rty) and not lang.is_abstract_class(rty)
123
138
 
124
139
  def fn(self, ctx: MarshalContext, rty: rfl.Type) -> Marshaler:
125
140
  ty = check.isinstance(rty, type)
126
141
  check.state(dc.is_dataclass(ty))
142
+ check.state(not lang.is_abstract_class(ty))
127
143
 
128
144
  dc_md = get_dataclass_metadata(ty)
145
+ fis = get_field_infos(ty, ctx.options)
129
146
 
130
147
  fields = [
131
148
  (fi, _make_field_obj(ctx, fi.type, fi.metadata.marshaler, fi.metadata.marshaler_factory))
132
- for fi in get_field_infos(ty, ctx.options)
149
+ for fi in fis
150
+ if fi.name not in dc_md.specials.set
133
151
  ]
134
152
 
135
153
  return ObjectMarshaler(
136
154
  fields,
137
- unknown_field=dc_md.unknown_field,
155
+ specials=dc_md.specials,
138
156
  )
139
157
 
140
158
 
@@ -143,12 +161,15 @@ class DataclassMarshalerFactory(MarshalerFactory):
143
161
 
144
162
  class DataclassUnmarshalerFactory(UnmarshalerFactory):
145
163
  def guard(self, ctx: UnmarshalContext, rty: rfl.Type) -> bool:
146
- return isinstance(rty, type) and dc.is_dataclass(rty)
164
+ return isinstance(rty, type) and dc.is_dataclass(rty) and not lang.is_abstract_class(rty)
147
165
 
148
166
  def fn(self, ctx: UnmarshalContext, rty: rfl.Type) -> Unmarshaler:
149
167
  ty = check.isinstance(rty, type)
150
168
  check.state(dc.is_dataclass(ty))
169
+ check.state(not lang.is_abstract_class(ty))
170
+
151
171
  dc_md = get_dataclass_metadata(ty)
172
+ fis = get_field_infos(ty, ctx.options)
152
173
 
153
174
  d: dict[str, tuple[FieldInfo, Unmarshaler]] = {}
154
175
  defaults: dict[str, ta.Any] = {}
@@ -161,7 +182,9 @@ class DataclassUnmarshalerFactory(UnmarshalerFactory):
161
182
  if fi.options.embed:
162
183
  e_ty = check.isinstance(fi.type, type)
163
184
  check.state(dc.is_dataclass(e_ty))
164
- # e_dc_md = get_dataclass_metadata(e_ty)
185
+ e_dc_md = get_dataclass_metadata(e_ty)
186
+ if e_dc_md.specials.set:
187
+ raise Exception(f'Embedded fields cannot have specials: {e_ty}')
165
188
 
166
189
  embeds[fi.name] = e_ty
167
190
  for e_fi in get_field_infos(e_ty, ctx.options):
@@ -185,14 +208,17 @@ class DataclassUnmarshalerFactory(UnmarshalerFactory):
185
208
 
186
209
  return ret
187
210
 
188
- for fi in get_field_infos(ty, ctx.options):
211
+ for fi in fis:
212
+ if fi.name in dc_md.specials.set:
213
+ continue
189
214
  add_field(fi)
190
215
 
191
216
  return ObjectUnmarshaler(
192
217
  ty,
193
218
  d,
194
- unknown_field=dc_md.unknown_field,
219
+ specials=dc_md.specials,
195
220
  defaults=defaults,
196
221
  embeds=embeds,
197
222
  embeds_by_unmarshal_name=embeds_by_unmarshal_name,
223
+ ignore_unknown=dc_md.ignore_unknown,
198
224
  )
omlish/marshal/global_.py CHANGED
@@ -17,7 +17,7 @@ T = ta.TypeVar('T')
17
17
  ##
18
18
 
19
19
 
20
- GLOBAL_REGISTRY = Registry()
20
+ GLOBAL_REGISTRY: Registry = Registry()
21
21
 
22
22
 
23
23
  ##
omlish/marshal/objects.py CHANGED
@@ -8,7 +8,9 @@ TODO:
8
8
  import collections.abc
9
9
  import typing as ta
10
10
 
11
+ from .. import cached
11
12
  from .. import check
13
+ from .. import collections as col
12
14
  from .. import dataclasses as dc
13
15
  from .. import lang
14
16
  from .. import reflect as rfl
@@ -33,6 +35,9 @@ class FieldOptions:
33
35
 
34
36
  embed: bool = False
35
37
 
38
+ no_marshal: bool = False
39
+ no_unmarshal: bool = False
40
+
36
41
 
37
42
  DEFAULT_FIELD_OPTIONS = FieldOptions()
38
43
  FIELD_OPTIONS_KWARGS: frozenset[str] = frozenset(dc.fields_dict(FieldOptions).keys())
@@ -45,10 +50,10 @@ class FieldMetadata:
45
50
 
46
51
  options: FieldOptions = DEFAULT_FIELD_OPTIONS
47
52
 
48
- marshaler: Marshaler | None = None
53
+ marshaler: Marshaler | None = dc.xfield(None, check_type=(Marshaler, None))
49
54
  marshaler_factory: MarshalerFactory | None = None
50
55
 
51
- unmarshaler: Unmarshaler | None = None
56
+ unmarshaler: Unmarshaler | None = dc.xfield(None, check_type=(Unmarshaler, None))
52
57
  unmarshaler_factory: UnmarshalerFactory | None = None
53
58
 
54
59
  def update(self, **kwargs: ta.Any) -> 'FieldMetadata':
@@ -66,9 +71,29 @@ class ObjectMetadata:
66
71
  field_naming: Naming | None = None
67
72
 
68
73
  unknown_field: str | None = None
74
+ source_field: str | None = None
75
+
76
+ @cached.property
77
+ def specials(self) -> 'ObjectSpecials':
78
+ return ObjectSpecials(
79
+ unknown=self.unknown_field,
80
+ source=self.source_field,
81
+ )
69
82
 
70
83
  field_defaults: FieldMetadata = FieldMetadata()
71
84
 
85
+ ignore_unknown: bool = False
86
+
87
+
88
+ @dc.dataclass(frozen=True, kw_only=True)
89
+ class ObjectSpecials:
90
+ unknown: str | None = None
91
+ source: str | None = None
92
+
93
+ @cached.property
94
+ def set(self) -> frozenset[str]:
95
+ return frozenset(k for k, v in dc.asdict(self).items() if v is not None)
96
+
72
97
 
73
98
  ##
74
99
 
@@ -78,7 +103,7 @@ class FieldInfo:
78
103
  name: str
79
104
  type: ta.Any
80
105
 
81
- marshal_name: str
106
+ marshal_name: str | None
82
107
  unmarshal_names: ta.Sequence[str]
83
108
 
84
109
  metadata: FieldMetadata = FieldMetadata()
@@ -86,6 +111,32 @@ class FieldInfo:
86
111
  options: FieldOptions = FieldOptions()
87
112
 
88
113
 
114
+ @dc.dataclass(frozen=True)
115
+ class FieldInfos:
116
+ lst: ta.Sequence[FieldInfo]
117
+
118
+ def __iter__(self) -> ta.Iterator[FieldInfo]:
119
+ return iter(self.lst)
120
+
121
+ def __len__(self) -> int:
122
+ return len(self.lst)
123
+
124
+ @cached.property
125
+ @dc.init
126
+ def by_name(self) -> ta.Mapping[str, FieldInfo]:
127
+ return col.make_map(((fi.name, fi) for fi in self), strict=True)
128
+
129
+ @cached.property
130
+ @dc.init
131
+ def by_marshal_name(self) -> ta.Mapping[str, FieldInfo]:
132
+ return col.make_map(((fi.marshal_name, fi) for fi in self if fi.marshal_name is not None), strict=True)
133
+
134
+ @cached.property
135
+ @dc.init
136
+ def by_unmarshal_name(self) -> ta.Mapping[str, FieldInfo]:
137
+ return col.make_map(((n, fi) for fi in self for n in fi.unmarshal_names), strict=True)
138
+
139
+
89
140
  ##
90
141
 
91
142
 
@@ -95,7 +146,7 @@ class ObjectMarshaler(Marshaler):
95
146
 
96
147
  _: dc.KW_ONLY
97
148
 
98
- unknown_field: str | None = None
149
+ specials: ObjectSpecials = ObjectSpecials()
99
150
 
100
151
  def marshal(self, ctx: MarshalContext, o: ta.Any) -> Value:
101
152
  ret: dict[str, ta.Any] = {}
@@ -105,17 +156,24 @@ class ObjectMarshaler(Marshaler):
105
156
  if fi.options.omit_if is not None and fi.options.omit_if(v):
106
157
  continue
107
158
 
159
+ if fi.name in self.specials.set:
160
+ continue
161
+
162
+ mn = fi.marshal_name
163
+ if mn is None:
164
+ continue
165
+
108
166
  mv = m.marshal(ctx, v)
109
167
 
110
168
  if fi.options.embed:
111
169
  for ek, ev in check.isinstance(mv, collections.abc.Mapping).items():
112
- ret[fi.marshal_name + check.non_empty_str(ek)] = ev # type: ignore
170
+ ret[mn + check.non_empty_str(ek)] = ev # type: ignore
113
171
 
114
172
  else:
115
- ret[fi.marshal_name] = mv
173
+ ret[mn] = mv
116
174
 
117
- if self.unknown_field is not None:
118
- if (ukf := getattr(o, self.unknown_field)):
175
+ if self.specials.unknown is not None:
176
+ if (ukf := getattr(o, self.specials.unknown)):
119
177
  if (dks := set(ret) & set(ukf)):
120
178
  raise KeyError(f'Unknown field keys duplicate fields: {dks!r}')
121
179
 
@@ -130,7 +188,7 @@ class SimpleObjectMarshalerFactory(MarshalerFactory):
130
188
 
131
189
  _: dc.KW_ONLY
132
190
 
133
- unknown_field: str | None = None
191
+ specials: ObjectSpecials = ObjectSpecials()
134
192
 
135
193
  def guard(self, ctx: MarshalContext, rty: rfl.Type) -> bool:
136
194
  return isinstance(rty, type) and rty in self.dct
@@ -138,7 +196,7 @@ class SimpleObjectMarshalerFactory(MarshalerFactory):
138
196
  def fn(self, ctx: MarshalContext, rty: rfl.Type) -> Marshaler:
139
197
  ty = check.isinstance(rty, type)
140
198
 
141
- flds = self.dct[ty]
199
+ flds = FieldInfos(self.dct[ty])
142
200
 
143
201
  fields = [
144
202
  (fi, ctx.make(fi.type))
@@ -147,7 +205,7 @@ class SimpleObjectMarshalerFactory(MarshalerFactory):
147
205
 
148
206
  return ObjectMarshaler(
149
207
  fields,
150
- unknown_field=self.unknown_field,
208
+ specials=self.specials,
151
209
  )
152
210
 
153
211
 
@@ -161,13 +219,15 @@ class ObjectUnmarshaler(Unmarshaler):
161
219
 
162
220
  _: dc.KW_ONLY
163
221
 
164
- unknown_field: str | None = None
222
+ specials: ObjectSpecials = ObjectSpecials()
165
223
 
166
224
  defaults: ta.Mapping[str, ta.Any] | None = None
167
225
 
168
226
  embeds: ta.Mapping[str, type] | None = None
169
227
  embeds_by_unmarshal_name: ta.Mapping[str, tuple[str, str]] | None = None
170
228
 
229
+ ignore_unknown: bool = False
230
+
171
231
  def unmarshal(self, ctx: UnmarshalContext, v: Value) -> ta.Any:
172
232
  ma = check.isinstance(v, collections.abc.Mapping)
173
233
 
@@ -177,8 +237,11 @@ class ObjectUnmarshaler(Unmarshaler):
177
237
 
178
238
  ekws: dict[str, dict[str, ta.Any]] = {en: {} for en in self.embeds or ()}
179
239
 
180
- if self.unknown_field is not None:
181
- kw[self.unknown_field] = ukf = {}
240
+ if self.specials.source is not None:
241
+ kw[self.specials.source] = v
242
+
243
+ if self.specials.unknown is not None:
244
+ kw[self.specials.unknown] = ukf = {}
182
245
 
183
246
  for k, mv in ma.items():
184
247
  ks = check.isinstance(k, str)
@@ -190,6 +253,10 @@ class ObjectUnmarshaler(Unmarshaler):
190
253
  if ukf is not None:
191
254
  ukf[ks] = mv # FIXME: unmarshal?
192
255
  continue
256
+
257
+ if self.ignore_unknown:
258
+ continue
259
+
193
260
  raise
194
261
 
195
262
  if self.embeds_by_unmarshal_name and (en := self.embeds_by_unmarshal_name.get(ks)):
@@ -220,7 +287,7 @@ class SimpleObjectUnmarshalerFactory(UnmarshalerFactory):
220
287
 
221
288
  _: dc.KW_ONLY
222
289
 
223
- unknown_field: str | None = None
290
+ specials: ObjectSpecials = ObjectSpecials()
224
291
 
225
292
  def guard(self, ctx: UnmarshalContext, rty: rfl.Type) -> bool:
226
293
  return isinstance(rty, type) and rty in self.dct
@@ -228,7 +295,7 @@ class SimpleObjectUnmarshalerFactory(UnmarshalerFactory):
228
295
  def fn(self, ctx: UnmarshalContext, rty: rfl.Type) -> Unmarshaler:
229
296
  ty = check.isinstance(rty, type)
230
297
 
231
- flds = self.dct[ty]
298
+ flds = FieldInfos(self.dct[ty])
232
299
 
233
300
  fields_by_unmarshal_name = {
234
301
  n: (fi, ctx.make(fi.type))
@@ -245,6 +312,6 @@ class SimpleObjectUnmarshalerFactory(UnmarshalerFactory):
245
312
  return ObjectUnmarshaler(
246
313
  ty,
247
314
  fields_by_unmarshal_name,
248
- unknown_field=self.unknown_field,
315
+ specials=self.specials,
249
316
  defaults=defaults,
250
317
  )
@@ -1,10 +1,13 @@
1
+ """
2
+ TODO:
3
+ - inheritance
4
+ """
1
5
  import dataclasses as dc
2
6
  import threading
3
7
  import typing as ta
4
8
 
5
- from .. import check
9
+ from .. import collections as col
6
10
  from .. import lang
7
- from .. import reflect as rfl
8
11
 
9
12
 
10
13
  class RegistryItem(lang.Abstract):
@@ -15,8 +18,8 @@ RegistryItemT = ta.TypeVar('RegistryItemT', bound=RegistryItem)
15
18
 
16
19
 
17
20
  @dc.dataclass(frozen=True)
18
- class _TypeRegistry:
19
- rty: rfl.Type
21
+ class _KeyRegistryItems:
22
+ key: ta.Any
20
23
  items: list[RegistryItem] = dc.field(default_factory=list)
21
24
  item_lists_by_ty: dict[type[RegistryItem], list[RegistryItem]] = dc.field(default_factory=dict)
22
25
 
@@ -30,28 +33,54 @@ class Registry:
30
33
  def __init__(self) -> None:
31
34
  super().__init__()
32
35
  self._mtx = threading.Lock()
33
- self._dct: dict[rfl.Type, _TypeRegistry] = {}
34
- self._ps: ta.Sequence[Registry] = []
36
+ self._idct: ta.MutableMapping[ta.Any, _KeyRegistryItems] = col.IdentityKeyDict()
37
+ self._dct: dict[ta.Any, _KeyRegistryItems] = {}
35
38
 
36
- def register(self, rty: rfl.Type, *items: RegistryItem) -> 'Registry':
37
- check.isinstance(rty, rfl.TYPES)
39
+ def register(
40
+ self,
41
+ key: ta.Any,
42
+ *items: RegistryItem,
43
+ identity: bool = False,
44
+ ) -> 'Registry':
38
45
  with self._mtx:
39
- if (sr := self._dct.get(rty)) is None:
40
- sr = self._dct[rty] = _TypeRegistry(rty)
46
+ dct: ta.Any = self._idct if identity else self._dct
47
+ if (sr := dct.get(key)) is None:
48
+ sr = dct[key] = _KeyRegistryItems(key)
41
49
  sr.add(*items)
42
50
  return self
43
51
 
44
- def get(self, rty: rfl.Type) -> ta.Sequence[RegistryItem]:
45
- check.isinstance(rty, rfl.TYPES)
52
+ def get(
53
+ self,
54
+ key: ta.Any,
55
+ *,
56
+ identity: bool | None = None,
57
+ ) -> ta.Sequence[RegistryItem]:
58
+ if identity is None:
59
+ return (
60
+ *self.get(key, identity=True),
61
+ *self.get(key, identity=False),
62
+ )
63
+ dct: ta.Any = self._idct if identity else self._dct
46
64
  try:
47
- return self._dct[rty].items
65
+ return dct[key].items
48
66
  except KeyError:
49
67
  return ()
50
68
 
51
- def get_of(self, rty: rfl.Type, item_ty: type[RegistryItemT]) -> ta.Sequence[RegistryItemT]:
52
- check.isinstance(rty, rfl.TYPES)
69
+ def get_of(
70
+ self,
71
+ key: ta.Any,
72
+ item_ty: type[RegistryItemT],
73
+ *,
74
+ identity: bool | None = None,
75
+ ) -> ta.Sequence[RegistryItemT]:
76
+ if identity is None:
77
+ return (
78
+ *self.get_of(key, item_ty, identity=True),
79
+ *self.get_of(key, item_ty, identity=False),
80
+ )
81
+ dct: ta.Any = self._idct if identity else self._dct
53
82
  try:
54
- sr = self._dct[rty]
83
+ sr = dct[key]
55
84
  except KeyError:
56
85
  return ()
57
- return sr.item_lists_by_ty.get(item_ty, ()) # type: ignore
86
+ return sr.item_lists_by_ty.get(item_ty, ())
@@ -7,6 +7,7 @@ from .secrets import ( # noqa
7
7
  FnSecrets,
8
8
  LoggingSecrets,
9
9
  MappingSecrets,
10
+ Secret,
10
11
  SecretRef,
11
12
  SecretRefOrStr,
12
13
  Secrets,
omlish/secrets/secrets.py CHANGED
@@ -99,6 +99,12 @@ class Secrets(lang.Abstract):
99
99
  else:
100
100
  return Secret(key=key, value=raw)
101
101
 
102
+ def try_get(self, key: str) -> Secret | None:
103
+ try:
104
+ return self.get(key)
105
+ except KeyError:
106
+ return None
107
+
102
108
  @abc.abstractmethod
103
109
  def _get_raw(self, key: str) -> str:
104
110
  raise NotImplementedError
@@ -119,15 +125,36 @@ EMPTY_SECRETS = EmptySecrets()
119
125
 
120
126
 
121
127
  class MappingSecrets(Secrets):
122
- def __init__(self, dct: ta.Mapping[str, str]) -> None:
128
+ def __init__(
129
+ self,
130
+ dct: ta.Mapping[str, str | Secret],
131
+ no_copy: bool = False,
132
+ ) -> None:
123
133
  super().__init__()
134
+
135
+ if not no_copy:
136
+ dct = {
137
+ k: v if isinstance(v, Secret) else Secret(key=k, value=v)
138
+ for k, v in dct.items()
139
+ }
140
+
124
141
  self._dct = dct
125
142
 
126
143
  def __repr__(self) -> str:
127
144
  return f'{self.__class__.__name__}({{{", ".join(map(repr, self._dct.keys()))}}})'
128
145
 
129
146
  def _get_raw(self, key: str) -> str:
130
- return self._dct[key]
147
+ try:
148
+ e = self._dct[key]
149
+ except KeyError: # noqa
150
+ raise
151
+ else:
152
+ if isinstance(e, Secret):
153
+ return e.reveal()
154
+ elif isinstance(e, str):
155
+ return e
156
+ else:
157
+ raise TypeError(e)
131
158
 
132
159
 
133
160
  ##
@@ -167,7 +194,7 @@ class CachingSecrets(Secrets):
167
194
  ) -> None:
168
195
  super().__init__()
169
196
  self._child = child
170
- self._dct: dict[str, str] = {}
197
+ self._dct: dict[str, Secret] = {}
171
198
  self._ttl_s = ttl_s
172
199
  self._clock = clock
173
200
  self._deque: collections.deque[tuple[str, float]] = collections.deque()
@@ -187,15 +214,17 @@ class CachingSecrets(Secrets):
187
214
  def _get_raw(self, key: str) -> str:
188
215
  self.evict()
189
216
  try:
190
- return self._dct[key]
217
+ e = self._dct[key]
191
218
  except KeyError:
192
219
  pass
193
- out = self._child._get_raw(key) # noqa
220
+ else:
221
+ return e.reveal()
222
+ out = self._child.get(key) # noqa
194
223
  self._dct[key] = out
195
224
  if self._ttl_s is not None:
196
225
  dl = self._clock() + self._ttl_s
197
226
  self._deque.append((key, dl))
198
- return out
227
+ return out.reveal()
199
228
 
200
229
 
201
230
  ##
@@ -1,6 +1,6 @@
1
1
  # @omlish-manifest
2
2
  _CLI_MODULE = {'$omdev.cli.types.CliModule': {
3
- 'cmd_name': 'jp',
3
+ 'cmd_name': ['jmespath', 'jp'],
4
4
  'mod_name': __name__,
5
5
  }}
6
6
 
@@ -172,21 +172,17 @@ def register(*args: inj.Element | inj.Elements) -> None:
172
172
  _HARNESS_ELEMENTS_LIST.append(inj.as_elements(*args))
173
173
 
174
174
 
175
- TypeT = ta.TypeVar('TypeT', bound=type)
176
-
177
-
178
175
  def bind(
179
176
  scope: PytestScope | str = PytestScope.SESSION,
180
177
  *,
181
178
  eager: bool = False, # FIXME
182
- ) -> ta.Callable[[TypeT], TypeT]:
183
- def inner(cls):
179
+ ) -> ta.Callable[[T], T]:
180
+ def inner(obj):
184
181
  pts = scope if isinstance(scope, PytestScope) else PytestScope[check.isinstance(scope, str).upper()]
185
- check.isinstance(cls, type)
186
182
  register(inj.as_elements(
187
- inj.bind(cls, in_=_SCOPES_BY_PYTEST_SCOPE[pts]),
183
+ inj.bind(obj, in_=_SCOPES_BY_PYTEST_SCOPE[pts]),
188
184
  ))
189
- return cls
185
+ return obj
190
186
  return inner
191
187
 
192
188
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: omlish
3
- Version: 0.0.0.dev51
3
+ Version: 0.0.0.dev53
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -26,7 +26,7 @@ Requires-Dist: psutil ~=6.0 ; extra == 'all'
26
26
  Requires-Dist: orjson ~=3.10 ; extra == 'all'
27
27
  Requires-Dist: ujson ~=5.10 ; extra == 'all'
28
28
  Requires-Dist: json5 ~=0.9 ; extra == 'all'
29
- Requires-Dist: pyyaml ~=5.0 ; extra == 'all'
29
+ Requires-Dist: pyyaml ~=6.0 ; extra == 'all'
30
30
  Requires-Dist: cbor2 ~=5.6 ; extra == 'all'
31
31
  Requires-Dist: cloudpickle ~=3.0 ; extra == 'all'
32
32
  Requires-Dist: httpx[http2] ~=0.27 ; extra == 'all'
@@ -61,13 +61,21 @@ Provides-Extra: formats
61
61
  Requires-Dist: orjson ~=3.10 ; extra == 'formats'
62
62
  Requires-Dist: ujson ~=5.10 ; extra == 'formats'
63
63
  Requires-Dist: json5 ~=0.9 ; extra == 'formats'
64
- Requires-Dist: pyyaml ~=5.0 ; extra == 'formats'
64
+ Requires-Dist: pyyaml ~=6.0 ; extra == 'formats'
65
65
  Requires-Dist: cbor2 ~=5.6 ; extra == 'formats'
66
66
  Requires-Dist: cloudpickle ~=3.0 ; extra == 'formats'
67
67
  Provides-Extra: http
68
68
  Requires-Dist: httpx[http2] ~=0.27 ; extra == 'http'
69
69
  Provides-Extra: misc
70
70
  Requires-Dist: wrapt ~=1.14 ; extra == 'misc'
71
+ Provides-Extra: plus
72
+ Requires-Dist: anyio ~=4.6 ; extra == 'plus'
73
+ Requires-Dist: sniffio ~=1.3 ; extra == 'plus'
74
+ Requires-Dist: asttokens ~=2.4 ; extra == 'plus'
75
+ Requires-Dist: executing ~=2.1 ; extra == 'plus'
76
+ Requires-Dist: orjson ~=3.10 ; extra == 'plus'
77
+ Requires-Dist: pyyaml ~=6.0 ; extra == 'plus'
78
+ Requires-Dist: wrapt ~=1.14 ; extra == 'plus'
71
79
  Provides-Extra: secrets
72
80
  Requires-Dist: cryptography ~=43.0 ; extra == 'secrets'
73
81
  Provides-Extra: sqlalchemy
@@ -1,5 +1,5 @@
1
- omlish/.manifests.json,sha256=sAddTbCUKdX0UYA4PeZ_z9JKF0vyzEpFYWq1tAAl9bw,1091
2
- omlish/__about__.py,sha256=jc5K7hc6tkDx6B2eK-ieJvhYrFDbPJ4znzwOrHgZmW0,2919
1
+ omlish/.manifests.json,sha256=Xj-NnBpowZX7faAyhZ2j7g4fPFFw9Da7ITTC8AojNlM,1135
2
+ omlish/__about__.py,sha256=4iuzysEDi0v06iklWiEVu40-L9v4vnDdEPsxeJVo3eU,3420
3
3
  omlish/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  omlish/argparse.py,sha256=Vr70_85EVLJLgEkRtwOr264tMRtqtlN7ncFfXRUk5aM,6914
5
5
  omlish/c3.py,sha256=4vogWgwPb8TbNS2KkZxpoWbwjj7MuHG2lQG-hdtkvjI,8062
@@ -34,7 +34,7 @@ omlish/bootstrap/diag.py,sha256=x_BKS_uhfW8QFk1NeH_VIocHif-A6FVTZ37262qCgZ0,5052
34
34
  omlish/bootstrap/harness.py,sha256=vDnpM0ZLSJaylxQNA4u2lwQwiU-KXZDb7MlkrhchFJY,2022
35
35
  omlish/bootstrap/main.py,sha256=u-TfxO4GkAK3LbRweQERogtO4kT0z3gqXRjnXvtJzC8,5328
36
36
  omlish/bootstrap/marshal.py,sha256=ZxdAeMNd2qXRZ1HUK89HmEhz8tqlS9OduW34QBscKw0,516
37
- omlish/bootstrap/sys.py,sha256=U0MFxO9tLFV3cdN5Y-Zrink6_45sFvzPUYQXyBk7-ns,8741
37
+ omlish/bootstrap/sys.py,sha256=i6veZeE83wO0HTl9b6ykj_pEN05fqu0enoAv4sw5Ayc,8742
38
38
  omlish/collections/__init__.py,sha256=tGUzvS_ZjiqALsLRy7JX3h4KZRQX2CmtdAfTRD7UwMk,1677
39
39
  omlish/collections/_abc.py,sha256=sP7BpTVhx6s6C59mTFeosBi4rHOWC6tbFBYbxdZmvh0,2365
40
40
  omlish/collections/_io_abc.py,sha256=Cxs8KB1B_69rxpUYxI-MTsilAmNooJJn3w07DKqYKkE,1255
@@ -64,16 +64,16 @@ omlish/configs/__init__.py,sha256=3uh09ezodTwkMI0nRmAMP0eEuJ_0VdF-LYyNmPjHiCE,77
64
64
  omlish/configs/classes.py,sha256=GLbB8xKjHjjoUQRCUQm3nEjM8z1qNTx9gPV7ODSt5dg,1317
65
65
  omlish/configs/flattening.py,sha256=AOlRpBHm449MxwMp3CiIRGunStOC1DUNs1f3CLou0wc,4731
66
66
  omlish/configs/strings.py,sha256=0brx1duL85r1GpfbNvbHcSvH4jWzutwuvMFXda9NeI0,2651
67
- omlish/dataclasses/__init__.py,sha256=LALx4dXSvBWAKzmZxb3rkNdoR7kOaXeGcVypTnECvcw,1354
68
- omlish/dataclasses/utils.py,sha256=Ewd6w31uXy1sVUj59sxmXfGuI0CgsAbcfNXx0tsrNco,3347
67
+ omlish/dataclasses/__init__.py,sha256=k358fyF6LWsiWfd7u1d4CHDn2F4wQZCb5hXtSSc1Hck,1374
68
+ omlish/dataclasses/utils.py,sha256=MzEeF8W6Yr5BjOVJOM0Au4YIMGAarXWxT0C6gzlhmfU,3425
69
69
  omlish/dataclasses/impl/LICENSE,sha256=Oy-B_iHRgcSZxZolbI4ZaEVdZonSaaqFNzv7avQdo78,13936
70
70
  omlish/dataclasses/impl/__init__.py,sha256=0hgOm3_u3yimjEkB-9fRMqX9rAW6kQC5t8XL0lpvffQ,410
71
- omlish/dataclasses/impl/api.py,sha256=6QtUAbP3DQZw8WEkgpsYfYKTn4CQBV9v0z2B4fTcR80,6405
71
+ omlish/dataclasses/impl/api.py,sha256=p7W519_EnDAWlkOVS-4BpP4SxadWIiUzC3RldSoB28o,6431
72
72
  omlish/dataclasses/impl/as_.py,sha256=CD-t7hkC1EP2F_jvZKIA_cVoDuwZ-Ln_xC4fJumPYX0,2598
73
73
  omlish/dataclasses/impl/copy.py,sha256=Tn8_n6Vohs-w4otbGdubBEvhd3TsSTaM3EfNGdS2LYo,591
74
74
  omlish/dataclasses/impl/descriptors.py,sha256=rEYE1Len99agTQCC25hSPMnM19BgPr0ZChABGi58Fdk,2476
75
75
  omlish/dataclasses/impl/exceptions.py,sha256=DeiM6rcjgncudn-XVuph9TDbVDEwBtyYb1bcbO3FFcA,193
76
- omlish/dataclasses/impl/fields.py,sha256=NIu30OggZvKhqQaZWad9dAE-B9yt9qvWtPR5U_TJIbQ,6281
76
+ omlish/dataclasses/impl/fields.py,sha256=iXA8j3q8GFQoj-6MgAKVLGG9GSSNOLGgyVtogCQ5q1E,6459
77
77
  omlish/dataclasses/impl/frozen.py,sha256=x87DSM8FIMZ3c_BIUE8NooCkExFjPsabeqIueEP5qKs,2988
78
78
  omlish/dataclasses/impl/hashing.py,sha256=FKnHuXCg9ylrzK2TLGqO5yfRN4HX3F415CSLlVYXtYE,3190
79
79
  omlish/dataclasses/impl/init.py,sha256=IgxO9nwHaHF8jGrUAk-Y5xke9uV2OwzfEe-88McE1Wg,6161
@@ -82,7 +82,7 @@ omlish/dataclasses/impl/main.py,sha256=Ti0PKbFKraKvfmoPuR-G7nLVNzRC8mvEuXhCuC-M2
82
82
  omlish/dataclasses/impl/metaclass.py,sha256=dlQEIN9MHBirll7Nx3StpzxYxXjrqxJ-QsorMcCNt7w,2828
83
83
  omlish/dataclasses/impl/metadata.py,sha256=4veWwTr-aA0KP-Y1cPEeOcXHup9EKJTYNJ0ozIxtzD4,1401
84
84
  omlish/dataclasses/impl/order.py,sha256=zWvWDkSTym8cc7vO1cLHqcBhhjOlucHOCUVJcdh4jt0,1369
85
- omlish/dataclasses/impl/params.py,sha256=IDM9VK-b5x7VauwYwXtwb9cg94UNpRUoZ0OH-Bv_kmM,2674
85
+ omlish/dataclasses/impl/params.py,sha256=-RDsDDHmTjXY-7bSJzKlRJJdyf1pNUfqwcswS4ZZhH0,2700
86
86
  omlish/dataclasses/impl/processing.py,sha256=DFxyFjL_h3awRyF_5eyTnB8QkuApx7Zc4QFnVoltlao,459
87
87
  omlish/dataclasses/impl/reflect.py,sha256=a19BbNxrmjNTbXzWuAl_794RCIQSMYyVqQ2Bf-DnNnM,5305
88
88
  omlish/dataclasses/impl/replace.py,sha256=wS9GHX4fIwaPv1JBJzIewdBfXyK3X3V7_t55Da87dYo,1217
@@ -219,28 +219,28 @@ omlish/logs/formatters.py,sha256=q79nMnR2mRIStPyGrydQHpYTXgC5HHptt8lH3W2Wwbs,671
219
219
  omlish/logs/handlers.py,sha256=nyuFgmO05By_Xwq7es58ClzS51-F53lJL7gD0x5IqAg,228
220
220
  omlish/logs/noisy.py,sha256=Ubc-eTH6ZbGYsLfUUi69JAotwuUwzb-SJBeGo_0dIZI,348
221
221
  omlish/logs/utils.py,sha256=MgGovbP0zUrZ3FGD3qYNQWn-l0jy0Y0bStcQvv5BOmQ,391
222
- omlish/marshal/__init__.py,sha256=_vx3txFh09j3SoxSfSS4AwwnDa9jgAWzXYjluIitGWA,1969
222
+ omlish/marshal/__init__.py,sha256=Aiux91y66MpEy4NiecWgASK8RB8vGXpc4GZ4HgbdwCg,2049
223
223
  omlish/marshal/any.py,sha256=e82OyYK3Emm1P1ClnsnxP7fIWC2iNVyW0H5nK4mLmWM,779
224
- omlish/marshal/base.py,sha256=ceNjOFxCwLNuxkmxofk3Sh5rE39JGxnc4giN7NNr9kA,6121
224
+ omlish/marshal/base.py,sha256=I7IOzFGn_DFeBRFCH8F0ONBa-NzM4mmMDld6bmoW-rc,6501
225
225
  omlish/marshal/base64.py,sha256=F-3ogJdcFCtWINRgJgWT0rErqgx6f4qahhcg8OrkqhE,1089
226
- omlish/marshal/dataclasses.py,sha256=B21hFukA9pNhp-PzBWG7rxz_F5BjNzMxU3nFURRrGXo,6037
226
+ omlish/marshal/dataclasses.py,sha256=G6Uh8t4vvNBAx2BhzH8ksj8Hq_bo6npFphQhyF298VU,6892
227
227
  omlish/marshal/datetimes.py,sha256=0ffg8cEvx9SMKIXZGD9b7MqpLfmgw0uKKdn6YTfoqok,3714
228
228
  omlish/marshal/enums.py,sha256=-0fKutBbyz8ygEaA0_P_8IOJrI9jMGigmnPbutV9Bg4,1464
229
229
  omlish/marshal/exceptions.py,sha256=jwQWn4LcPnadT2KRI_1JJCOSkwWh0yHnYK9BmSkNN4U,302
230
230
  omlish/marshal/factories.py,sha256=UV2Svjok-lTWsRqKGh-CeuAhvlohw9uJe7ZLyoKMvTM,2968
231
231
  omlish/marshal/forbidden.py,sha256=BNshzm4lN5O8sUZ1YvxrSYq3WPklq9NMQCRZ7RC3DLM,865
232
- omlish/marshal/global_.py,sha256=8XCjPcIjA65StESshzNfQiSyuckVaEiiWROmC3qk0mo,1117
232
+ omlish/marshal/global_.py,sha256=K76wB1-pdg4VWgiqR7wyxRNYr-voJApexYW2nV-R4DM,1127
233
233
  omlish/marshal/helpers.py,sha256=-SOgYJmrURILHpPK6Wu3cCvhj8RJrqfJxuKhh9UMs7o,1102
234
234
  omlish/marshal/iterables.py,sha256=6I_ZdJemLSQtJ4J5NrB9wi-eyxiJZS61HzHXp1yeiX8,2592
235
235
  omlish/marshal/mappings.py,sha256=zhLtyot7tzQtBNj7C4RBxjMELxA5r2q2Mth8Br7xkFs,2803
236
236
  omlish/marshal/maybes.py,sha256=mgK3QsWHkXgRqo076KxYKH6elRxzJ_QDTodv93mgHR0,2198
237
237
  omlish/marshal/naming.py,sha256=lIklR_Od4x1ghltAgOzqcKhHs-leeSv2YmFhCHO7GIs,613
238
238
  omlish/marshal/numbers.py,sha256=oY_yMNJEnJhjfLh89gpPXvKqeUyhQcaTcQB6ecyHiG8,1704
239
- omlish/marshal/objects.py,sha256=fe4dPEF6BqZRWHSn3D7Z5JyLg-Z7JFPhBe2gjUGBefw,6543
239
+ omlish/marshal/objects.py,sha256=72xf6v-QBGtkSyoAoGYReqyp2uWnPNhZiBDnzzruEKI,8437
240
240
  omlish/marshal/optionals.py,sha256=r0XB5rqfasvgZJNrKYd6Unq2U4nHt3JURi26j0dYHlw,1499
241
241
  omlish/marshal/polymorphism.py,sha256=doA8aLUhna6aco5b2Ok3jsem1V4NsF3rM5RTfJt0a7U,5708
242
242
  omlish/marshal/primitives.py,sha256=wcvcs5GH_TWVmzAszh3dvyKibJgBxnXke-AlAXiwrrI,1107
243
- omlish/marshal/registries.py,sha256=GI2KogcxawMkk02Ky7-TsnijChoe1I7YTOPIbUNwSAI,1665
243
+ omlish/marshal/registries.py,sha256=FvC6qXHCizNB2QmU_N3orxW7iqfGYkiUXYYdTRWS6HA,2353
244
244
  omlish/marshal/standard.py,sha256=uQZIGiCwihmhB1tmhpKnZWZly0DDkdGjCnN0d41WHho,2985
245
245
  omlish/marshal/unions.py,sha256=ZWl0maHwh1V_cSnNmuCbbCQZzqlNtOModsTwnVTXNPA,2735
246
246
  omlish/marshal/utils.py,sha256=puKJpwPpuDlMOIrKMcLTRLJyMiL6n_Xs-p59AuDEymA,543
@@ -255,17 +255,17 @@ omlish/reflect/isinstance.py,sha256=x5T9S2634leinBT4hl3CZZkRttvdvvlxChkC_x9Qu2s,
255
255
  omlish/reflect/ops.py,sha256=RJ6jzrM4ieFsXzWyNXWV43O_WgzEaUvlHSc5N2ezW2A,2044
256
256
  omlish/reflect/subst.py,sha256=JM2RGv2-Rcex8wCqhmgvRG59zD242P9jM3O2QLjKWWo,3586
257
257
  omlish/reflect/types.py,sha256=Zkcp8nx_vFNH7pBZ5pU5P0wIgQCauj5Nic3BZb5cRik,7030
258
- omlish/secrets/__init__.py,sha256=VKB2IF9vz4h4RXcZxgXj36KXOLcGBzfqVnxPgPDWpmg,408
258
+ omlish/secrets/__init__.py,sha256=SGB1KrlNrxlNpazEHYy95NTzteLi8ndoEgMhU7luBl8,420
259
259
  omlish/secrets/crypto.py,sha256=6CsLy0UEqCrBK8Xx_3-iFF6SKtu2GlEqUQ8-MliY3tk,3709
260
260
  omlish/secrets/marshal.py,sha256=U9uSRTWzZmumfNZeh_dROwVdGrARsp155TylRbjilP8,2048
261
261
  omlish/secrets/openssl.py,sha256=wxA_wIlxtuOUy71ABxAJgavh-UI_taOfm-A0dVlmSwM,6219
262
262
  omlish/secrets/passwords.py,sha256=3r-vEK6Gp6aq4L5Csnd06QnrjO9xfzHJP-g_7I9W_ao,4101
263
- omlish/secrets/secrets.py,sha256=ClD7t_mkmWkseVk4ahLzYLuLXeTxiwwPiidYm42vLh4,6871
263
+ omlish/secrets/secrets.py,sha256=XkzCrGNRLXUBXbw6_2pFGV2fuphbcgehtpp8zsjHaWM,7580
264
264
  omlish/secrets/subprocesses.py,sha256=EcnKlHHtnUMHGrBWXDfu8tv28wlgZx4P4GOiuPW9Vo8,1105
265
265
  omlish/specs/__init__.py,sha256=Xl4fT1o1MlcEIAjMt5EifgMuO4UBSa9Suj5NE9eMX1A,87
266
266
  omlish/specs/jmespath/LICENSE,sha256=IH-ZZlZkS8XMkf_ubNVD1aYHQ2l_wd0tmHtXrCcYpRU,1113
267
267
  omlish/specs/jmespath/__init__.py,sha256=Lz8JO0vP-pwrBtq9Y94y6LrOA7o1u1kCdPmMf_4lJBY,1918
268
- omlish/specs/jmespath/__main__.py,sha256=pZ4PnDWEtvTSpVOsNswkE9esg6Wu1i1b3P2aLvwBnKc,186
268
+ omlish/specs/jmespath/__main__.py,sha256=wIXm6bs08etNG_GZlN2rBkADPb0rKfL2HSkm8spnpxw,200
269
269
  omlish/specs/jmespath/ast.py,sha256=TP3oSAD5CU7oAawRVEY6UZLSD6CQOci8LQKWhiTtBM4,2744
270
270
  omlish/specs/jmespath/cli.py,sha256=3qHhwVC80qT7Z9JVC0nNL5YvfTxkjirnH5LAoBfVwcM,1748
271
271
  omlish/specs/jmespath/exceptions.py,sha256=8txtnzFYqoL_2YfMnlAFAcrJrZFehLeUsukYSq_6i1w,4373
@@ -320,7 +320,7 @@ omlish/testing/pytest/helpers.py,sha256=TJpD60mBtLi9FtxX4TThfuXvg5FIRPSiZk1aeRwe
320
320
  omlish/testing/pytest/marks.py,sha256=ExuwitbMr1txMbaAcWZ652pYa30M-i3wVacnjqschTs,424
321
321
  omlish/testing/pytest/skip.py,sha256=uACMFtQQNJfFDbWrppjWevdrQgKVH1MUmH5rXIpv0IE,846
322
322
  omlish/testing/pytest/inject/__init__.py,sha256=pdRKv1HcDmJ_yArKJbYITPXXZthRSGgBJWqITr0Er38,117
323
- omlish/testing/pytest/inject/harness.py,sha256=sMKjP2EWHq-eeTB1YVXcANli2Czxt56_9ERg4HtkVPg,5810
323
+ omlish/testing/pytest/inject/harness.py,sha256=v4DaKJ0KL8oQjzIMK43Gh8GHP4hiI6-lY37O9lyOHRk,5724
324
324
  omlish/testing/pytest/plugins/__init__.py,sha256=ys1zXrYrNm7Uo6YOIVJ6Bd3dQo6kv387k7MbTYlqZSI,467
325
325
  omlish/testing/pytest/plugins/_registry.py,sha256=IK04KlBgiOJxKAyCCgjpX2R-9tE-btalYJkgjLc8Te8,77
326
326
  omlish/testing/pytest/plugins/asyncs.py,sha256=SV6oKCy50CGkzLGYX-CT4MfWNqsrH8ONEbIWC3tFcHA,5324
@@ -339,9 +339,9 @@ omlish/text/delimit.py,sha256=ubPXcXQmtbOVrUsNh5gH1mDq5H-n1y2R4cPL5_DQf68,4928
339
339
  omlish/text/glyphsplit.py,sha256=Ug-dPRO7x-OrNNr8g1y6DotSZ2KH0S-VcOmUobwa4B0,3296
340
340
  omlish/text/indent.py,sha256=6Jj6TFY9unaPa4xPzrnZemJ-fHsV53IamP93XGjSUHs,1274
341
341
  omlish/text/parts.py,sha256=7vPF1aTZdvLVYJ4EwBZVzRSy8XB3YqPd7JwEnNGGAOo,6495
342
- omlish-0.0.0.dev51.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
343
- omlish-0.0.0.dev51.dist-info/METADATA,sha256=dX7TOPWFihpNQKvxpeumwoK_bZt8O4IVpS0__xA04u0,3817
344
- omlish-0.0.0.dev51.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
345
- omlish-0.0.0.dev51.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
346
- omlish-0.0.0.dev51.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
347
- omlish-0.0.0.dev51.dist-info/RECORD,,
342
+ omlish-0.0.0.dev53.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
343
+ omlish-0.0.0.dev53.dist-info/METADATA,sha256=diMO9VXqesB02C0XD2G1yLkFn0RX0ZfoZJslGDExPyo,4167
344
+ omlish-0.0.0.dev53.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
345
+ omlish-0.0.0.dev53.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
346
+ omlish-0.0.0.dev53.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
347
+ omlish-0.0.0.dev53.dist-info/RECORD,,