omdev 0.0.0.dev213__py3-none-any.whl → 0.0.0.dev215__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.
@@ -4962,6 +4962,7 @@ inj = InjectionApi()
4962
4962
  TODO:
4963
4963
  - pickle stdlib objs? have to pin to 3.8 pickle protocol, will be cross-version
4964
4964
  - literals
4965
+ - Options.sequence_cls = list, mapping_cls = dict, ... - def with_mutable_containers() -> Options
4965
4966
  """
4966
4967
 
4967
4968
 
@@ -5114,21 +5115,55 @@ class IterableObjMarshaler(ObjMarshaler):
5114
5115
  @dc.dataclass(frozen=True)
5115
5116
  class FieldsObjMarshaler(ObjMarshaler):
5116
5117
  ty: type
5117
- fs: ta.Mapping[str, ObjMarshaler]
5118
+
5119
+ @dc.dataclass(frozen=True)
5120
+ class Field:
5121
+ att: str
5122
+ key: str
5123
+ m: ObjMarshaler
5124
+
5125
+ omit_if_none: bool = False
5126
+
5127
+ fs: ta.Sequence[Field]
5128
+
5118
5129
  non_strict: bool = False
5119
5130
 
5131
+ #
5132
+
5133
+ _fs_by_att: ta.ClassVar[ta.Mapping[str, Field]]
5134
+ _fs_by_key: ta.ClassVar[ta.Mapping[str, Field]]
5135
+
5136
+ def __post_init__(self) -> None:
5137
+ fs_by_att: dict = {}
5138
+ fs_by_key: dict = {}
5139
+ for f in self.fs:
5140
+ check.not_in(check.non_empty_str(f.att), fs_by_att)
5141
+ check.not_in(check.non_empty_str(f.key), fs_by_key)
5142
+ fs_by_att[f.att] = f
5143
+ fs_by_key[f.key] = f
5144
+ self.__dict__['_fs_by_att'] = fs_by_att
5145
+ self.__dict__['_fs_by_key'] = fs_by_key
5146
+
5147
+ #
5148
+
5120
5149
  def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
5121
- return {
5122
- k: m.marshal(getattr(o, k), ctx)
5123
- for k, m in self.fs.items()
5124
- }
5150
+ d = {}
5151
+ for f in self.fs:
5152
+ mv = f.m.marshal(getattr(o, f.att), ctx)
5153
+ if mv is None and f.omit_if_none:
5154
+ continue
5155
+ d[f.key] = mv
5156
+ return d
5125
5157
 
5126
5158
  def unmarshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
5127
- return self.ty(**{
5128
- k: self.fs[k].unmarshal(v, ctx)
5129
- for k, v in o.items()
5130
- if not (self.non_strict or ctx.options.non_strict_fields) or k in self.fs
5131
- })
5159
+ kw = {}
5160
+ for k, v in o.items():
5161
+ if (f := self._fs_by_key.get(k)) is None:
5162
+ if not (self.non_strict or ctx.options.non_strict_fields):
5163
+ raise KeyError(k)
5164
+ continue
5165
+ kw[f.att] = f.m.unmarshal(v, ctx)
5166
+ return self.ty(**kw)
5132
5167
 
5133
5168
 
5134
5169
  @dc.dataclass(frozen=True)
@@ -5263,6 +5298,22 @@ def register_single_field_type_obj_marshaler(fld, ty=None):
5263
5298
  ##
5264
5299
 
5265
5300
 
5301
+ class ObjMarshalerFieldMetadata:
5302
+ def __new__(cls, *args, **kwargs): # noqa
5303
+ raise TypeError
5304
+
5305
+
5306
+ class OBJ_MARSHALER_FIELD_KEY(ObjMarshalerFieldMetadata): # noqa
5307
+ pass
5308
+
5309
+
5310
+ class OBJ_MARSHALER_OMIT_IF_NONE(ObjMarshalerFieldMetadata): # noqa
5311
+ pass
5312
+
5313
+
5314
+ ##
5315
+
5316
+
5266
5317
  class ObjMarshalerManager:
5267
5318
  def __init__(
5268
5319
  self,
@@ -5322,14 +5373,30 @@ class ObjMarshalerManager:
5322
5373
  if dc.is_dataclass(ty):
5323
5374
  return FieldsObjMarshaler(
5324
5375
  ty,
5325
- {f.name: rec(f.type) for f in dc.fields(ty)},
5376
+ [
5377
+ FieldsObjMarshaler.Field(
5378
+ att=f.name,
5379
+ key=check.non_empty_str(fk),
5380
+ m=rec(f.type),
5381
+ omit_if_none=check.isinstance(f.metadata.get(OBJ_MARSHALER_OMIT_IF_NONE, False), bool),
5382
+ )
5383
+ for f in dc.fields(ty)
5384
+ if (fk := f.metadata.get(OBJ_MARSHALER_FIELD_KEY, f.name)) is not None
5385
+ ],
5326
5386
  non_strict=non_strict_fields,
5327
5387
  )
5328
5388
 
5329
5389
  if issubclass(ty, tuple) and hasattr(ty, '_fields'):
5330
5390
  return FieldsObjMarshaler(
5331
5391
  ty,
5332
- {p.name: rec(p.annotation) for p in inspect.signature(ty).parameters.values()},
5392
+ [
5393
+ FieldsObjMarshaler.Field(
5394
+ att=p.name,
5395
+ key=p.name,
5396
+ m=rec(p.annotation),
5397
+ )
5398
+ for p in inspect.signature(ty).parameters.values()
5399
+ ],
5333
5400
  non_strict=non_strict_fields,
5334
5401
  )
5335
5402
 
omdev/tools/docker.py CHANGED
@@ -1,6 +1,12 @@
1
1
  """
2
2
  TODO:
3
3
  - https://github.com/zeromake/docker-debug
4
+ - prune
5
+ - docker container prune --force
6
+ - docker system prune --all --force --filter "until=720h"
7
+ - docker container prune --force --filter "until=720h"
8
+ - docker image prune --all --force --filter "until=720h"
9
+ - docker builder prune --all --force --filter "until=720h"
4
10
  """
5
11
  import os
6
12
  import re
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: omdev
3
- Version: 0.0.0.dev213
3
+ Version: 0.0.0.dev215
4
4
  Summary: omdev
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -12,7 +12,7 @@ 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: omlish==0.0.0.dev213
15
+ Requires-Dist: omlish==0.0.0.dev215
16
16
  Provides-Extra: all
17
17
  Requires-Dist: black~=24.10; extra == "all"
18
18
  Requires-Dist: pycparser~=2.22; extra == "all"
@@ -1,4 +1,4 @@
1
- omdev/.manifests.json,sha256=kIHxCLwrqvBumPKT0GKsgRPhrJSovHf9jDnWzUDZMHs,9092
1
+ omdev/.manifests.json,sha256=VUg0T7DFMxatE-hsLqocMvGoNmELDiZZaudO1tcz-FE,9092
2
2
  omdev/__about__.py,sha256=j3vFclhFvyPICV6FK4aDApFzMCqJWxv9FaWwdwXrSgw,1215
3
3
  omdev/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  omdev/bracepy.py,sha256=I8EdqtDvxzAi3I8TuMEW-RBfwXfqKbwp06CfOdj3L1o,2743
@@ -69,22 +69,24 @@ omdev/cexts/_distutils/compilers/__init__.py,sha256=amL_zrFlba0lHIvpqDne9uhqhLem
69
69
  omdev/cexts/_distutils/compilers/ccompiler.py,sha256=cTs88qrvj0hBVXHfemSDE_du_nEA4_qo3Qst5TpQkVI,43606
70
70
  omdev/cexts/_distutils/compilers/options.py,sha256=H7r5IcLvga5Fs3jjXWIT-6ap3JBduXRKgtpDmSGCZxs,3818
71
71
  omdev/cexts/_distutils/compilers/unixccompiler.py,sha256=o1h8QuyupLntv4F21_XjzAZmCiwwxJuTmOirvBSL-Qw,15419
72
- omdev/ci/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
72
+ omdev/ci/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
73
73
  omdev/ci/__main__.py,sha256=Jsrv3P7LX2Cg08W7ByZfZ1JQT4lgLDPW1qNAmShFuMk,75
74
- omdev/ci/cache.py,sha256=jGrsnYNHnnOLJGIEoyHJUdpVzCBdh4tmy2d22Xgarnk,4132
75
- omdev/ci/ci.py,sha256=D7NkXNIABthkAeXuI0e3HCIVB4IJOURtWxQJ3t4TCOc,8369
76
- omdev/ci/cli.py,sha256=G3gmqWmqehlzzmd4bfnYWP9dTaxYQP7VcsbT8CNtCr8,5549
77
- omdev/ci/compose.py,sha256=X5j4imFa6QxYDONFRmhXOD8L9a-76zRfu8QJfVPlc9w,4726
78
- omdev/ci/docker.py,sha256=5FNQXlyvbBgOJw6jFyb4don_IYbT6fVgE09wIh7rYEk,3785
79
- omdev/ci/requirements.py,sha256=9K-f3DXZANoOonLjCCtpE6wR8JPJxj33ouo0VKNjZUE,2115
80
- omdev/ci/shell.py,sha256=KTkVZb_piQeB5Z12M2jUS_zGJfLR_Y2W2uYkrQpJpyw,850
81
- omdev/ci/utils.py,sha256=yiLSFOy4nNN9EY1C8rBe8fXdTmjpfBb6n1IgpzVJ00g,1605
74
+ omdev/ci/cache.py,sha256=hHV7ovvOwkSRcIF49ovb1A7s43mUl0IWXi1iIQeRMdA,3643
75
+ omdev/ci/ci.py,sha256=lEP5wgX0rInvkLJtGZQ-NSLO1Fc0CdQjVaUoMmeRCjQ,8110
76
+ omdev/ci/cli.py,sha256=0KBGKxaKzhSbhk3YFDOgzrb_OVOY22a4qpIaTu5zBeA,6243
77
+ omdev/ci/compose.py,sha256=vHLuXO5e2paafBC0Kf-OUGoamtIJmQ19r2U3_oikk_g,4541
78
+ omdev/ci/consts.py,sha256=1puYfksvGOaVWEnbARM_sdMqs8oTn_VvsevsOtLsFno,21
79
+ omdev/ci/docker.py,sha256=d3wQyL-N4mmzkIVbSgNx2Xd-K6RniFQN8nR-THKuDZs,3770
80
+ omdev/ci/requirements.py,sha256=iKAINTDyVQaqESGlfE9OXkKiW_CZ9kP70PEc121Ix-Q,2100
81
+ omdev/ci/shell.py,sha256=cBPLMKiAJuNpPGj3ou6hpl88Xw7r99xpL91KJBQ0rqw,835
82
+ omdev/ci/utils.py,sha256=mnf6yZmholvj0s_7JGbaO0Q1EWCn_saSv6BKMQQUCoQ,1450
82
83
  omdev/ci/github/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
83
- omdev/ci/github/bootstrap.py,sha256=KZxcg97DsbuE0UuL1G1qTqQEPjr3xiyJvALGnIyMz4s,249
84
- omdev/ci/github/cache.py,sha256=mItUXedRzffBHmiLCg6NdP07vDBDNf37pKgdtx6rFF0,9129
85
- omdev/ci/github/cacheapi.py,sha256=h7iJDcMicXYPf_4gqwUZu3DnaEp83ndMdVmGZXZUGas,5213
86
- omdev/ci/github/cli.py,sha256=ttBYHRIEXQZ6xi12aGZOgJJRfR22twyi3vL9R6eHvRA,975
87
- omdev/ci/github/curl.py,sha256=0UnLuOD1NR3b--Gr_T7klSub4zOFkQZcnXn7htd2j-M,5398
84
+ omdev/ci/github/api.py,sha256=Vqza7Hm1OCSfZYgdXF4exkjneqNjFcdO1pl8qmODskU,5198
85
+ omdev/ci/github/bootstrap.py,sha256=9OuftAz7CUd7uf2Or3sJFVozQQiwu0RGAlTOQNpLQIY,430
86
+ omdev/ci/github/cache.py,sha256=cXbPPMIWK-qjGyuCScEJGe-l4QKLwGBkW0GxOhGO_8E,1801
87
+ omdev/ci/github/cli.py,sha256=6mG0CllwrOoC7MDzKfKDqBHAjfF0gEI6aT5UAGMmuss,1114
88
+ omdev/ci/github/client.py,sha256=cSewCoHC4cDM4BMQObcrf5g2wwD6rTlil_h2repAkf8,14341
89
+ omdev/ci/github/env.py,sha256=FQFjP_m7JWM7es9I51U-6UgJTwAt_UCVHFIYKTd9NKM,394
88
90
  omdev/cli/__init__.py,sha256=V_l6VP1SZMlJbO-8CJwSuO9TThOy2S_oaPepNYgIrbE,37
89
91
  omdev/cli/__main__.py,sha256=mOJpgc07o0r5luQ1DlX4tk2PqZkgmbwPbdzJ3KmtjgQ,138
90
92
  omdev/cli/_pathhack.py,sha256=kxqb2kHap68Lkh8b211rDbcgj06hidBiAKA3f9posyc,2119
@@ -172,12 +174,12 @@ omdev/pyproject/resources/docker-dev.sh,sha256=DHkz5D18jok_oDolfg2mqrvGRWFoCe9GQ
172
174
  omdev/pyproject/resources/python.sh,sha256=jvrwddYw2KNttpuImLbdCdJK0HsUNMrHtTnmLvhxQxg,757
173
175
  omdev/scripts/__init__.py,sha256=MKCvUAEQwsIvwLixwtPlpBqmkMXLCnjjXyAXvVpDwVk,91
174
176
  omdev/scripts/bumpversion.py,sha256=Kn7fo73Hs8uJh3Hi3EIyLOlzLPWAC6dwuD_lZ3cIzuY,1064
175
- omdev/scripts/ci.py,sha256=g3jY4hHJaYu9cWnJJgk56YYGw_9USgPRY_45IQHFx-4,102884
177
+ omdev/scripts/ci.py,sha256=yDx6VsztaY1VqYWF1i9Ywt2YTIseSc5wYtdvtmh5qyI,108870
176
178
  omdev/scripts/execrss.py,sha256=mR0G0wERBYtQmVIn63lCIIFb5zkCM6X_XOENDFYDBKc,651
177
179
  omdev/scripts/exectime.py,sha256=sFb376GflU6s9gNX-2-we8hgH6w5MuQNS9g6i4SqJIo,610
178
180
  omdev/scripts/importtrace.py,sha256=oa7CtcWJVMNDbyIEiRHej6ICfABfErMeo4_haIqe18Q,14041
179
181
  omdev/scripts/interp.py,sha256=7NrLbOkiDjBldnzpf-EpL8UTmU6U3lakvHqhSlY3X_U,141851
180
- omdev/scripts/pyproject.py,sha256=GaA3zZ6kRGbGl9tdpJCsJMGEEj3ltTGt8kprWieMQ98,243677
182
+ omdev/scripts/pyproject.py,sha256=HDors8tvpSgCUzESwQ2E-Gx5jLisaYoOApOTCgmQ5P0,245595
181
183
  omdev/scripts/slowcat.py,sha256=lssv4yrgJHiWfOiHkUut2p8E8Tq32zB-ujXESQxFFHY,2728
182
184
  omdev/scripts/tmpexec.py,sha256=WTYcf56Tj2qjYV14AWmV8SfT0u6Y8eIU6cKgQRvEK3c,1442
183
185
  omdev/tokens/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -187,7 +189,7 @@ omdev/tokens/utils.py,sha256=DJA2jsDzrtQxnO0bdkUk1-GmenX4ECugdhl1xOBe7QI,1448
187
189
  omdev/tools/__init__.py,sha256=iVJAOQ0viGTQOm0DLX4uZLro-9jOioYJGLg9s0kDx1A,78
188
190
  omdev/tools/cloc.py,sha256=jYlMHBae9oGKN4VKeBGuqjiQNcM2be7KIoTF0oNwx_I,5205
189
191
  omdev/tools/doc.py,sha256=wvgGhv6aFaV-Zl-Qivejx37i-lKQ207rZ-4K2fPf-Ss,2547
190
- omdev/tools/docker.py,sha256=KVFckA8eAdiapFUr8xkfMw9Uv3Qy4oNq0e70Lqt1F7I,7352
192
+ omdev/tools/docker.py,sha256=mRd5ziNOnJSJ__9MlldASIF6bBD7m48fDKCD1VEUNUw,7633
191
193
  omdev/tools/git.py,sha256=fiQc4w2w63PELLLyMXdwpmgpzFzs7UNn35vewWckScM,7514
192
194
  omdev/tools/importscan.py,sha256=nhJIhtjDY6eFVlReP7fegvv6L5ZjN-Z2VeyhsBonev4,4639
193
195
  omdev/tools/linehisto.py,sha256=0ZNm34EuiZBE9Q2YC6KNLNNydNT8QPSOwvYzXiU9S2Q,8881
@@ -209,9 +211,9 @@ omdev/tools/json/rendering.py,sha256=tMcjOW5edfozcMSTxxvF7WVTsbYLoe9bCKFh50qyaGw
209
211
  omdev/tools/pawk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
210
212
  omdev/tools/pawk/__main__.py,sha256=VCqeRVnqT1RPEoIrqHFSu4PXVMg4YEgF4qCQm90-eRI,66
211
213
  omdev/tools/pawk/pawk.py,sha256=zsEkfQX0jF5bn712uqPAyBSdJt2dno1LH2oeSMNfXQI,11424
212
- omdev-0.0.0.dev213.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
213
- omdev-0.0.0.dev213.dist-info/METADATA,sha256=9a3ViiPq2bMjH4oIJbymsj81T6dJuGB4ZAjgWVSdNDs,1638
214
- omdev-0.0.0.dev213.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
215
- omdev-0.0.0.dev213.dist-info/entry_points.txt,sha256=dHLXFmq5D9B8qUyhRtFqTGWGxlbx3t5ejedjrnXNYLU,33
216
- omdev-0.0.0.dev213.dist-info/top_level.txt,sha256=1nr7j30fEWgLYHW3lGR9pkdHkb7knv1U1ES1XRNVQ6k,6
217
- omdev-0.0.0.dev213.dist-info/RECORD,,
214
+ omdev-0.0.0.dev215.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
215
+ omdev-0.0.0.dev215.dist-info/METADATA,sha256=oNR4sVjlhZ4v-B5bp8h4XPFlDnI8aniDWCUq9WLk-ZM,1638
216
+ omdev-0.0.0.dev215.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
217
+ omdev-0.0.0.dev215.dist-info/entry_points.txt,sha256=dHLXFmq5D9B8qUyhRtFqTGWGxlbx3t5ejedjrnXNYLU,33
218
+ omdev-0.0.0.dev215.dist-info/top_level.txt,sha256=1nr7j30fEWgLYHW3lGR9pkdHkb7knv1U1ES1XRNVQ6k,6
219
+ omdev-0.0.0.dev215.dist-info/RECORD,,
omdev/ci/github/curl.py DELETED
@@ -1,209 +0,0 @@
1
- # ruff: noqa: UP006 UP007
2
- # @omlish-lite
3
- import dataclasses as dc
4
- import json
5
- import os
6
- import shlex
7
- import typing as ta
8
-
9
- from omlish.lite.check import check
10
- from omlish.lite.contextmanagers import defer
11
- from omlish.lite.json import json_dumps_compact
12
- from omlish.subprocesses import subprocesses
13
-
14
- from ..shell import ShellCmd
15
- from ..utils import make_temp_file
16
-
17
-
18
- ##
19
-
20
-
21
- class GithubServiceCurlClient:
22
- def __init__(
23
- self,
24
- service_url: str,
25
- auth_token: ta.Optional[str] = None,
26
- *,
27
- api_version: ta.Optional[str] = None,
28
- ) -> None:
29
- super().__init__()
30
-
31
- self._service_url = check.non_empty_str(service_url)
32
- self._auth_token = auth_token
33
- self._api_version = api_version
34
-
35
- #
36
-
37
- _MISSING = object()
38
-
39
- def build_headers(
40
- self,
41
- headers: ta.Optional[ta.Mapping[str, str]] = None,
42
- *,
43
- auth_token: ta.Any = _MISSING,
44
- content_type: ta.Optional[str] = None,
45
- ) -> ta.Dict[str, str]:
46
- dct = {
47
- 'Accept': ';'.join([
48
- 'application/json',
49
- *([f'api-version={self._api_version}'] if self._api_version else []),
50
- ]),
51
- }
52
-
53
- if auth_token is self._MISSING:
54
- auth_token = self._auth_token
55
- if auth_token:
56
- dct['Authorization'] = f'Bearer {auth_token}'
57
-
58
- if content_type is not None:
59
- dct['Content-Type'] = content_type
60
-
61
- if headers:
62
- dct.update(headers)
63
-
64
- return dct
65
-
66
- #
67
-
68
- HEADER_AUTH_TOKEN_ENV_KEY_PREFIX = '_GITHUB_SERVICE_AUTH_TOKEN' # noqa
69
-
70
- @property
71
- def header_auth_token_env_key(self) -> str:
72
- return f'{self.HEADER_AUTH_TOKEN_ENV_KEY_PREFIX}_{id(self)}'
73
-
74
- def build_cmd(
75
- self,
76
- method: str,
77
- url: str,
78
- *,
79
- json_content: bool = False,
80
- content_type: ta.Optional[str] = None,
81
- headers: ta.Optional[ta.Dict[str, str]] = None,
82
- ) -> ShellCmd:
83
- if content_type is None and json_content:
84
- content_type = 'application/json'
85
-
86
- env = {}
87
-
88
- header_auth_token: ta.Optional[str]
89
- if self._auth_token:
90
- header_env_key = self.header_auth_token_env_key
91
- env[header_env_key] = self._auth_token
92
- header_auth_token = f'${header_env_key}'
93
- else:
94
- header_auth_token = None
95
-
96
- built_hdrs = self.build_headers(
97
- headers,
98
- auth_token=header_auth_token,
99
- content_type=content_type,
100
- )
101
-
102
- url = f'{self._service_url}/{url}'
103
-
104
- cmd = ' '.join([
105
- 'curl',
106
- '-s',
107
- '-X', method,
108
- url,
109
- *[f'-H "{k}: {v}"' for k, v in built_hdrs.items()],
110
- ])
111
-
112
- return ShellCmd(
113
- cmd,
114
- env=env,
115
- )
116
-
117
- def build_post_json_cmd(
118
- self,
119
- url: str,
120
- obj: ta.Any,
121
- **kwargs: ta.Any,
122
- ) -> ShellCmd:
123
- curl_cmd = self.build_cmd(
124
- 'POST',
125
- url,
126
- json_content=True,
127
- **kwargs,
128
- )
129
-
130
- obj_json = json_dumps_compact(obj)
131
-
132
- return dc.replace(curl_cmd, s=f'{curl_cmd.s} -d {shlex.quote(obj_json)}')
133
-
134
- #
135
-
136
- @dc.dataclass()
137
- class Error(RuntimeError):
138
- status_code: int
139
- body: ta.Optional[bytes]
140
-
141
- def __str__(self) -> str:
142
- return repr(self)
143
-
144
- @dc.dataclass(frozen=True)
145
- class Result:
146
- status_code: int
147
- body: ta.Optional[bytes]
148
-
149
- def as_error(self) -> 'GithubServiceCurlClient.Error':
150
- return GithubServiceCurlClient.Error(
151
- status_code=self.status_code,
152
- body=self.body,
153
- )
154
-
155
- def run_cmd(
156
- self,
157
- cmd: ShellCmd,
158
- *,
159
- raise_: bool = False,
160
- **subprocess_kwargs: ta.Any,
161
- ) -> Result:
162
- out_file = make_temp_file()
163
- with defer(lambda: os.unlink(out_file)):
164
- run_cmd = dc.replace(cmd, s=f"{cmd.s} -o {out_file} -w '%{{json}}'")
165
-
166
- out_json_bytes = run_cmd.run(
167
- subprocesses.check_output,
168
- **subprocess_kwargs,
169
- )
170
-
171
- out_json = json.loads(out_json_bytes.decode())
172
- status_code = check.isinstance(out_json['response_code'], int)
173
-
174
- with open(out_file, 'rb') as f:
175
- body = f.read()
176
-
177
- result = self.Result(
178
- status_code=status_code,
179
- body=body,
180
- )
181
-
182
- if raise_ and (500 <= status_code <= 600):
183
- raise result.as_error()
184
-
185
- return result
186
-
187
- def run_json_cmd(
188
- self,
189
- cmd: ShellCmd,
190
- *,
191
- success_status_codes: ta.Optional[ta.Container[int]] = None,
192
- ) -> ta.Optional[ta.Any]:
193
- result = self.run_cmd(cmd, raise_=True)
194
-
195
- if success_status_codes is not None:
196
- is_success = result.status_code in success_status_codes
197
- else:
198
- is_success = 200 <= result.status_code < 300
199
-
200
- if is_success:
201
- if not (body := result.body):
202
- return None
203
- return json.loads(body.decode('utf-8-sig'))
204
-
205
- elif result.status_code == 404:
206
- return None
207
-
208
- else:
209
- raise result.as_error()