omlish 0.0.0.dev227__py3-none-any.whl → 0.0.0.dev229__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
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