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
@@ -1,42 +1,42 @@
1
1
  from ..funcs import match as mfs
2
- from .any import ANY_MARSHALER_FACTORY
3
- from .any import ANY_UNMARSHALER_FACTORY
4
2
  from .base import MarshalerFactory
5
3
  from .base import RecursiveMarshalerFactory
6
4
  from .base import RecursiveUnmarshalerFactory
7
5
  from .base import TypeCacheMarshalerFactory
8
6
  from .base import TypeCacheUnmarshalerFactory
9
7
  from .base import UnmarshalerFactory
10
- from .base64 import BASE64_MARSHALER_FACTORY
11
- from .base64 import BASE64_UNMARSHALER_FACTORY
12
- from .dataclasses import DataclassMarshalerFactory
13
- from .dataclasses import DataclassUnmarshalerFactory
14
- from .datetimes import DATETIME_MARSHALER_FACTORY
15
- from .datetimes import DATETIME_UNMARSHALER_FACTORY
16
- from .enums import EnumMarshalerFactory
17
- from .enums import EnumUnmarshalerFactory
18
- from .iterables import IterableMarshalerFactory
19
- from .iterables import IterableUnmarshalerFactory
20
- from .literals import LiteralMarshalerFactory
21
- from .literals import LiteralUnmarshalerFactory
22
- from .mappings import MappingMarshalerFactory
23
- from .mappings import MappingUnmarshalerFactory
24
- from .maybes import MaybeMarshalerFactory
25
- from .maybes import MaybeUnmarshalerFactory
26
- from .namedtuples import NamedtupleMarshalerFactory
27
- from .namedtuples import NamedtupleUnmarshalerFactory
28
- from .newtypes import NewtypeMarshalerFactory
29
- from .newtypes import NewtypeUnmarshalerFactory
30
- from .numbers import NUMBERS_MARSHALER_FACTORY
31
- from .numbers import NUMBERS_UNMARSHALER_FACTORY
32
- from .optionals import OptionalMarshalerFactory
33
- from .optionals import OptionalUnmarshalerFactory
34
- from .primitives import PRIMITIVE_MARSHALER_FACTORY
35
- from .primitives import PRIMITIVE_UNMARSHALER_FACTORY
36
- from .unions import PrimitiveUnionMarshalerFactory
37
- from .unions import PrimitiveUnionUnmarshalerFactory
38
- from .uuids import UUID_MARSHALER_FACTORY
39
- from .uuids import UUID_UNMARSHALER_FACTORY
8
+ from .composite.iterables import IterableMarshalerFactory
9
+ from .composite.iterables import IterableUnmarshalerFactory
10
+ from .composite.literals import LiteralMarshalerFactory
11
+ from .composite.literals import LiteralUnmarshalerFactory
12
+ from .composite.mappings import MappingMarshalerFactory
13
+ from .composite.mappings import MappingUnmarshalerFactory
14
+ from .composite.maybes import MaybeMarshalerFactory
15
+ from .composite.maybes import MaybeUnmarshalerFactory
16
+ from .composite.newtypes import NewtypeMarshalerFactory
17
+ from .composite.newtypes import NewtypeUnmarshalerFactory
18
+ from .composite.optionals import OptionalMarshalerFactory
19
+ from .composite.optionals import OptionalUnmarshalerFactory
20
+ from .objects.dataclasses import DataclassMarshalerFactory
21
+ from .objects.dataclasses import DataclassUnmarshalerFactory
22
+ from .objects.namedtuples import NamedtupleMarshalerFactory
23
+ from .objects.namedtuples import NamedtupleUnmarshalerFactory
24
+ from .polymorphism.unions import PrimitiveUnionMarshalerFactory
25
+ from .polymorphism.unions import PrimitiveUnionUnmarshalerFactory
26
+ from .singular.any import ANY_MARSHALER_FACTORY
27
+ from .singular.any import ANY_UNMARSHALER_FACTORY
28
+ from .singular.base64 import BASE64_MARSHALER_FACTORY
29
+ from .singular.base64 import BASE64_UNMARSHALER_FACTORY
30
+ from .singular.datetimes import DATETIME_MARSHALER_FACTORY
31
+ from .singular.datetimes import DATETIME_UNMARSHALER_FACTORY
32
+ from .singular.enums import EnumMarshalerFactory
33
+ from .singular.enums import EnumUnmarshalerFactory
34
+ from .singular.numbers import NUMBERS_MARSHALER_FACTORY
35
+ from .singular.numbers import NUMBERS_UNMARSHALER_FACTORY
36
+ from .singular.primitives import PRIMITIVE_MARSHALER_FACTORY
37
+ from .singular.primitives import PRIMITIVE_UNMARSHALER_FACTORY
38
+ from .singular.uuids import UUID_MARSHALER_FACTORY
39
+ from .singular.uuids import UUID_UNMARSHALER_FACTORY
40
40
 
41
41
 
42
42
  ##
omlish/os/death.py CHANGED
@@ -4,8 +4,11 @@ import signal
4
4
  import sys
5
5
  import time
6
6
  import typing as ta
7
+ import weakref
7
8
 
8
9
  from .. import check
10
+ from .forkhooks import ForkHook
11
+ from .forkhooks import get_fork_depth
9
12
 
10
13
 
11
14
  ##
@@ -82,12 +85,24 @@ class BaseDeathpact(Deathpact, abc.ABC):
82
85
 
83
86
 
84
87
  class PipeDeathpact(BaseDeathpact):
88
+ """
89
+ NOTE: Closes write side in children lazily on poll - does not proactively close write sides on fork. This means
90
+ parents which fork children into codepaths unaware of live PipeDeathpacts will leave write sides open in those
91
+ children, potentially leading to zombies (if those children outlast the parent). Use ForkAwarePipeDeathpact to
92
+ handle such cases.
93
+ """
94
+
95
+ _COOKIE: ta.ClassVar[bytes] = os.urandom(16)
96
+
85
97
  def __init__(self, **kwargs: ta.Any) -> None:
86
98
  super().__init__(**kwargs)
87
99
 
88
100
  self._rfd: int | None = None
89
101
  self._wfd: int | None = None
90
102
 
103
+ self._cookie: bytes | None = self._COOKIE
104
+ self._fork_depth: int | None = get_fork_depth()
105
+
91
106
  def __repr__(self) -> str:
92
107
  return f'{self.__class__.__name__}(rfd={self._rfd}, wfd={self._wfd})'
93
108
 
@@ -95,26 +110,54 @@ class PipeDeathpact(BaseDeathpact):
95
110
  def pass_fd(self) -> int:
96
111
  return check.not_none(self._rfd)
97
112
 
113
+ def is_parent(self) -> bool:
114
+ return (self._COOKIE, get_fork_depth()) == (self._cookie, self._fork_depth)
115
+
116
+ #
117
+
98
118
  def __enter__(self) -> ta.Self:
99
119
  check.none(self._rfd)
100
120
  check.none(self._wfd)
101
121
 
102
122
  self._rfd, self._wfd = os.pipe()
103
123
 
104
- os.set_inheritable(self._rfd, True)
105
124
  os.set_blocking(self._rfd, False)
106
125
 
107
126
  return self
108
127
 
109
- def __exit__(self, exc_type, exc_val, exc_tb):
110
- if self._rfd is not None:
111
- os.close(check.not_none(self._wfd))
128
+ def _close_wfd_if_not_parent(self) -> None:
129
+ if self._wfd is not None:
130
+ if not self.is_parent():
131
+ os.close(check.not_none(self._wfd))
112
132
  self._wfd = None
113
133
 
134
+ def __exit__(self, exc_type, exc_val, exc_tb):
135
+ if self._rfd is not None:
114
136
  os.close(self._rfd)
115
137
  self._rfd = None
116
138
 
139
+ self._close_wfd_if_not_parent()
140
+
141
+ #
142
+
143
+ def __getstate__(self):
144
+ return {
145
+ **self.__dict__,
146
+ **dict(
147
+ _wfd=None,
148
+ _cookie=None,
149
+ _fork_depth=None,
150
+ ),
151
+ }
152
+
153
+ def __setstate__(self, state):
154
+ self.__dict__.update(state)
155
+
156
+ #
157
+
117
158
  def should_die(self) -> bool:
159
+ self._close_wfd_if_not_parent()
160
+
118
161
  try:
119
162
  buf = os.read(check.not_none(self._rfd), 1)
120
163
  except BlockingIOError:
@@ -125,3 +168,28 @@ class PipeDeathpact(BaseDeathpact):
125
168
  self.die()
126
169
 
127
170
  return True
171
+
172
+
173
+ #
174
+
175
+
176
+ class ForkAwarePipeDeathpact(PipeDeathpact):
177
+ """
178
+ TODO:
179
+ - Despite no correct way to do threads+forks, still audit thread-safety. Is WeakSet threadsafe? Probably not..
180
+ """
181
+
182
+ _PARENTS: ta.ClassVar[ta.MutableSet['ForkAwarePipeDeathpact']] = weakref.WeakSet()
183
+
184
+ def __init__(self, **kwargs: ta.Any) -> None:
185
+ super().__init__(**kwargs)
186
+
187
+ self._ForkHook.install()
188
+ self._PARENTS.add(self)
189
+
190
+ class _ForkHook(ForkHook):
191
+ @classmethod
192
+ def _after_fork_in_child(cls) -> None:
193
+ for pdp in ForkAwarePipeDeathpact._PARENTS:
194
+ pdp._close_wfd_if_not_parent() # noqa
195
+ ForkAwarePipeDeathpact._PARENTS.clear()
omlish/os/fcntl.py CHANGED
@@ -19,7 +19,7 @@ class FcntlLockData:
19
19
 
20
20
  #
21
21
 
22
- _STRUCT_PACK_BY_PLATFORM: ta.ClassVar[ta.Mapping[str, ta.Sequence[ta.Tuple[str, str]]]] = {
22
+ _STRUCT_PACKING_BY_PLATFORM: ta.ClassVar[ta.Mapping[str, ta.Sequence[ta.Tuple[str, str]]]] = {
23
23
  'linux': [
24
24
  ('type', 'h'),
25
25
  ('whence', 'h'),
@@ -36,24 +36,23 @@ class FcntlLockData:
36
36
  ],
37
37
  }
38
38
 
39
- def pack(self) -> bytes:
39
+ @classmethod
40
+ def _struct_packing(cls) -> ta.Sequence[ta.Tuple[str, str]]:
40
41
  try:
41
- pack = self._STRUCT_PACK_BY_PLATFORM[sys.platform]
42
+ return cls._STRUCT_PACKING_BY_PLATFORM[sys.platform]
42
43
  except KeyError:
43
44
  raise OSError from None
44
45
 
45
- fmt = ''.join(f for _, f in pack)
46
- tup = [getattr(self, a) for a, _ in pack]
46
+ def pack(self) -> bytes:
47
+ packing = self._struct_packing()
48
+ fmt = ''.join(f for _, f in packing)
49
+ tup = [getattr(self, a) for a, _ in packing]
47
50
  return struct.pack(fmt, *tup)
48
51
 
49
52
  @classmethod
50
53
  def unpack(cls, data: bytes) -> 'FcntlLockData':
51
- try:
52
- pack = cls._STRUCT_PACK_BY_PLATFORM[sys.platform]
53
- except KeyError:
54
- raise OSError from None
55
-
56
- fmt = ''.join(f for _, f in pack)
54
+ packing = cls._struct_packing()
55
+ fmt = ''.join(f for _, f in packing)
57
56
  tup = struct.unpack(fmt, data)
58
- kw = {a: v for (a, _), v in zip(pack, tup)}
57
+ kw = {a: v for (a, _), v in zip(packing, tup)}
59
58
  return FcntlLockData(**kw)
omlish/os/files.py CHANGED
@@ -1,24 +1,39 @@
1
1
  # ruff: noqa: UP006 UP007
2
2
  # @omlish-lite
3
3
  import contextlib
4
+ import errno
5
+ import fcntl
4
6
  import os
5
7
  import typing as ta
6
8
 
7
9
 
8
- def touch(self, mode: int = 0o666, exist_ok: bool = True) -> None:
10
+ def is_fd_open(fd: int) -> bool:
11
+ try:
12
+ fcntl.fcntl(fd, fcntl.F_GETFD)
13
+ except OSError as e:
14
+ if e.errno == errno.EBADF:
15
+ return False
16
+ raise
17
+ else:
18
+ return True
19
+
20
+
21
+ def touch(path: str, mode: int = 0o666, exist_ok: bool = True) -> None:
9
22
  if exist_ok:
10
23
  # First try to bump modification time
11
24
  # Implementation note: GNU touch uses the UTIME_NOW option of the utimensat() / futimens() functions.
12
25
  try:
13
- os.utime(self, None)
26
+ os.utime(path, None)
14
27
  except OSError:
15
28
  pass
16
29
  else:
17
30
  return
31
+
18
32
  flags = os.O_CREAT | os.O_WRONLY
19
33
  if not exist_ok:
20
34
  flags |= os.O_EXCL
21
- fd = os.open(self, flags, mode)
35
+
36
+ fd = os.open(path, flags, mode)
22
37
  os.close(fd)
23
38
 
24
39
 
omlish/os/forkhooks.py ADDED
@@ -0,0 +1,215 @@
1
+ # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
3
+ """
4
+ TODO:
5
+ - ForkHook base class? all classmethods? prevents pickling
6
+ """
7
+ import abc
8
+ import os
9
+ import threading
10
+ import typing as ta
11
+
12
+ from ..lite.check import check
13
+
14
+
15
+ ##
16
+
17
+
18
+ class _ForkHookManager:
19
+ def __new__(cls, *args, **kwargs): # noqa
20
+ raise TypeError
21
+
22
+ def __init_subclass__(cls, **kwargs): # noqa
23
+ raise TypeError
24
+
25
+ #
26
+
27
+ # Intentionally not an RLock - do not nest calls.
28
+ _lock: ta.ClassVar[threading.Lock] = threading.Lock()
29
+
30
+ #
31
+
32
+ _installed: ta.ClassVar[bool] = False
33
+
34
+ @classmethod
35
+ def _install(cls) -> bool:
36
+ if cls._installed:
37
+ return False
38
+
39
+ check.state(not cls._installed)
40
+
41
+ os.register_at_fork(
42
+ before=cls._before_fork,
43
+ after_in_parent=cls._after_fork_in_parent,
44
+ after_in_child=cls._after_fork_in_child,
45
+ )
46
+
47
+ cls._installed = True
48
+ return True
49
+
50
+ @classmethod
51
+ def install(cls) -> bool:
52
+ with cls._lock:
53
+ return cls._install()
54
+
55
+ #
56
+
57
+ class Hook(ta.NamedTuple):
58
+ key: ta.Any
59
+ priority: int
60
+
61
+ # NOTE: these are called inside the global, non-reentrant manager lock
62
+ before_fork: ta.Optional[ta.Callable[[], None]] = None
63
+ after_fork_in_parent: ta.Optional[ta.Callable[[], None]] = None
64
+ after_fork_in_child: ta.Optional[ta.Callable[[], None]] = None
65
+
66
+ #
67
+
68
+ _hooks_by_key: ta.ClassVar[ta.Dict[str, Hook]] = {}
69
+
70
+ _hook_keys: ta.ClassVar[ta.FrozenSet[str]] = frozenset()
71
+ _priority_ordered_hooks: ta.ClassVar[ta.List[Hook]] = []
72
+
73
+ @classmethod
74
+ def _rebuild_hook_collections(cls) -> None:
75
+ cls._hook_keys = frozenset(cls._hooks_by_key)
76
+
77
+ # Uses on dict order preservation for insertion-order of hooks of equal priority (although that shouldn't be
78
+ # depended upon for usecase correctness.
79
+ cls._priority_ordered_hooks = sorted(cls._hooks_by_key.values(), key=lambda h: h.priority)
80
+
81
+ #
82
+
83
+ class HookAlreadyPresentError(Exception):
84
+ pass
85
+
86
+ @classmethod
87
+ def add_hook(cls, hook: Hook) -> None:
88
+ with cls._lock:
89
+ if hook.key in cls._hooks_by_key:
90
+ raise cls.HookAlreadyPresentError(hook.key)
91
+
92
+ check.isinstance(hook.priority, int)
93
+
94
+ cls._hooks_by_key[hook.key] = hook
95
+ cls._rebuild_hook_collections()
96
+
97
+ cls._install()
98
+
99
+ @classmethod
100
+ def try_add_hook(cls, hook: Hook) -> bool:
101
+ if hook.key in cls._hook_keys:
102
+ return False
103
+
104
+ try:
105
+ cls.add_hook(hook)
106
+ except cls.HookAlreadyPresentError:
107
+ return False
108
+ else:
109
+ return True
110
+
111
+ @classmethod
112
+ def contains_hook(cls, key: ta.Any) -> bool:
113
+ return key in cls._hook_keys
114
+
115
+ @classmethod
116
+ def remove_hook(cls, key: ta.Any) -> None:
117
+ with cls._lock:
118
+ del cls._hooks_by_key[key]
119
+
120
+ cls._rebuild_hook_collections()
121
+
122
+ #
123
+
124
+ @classmethod
125
+ def _before_fork(cls) -> None:
126
+ cls._lock.acquire()
127
+
128
+ for hook in cls._priority_ordered_hooks:
129
+ if (fn := hook.before_fork) is not None:
130
+ fn()
131
+
132
+ @classmethod
133
+ def _after_fork_in_parent(cls) -> None:
134
+ for hook in cls._priority_ordered_hooks:
135
+ if (fn := hook.after_fork_in_parent) is not None:
136
+ fn()
137
+
138
+ cls._lock.release()
139
+
140
+ @classmethod
141
+ def _after_fork_in_child(cls) -> None:
142
+ for hook in cls._priority_ordered_hooks:
143
+ if (fn := hook.after_fork_in_child) is not None:
144
+ fn()
145
+
146
+ cls._lock.release()
147
+
148
+
149
+ #
150
+
151
+
152
+ class ForkHook(abc.ABC): # noqa
153
+ @ta.final
154
+ def __new__(cls, *args, **kwargs): # noqa
155
+ raise TypeError
156
+
157
+ @classmethod
158
+ @ta.final
159
+ def install(cls) -> bool:
160
+ if _ForkHookManager.contains_hook(cls):
161
+ return False
162
+
163
+ return _ForkHookManager.try_add_hook(_ForkHookManager.Hook(
164
+ key=cls,
165
+ priority=cls._hook_priority,
166
+
167
+ before_fork=cls._before_fork,
168
+ after_fork_in_parent=cls._after_fork_in_parent,
169
+ after_fork_in_child=cls._after_fork_in_child,
170
+ ))
171
+
172
+ def __init_subclass__(cls, install: bool = False, **kwargs: ta.Any) -> None:
173
+ super().__init_subclass__(**kwargs)
174
+
175
+ if install:
176
+ cls.install()
177
+
178
+ #
179
+
180
+ _hook_priority: ta.ClassVar[int] = 0
181
+
182
+ @classmethod # noqa
183
+ def _before_fork(cls) -> None:
184
+ pass
185
+
186
+ @classmethod # noqa
187
+ def _after_fork_in_parent(cls) -> None:
188
+ pass
189
+
190
+ @classmethod # noqa
191
+ def _after_fork_in_child(cls) -> None:
192
+ pass
193
+
194
+
195
+ ##
196
+
197
+
198
+ class _ForkDepthTracker(ForkHook):
199
+ _hook_priority = -1000
200
+
201
+ _fork_depth: ta.ClassVar[int] = 0
202
+
203
+ @classmethod
204
+ def _after_fork_in_child(cls) -> None:
205
+ cls._fork_depth += 1
206
+
207
+ @classmethod
208
+ def get_fork_depth(cls) -> int:
209
+ cls.install()
210
+
211
+ return cls._fork_depth
212
+
213
+
214
+ def get_fork_depth() -> int:
215
+ return _ForkDepthTracker.get_fork_depth()
@@ -1,6 +1,10 @@
1
1
  # ruff: noqa: UP006 UP007
2
2
  # @omlish-lite
3
3
  """
4
+ Notes:
5
+ - still racy as to if it's a different actual process as initial check, just with same pid, but due to 'identity' /
6
+ semantic meaning of the named pidfile the processes are considered equivalent
7
+
4
8
  Strategies:
5
9
  - linux
6
10
  - get pid of owner (lslocks or F_GETLK)
omlish/sockets/bind.py CHANGED
@@ -15,10 +15,10 @@ import socket as socket_
15
15
  import stat
16
16
  import typing as ta
17
17
 
18
- from omlish.lite.check import check
19
- from omlish.lite.dataclasses import dataclass_maybe_post_init
20
- from omlish.sockets.addresses import SocketAddress
21
- from omlish.sockets.addresses import SocketAndAddress
18
+ from ..lite.check import check
19
+ from ..lite.dataclasses import dataclass_maybe_post_init
20
+ from .addresses import SocketAddress
21
+ from .addresses import SocketAndAddress
22
22
 
23
23
 
24
24
  SocketBinderT = ta.TypeVar('SocketBinderT', bound='SocketBinder')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: omlish
3
- Version: 0.0.0.dev227
3
+ Version: 0.0.0.dev229
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -32,7 +32,7 @@ Requires-Dist: cbor2~=5.6; extra == "all"
32
32
  Requires-Dist: cloudpickle~=3.1; extra == "all"
33
33
  Requires-Dist: httpx[http2]~=0.28; extra == "all"
34
34
  Requires-Dist: wrapt~=1.17; extra == "all"
35
- Requires-Dist: cryptography~=43.0; extra == "all"
35
+ Requires-Dist: cryptography~=44.0; extra == "all"
36
36
  Requires-Dist: sqlalchemy[asyncio]~=2.0; extra == "all"
37
37
  Requires-Dist: pg8000~=1.31; extra == "all"
38
38
  Requires-Dist: pymysql~=1.1; extra == "all"
@@ -76,7 +76,7 @@ Requires-Dist: httpx[http2]~=0.28; extra == "http"
76
76
  Provides-Extra: misc
77
77
  Requires-Dist: wrapt~=1.17; extra == "misc"
78
78
  Provides-Extra: secrets
79
- Requires-Dist: cryptography~=43.0; extra == "secrets"
79
+ Requires-Dist: cryptography~=44.0; extra == "secrets"
80
80
  Provides-Extra: sqlalchemy
81
81
  Requires-Dist: sqlalchemy[asyncio]~=2.0; extra == "sqlalchemy"
82
82
  Provides-Extra: sqldrivers