ominfra 0.0.0.dev200__py3-none-any.whl → 0.0.0.dev202__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.
@@ -1,4 +1,5 @@
1
1
  import dataclasses as dc
2
+ import keyword
2
3
  import os.path
3
4
  import sys
4
5
  import typing as ta
@@ -78,7 +79,10 @@ class Cli(ap.Cli):
78
79
  operation_names=svc.operations,
79
80
  )
80
81
 
81
- output_file = os.path.join(output_dir, f'{svc.name}.py')
82
+ fn = svc.name
83
+ if fn in keyword.kwlist:
84
+ fn += '_'
85
+ output_file = os.path.join(output_dir, f'{fn}.py')
82
86
  with open(output_file, 'w') as f:
83
87
  f.write(mod)
84
88
 
@@ -105,6 +109,11 @@ class Cli(ap.Cli):
105
109
 
106
110
  #
107
111
 
112
+ @ap.cmd()
113
+ def list_services(self) -> None:
114
+ for name in sorted(ModelGen.list_available_services()):
115
+ print(name)
116
+
108
117
  @ap.cmd(
109
118
  ap.arg('service'),
110
119
  )
@@ -3,6 +3,7 @@ TODO:
3
3
  - default values? nullability? maybe a new_default helper?
4
4
  - relative import base
5
5
  """
6
+ import builtins
6
7
  import dataclasses as dc
7
8
  import io
8
9
  import typing as ta
@@ -13,10 +14,12 @@ from omlish import lang
13
14
 
14
15
 
15
16
  if ta.TYPE_CHECKING:
17
+ import botocore.loaders
16
18
  import botocore.model
17
19
  import botocore.session
18
20
  else:
19
21
  botocore = lang.proxy_import('botocore', extras=[
22
+ 'loaders',
20
23
  'model',
21
24
  'session',
22
25
  ])
@@ -25,6 +28,13 @@ else:
25
28
  ##
26
29
 
27
30
 
31
+ ServiceTypeName: ta.TypeAlias = ta.Literal[
32
+ 'service-2',
33
+ 'paginators-1',
34
+ 'waiters-2',
35
+ ]
36
+
37
+
28
38
  class ModelGen:
29
39
  def __init__(
30
40
  self,
@@ -53,16 +63,29 @@ class ModelGen:
53
63
 
54
64
  #
55
65
 
66
+ @classmethod
67
+ def create_data_loader(cls) -> 'botocore.loaders.Loader':
68
+ session = botocore.session.get_session()
69
+ return session.get_component('data_loader')
70
+
71
+ @classmethod
72
+ def list_available_services(
73
+ cls,
74
+ *,
75
+ type_name: ServiceTypeName = 'service-2',
76
+ ) -> list[str]:
77
+ loader = cls.create_data_loader()
78
+ return list(loader.list_available_services(type_name))
79
+
56
80
  @classmethod
57
81
  def load_service_model(
58
82
  cls,
59
83
  service_name: str,
60
84
  *,
61
- type_name: ta.Literal['service-2', 'paginators-1', 'waiters-2'] = 'service-2',
85
+ type_name: ServiceTypeName = 'service-2',
62
86
  api_version: str | None = None,
63
87
  ) -> 'botocore.model.ServiceModel':
64
- session = botocore.session.get_session()
65
- loader = session.get_component('data_loader')
88
+ loader = cls.create_data_loader()
66
89
  json_model = loader.load_service_model(service_name, type_name, api_version=api_version)
67
90
  return botocore.model.ServiceModel(json_model, service_name=service_name)
68
91
 
@@ -137,6 +160,7 @@ class ModelGen:
137
160
  pass
138
161
 
139
162
  if name in self._shape_names:
163
+ name = self.sanitize_class_name(name)
140
164
  if not unquoted_names:
141
165
  return f"'{name}'"
142
166
  else:
@@ -150,44 +174,69 @@ class ModelGen:
150
174
  'AAAA',
151
175
  'ACL',
152
176
  'ACP',
177
+ 'AES',
178
+ 'AES256',
179
+ 'AZ',
180
+ 'CA',
153
181
  'CRC32',
154
182
  'CRC32C',
183
+ 'DB',
184
+ 'EFS',
155
185
  'ETag',
186
+ 'IAM',
187
+ 'IO',
188
+ 'IP',
189
+ 'JSON',
156
190
  'KMS',
157
191
  'MD5',
158
192
  'MFA',
159
193
  'SHA1',
160
194
  'SHA256',
161
195
  'SSE',
196
+ 'TTL',
162
197
  ]
163
198
 
164
199
  def demangle_name(self, n: str) -> str:
165
200
  ps: list[str] = []
166
201
  while n:
167
202
  ms: list[tuple[str, int]] = []
203
+
168
204
  for pfx in self.DEMANGLE_PREFIXES:
169
205
  if (i := n.find(pfx)) >= 0:
170
206
  ms.append((pfx, i))
207
+
171
208
  if not ms:
172
209
  ps.append(n)
173
210
  break
211
+
174
212
  if len(ms) > 1:
175
213
  m = sorted(ms, key=lambda t: (t[1], -len(t[0])))[0]
176
214
  else:
177
215
  m = ms[0]
216
+
178
217
  pfx, i = m
179
218
  l, r = n[:i], n[i + len(pfx):]
219
+
180
220
  if l:
181
221
  ps.append(l)
182
222
  ps.append(pfx.lower())
223
+
183
224
  n = r
225
+
184
226
  return '_'.join(lang.snake_case(p) for p in ps)
185
227
 
186
228
  #
187
229
 
230
+ def sanitize_class_name(self, n: str) -> str:
231
+ if hasattr(builtins, n):
232
+ n += '_'
233
+ return n
234
+
235
+ #
236
+
188
237
  PREAMBLE_LINES: ta.Sequence[str] = [
189
238
  '# flake8: noqa: E501',
190
- '# ruff: noqa: S105',
239
+ '# ruff: noqa: N801 S105',
191
240
  '# fmt: off',
192
241
  'import dataclasses as _dc # noqa',
193
242
  'import enum as _enum # noqa',
@@ -229,6 +278,8 @@ class ModelGen:
229
278
  ) -> ShapeSrc:
230
279
  shape: botocore.model.Shape = self._service_model.shape_for(name)
231
280
 
281
+ san_name = self.sanitize_class_name(shape.name)
282
+
232
283
  if isinstance(shape, botocore.model.StructureShape):
233
284
  lines: list[str] = []
234
285
 
@@ -238,7 +289,7 @@ class ModelGen:
238
289
 
239
290
  lines.extend([
240
291
  '@_dc.dataclass(frozen=True)',
241
- f'class {shape.name}(',
292
+ f'class {san_name}(',
242
293
  ' _base.Shape,',
243
294
  *[f' {dl},' for dl in mds],
244
295
  '):',
@@ -247,7 +298,9 @@ class ModelGen:
247
298
  if not shape.members:
248
299
  lines.append(' pass')
249
300
 
250
- for mn, ms in shape.members.items():
301
+ for i, (mn, ms) in enumerate(shape.members.items()):
302
+ if i:
303
+ lines.append('')
251
304
  fn = self.demangle_name(mn)
252
305
  mds = [
253
306
  f'member_name={mn!r}',
@@ -268,7 +321,7 @@ class ModelGen:
268
321
 
269
322
  return self.ShapeSrc(
270
323
  '\n'.join(lines),
271
- class_name=shape.name,
324
+ class_name=san_name,
272
325
  double_space=True,
273
326
  )
274
327
 
@@ -278,7 +331,7 @@ class ModelGen:
278
331
  mn,
279
332
  unquoted_names=unquoted_names,
280
333
  )
281
- l = f'{shape.name}: _ta.TypeAlias = _ta.Sequence[{ma or mn}]'
334
+ l = f'{san_name}: _ta.TypeAlias = _ta.Sequence[{ma or mn}]'
282
335
  if ma is None:
283
336
  l = '# ' + l
284
337
  return self.ShapeSrc(l)
@@ -295,7 +348,7 @@ class ModelGen:
295
348
  vn,
296
349
  unquoted_names=unquoted_names,
297
350
  )
298
- l = f'{shape.name}: _ta.TypeAlias = _ta.Mapping[{ka or kn}, {va or vn}]'
351
+ l = f'{san_name}: _ta.TypeAlias = _ta.Mapping[{ka or kn}, {va or vn}]'
299
352
  if ka is None or va is None:
300
353
  l = '# ' + l
301
354
  return self.ShapeSrc(l)
@@ -303,10 +356,14 @@ class ModelGen:
303
356
  elif isinstance(shape, botocore.model.StringShape):
304
357
  if shape.enum:
305
358
  ls = [
306
- f'class {shape.name}(_enum.Enum):',
359
+ f'class {san_name}(_enum.Enum):',
307
360
  ]
361
+ all_caps = all(v == v.upper() for v in shape.enum)
308
362
  for v in shape.enum:
309
- n = v.upper()
363
+ n = v
364
+ if not all_caps:
365
+ n = self.demangle_name(n)
366
+ n = n.upper()
310
367
  for c in '.-:':
311
368
  n = n.replace(c, '_')
312
369
  ls.append(f' {n} = {v!r}')
@@ -316,10 +373,10 @@ class ModelGen:
316
373
  )
317
374
 
318
375
  else:
319
- return self.ShapeSrc(f"{shape.name} = _ta.NewType('{shape.name}', str)")
376
+ return self.ShapeSrc(f"{san_name} = _ta.NewType('{san_name}', str)")
320
377
 
321
378
  elif (pt := self.PRIMITIVE_SHAPE_TYPES.get(shape.type_name)) is not None:
322
- return self.ShapeSrc(f"{shape.name} = _ta.NewType('{shape.name}', {pt})")
379
+ return self.ShapeSrc(f'{san_name} = _ta.NewType({san_name!r}, {pt})')
323
380
 
324
381
  else:
325
382
  raise TypeError(shape.type_name)
@@ -354,7 +411,7 @@ class ModelGen:
354
411
 
355
412
  out.write('\n\n')
356
413
  out.write('ALL_SHAPES: frozenset[type[_base.Shape]] = frozenset([\n')
357
- for n in all_shapes:
414
+ for n in sorted(all_shapes):
358
415
  out.write(f' {n},\n')
359
416
  out.write('])\n')
360
417
 
@@ -384,7 +441,7 @@ class ModelGen:
384
441
 
385
442
  if operation.error_shapes:
386
443
  fls.append('errors=[')
387
- for osn in [es.name for es in operation.error_shapes]:
444
+ for osn in sorted(es.name for es in operation.error_shapes):
388
445
  fls.append(f' {osn},')
389
446
  fls.append('],')
390
447
 
@@ -415,7 +472,7 @@ class ModelGen:
415
472
 
416
473
  out.write('\n')
417
474
  out.write('ALL_OPERATIONS: frozenset[_base.Operation] = frozenset([\n')
418
- for n in all_operations:
475
+ for n in sorted(all_operations):
419
476
  out.write(f' {n},\n')
420
477
  out.write('])\n')
421
478