Skip to content

Commit e215cb1

Browse files
committed
Merge branch 'morosi-types' into 'master'
Add missing types in e3.aws.cfn/ec2 See merge request it/e3-aws!61
2 parents 134a50c + ae035fa commit e215cb1

File tree

14 files changed

+799
-801
lines changed

14 files changed

+799
-801
lines changed

src/e3/aws/cfn/__init__.py

Lines changed: 48 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ def client(name: str) -> Callable:
2828
:type name: str
2929
"""
3030

31-
def decorator(func):
32-
def wrapper(*args, **kwargs):
31+
def decorator(func: Callable) -> Callable:
32+
def wrapper(*args: Any, **kwargs: Any) -> Callable:
3333
aws_env = Env().aws_env
3434
if "region" in kwargs:
3535
region = kwargs["region"]
@@ -80,13 +80,11 @@ class AWSType(Enum):
8080
class GetAtt(object):
8181
"""Intrinsic function Fn::Getatt."""
8282

83-
def __init__(self, name, attribute):
83+
def __init__(self, name: str, attribute: str) -> None:
8484
"""Initialize a Getatt instance.
8585
8686
:param name: resource name
87-
:type name: str
8887
:param attribute: attribute name
89-
:type attribute: str
9088
"""
9189
self.name = name
9290
self.attribute = attribute
@@ -95,37 +93,33 @@ def __init__(self, name, attribute):
9593
class Ref(object):
9694
"""Intrinsic function Fn::Ref."""
9795

98-
def __init__(self, name):
96+
def __init__(self, name: str) -> None:
9997
"""Initialize a reference.
10098
10199
:param name: resource name
102-
:type name: str
103100
"""
104101
self.name = name
105102

106103

107104
class Base64(object):
108105
"""Intrinsic function Fn::Base64."""
109106

110-
def __init__(self, content):
107+
def __init__(self, content: str | Sub) -> None:
111108
"""Initialize a base64 content.
112109
113110
:param content: content to be encoded into base64
114-
:type content: str
115111
"""
116112
self.content = content
117113

118114

119115
class Join(object):
120116
"""Intrinsic function Fn::Join."""
121117

122-
def __init__(self, content, delimiter=""):
118+
def __init__(self, content: list[Any], delimiter: str = "") -> None:
123119
"""Initialize a Join object.
124120
125121
:param content: a list
126-
:type content: list
127122
:param delimiter: a join delimiter
128-
:type delimiter: str
129123
"""
130124
self.content = content
131125
self.delimiter = delimiter
@@ -134,49 +128,46 @@ def __init__(self, content, delimiter=""):
134128
class Sub(object):
135129
"""Intrinsic function Fn::Sub."""
136130

137-
def __init__(self, content, variables=None):
131+
def __init__(self, content: str, variables: dict[str, str] | None = None) -> None:
138132
"""Initialize a Sub object.
139133
140134
:param content: a string
141-
:type content: str
142135
:param variables: a dict asssociating a key to a value
143-
:type variables: dict(str, str)
144136
"""
145137
self.content = content
146-
if variables:
147-
self.variables = dict(variables)
148-
else:
149-
self.variables = None
138+
self.variables = dict(variables) if variables else None
150139

151140

152141
# Declare Yaml representer for intrinsic functions
153142

154143

155-
def getatt_representer(dumper, data):
144+
def getatt_representer(dumper: CFNYamlDumper, data: Any) -> yaml.ScalarNode:
156145
return dumper.represent_scalar("!GetAtt", "%s.%s" % (data.name, data.attribute))
157146

158147

159-
def ref_representer(dumper, data):
148+
def ref_representer(dumper: CFNYamlDumper, data: Any) -> yaml.ScalarNode:
160149
return dumper.represent_scalar("!Ref", data.name)
161150

162151

163-
def base64_representer(dumper, data):
152+
def base64_representer(dumper: CFNYamlDumper, data: Any) -> yaml.MappingNode:
164153
return dumper.represent_dict({"Fn::Base64": data.content})
165154

166155

167-
def sub_representer(dumper, data):
156+
def sub_representer(
157+
dumper: CFNYamlDumper, data: Any
158+
) -> yaml.SequenceNode | yaml.ScalarNode:
168159
if data.variables:
169160
return dumper.represent_sequence("!Sub", [data.content, data.variables])
170161
else:
171162
return dumper.represent_scalar("!Sub", data.content)
172163

173164

174-
def join_representer(dumper, data):
165+
def join_representer(dumper: CFNYamlDumper, data: Any) -> yaml.SequenceNode:
175166
return dumper.represent_sequence("!Join", [data.delimiter, data.content])
176167

177168

178169
class CFNYamlDumper(yaml.Dumper):
179-
def __init__(self, *args, **kwargs):
170+
def __init__(self, *args: Any, **kwargs: Any) -> None:
180171
"""Yaml dumper for cloud formation templates.
181172
182173
See yaml.Dumper documentation.
@@ -189,7 +180,7 @@ def __init__(self, *args, **kwargs):
189180
self.add_representer(Join, join_representer)
190181
self.add_representer(Sub, sub_representer)
191182

192-
def ignore_aliases(self, data):
183+
def ignore_aliases(self, data: Any) -> bool:
193184
"""Ignore aliases."""
194185
return True
195186

@@ -200,7 +191,7 @@ class Resource:
200191
# List of valid attribute names
201192
ATTRIBUTES: Iterable[str] = ()
202193

203-
def __init__(self, name: str, kind: AWSType):
194+
def __init__(self, name: str, kind: AWSType) -> None:
204195
"""Initialize a resource.
205196
206197
:param name: name of the resource (alphanumeric)
@@ -212,7 +203,7 @@ def __init__(self, name: str, kind: AWSType):
212203
assert name.isalnum(), "resource name should be alphanumeric: found %s" % name
213204
self.name = name
214205
self.kind = kind
215-
self.depends = None
206+
self.depends: str | None = None
216207

217208
# Track region in which the resource is created
218209
e = Env()
@@ -222,34 +213,30 @@ def __init__(self, name: str, kind: AWSType):
222213
self.region = "invalid-region"
223214
self.metadata: dict = {}
224215

225-
def getatt(self, name):
216+
def getatt(self, name: str) -> GetAtt:
226217
"""Return an attribute reference.
227218
228219
:param name: attribute name. should one of the valid attribute
229220
declared in ATTRIBUTES class variable
230-
:type name: str
231221
:return: a getatt object
232-
:rtype: e3.aws.cfn.types.GetAtt
233222
234223
"""
235224
assert name in self.ATTRIBUTES, "invalid attribute %s" % name
236225
return GetAtt(self.name, name)
237226

238227
@property
239-
def ref(self):
228+
def ref(self) -> Ref:
240229
"""Return a reference to the current resource.
241230
242231
:return: a reference
243-
:rtype: e3.aws.cfn.types.Ref
244232
"""
245233
return Ref(self.name)
246234

247235
@property
248-
def properties(self):
236+
def properties(self) -> dict[str, Any]:
249237
"""Return the resource properties dict.
250238
251239
:return: the resources Properties key value for the current resource.
252-
:rtype: dict
253240
"""
254241
return {}
255242

@@ -477,23 +464,21 @@ def add(self, element: Stack | Resource) -> Stack:
477464
self.resources[element.name] = element
478465
return self
479466

480-
def __iadd__(self, element):
467+
def __iadd__(self, element: Stack | Resource) -> Stack:
481468
"""Add a resource or merge a stack.
482469
483470
:param element: if a resource add the resource to the stack. If a stack
484471
merge its resources into the current stack.
485-
:type element: Stack | Resources
486472
:return: the current stack
487-
:rtype: Stack
488473
"""
489474
return self.add(element)
490475

491-
def __getitem__(self, key):
476+
def __getitem__(self, key: str) -> Resource | Stack:
492477
if key not in self.resources:
493478
raise KeyError
494479
return self.resources[key]
495480

496-
def __contains__(self, key):
481+
def __contains__(self, key: str) -> bool:
497482
return key in self.resources
498483

499484
def create_data_dir(self, root_dir: str) -> None:
@@ -508,7 +493,6 @@ def export(self) -> dict:
508493
"""Export stack as dict.
509494
510495
:return: a dict that can be serialized as YAML to produce a template
511-
:rtype: dict
512496
"""
513497
resources = {}
514498
for resource in self.resources.values():
@@ -532,7 +516,6 @@ def body(self) -> str:
532516
"""Export stack as a CloudFormation template.
533517
534518
:return: a valid CloudFormation template
535-
:rtype: str
536519
"""
537520
return yaml.dump(self.export(), Dumper=CFNYamlDumper)
538521

@@ -601,50 +584,48 @@ def exists(self) -> bool:
601584
return False
602585

603586
@client("cloudformation")
604-
def state(self, client):
587+
def state(self, client: botocore.client.BaseClient) -> Any:
605588
"""Return state of the stack on AWS."""
606589
result = client.describe_stacks(StackName=self.stack_id)["Stacks"][0]
607590
if self.stack_id != result["StackId"]:
608591
self.stack_id = result["StackId"]
609592
return result
610593

611594
@client("cloudformation")
612-
def validate(self, client, url=None):
595+
def validate(
596+
self, client: botocore.client.BaseClient, url: str | None = None
597+
) -> Any:
613598
"""Validate a template.
614599
615600
:param client: a botocore client
616-
:type client: botocore.client.Client. This parameter is handled by the
617-
decorator
618601
param url: url of the template body in S3. When not None this suppose
619602
the user has uploaded the template body on S3 first at the given
620603
url. Use S3 to refer to the template body rather than using inline
621604
version allows to use template of size up to 500Ko instead of
622605
50Ko.
623-
:type url: str | None
624606
"""
625607
if url is None:
626608
return client.validate_template(TemplateBody=self.body)
627609
else:
628610
return client.validate_template(TemplateURL=url)
629611

630612
@client("cloudformation")
631-
def create_change_set(self, name, client, url=None):
613+
def create_change_set(
614+
self, name: str, client: botocore.client.BaseClient, url: str | None = None
615+
) -> Any:
632616
"""Create a change set.
633617
634618
This creates a difference between the state of the stack on AWS servers
635619
and the current one generated with e3-aws.
636620
637621
:param client: a botocore client. This parameter is handled by the
638622
decorator
639-
:type client: botocore.client.Client
640623
:param name: name of the changeset
641-
:type name: str
642624
:param url: url of the template body in S3. When not None this suppose
643625
the user has uploaded the template body on S3 first at the given
644626
url. Use S3 to refer to the template body rather than using inline
645627
version allows to use template of size up to 500Ko instead of
646628
50Ko.
647-
:type url: str | None
648629
"""
649630
parameters = {
650631
"ChangeSetName": name,
@@ -667,20 +648,19 @@ def create_change_set(self, name, client, url=None):
667648
)
668649

669650
@client("cloudformation")
670-
def describe_change_set(self, name, client):
651+
def describe_change_set(self, name: str, client: botocore.client.BaseClient) -> Any:
671652
"""Describe a change set.
672653
673654
Retrieve status of a given changeset
674655
675656
:param client: a botocore client
676-
:type client: botocore.client.Client
677657
:param name: name of the changeset
678658
:type name: str
679659
"""
680660
return client.describe_change_set(ChangeSetName=name, StackName=self.name)
681661

682662
@client("cloudformation")
683-
def delete_change_set(self, name, client):
663+
def delete_change_set(self, name: str, client: botocore.client.BaseClient) -> Any:
684664
"""Delete a change set.
685665
686666
:param client: a botocore client
@@ -755,24 +735,25 @@ def events(
755735
yield event
756736

757737
@client("cloudformation")
758-
def cost(self, client):
738+
def cost(self, client: botocore.client.BaseClient) -> Any:
759739
"""Compute cost of the stack (estimation).
760740
761741
:param client: a botocore client
762-
:type client: botocore.client.BaseClient
763742
"""
764743
return client.estimate_template_cost(TemplateBody=self.body)
765744

766745
@client("cloudformation")
767-
def execute_change_set(self, client, changeset_name, wait=False):
746+
def execute_change_set(
747+
self,
748+
client: botocore.client.BaseClient,
749+
changeset_name: str,
750+
wait: bool = False,
751+
) -> Any:
768752
"""Execute a changeset.
769753
770754
:param client: a botocore client
771-
:type client: botocore.client.BaseClient
772755
:param changeset_name: name of the changeset to apply
773-
:type changeset_name: str
774756
:param wait: whether to wait for the completion of the command
775-
:type wait: bool
776757
"""
777758
client.execute_change_set(
778759
ChangeSetName=changeset_name,
@@ -785,19 +766,18 @@ def execute_change_set(self, client, changeset_name, wait=False):
785766
logging.info(f"Done (status: {self.wait()})")
786767

787768
@client("cloudformation")
788-
def resource_status(self, client, in_progress_only=True):
769+
def resource_status(
770+
self, client: botocore.client.BaseClient, in_progress_only: bool = True
771+
) -> Any:
789772
"""Return status of each resources of the stack.
790773
791774
The state of the stack taken is the one pushed on AWS (after a call
792775
to create for example).
793776
794777
:param client: a botocore client
795-
:type client: botocore.client.BaseClient
796778
:param in_progress_only: if True return only resources that are in
797779
one of the "PROGRESS" state (deletion, creation, ...)
798-
:type in_progress_only: bool
799780
:return: a dict associating a resource logical name to a status name
800-
:rtype: dict
801781
"""
802782
aws_result = client.describe_stack_resources(StackName=self.name)
803783
assert "StackResources" in aws_result
@@ -808,7 +788,7 @@ def resource_status(self, client, in_progress_only=True):
808788
return result
809789

810790
@client("cloudformation")
811-
def enable_termination_protection(self, client):
791+
def enable_termination_protection(self, client: botocore.client.BaseClient) -> Any:
812792
"""Enable termination protection for a stack."""
813793
aws_result = self.state()
814794
if aws_result["EnableTerminationProtection"]:
@@ -822,11 +802,12 @@ def enable_termination_protection(self, client):
822802
print("Stack termination protection enabled")
823803

824804
@client("cloudformation")
825-
def set_stack_policy(self, stack_policy_body, client):
805+
def set_stack_policy(
806+
self, stack_policy_body: str, client: botocore.client.BaseClient
807+
) -> Any:
826808
"""Set a stack policy.
827809
828810
:param stack_policy_body: stack policy body to apply
829-
:type stack_policy_body: str
830811
"""
831812
aws_result = client.get_stack_policy(StackName=self.name)
832813

0 commit comments

Comments
 (0)