ominfra 0.0.0.dev205__py3-none-any.whl → 0.0.0.dev207__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
File without changes
@@ -0,0 +1,4 @@
1
+ if __name__ == '__main__':
2
+ from .cli import _main # noqa
3
+
4
+ _main()
@@ -0,0 +1,12 @@
1
+ import gzip
2
+ import typing as ta
3
+
4
+ from omlish import lang
5
+ from omlish.formats import json
6
+
7
+
8
+ @lang.cached_function()
9
+ def load_instance_types() -> ta.Mapping[str, ta.Mapping[str, ta.Any]]:
10
+ raw = lang.get_relative_resources(globals=globals())['cache.json.gz'].read_bytes()
11
+ data = gzip.decompress(raw)
12
+ return json.loads(data)
@@ -0,0 +1,80 @@
1
+ import datetime
2
+ import gzip
3
+ import os.path
4
+ import typing as ta
5
+
6
+ from omdev.secrets import load_secrets
7
+ from omlish import lang
8
+ from omlish import secrets as sec
9
+ from omlish.argparse import all as ap
10
+ from omlish.formats import json
11
+
12
+ from .cache import load_instance_types
13
+
14
+
15
+ if ta.TYPE_CHECKING:
16
+ import boto3
17
+ else:
18
+ boto3 = lang.proxy_import('boto3')
19
+
20
+
21
+ # Use a hardcoded gz mtime to prevent the gz file from changing when the contents don't. We still have the git metadata
22
+ # to track modifications.
23
+ FIXED_CACHE_TIMESTAMP = datetime.datetime(2025, 1, 1, tzinfo=datetime.UTC).timestamp()
24
+
25
+
26
+ @lang.cached_function
27
+ def _get_secrets() -> sec.Secrets:
28
+ return load_secrets()
29
+
30
+
31
+ def get_ec2_instance_types(session: boto3.Session) -> dict[str, dict[str, ta.Any]]:
32
+ ec2 = session.client('ec2')
33
+ next_token = None
34
+ dct = {}
35
+ while True:
36
+ resp = ec2.describe_instance_types(**(dict(NextToken=next_token) if next_token else {}))
37
+ for instance_type in resp['InstanceTypes']:
38
+ name = instance_type['InstanceType']
39
+ dct[name] = instance_type
40
+ next_token = resp.get('NextToken')
41
+ if not next_token:
42
+ break
43
+ dct = dict(sorted(dct.items(), key=lambda t: t[0]))
44
+ return dct
45
+
46
+
47
+ class Cli(ap.Cli):
48
+ @ap.cmd()
49
+ def fetch(self) -> None:
50
+ cfg = _get_secrets()
51
+
52
+ session = boto3.Session(
53
+ aws_access_key_id=cfg.get('aws_access_key_id').reveal(),
54
+ aws_secret_access_key=cfg.get('aws_secret_access_key').reveal(),
55
+ region_name=cfg.get('aws_region').reveal(),
56
+ )
57
+
58
+ instance_types = get_ec2_instance_types(session)
59
+
60
+ cache_file = os.path.join(os.path.dirname(__file__), 'cache.json.gz')
61
+ with open(cache_file, 'wb') as f:
62
+ with gzip.GzipFile(
63
+ fileobj=f,
64
+ mode='w',
65
+ mtime=FIXED_CACHE_TIMESTAMP,
66
+ ) as gf:
67
+ gf.write(json.dumps_compact(instance_types).encode('utf-8'))
68
+
69
+ @ap.cmd()
70
+ def dump(self) -> None:
71
+ dct = load_instance_types()
72
+ print(json.dumps_pretty(dct))
73
+
74
+
75
+ def _main() -> None:
76
+ Cli()()
77
+
78
+
79
+ if __name__ == '__main__':
80
+ _main()
@@ -1,7 +1,9 @@
1
- import dataclasses as dc
2
1
  import typing as ta
3
2
 
3
+ from omlish import cached
4
4
  from omlish import check
5
+ from omlish import collections as col
6
+ from omlish import dataclasses as dc
5
7
  from omlish import lang
6
8
 
7
9
 
@@ -21,17 +23,10 @@ class TagList:
21
23
  ##
22
24
 
23
25
 
24
- class MEMBER_NAME(lang.Marker): # noqa
25
- pass
26
-
27
-
28
26
  class SHAPE_NAME(lang.Marker): # noqa
29
27
  pass
30
28
 
31
29
 
32
- ##
33
-
34
-
35
30
  def common_metadata(
36
31
  *,
37
32
  shape_name: str | None = None,
@@ -55,9 +50,58 @@ def shape_metadata(
55
50
  return md
56
51
 
57
52
 
53
+ class ShapeInfo:
54
+ def __init__(
55
+ self,
56
+ cls: type['Shape'],
57
+ metadata: ta.Mapping[ta.Any, ta.Any],
58
+ ) -> None:
59
+ super().__init__()
60
+
61
+ self._cls = check.issubclass(cls, Shape)
62
+ self._metadata = metadata
63
+
64
+ @property
65
+ def cls(self) -> type['Shape']:
66
+ return self._cls
67
+
68
+ @property
69
+ def metadata(self) -> ta.Mapping[ta.Any, ta.Any]:
70
+ return self._metadata
71
+
72
+ #
73
+
74
+ @cached.function
75
+ def fields(self) -> ta.Sequence[dc.Field]:
76
+ check.state(dc.is_immediate_dataclass(self._cls))
77
+ fls = dc.fields(self._cls)
78
+ return fls # noqa
79
+
80
+ @cached.function
81
+ def fields_by_name(self) -> ta.Mapping[str, dc.Field]:
82
+ return col.make_map_by(lambda fl: fl.name, self.fields(), strict=True)
83
+
84
+ @cached.function
85
+ def fields_by_member_name(self) -> ta.Mapping[str, dc.Field]:
86
+ return col.make_map(
87
+ [(n, f) for f in self.fields() if (n := f.metadata.get(MEMBER_NAME)) is not None],
88
+ strict=True,
89
+ )
90
+
91
+ @cached.function
92
+ def fields_by_serialization_name(self) -> ta.Mapping[str, dc.Field]:
93
+ l = []
94
+ for f in self.fields():
95
+ if sn := f.metadata.get(SERIALIZATION_NAME):
96
+ l.append((sn, f))
97
+ elif mn := f.metadata.get(MEMBER_NAME):
98
+ l.append((mn, f))
99
+ return col.make_map(l, strict=True)
100
+
101
+
58
102
  @dc.dataclass(frozen=True)
59
103
  class Shape:
60
- __shape_metadata__: ta.ClassVar[ta.Mapping[ta.Any, ta.Any]]
104
+ __shape__: ShapeInfo
61
105
 
62
106
  def __init_subclass__(
63
107
  cls,
@@ -67,23 +111,39 @@ class Shape:
67
111
  ) -> None:
68
112
  super().__init_subclass__(**kwargs)
69
113
 
70
- check.state(not hasattr(cls, '__shape_metadata__'))
114
+ check.state(not hasattr(cls, '__shape__'))
71
115
 
72
- cls.__shape_metadata__ = shape_metadata(**kwargs)
116
+ info = ShapeInfo(
117
+ cls,
118
+ shape_metadata(**kwargs),
119
+ )
120
+
121
+ cls.__shape__ = info
73
122
 
74
123
 
75
124
  ##
76
125
 
77
126
 
127
+ class MEMBER_NAME(lang.Marker): # noqa
128
+ pass
129
+
130
+
131
+ class SERIALIZATION_NAME(lang.Marker): # noqa
132
+ pass
133
+
134
+
78
135
  def field_metadata(
79
136
  *,
80
137
  member_name: str | None = None,
138
+ serialization_name: str | None = None,
81
139
  **kwargs: ta.Any,
82
140
  ) -> dict[ta.Any, ta.Any]:
83
141
  md = {**common_metadata(**kwargs)}
84
142
 
85
143
  if member_name is not None:
86
144
  md[MEMBER_NAME] = member_name
145
+ if serialization_name is not None:
146
+ md[SERIALIZATION_NAME] = serialization_name
87
147
 
88
148
  return md
89
149
 
@@ -156,6 +156,7 @@ class ModelGen:
156
156
  'Boolean': 'bool',
157
157
 
158
158
  'Integer': 'int',
159
+ 'Long': 'int',
159
160
 
160
161
  'String': 'str',
161
162
 
@@ -317,8 +318,10 @@ class ModelGen:
317
318
  fn = self.demangle_name(mn)
318
319
  mds = [
319
320
  f'member_name={mn!r}',
320
- f'shape_name={ms.name!r}',
321
321
  ]
322
+ if msn := ms.serialization.get('name'):
323
+ mds.append(f'serialization_name={msn!r}')
324
+ mds.append(f'shape_name={ms.name!r}')
322
325
  ma = self.get_type_ann(
323
326
  ms.name,
324
327
  unquoted_names=unquoted_names,
@@ -508,3 +511,7 @@ class ModelGen:
508
511
  self.gen_all_operations(out)
509
512
 
510
513
  return out.getvalue()
514
+
515
+
516
+ if __name__ == '__main__':
517
+ raise RuntimeError('Use cli')