omlish 0.0.0.dev227__py3-none-any.whl → 0.0.0.dev229__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.
Files changed (47) hide show
  1. omlish/__about__.py +3 -3
  2. omlish/diag/lsof.py +4 -5
  3. omlish/diag/ps.py +9 -0
  4. omlish/lite/timeouts.py +1 -1
  5. omlish/marshal/__init__.py +39 -24
  6. omlish/marshal/composite/__init__.py +0 -0
  7. omlish/marshal/{iterables.py → composite/iterables.py} +10 -10
  8. omlish/marshal/{literals.py → composite/literals.py} +9 -9
  9. omlish/marshal/{mappings.py → composite/mappings.py} +10 -10
  10. omlish/marshal/{maybes.py → composite/maybes.py} +11 -11
  11. omlish/marshal/{newtypes.py → composite/newtypes.py} +8 -8
  12. omlish/marshal/{optionals.py → composite/optionals.py} +9 -9
  13. omlish/marshal/objects/__init__.py +7 -0
  14. omlish/marshal/{dataclasses.py → objects/dataclasses.py} +24 -24
  15. omlish/marshal/{helpers.py → objects/helpers.py} +6 -3
  16. omlish/marshal/objects/marshal.py +108 -0
  17. omlish/marshal/objects/metadata.py +124 -0
  18. omlish/marshal/{namedtuples.py → objects/namedtuples.py} +16 -16
  19. omlish/marshal/objects/unmarshal.py +141 -0
  20. omlish/marshal/polymorphism/__init__.py +7 -0
  21. omlish/marshal/polymorphism/marshal.py +66 -0
  22. omlish/marshal/polymorphism/metadata.py +140 -0
  23. omlish/marshal/{unions.py → polymorphism/unions.py} +18 -18
  24. omlish/marshal/polymorphism/unmarshal.py +73 -0
  25. omlish/marshal/singular/__init__.py +0 -0
  26. omlish/marshal/{any.py → singular/any.py} +8 -8
  27. omlish/marshal/{base64.py → singular/base64.py} +9 -9
  28. omlish/marshal/{datetimes.py → singular/datetimes.py} +9 -9
  29. omlish/marshal/{enums.py → singular/enums.py} +9 -9
  30. omlish/marshal/{numbers.py → singular/numbers.py} +8 -8
  31. omlish/marshal/{primitives.py → singular/primitives.py} +8 -8
  32. omlish/marshal/{uuids.py → singular/uuids.py} +8 -8
  33. omlish/marshal/standard.py +32 -32
  34. omlish/os/death.py +72 -4
  35. omlish/os/fcntl.py +11 -12
  36. omlish/os/files.py +18 -3
  37. omlish/os/forkhooks.py +215 -0
  38. omlish/os/pidfiles/pinning.py +4 -0
  39. omlish/sockets/bind.py +4 -4
  40. {omlish-0.0.0.dev227.dist-info → omlish-0.0.0.dev229.dist-info}/METADATA +3 -3
  41. {omlish-0.0.0.dev227.dist-info → omlish-0.0.0.dev229.dist-info}/RECORD +45 -36
  42. omlish/marshal/objects.py +0 -317
  43. omlish/marshal/polymorphism.py +0 -267
  44. {omlish-0.0.0.dev227.dist-info → omlish-0.0.0.dev229.dist-info}/LICENSE +0 -0
  45. {omlish-0.0.0.dev227.dist-info → omlish-0.0.0.dev229.dist-info}/WHEEL +0 -0
  46. {omlish-0.0.0.dev227.dist-info → omlish-0.0.0.dev229.dist-info}/entry_points.txt +0 -0
  47. {omlish-0.0.0.dev227.dist-info → omlish-0.0.0.dev229.dist-info}/top_level.txt +0 -0
omlish/__about__.py CHANGED
@@ -1,5 +1,5 @@
1
- __version__ = '0.0.0.dev227'
2
- __revision__ = '2faa3e7f9120edd3e6dd79fad6401fd87d89f5cf'
1
+ __version__ = '0.0.0.dev229'
2
+ __revision__ = '646f2d8caaef32d279a6ebcfd121449752fbae93'
3
3
 
4
4
 
5
5
  #
@@ -79,7 +79,7 @@ class Project(ProjectBase):
79
79
  ],
80
80
 
81
81
  'secrets': [
82
- 'cryptography ~= 43.0',
82
+ 'cryptography ~= 44.0',
83
83
  ],
84
84
 
85
85
  'sqlalchemy': [
omlish/diag/lsof.py CHANGED
@@ -2,9 +2,6 @@
2
2
  # @omlish-lite
3
3
  """
4
4
  https://man7.org/linux/man-pages/man8/lsof.8.html
5
-
6
- Included in the process set are fields that identify the command, the process group IDentification (PGID) number, the
7
- task (thread) ID (TID), and the user ID (UID) number or login name.
8
5
  """
9
6
  import dataclasses as dc
10
7
  import enum
@@ -215,8 +212,7 @@ LsofItem._DEFAULT_PREFIXES = ''.join(LsofItem._FIELDS_BY_PREFIX) # noqa
215
212
 
216
213
 
217
214
  @dc.dataclass(frozen=True)
218
- class \
219
- LsofCommand(SubprocessRunnable[ta.List[LsofItem]]):
215
+ class LsofCommand(SubprocessRunnable[ta.List[LsofItem]]):
220
216
  pid: ta.Optional[int] = None
221
217
  file: ta.Optional[str] = None
222
218
 
@@ -242,6 +238,9 @@ class \
242
238
  return LsofItem.from_prefix_lines(lines)
243
239
 
244
240
 
241
+ ##
242
+
243
+
245
244
  if __name__ == '__main__':
246
245
  def _main() -> None:
247
246
  argparse = __import__('argparse')
omlish/diag/ps.py CHANGED
@@ -12,6 +12,9 @@ from ..subprocesses.run import SubprocessRunOutput
12
12
  from ..subprocesses.sync import subprocesses
13
13
 
14
14
 
15
+ ##
16
+
17
+
15
18
  @dc.dataclass(frozen=True)
16
19
  class PsItem:
17
20
  pid: int
@@ -43,6 +46,9 @@ class PsCommand(SubprocessRunnable):
43
46
  )
44
47
 
45
48
 
49
+ ##
50
+
51
+
46
52
  def get_ps_item(pid: int, timeout: ta.Optional[Timeout] = None) -> PsItem:
47
53
  return PsCommand(pid).run(subprocesses, timeout=timeout)
48
54
 
@@ -59,6 +65,9 @@ def get_ps_lineage(pid: int, timeout: ta.Optional[Timeout] = None) -> ta.List[Ps
59
65
  return ret
60
66
 
61
67
 
68
+ ##
69
+
70
+
62
71
  if __name__ == '__main__':
63
72
  def _main() -> None:
64
73
  print(get_ps_lineage(os.getpid()))
omlish/lite/timeouts.py CHANGED
@@ -50,7 +50,7 @@ class Timeout(abc.ABC):
50
50
 
51
51
  @classmethod
52
52
  def _now(cls) -> float:
53
- return time.time()
53
+ return time.monotonic()
54
54
 
55
55
  #
56
56
 
@@ -42,14 +42,11 @@ from .forbidden import ( # noqa
42
42
  from .global_ import ( # noqa
43
43
  GLOBAL_REGISTRY,
44
44
 
45
+ global_marshaler_factory,
45
46
  marshal,
46
- unmarshal,
47
- )
48
47
 
49
- from .helpers import ( # noqa
50
- update_field_metadata,
51
- update_fields_metadata,
52
- update_object_metadata,
48
+ global_unmarshaler_factory,
49
+ unmarshal,
53
50
  )
54
51
 
55
52
  from .naming import ( # noqa
@@ -62,31 +59,59 @@ from .nop import ( # noqa
62
59
  NopMarshalerUnmarshaler,
63
60
  )
64
61
 
65
- from .objects import ( # noqa
62
+ from .objects.helpers import ( # noqa
63
+ update_field_metadata,
64
+ update_fields_metadata,
65
+ update_object_metadata,
66
+ )
67
+
68
+ from .objects.marshal import ( # noqa
69
+ ObjectMarshaler,
70
+ SimpleObjectMarshalerFactory,
71
+ )
72
+
73
+ from .objects.metadata import ( # noqa
66
74
  FieldInfo,
67
75
  FieldInfos,
68
76
  FieldMetadata,
69
77
  FieldOptions,
70
- ObjectMarshaler,
71
78
  ObjectMetadata,
72
79
  ObjectSpecials,
80
+ )
81
+
82
+ from .objects.unmarshal import ( # noqa
73
83
  ObjectUnmarshaler,
74
- SimpleObjectMarshalerFactory,
75
84
  SimpleObjectUnmarshalerFactory,
76
85
  )
77
86
 
78
- from .polymorphism import ( # noqa
87
+ from .polymorphism.marshal import ( # noqa
88
+ PolymorphismMarshalerFactory,
89
+ make_polymorphism_marshaler,
90
+ )
91
+
92
+ from .polymorphism.metadata import ( # noqa
79
93
  Impl,
80
94
  Impls,
81
95
  Polymorphism,
82
- PolymorphismMarshalerFactory,
96
+ polymorphism_from_subclasses,
97
+ )
98
+
99
+ from .polymorphism.unions import ( # noqa
100
+ PRIMITIVE_UNION_TYPES,
101
+ PolymorphismUnionMarshalerFactory,
102
+ PolymorphismUnionUnmarshalerFactory,
103
+ PrimitiveUnionMarshaler,
104
+ PrimitiveUnionMarshalerFactory,
105
+ PrimitiveUnionUnmarshaler,
106
+ PrimitiveUnionUnmarshalerFactory,
107
+ )
108
+
109
+ from .polymorphism.unmarshal import ( # noqa
83
110
  PolymorphismUnmarshalerFactory,
84
- make_polymorphism_marshaler,
85
111
  make_polymorphism_unmarshaler,
86
- polymorphism_from_subclasses,
87
112
  )
88
113
 
89
- from .primitives import ( # noqa
114
+ from .singular.primitives import ( # noqa
90
115
  PRIMITIVE_TYPES,
91
116
  )
92
117
 
@@ -102,16 +127,6 @@ from .standard import ( # noqa
102
127
  new_standard_unmarshaler_factory,
103
128
  )
104
129
 
105
- from .unions import ( # noqa
106
- PRIMITIVE_UNION_TYPES,
107
- PolymorphismUnionMarshalerFactory,
108
- PolymorphismUnionUnmarshalerFactory,
109
- PrimitiveUnionMarshaler,
110
- PrimitiveUnionMarshalerFactory,
111
- PrimitiveUnionUnmarshaler,
112
- PrimitiveUnionUnmarshalerFactory,
113
- )
114
-
115
130
  from .values import ( # noqa
116
131
  Value,
117
132
  )
File without changes
@@ -7,16 +7,16 @@ import dataclasses as dc
7
7
  import functools
8
8
  import typing as ta
9
9
 
10
- from .. import check
11
- from .. import reflect as rfl
12
- from ..funcs import match as mfs
13
- from .base import MarshalContext
14
- from .base import Marshaler
15
- from .base import MarshalerFactoryMatchClass
16
- from .base import UnmarshalContext
17
- from .base import Unmarshaler
18
- from .base import UnmarshalerFactoryMatchClass
19
- from .values import Value
10
+ from ... import check
11
+ from ... import reflect as rfl
12
+ from ...funcs import match as mfs
13
+ from ..base import MarshalContext
14
+ from ..base import Marshaler
15
+ from ..base import MarshalerFactoryMatchClass
16
+ from ..base import UnmarshalContext
17
+ from ..base import Unmarshaler
18
+ from ..base import UnmarshalerFactoryMatchClass
19
+ from ..values import Value
20
20
 
21
21
 
22
22
  DEFAULT_ITERABLE_CONCRETE_TYPES: dict[type[collections.abc.Iterable], type[collections.abc.Iterable]] = {
@@ -1,15 +1,15 @@
1
1
  import dataclasses as dc
2
2
  import typing as ta
3
3
 
4
- from .. import check
5
- from .. import reflect as rfl
6
- from .base import MarshalContext
7
- from .base import Marshaler
8
- from .base import MarshalerFactory
9
- from .base import UnmarshalContext
10
- from .base import Unmarshaler
11
- from .base import UnmarshalerFactory
12
- from .values import Value
4
+ from ... import check
5
+ from ... import reflect as rfl
6
+ from ..base import MarshalContext
7
+ from ..base import Marshaler
8
+ from ..base import MarshalerFactory
9
+ from ..base import UnmarshalContext
10
+ from ..base import Unmarshaler
11
+ from ..base import UnmarshalerFactory
12
+ from ..values import Value
13
13
 
14
14
 
15
15
  @dc.dataclass(frozen=True)
@@ -2,16 +2,16 @@ import collections.abc
2
2
  import dataclasses as dc
3
3
  import typing as ta
4
4
 
5
- from .. import check
6
- from .. import reflect as rfl
7
- from ..funcs import match as mfs
8
- from .base import MarshalContext
9
- from .base import Marshaler
10
- from .base import MarshalerFactoryMatchClass
11
- from .base import UnmarshalContext
12
- from .base import Unmarshaler
13
- from .base import UnmarshalerFactoryMatchClass
14
- from .values import Value
5
+ from ... import check
6
+ from ... import reflect as rfl
7
+ from ...funcs import match as mfs
8
+ from ..base import MarshalContext
9
+ from ..base import Marshaler
10
+ from ..base import MarshalerFactoryMatchClass
11
+ from ..base import UnmarshalContext
12
+ from ..base import Unmarshaler
13
+ from ..base import UnmarshalerFactoryMatchClass
14
+ from ..values import Value
15
15
 
16
16
 
17
17
  DEFAULT_MAPPING_CONCRETE_TYPES: dict[type[collections.abc.Mapping], type[collections.abc.Mapping]] = {
@@ -5,17 +5,17 @@ TODO:
5
5
  import dataclasses as dc
6
6
  import typing as ta
7
7
 
8
- from .. import check
9
- from .. import lang
10
- from .. import reflect as rfl
11
- from ..funcs import match as mfs
12
- from .base import MarshalContext
13
- from .base import Marshaler
14
- from .base import MarshalerFactoryMatchClass
15
- from .base import UnmarshalContext
16
- from .base import Unmarshaler
17
- from .base import UnmarshalerFactoryMatchClass
18
- from .values import Value
8
+ from ... import check
9
+ from ... import lang
10
+ from ... import reflect as rfl
11
+ from ...funcs import match as mfs
12
+ from ..base import MarshalContext
13
+ from ..base import Marshaler
14
+ from ..base import MarshalerFactoryMatchClass
15
+ from ..base import UnmarshalContext
16
+ from ..base import Unmarshaler
17
+ from ..base import UnmarshalerFactoryMatchClass
18
+ from ..values import Value
19
19
 
20
20
 
21
21
  @dc.dataclass(frozen=True)
@@ -1,11 +1,11 @@
1
- from .. import check
2
- from .. import reflect as rfl
3
- from .base import MarshalContext
4
- from .base import Marshaler
5
- from .base import MarshalerFactory
6
- from .base import UnmarshalContext
7
- from .base import Unmarshaler
8
- from .base import UnmarshalerFactory
1
+ from ... import check
2
+ from ... import reflect as rfl
3
+ from ..base import MarshalContext
4
+ from ..base import Marshaler
5
+ from ..base import MarshalerFactory
6
+ from ..base import UnmarshalContext
7
+ from ..base import Unmarshaler
8
+ from ..base import UnmarshalerFactory
9
9
 
10
10
 
11
11
  class NewtypeMarshalerFactory(MarshalerFactory):
@@ -1,15 +1,15 @@
1
1
  import dataclasses as dc
2
2
  import typing as ta
3
3
 
4
- from .. import check
5
- from .. import reflect as rfl
6
- from .base import MarshalContext
7
- from .base import Marshaler
8
- from .base import MarshalerFactory
9
- from .base import UnmarshalContext
10
- from .base import Unmarshaler
11
- from .base import UnmarshalerFactory
12
- from .values import Value
4
+ from ... import check
5
+ from ... import reflect as rfl
6
+ from ..base import MarshalContext
7
+ from ..base import Marshaler
8
+ from ..base import MarshalerFactory
9
+ from ..base import UnmarshalContext
10
+ from ..base import Unmarshaler
11
+ from ..base import UnmarshalerFactory
12
+ from ..values import Value
13
13
 
14
14
 
15
15
  @dc.dataclass(frozen=True)
@@ -0,0 +1,7 @@
1
+ """
2
+ TODO:
3
+ - cfg naming
4
+ - adapters for dataclasses / namedtuples / user objects (as configured)
5
+ - mro-merge ObjectMetadata
6
+ - key ordering override - like slice, -1 means last
7
+ """
@@ -4,30 +4,30 @@ TODO:
4
4
  """
5
5
  import typing as ta
6
6
 
7
- from .. import check
8
- from .. import collections as col
9
- from .. import dataclasses as dc
10
- from .. import lang
11
- from .. import reflect as rfl
12
- from ..lite import marshal as lm
13
- from .base import MarshalContext
14
- from .base import Marshaler
15
- from .base import MarshalerFactory
16
- from .base import Option
17
- from .base import UnmarshalContext
18
- from .base import Unmarshaler
19
- from .base import UnmarshalerFactory
20
- from .naming import Naming
21
- from .naming import translate_name
22
- from .objects import DEFAULT_FIELD_OPTIONS
23
- from .objects import FIELD_OPTIONS_KWARGS
24
- from .objects import FieldInfo
25
- from .objects import FieldInfos
26
- from .objects import FieldMetadata
27
- from .objects import FieldOptions
28
- from .objects import ObjectMarshaler
29
- from .objects import ObjectMetadata
30
- from .objects import ObjectUnmarshaler
7
+ from ... import check
8
+ from ... import collections as col
9
+ from ... import dataclasses as dc
10
+ from ... import lang
11
+ from ... import reflect as rfl
12
+ from ...lite import marshal as lm
13
+ from ..base import MarshalContext
14
+ from ..base import Marshaler
15
+ from ..base import MarshalerFactory
16
+ from ..base import Option
17
+ from ..base import UnmarshalContext
18
+ from ..base import Unmarshaler
19
+ from ..base import UnmarshalerFactory
20
+ from ..naming import Naming
21
+ from ..naming import translate_name
22
+ from .marshal import ObjectMarshaler
23
+ from .metadata import DEFAULT_FIELD_OPTIONS
24
+ from .metadata import FIELD_OPTIONS_KWARGS
25
+ from .metadata import FieldInfo
26
+ from .metadata import FieldInfos
27
+ from .metadata import FieldMetadata
28
+ from .metadata import FieldOptions
29
+ from .metadata import ObjectMetadata
30
+ from .unmarshal import ObjectUnmarshaler
31
31
 
32
32
 
33
33
  ##
@@ -1,13 +1,16 @@
1
1
  import typing as ta
2
2
 
3
- from .. import dataclasses as dc
4
- from .objects import FieldMetadata
5
- from .objects import ObjectMetadata
3
+ from ... import dataclasses as dc
4
+ from .metadata import FieldMetadata
5
+ from .metadata import ObjectMetadata
6
6
 
7
7
 
8
8
  T = ta.TypeVar('T')
9
9
 
10
10
 
11
+ ##
12
+
13
+
11
14
  def update_field_metadata(**kwargs: ta.Any) -> dc.field_modifier:
12
15
  @dc.field_modifier
13
16
  def inner(f: dc.Field) -> dc.Field:
@@ -0,0 +1,108 @@
1
+ import collections.abc
2
+ import typing as ta
3
+
4
+ from ... import check
5
+ from ... import dataclasses as dc
6
+ from ... import reflect as rfl
7
+ from ..base import MarshalContext
8
+ from ..base import Marshaler
9
+ from ..base import MarshalerFactory
10
+ from ..values import Value
11
+ from .metadata import FieldInfo
12
+ from .metadata import FieldInfos
13
+ from .metadata import ObjectSpecials
14
+
15
+
16
+ ##
17
+
18
+
19
+ @dc.dataclass(frozen=True)
20
+ class ObjectMarshaler(Marshaler):
21
+ fields: ta.Sequence[tuple[FieldInfo, Marshaler]]
22
+
23
+ _: dc.KW_ONLY
24
+
25
+ specials: ObjectSpecials = ObjectSpecials()
26
+
27
+ attr_getter: ta.Callable[[ta.Any, str], ta.Any] | None = None
28
+
29
+ @classmethod
30
+ def make(
31
+ cls,
32
+ ctx: MarshalContext,
33
+ fis: FieldInfos,
34
+ **kwargs: ta.Any,
35
+ ) -> Marshaler:
36
+ fields = [
37
+ (fi, ctx.make(fi.type))
38
+ for fi in fis
39
+ ]
40
+
41
+ return cls(
42
+ fields,
43
+ **kwargs,
44
+ )
45
+
46
+ #
47
+
48
+ def marshal(self, ctx: MarshalContext, o: ta.Any) -> Value:
49
+ if (attr_getter := self.attr_getter) is None:
50
+ attr_getter = getattr
51
+
52
+ ret: dict[str, ta.Any] = {}
53
+ for fi, m in self.fields:
54
+ v = attr_getter(o, fi.name)
55
+
56
+ if fi.options.omit_if is not None and fi.options.omit_if(v):
57
+ continue
58
+
59
+ if fi.name in self.specials.set:
60
+ continue
61
+
62
+ mn = fi.marshal_name
63
+ if mn is None:
64
+ continue
65
+
66
+ mv = m.marshal(ctx, v)
67
+
68
+ if fi.options.embed:
69
+ for ek, ev in check.isinstance(mv, collections.abc.Mapping).items():
70
+ ret[mn + check.non_empty_str(ek)] = ev
71
+
72
+ else:
73
+ ret[mn] = mv
74
+
75
+ if self.specials.unknown is not None:
76
+ if (ukf := attr_getter(o, self.specials.unknown)):
77
+ if (dks := set(ret) & set(ukf)):
78
+ raise KeyError(f'Unknown field keys duplicate fields: {dks!r}')
79
+
80
+ ret.update(ukf) # FIXME: marshal?
81
+
82
+ return ret
83
+
84
+
85
+ ##
86
+
87
+
88
+ @dc.dataclass(frozen=True)
89
+ class SimpleObjectMarshalerFactory(MarshalerFactory):
90
+ dct: ta.Mapping[type, ta.Sequence[FieldInfo]]
91
+
92
+ _: dc.KW_ONLY
93
+
94
+ specials: ObjectSpecials = ObjectSpecials()
95
+
96
+ def guard(self, ctx: MarshalContext, rty: rfl.Type) -> bool:
97
+ return isinstance(rty, type) and rty in self.dct
98
+
99
+ def fn(self, ctx: MarshalContext, rty: rfl.Type) -> Marshaler:
100
+ ty = check.isinstance(rty, type)
101
+
102
+ fis = FieldInfos(self.dct[ty])
103
+
104
+ return ObjectMarshaler.make(
105
+ ctx,
106
+ fis,
107
+ specials=self.specials,
108
+ )
@@ -0,0 +1,124 @@
1
+ import typing as ta
2
+
3
+ from ... import cached
4
+ from ... import collections as col
5
+ from ... import dataclasses as dc
6
+ from ... import lang
7
+ from ..base import Marshaler
8
+ from ..base import MarshalerFactory
9
+ from ..base import Unmarshaler
10
+ from ..base import UnmarshalerFactory
11
+ from ..naming import Naming
12
+
13
+
14
+ ##
15
+
16
+
17
+ @dc.dataclass(frozen=True, kw_only=True)
18
+ class FieldOptions:
19
+ omit_if: ta.Callable[[ta.Any], bool] | None = None
20
+
21
+ default: lang.Maybe[ta.Any] = dc.xfield(default=lang.empty(), check_type=lang.Maybe)
22
+
23
+ embed: bool = False
24
+
25
+ no_marshal: bool = False
26
+ no_unmarshal: bool = False
27
+
28
+
29
+ DEFAULT_FIELD_OPTIONS = FieldOptions()
30
+ FIELD_OPTIONS_KWARGS: frozenset[str] = frozenset(dc.fields_dict(FieldOptions).keys())
31
+
32
+
33
+ @dc.dataclass(frozen=True, kw_only=True)
34
+ class FieldMetadata:
35
+ name: str | None = None
36
+ alts: ta.Iterable[str] | None = None
37
+
38
+ options: FieldOptions = DEFAULT_FIELD_OPTIONS
39
+
40
+ marshaler: Marshaler | None = dc.xfield(None, check_type=(Marshaler, None))
41
+ marshaler_factory: MarshalerFactory | None = None
42
+
43
+ unmarshaler: Unmarshaler | None = dc.xfield(None, check_type=(Unmarshaler, None))
44
+ unmarshaler_factory: UnmarshalerFactory | None = None
45
+
46
+ def update(self, **kwargs: ta.Any) -> 'FieldMetadata':
47
+ okw = {k: v for k, v in kwargs.items() if k in FIELD_OPTIONS_KWARGS}
48
+ mkw = {k: v for k, v in kwargs.items() if k not in FIELD_OPTIONS_KWARGS}
49
+ return dc.replace(
50
+ self,
51
+ **(dict(options=dc.replace(self.options, **okw)) if okw else {}),
52
+ **mkw,
53
+ )
54
+
55
+
56
+ @dc.dataclass(frozen=True, kw_only=True)
57
+ class ObjectMetadata:
58
+ field_naming: Naming | None = None
59
+
60
+ unknown_field: str | None = None
61
+ source_field: str | None = None
62
+
63
+ @cached.property
64
+ def specials(self) -> 'ObjectSpecials':
65
+ return ObjectSpecials(
66
+ unknown=self.unknown_field,
67
+ source=self.source_field,
68
+ )
69
+
70
+ field_defaults: FieldMetadata = FieldMetadata()
71
+
72
+ ignore_unknown: bool = False
73
+
74
+
75
+ @dc.dataclass(frozen=True, kw_only=True)
76
+ class ObjectSpecials:
77
+ unknown: str | None = None
78
+ source: str | None = None
79
+
80
+ @cached.property
81
+ def set(self) -> frozenset[str]:
82
+ return frozenset(v for v in dc.asdict(self).values() if v is not None)
83
+
84
+
85
+ ##
86
+
87
+
88
+ @dc.dataclass(frozen=True, kw_only=True)
89
+ class FieldInfo:
90
+ name: str
91
+ type: ta.Any
92
+
93
+ marshal_name: str | None
94
+ unmarshal_names: ta.Sequence[str]
95
+
96
+ metadata: FieldMetadata = FieldMetadata()
97
+
98
+ options: FieldOptions = FieldOptions()
99
+
100
+
101
+ @dc.dataclass(frozen=True)
102
+ class FieldInfos:
103
+ lst: ta.Sequence[FieldInfo]
104
+
105
+ def __iter__(self) -> ta.Iterator[FieldInfo]:
106
+ return iter(self.lst)
107
+
108
+ def __len__(self) -> int:
109
+ return len(self.lst)
110
+
111
+ @cached.property
112
+ @dc.init
113
+ def by_name(self) -> ta.Mapping[str, FieldInfo]:
114
+ return col.make_map(((fi.name, fi) for fi in self), strict=True)
115
+
116
+ @cached.property
117
+ @dc.init
118
+ def by_marshal_name(self) -> ta.Mapping[str, FieldInfo]:
119
+ return col.make_map(((fi.marshal_name, fi) for fi in self if fi.marshal_name is not None), strict=True)
120
+
121
+ @cached.property
122
+ @dc.init
123
+ def by_unmarshal_name(self) -> ta.Mapping[str, FieldInfo]:
124
+ return col.make_map(((n, fi) for fi in self for n in fi.unmarshal_names), strict=True)