ominfra 0.0.0.dev159__py3-none-any.whl → 0.0.0.dev161__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.
@@ -2296,6 +2296,10 @@ def is_new_type(spec: ta.Any) -> bool:
2296
2296
  return isinstance(spec, types.FunctionType) and spec.__code__ is ta.NewType.__code__.co_consts[1] # type: ignore # noqa
2297
2297
 
2298
2298
 
2299
+ def get_new_type_supertype(spec: ta.Any) -> ta.Any:
2300
+ return spec.__supertype__
2301
+
2302
+
2299
2303
  def deep_subclasses(cls: ta.Type[T]) -> ta.Iterator[ta.Type[T]]:
2300
2304
  seen = set()
2301
2305
  todo = list(reversed(cls.__subclasses__()))
@@ -4854,9 +4858,7 @@ inj = Injection
4854
4858
  """
4855
4859
  TODO:
4856
4860
  - pickle stdlib objs? have to pin to 3.8 pickle protocol, will be cross-version
4857
- - namedtuple
4858
4861
  - literals
4859
- - newtypes?
4860
4862
  """
4861
4863
 
4862
4864
 
@@ -4866,7 +4868,7 @@ TODO:
4866
4868
  @dc.dataclass(frozen=True)
4867
4869
  class ObjMarshalOptions:
4868
4870
  raw_bytes: bool = False
4869
- nonstrict_dataclasses: bool = False
4871
+ non_strict_fields: bool = False
4870
4872
 
4871
4873
 
4872
4874
  class ObjMarshaler(abc.ABC):
@@ -4995,10 +4997,10 @@ class IterableObjMarshaler(ObjMarshaler):
4995
4997
 
4996
4998
 
4997
4999
  @dc.dataclass(frozen=True)
4998
- class DataclassObjMarshaler(ObjMarshaler):
5000
+ class FieldsObjMarshaler(ObjMarshaler):
4999
5001
  ty: type
5000
5002
  fs: ta.Mapping[str, ObjMarshaler]
5001
- nonstrict: bool = False
5003
+ non_strict: bool = False
5002
5004
 
5003
5005
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
5004
5006
  return {
@@ -5010,7 +5012,7 @@ class DataclassObjMarshaler(ObjMarshaler):
5010
5012
  return self.ty(**{
5011
5013
  k: self.fs[k].unmarshal(v, ctx)
5012
5014
  for k, v in o.items()
5013
- if not (self.nonstrict or ctx.options.nonstrict_dataclasses) or k in self.fs
5015
+ if not (self.non_strict or ctx.options.non_strict_fields) or k in self.fs
5014
5016
  })
5015
5017
 
5016
5018
 
@@ -5142,7 +5144,7 @@ class ObjMarshalerManager:
5142
5144
  ty: ta.Any,
5143
5145
  rec: ta.Callable[[ta.Any], ObjMarshaler],
5144
5146
  *,
5145
- nonstrict_dataclasses: bool = False,
5147
+ non_strict_fields: bool = False,
5146
5148
  ) -> ObjMarshaler:
5147
5149
  if isinstance(ty, type):
5148
5150
  if abc.ABC in ty.__bases__:
@@ -5164,12 +5166,22 @@ class ObjMarshalerManager:
5164
5166
  return EnumObjMarshaler(ty)
5165
5167
 
5166
5168
  if dc.is_dataclass(ty):
5167
- return DataclassObjMarshaler(
5169
+ return FieldsObjMarshaler(
5168
5170
  ty,
5169
5171
  {f.name: rec(f.type) for f in dc.fields(ty)},
5170
- nonstrict=nonstrict_dataclasses,
5172
+ non_strict=non_strict_fields,
5173
+ )
5174
+
5175
+ if issubclass(ty, tuple) and hasattr(ty, '_fields'):
5176
+ return FieldsObjMarshaler(
5177
+ ty,
5178
+ {p.name: rec(p.annotation) for p in inspect.signature(ty).parameters.values()},
5179
+ non_strict=non_strict_fields,
5171
5180
  )
5172
5181
 
5182
+ if is_new_type(ty):
5183
+ return rec(get_new_type_supertype(ty))
5184
+
5173
5185
  if is_generic_alias(ty):
5174
5186
  try:
5175
5187
  mt = self._generic_mapping_types[ta.get_origin(ty)]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ominfra
3
- Version: 0.0.0.dev159
3
+ Version: 0.0.0.dev161
4
4
  Summary: ominfra
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -12,8 +12,8 @@ Classifier: Operating System :: OS Independent
12
12
  Classifier: Operating System :: POSIX
13
13
  Requires-Python: >=3.12
14
14
  License-File: LICENSE
15
- Requires-Dist: omdev==0.0.0.dev159
16
- Requires-Dist: omlish==0.0.0.dev159
15
+ Requires-Dist: omdev==0.0.0.dev161
16
+ Requires-Dist: omlish==0.0.0.dev161
17
17
  Provides-Extra: all
18
18
  Requires-Dist: paramiko~=3.5; extra == "all"
19
19
  Requires-Dist: asyncssh~=2.18; extra == "all"
@@ -44,18 +44,17 @@ ominfra/manage/commands/ping.py,sha256=DVZFzL1Z_f-Bq53vxMrL3xOi0iK_nMonJE4KvQf9w
44
44
  ominfra/manage/commands/subprocess.py,sha256=yHGMbAI-xKe_9BUs5IZ3Yav8qRE-I9aGnBtTwW15Pnw,2440
45
45
  ominfra/manage/commands/types.py,sha256=XFZPeqeIBAaIIQF3pdPbGxLlb-LCrz6WtlDWO2q_vz0,210
46
46
  ominfra/manage/deploy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
- ominfra/manage/deploy/apps.py,sha256=zXoIiY2FARQ5Bwpqqh69nQt5hon9nliYRIarSNZuST4,1888
48
- ominfra/manage/deploy/atomics.py,sha256=j9_L2LXls2dR1I4rQw3msIa2D90JwEO9Mb8KBGOKmyU,5180
49
- ominfra/manage/deploy/commands.py,sha256=YZGdpiaqj_-iMp2SMdz4hB6bTKk3UQxnHeTblGyxuuk,560
47
+ ominfra/manage/deploy/apps.py,sha256=lXcbyX8_wrvvwKtIMM9P_Mh7xL8yj6z9_PFTl_0u-0U,1887
48
+ ominfra/manage/deploy/commands.py,sha256=N9qVntnRgJ_IneI7rEQB2Za0oU7gouPfm-sl2MCwW1E,764
50
49
  ominfra/manage/deploy/config.py,sha256=aR6ubMEWqkTI55XtcG1Cczn6YhCVN6eSL8DT5EHQJN0,166
51
- ominfra/manage/deploy/git.py,sha256=t_GQBElH5dL56ww-OLoPKu__Qdtbz9VvR_DQExwtS8M,3606
52
- ominfra/manage/deploy/inject.py,sha256=JBc96rxOL7Q6P78yZP4WHp08i2AHvV0JHbRpUzbFblw,1444
50
+ ominfra/manage/deploy/git.py,sha256=6CGLvGH8uYkuT8gyZHybJb7sgUPTtFgy7grj1YHkI9g,3747
51
+ ominfra/manage/deploy/inject.py,sha256=8wuIgdzkDCHbc69nD1meLjwfCOMdWOIfDT5yijL-du8,1441
53
52
  ominfra/manage/deploy/interp.py,sha256=OKkenH8YKEW_mEDR6X7_ZLxK9a1Ox6KHSwFPTHT6OzA,1029
54
- ominfra/manage/deploy/paths.py,sha256=Wda2kvn-AjIBTnfk5XwC9Dpj89Px6CaocHvPNy5uRNA,7203
55
- ominfra/manage/deploy/specs.py,sha256=q71CORthSCAtJaR-dNRFVFF3zQvM58Xuo3tE-urNZWU,882
56
- ominfra/manage/deploy/tmp.py,sha256=Wg29UMsWL_A8anFsE-XyvkTNsMfH26Nr8BvJxgKNxMo,1248
53
+ ominfra/manage/deploy/paths.py,sha256=tK8zZFWOHDRdTN5AlTe-3MpgZqovhWrljGosQmeEYvo,6839
54
+ ominfra/manage/deploy/specs.py,sha256=Yq3WiLNJcodUBEsJfP18gPGB3X2ABI1g8YLlsUvJOXg,1230
55
+ ominfra/manage/deploy/tmp.py,sha256=L0pIfQuxQ7_6gC_AAv7eubI37_IPzCVR29hkn1MHL2Q,1230
57
56
  ominfra/manage/deploy/types.py,sha256=o95wqvTGNRq8Cxx7VpqeX-9x1tI8k8BpqPFvJZkJYBA,305
58
- ominfra/manage/deploy/venvs.py,sha256=A1nqFo1Zhxg-Sw3Uyxe6hck4ZEh3bBq8GIjnJPvNLd8,2232
57
+ ominfra/manage/deploy/venvs.py,sha256=ZG9tXhzg0R173T1IFIc5DE45xEuJK97DjlN1cQPAvXI,2229
59
58
  ominfra/manage/remote/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
60
59
  ominfra/manage/remote/_main.py,sha256=p5KoiS2WMw6QAqlDl_Zun-JybmCsy8awIfpBMLBjGMY,4356
61
60
  ominfra/manage/remote/channel.py,sha256=36xR9Ti9ZA8TUBtxmY0u7_3Lv7E6wzQTxlZl7gLR5GE,2224
@@ -72,13 +71,13 @@ ominfra/manage/system/inject.py,sha256=Ksc7Xw_Yh3lWwkTRxB2JCeOYO-nMyKj-Kssd1RDkR
72
71
  ominfra/manage/system/packages.py,sha256=HImCsgzXxcfzAoD2PjrstaSE_qgBWtTFUVb0lTEOxkI,4614
73
72
  ominfra/manage/system/platforms.py,sha256=F0bgYzUzCjZ2LbWVvnEq2ya_X_LfRW406LQYFL7bG44,1202
74
73
  ominfra/manage/targets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
75
- ominfra/manage/targets/connection.py,sha256=j2QrVS-QFOZJ47TqwaMt8MSPg0whokysGePagjJg3Jg,4637
74
+ ominfra/manage/targets/connection.py,sha256=5e8h9Miej2DKJxZfLyxpGe8y-Y0V_b_AuUW159XVeJM,4643
76
75
  ominfra/manage/targets/inject.py,sha256=P4597xWM-V3I_gCt2O71OLhYQkkXtuJvkYRsIbhhMcE,1561
77
76
  ominfra/manage/targets/targets.py,sha256=CFl8Uirgn3gfowO1Fn-LBK-6qYqEMFJ9snPUl0gCRuM,1753
78
77
  ominfra/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
79
- ominfra/scripts/journald2aws.py,sha256=ptC5QEa-AQo1XQQnrEdroExdUfX47hnegrIF8-cWYtY,154666
80
- ominfra/scripts/manage.py,sha256=uxnQ19q9uIbspC_vIN6SM0IikyW5zC16kibqtgjBnTM,293288
81
- ominfra/scripts/supervisor.py,sha256=5qEwZY701LZVZgN3zfesv2eo-zI4NieJyQW1ZzuxPa4,273568
78
+ ominfra/scripts/journald2aws.py,sha256=EC8tSKW3hztBV_Kr_ykK72AmcvnWivUxcz6Sfg3M_hI,155085
79
+ ominfra/scripts/manage.py,sha256=MQQGcgbIDwUfD31nDGJD2DhWhlazj8GVwQi7kOzi3gc,293788
80
+ ominfra/scripts/supervisor.py,sha256=npGYEWSZfY7E24mdkJ3HrL_ax6AcqjHfqh-7nZ_sX0U,273987
82
81
  ominfra/supervisor/LICENSE.txt,sha256=yvqaMNsDhWxziHa9ien6qCW1SkZv-DQlAg96XjfSee8,1746
83
82
  ominfra/supervisor/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
84
83
  ominfra/supervisor/__main__.py,sha256=I0yFw-C08OOiZ3BF6lF1Oiv789EQXu-_j6whDhQUTEA,66
@@ -120,9 +119,9 @@ ominfra/tailscale/api.py,sha256=C5-t_b6jZXUWcy5k8bXm7CFnk73pSdrlMOgGDeGVrpw,1370
120
119
  ominfra/tailscale/cli.py,sha256=h6akQJMl0KuWLHS7Ur6WcBZ2JwF0DJQhsPTnFBdGyNk,3571
121
120
  ominfra/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
122
121
  ominfra/tools/listresources.py,sha256=4qVg5txsb10EHhvqXXeM6gJ2jx9LbroEnPydDv1uXs0,6176
123
- ominfra-0.0.0.dev159.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
124
- ominfra-0.0.0.dev159.dist-info/METADATA,sha256=7V3dKKJZtJN-ecCQ8V4428AnWq-mr7W7HR64ez-s5mg,731
125
- ominfra-0.0.0.dev159.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
126
- ominfra-0.0.0.dev159.dist-info/entry_points.txt,sha256=kgecQ2MgGrM9qK744BoKS3tMesaC3yjLnl9pa5CRczg,37
127
- ominfra-0.0.0.dev159.dist-info/top_level.txt,sha256=E-b2OHkk_AOBLXHYZQ2EOFKl-_6uOGd8EjeG-Zy6h_w,8
128
- ominfra-0.0.0.dev159.dist-info/RECORD,,
122
+ ominfra-0.0.0.dev161.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
123
+ ominfra-0.0.0.dev161.dist-info/METADATA,sha256=9BUyOL7-nhzomsloRZDx7T8VL-T0KbCHxyQ74LxzbFY,731
124
+ ominfra-0.0.0.dev161.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
125
+ ominfra-0.0.0.dev161.dist-info/entry_points.txt,sha256=kgecQ2MgGrM9qK744BoKS3tMesaC3yjLnl9pa5CRczg,37
126
+ ominfra-0.0.0.dev161.dist-info/top_level.txt,sha256=E-b2OHkk_AOBLXHYZQ2EOFKl-_6uOGd8EjeG-Zy6h_w,8
127
+ ominfra-0.0.0.dev161.dist-info/RECORD,,
@@ -1,207 +0,0 @@
1
- # ruff: noqa: UP006 UP007
2
- import abc
3
- import os
4
- import shutil
5
- import tempfile
6
- import typing as ta
7
-
8
- from omlish.lite.check import check
9
- from omlish.lite.strings import attr_repr
10
-
11
-
12
- DeployAtomicPathSwapKind = ta.Literal['dir', 'file']
13
- DeployAtomicPathSwapState = ta.Literal['open', 'committed', 'aborted'] # ta.TypeAlias
14
-
15
-
16
- ##
17
-
18
-
19
- class DeployAtomicPathSwap(abc.ABC):
20
- def __init__(
21
- self,
22
- kind: DeployAtomicPathSwapKind,
23
- dst_path: str,
24
- *,
25
- auto_commit: bool = False,
26
- ) -> None:
27
- super().__init__()
28
-
29
- self._kind = kind
30
- self._dst_path = dst_path
31
- self._auto_commit = auto_commit
32
-
33
- self._state: DeployAtomicPathSwapState = 'open'
34
-
35
- def __repr__(self) -> str:
36
- return attr_repr(self, 'kind', 'dst_path', 'tmp_path')
37
-
38
- @property
39
- def kind(self) -> DeployAtomicPathSwapKind:
40
- return self._kind
41
-
42
- @property
43
- def dst_path(self) -> str:
44
- return self._dst_path
45
-
46
- @property
47
- @abc.abstractmethod
48
- def tmp_path(self) -> str:
49
- raise NotImplementedError
50
-
51
- #
52
-
53
- @property
54
- def state(self) -> DeployAtomicPathSwapState:
55
- return self._state
56
-
57
- def _check_state(self, *states: DeployAtomicPathSwapState) -> None:
58
- if self._state not in states:
59
- raise RuntimeError(f'Atomic path swap not in correct state: {self._state}, {states}')
60
-
61
- #
62
-
63
- @abc.abstractmethod
64
- def _commit(self) -> None:
65
- raise NotImplementedError
66
-
67
- def commit(self) -> None:
68
- if self._state == 'committed':
69
- return
70
- self._check_state('open')
71
- try:
72
- self._commit()
73
- except Exception: # noqa
74
- self._abort()
75
- raise
76
- else:
77
- self._state = 'committed'
78
-
79
- #
80
-
81
- @abc.abstractmethod
82
- def _abort(self) -> None:
83
- raise NotImplementedError
84
-
85
- def abort(self) -> None:
86
- if self._state == 'aborted':
87
- return
88
- self._abort()
89
- self._state = 'aborted'
90
-
91
- #
92
-
93
- def __enter__(self) -> 'DeployAtomicPathSwap':
94
- return self
95
-
96
- def __exit__(self, exc_type, exc_val, exc_tb):
97
- if (
98
- exc_type is None and
99
- self._auto_commit and
100
- self._state == 'open'
101
- ):
102
- self.commit()
103
- else:
104
- self.abort()
105
-
106
-
107
- #
108
-
109
-
110
- class DeployAtomicPathSwapping(abc.ABC):
111
- @abc.abstractmethod
112
- def begin_atomic_path_swap(
113
- self,
114
- kind: DeployAtomicPathSwapKind,
115
- dst_path: str,
116
- *,
117
- name_hint: ta.Optional[str] = None,
118
- make_dirs: bool = False,
119
- **kwargs: ta.Any,
120
- ) -> DeployAtomicPathSwap:
121
- raise NotImplementedError
122
-
123
-
124
- ##
125
-
126
-
127
- class OsRenameDeployAtomicPathSwap(DeployAtomicPathSwap):
128
- def __init__(
129
- self,
130
- kind: DeployAtomicPathSwapKind,
131
- dst_path: str,
132
- tmp_path: str,
133
- **kwargs: ta.Any,
134
- ) -> None:
135
- if kind == 'dir':
136
- check.state(os.path.isdir(tmp_path))
137
- elif kind == 'file':
138
- check.state(os.path.isfile(tmp_path))
139
- else:
140
- raise TypeError(kind)
141
-
142
- super().__init__(
143
- kind,
144
- dst_path,
145
- **kwargs,
146
- )
147
-
148
- self._tmp_path = tmp_path
149
-
150
- @property
151
- def tmp_path(self) -> str:
152
- return self._tmp_path
153
-
154
- def _commit(self) -> None:
155
- os.rename(self._tmp_path, self._dst_path)
156
-
157
- def _abort(self) -> None:
158
- shutil.rmtree(self._tmp_path, ignore_errors=True)
159
-
160
-
161
- class TempDirDeployAtomicPathSwapping(DeployAtomicPathSwapping):
162
- def __init__(
163
- self,
164
- *,
165
- temp_dir: ta.Optional[str] = None,
166
- root_dir: ta.Optional[str] = None,
167
- ) -> None:
168
- super().__init__()
169
-
170
- if root_dir is not None:
171
- root_dir = os.path.abspath(root_dir)
172
- self._root_dir = root_dir
173
- self._temp_dir = temp_dir
174
-
175
- def begin_atomic_path_swap(
176
- self,
177
- kind: DeployAtomicPathSwapKind,
178
- dst_path: str,
179
- *,
180
- name_hint: ta.Optional[str] = None,
181
- make_dirs: bool = False,
182
- **kwargs: ta.Any,
183
- ) -> DeployAtomicPathSwap:
184
- dst_path = os.path.abspath(dst_path)
185
- if self._root_dir is not None and not dst_path.startswith(check.non_empty_str(self._root_dir)):
186
- raise RuntimeError(f'Atomic path swap dst must be in root dir: {dst_path}, {self._root_dir}')
187
-
188
- dst_dir = os.path.dirname(dst_path)
189
- if make_dirs:
190
- os.makedirs(dst_dir, exist_ok=True)
191
- if not os.path.isdir(dst_dir):
192
- raise RuntimeError(f'Atomic path swap dst dir does not exist: {dst_dir}')
193
-
194
- if kind == 'dir':
195
- tmp_path = tempfile.mkdtemp(prefix=name_hint, dir=self._temp_dir)
196
- elif kind == 'file':
197
- fd, tmp_path = tempfile.mkstemp(prefix=name_hint, dir=self._temp_dir)
198
- os.close(fd)
199
- else:
200
- raise TypeError(kind)
201
-
202
- return OsRenameDeployAtomicPathSwap(
203
- kind,
204
- dst_path,
205
- tmp_path,
206
- **kwargs,
207
- )