diff --git a/moto/ec2/exceptions.py b/moto/ec2/exceptions.py index 7358f399b..bd813f581 100644 --- a/moto/ec2/exceptions.py +++ b/moto/ec2/exceptions.py @@ -220,7 +220,7 @@ class InvalidRouteTableIdError(EC2ClientError): class InvalidRouteError(EC2ClientError): - def __init__(self, route_table_id, cidr): + def __init__(self, route_table_id: str, cidr: str): super().__init__( "InvalidRoute.NotFound", f"no route with destination-cidr-block {cidr} in route table {route_table_id}", @@ -228,7 +228,7 @@ class InvalidRouteError(EC2ClientError): class RouteAlreadyExistsError(EC2ClientError): - def __init__(self, cidr): + def __init__(self, cidr: str): super().__init__( "RouteAlreadyExists", f"The route identified by {cidr} already exists" ) @@ -593,7 +593,7 @@ class InvalidCIDRBlockParameterError(EC2ClientError): class InvalidDestinationCIDRBlockParameterError(EC2ClientError): - def __init__(self, cidr_block): + def __init__(self, cidr_block: str): super().__init__( "InvalidParameterValue", f"Value ({cidr_block}) for parameter destinationCidrBlock is invalid. This is not a valid CIDR block.", diff --git a/moto/ec2/models/__init__.py b/moto/ec2/models/__init__.py index 0c2db3a9f..6d6935e53 100644 --- a/moto/ec2/models/__init__.py +++ b/moto/ec2/models/__init__.py @@ -28,7 +28,7 @@ from .instance_types import InstanceTypeBackend, InstanceTypeOfferingBackend from .nat_gateways import NatGatewayBackend from .network_acls import NetworkAclBackend from .availability_zones_and_regions import RegionsAndZonesBackend -from .route_tables import RouteBackend, RouteTableBackend +from .route_tables import RouteBackend from .security_groups import SecurityGroupBackend from .spot_requests import ( SpotRequestBackend, @@ -101,7 +101,6 @@ class EC2Backend( VPNConnectionBackend, VPCServiceConfigurationBackend, VPCPeeringConnectionBackend, - RouteTableBackend, RouteBackend, InternetGatewayBackend, EgressOnlyInternetGatewayBackend, diff --git a/moto/ec2/models/route_tables.py b/moto/ec2/models/route_tables.py index 34e2ed080..852cc2744 100644 --- a/moto/ec2/models/route_tables.py +++ b/moto/ec2/models/route_tables.py @@ -1,6 +1,16 @@ import ipaddress +from typing import Any, Dict, List, Optional, Set from moto.core import CloudFormationModel +from moto.ec2.models.carrier_gateways import CarrierGateway +from moto.ec2.models.elastic_network_interfaces import NetworkInterface +from moto.ec2.models.internet_gateways import EgressOnlyInternetGateway +from moto.ec2.models.instances import Instance +from moto.ec2.models.managed_prefixes import ManagedPrefixList +from moto.ec2.models.nat_gateways import NatGateway +from moto.ec2.models.transit_gateway import TransitGateway +from moto.ec2.models.vpc_peering_connections import VPCPeeringConnection +from moto.ec2.models.vpn_gateway import VpnGateway from .core import TaggedEC2Resource from ..exceptions import ( DependencyViolationError, @@ -16,39 +26,42 @@ from ..utils import ( generic_filter, random_subnet_association_id, random_route_table_id, - split_route_id, ) class RouteTable(TaggedEC2Resource, CloudFormationModel): - def __init__(self, ec2_backend, route_table_id, vpc_id, main=False): + def __init__( + self, ec2_backend: Any, route_table_id: str, vpc_id: str, main: bool = False + ): self.ec2_backend = ec2_backend self.id = route_table_id self.vpc_id = vpc_id - if main: - self.main_association_id = random_subnet_association_id() - else: - self.main_association_id = None - self.associations = {} - self.routes = {} + self.main_association_id = random_subnet_association_id() if main else None + self.associations: Dict[str, str] = {} + self.routes: Dict[str, Route] = {} @property - def owner_id(self): + def owner_id(self) -> str: return self.ec2_backend.account_id @staticmethod - def cloudformation_name_type(): - return None + def cloudformation_name_type() -> str: + return "" @staticmethod - def cloudformation_type(): + def cloudformation_type() -> str: # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-routetable.html return "AWS::EC2::RouteTable" @classmethod - def create_from_cloudformation_json( - cls, resource_name, cloudformation_json, account_id, region_name, **kwargs - ): + def create_from_cloudformation_json( # type: ignore[misc] + cls, + resource_name: str, + cloudformation_json: Any, + account_id: str, + region_name: str, + **kwargs: Any, + ) -> "RouteTable": from ..models import ec2_backends properties = cloudformation_json["Properties"] @@ -59,10 +72,12 @@ class RouteTable(TaggedEC2Resource, CloudFormationModel): return route_table @property - def physical_resource_id(self): + def physical_resource_id(self) -> str: return self.id - def get_filter_value(self, filter_name): + def get_filter_value( + self, filter_name: str, method_name: Optional[str] = None + ) -> Any: if filter_name == "association.main": # Note: Boto only supports 'true'. # https://github.com/boto/boto/issues/1742 @@ -96,7 +111,7 @@ class RouteTable(TaggedEC2Resource, CloudFormationModel): return super().get_filter_value(filter_name, "DescribeRouteTables") @property - def all_associations_ids(self): + def all_associations_ids(self) -> Set[str]: # NOTE(yoctozepto): Doing an explicit copy to not touch the original. all_associations = set(self.associations) if self.main_association_id is not None: @@ -104,16 +119,108 @@ class RouteTable(TaggedEC2Resource, CloudFormationModel): return all_associations -class RouteTableBackend: - def __init__(self): - self.route_tables = {} +class Route(CloudFormationModel): + def __init__( + self, + route_table: RouteTable, + destination_cidr_block: Optional[str], + destination_ipv6_cidr_block: Optional[str], + destination_prefix_list: Optional[ManagedPrefixList] = None, + local: bool = False, + gateway: Optional[VpnGateway] = None, + instance: Optional[Instance] = None, + nat_gateway: Optional[NatGateway] = None, + egress_only_igw: Optional[EgressOnlyInternetGateway] = None, + transit_gateway: Optional[TransitGateway] = None, + interface: Optional[NetworkInterface] = None, + vpc_pcx: Optional[VPCPeeringConnection] = None, + carrier_gateway: Optional[CarrierGateway] = None, + ): + self.id = generate_route_id( + route_table.id, + destination_cidr_block, + destination_ipv6_cidr_block, + destination_prefix_list.id if destination_prefix_list else None, + ) + self.route_table = route_table + self.destination_cidr_block = destination_cidr_block + self.destination_ipv6_cidr_block = destination_ipv6_cidr_block + self.destination_prefix_list = destination_prefix_list + self.local = local + self.gateway = gateway + self.instance = instance + self.nat_gateway = nat_gateway + self.egress_only_igw = egress_only_igw + self.transit_gateway = transit_gateway + self.interface = interface + self.vpc_pcx = vpc_pcx + self.carrier_gateway = carrier_gateway - def create_route_table(self, vpc_id, tags=None, main=False): + @property + def physical_resource_id(self) -> str: + return self.id + + @staticmethod + def cloudformation_name_type() -> str: + return "" + + @staticmethod + def cloudformation_type() -> str: + # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-route.html + return "AWS::EC2::Route" + + @classmethod + def create_from_cloudformation_json( # type: ignore[misc] + cls, + resource_name: str, + cloudformation_json: Any, + account_id: str, + region_name: str, + **kwargs: str, + ) -> "Route": + from ..models import ec2_backends + + properties = cloudformation_json["Properties"] + + gateway_id = properties.get("GatewayId") + instance_id = properties.get("InstanceId") + interface_id = properties.get("NetworkInterfaceId") + nat_gateway_id = properties.get("NatGatewayId") + egress_only_igw_id = properties.get("EgressOnlyInternetGatewayId") + transit_gateway_id = properties.get("TransitGatewayId") + pcx_id = properties.get("VpcPeeringConnectionId") + + route_table_id = properties["RouteTableId"] + ec2_backend = ec2_backends[account_id][region_name] + route = ec2_backend.create_route( + route_table_id=route_table_id, + destination_cidr_block=properties.get("DestinationCidrBlock"), + gateway_id=gateway_id, + instance_id=instance_id, + nat_gateway_id=nat_gateway_id, + egress_only_igw_id=egress_only_igw_id, + transit_gateway_id=transit_gateway_id, + interface_id=interface_id, + vpc_peering_connection_id=pcx_id, + ) + return route + + +class RouteBackend: + def __init__(self) -> None: + self.route_tables: Dict[str, RouteTable] = {} + + def create_route_table( + self, + vpc_id: str, + tags: Optional[List[Dict[str, str]]] = None, + main: bool = False, + ) -> RouteTable: route_table_id = random_route_table_id() - vpc = self.get_vpc(vpc_id) # Validate VPC exists + vpc = self.get_vpc(vpc_id) # type: ignore[attr-defined] # Validate VPC exists route_table = RouteTable(self, route_table_id, vpc_id, main=main) for tag in tags or []: - route_table.add_tag(tag.get("Key"), tag.get("Value")) + route_table.add_tag(tag["Key"], tag["Value"]) self.route_tables[route_table_id] = route_table # creating default routes for ipv4 cirds @@ -133,14 +240,16 @@ class RouteTableBackend: return route_table - def get_route_table(self, route_table_id): + def get_route_table(self, route_table_id: str) -> RouteTable: route_table = self.route_tables.get(route_table_id, None) if not route_table: raise InvalidRouteTableIdError(route_table_id) return route_table - def describe_route_tables(self, route_table_ids=None, filters=None): - route_tables = self.route_tables.copy().values() + def describe_route_tables( + self, route_table_ids: Optional[List[str]] = None, filters: Any = None + ) -> List[RouteTable]: + route_tables = list(self.route_tables.values()) if route_table_ids: route_tables = [ @@ -158,16 +267,20 @@ class RouteTableBackend: return generic_filter(filters, route_tables) - def delete_route_table(self, route_table_id): + def delete_route_table(self, route_table_id: str) -> None: route_table = self.get_route_table(route_table_id) if route_table.associations: raise DependencyViolationError( f"The routeTable '{route_table_id}' has dependencies and cannot be deleted." ) self.route_tables.pop(route_table_id) - return True - def associate_route_table(self, route_table_id, gateway_id=None, subnet_id=None): + def associate_route_table( + self, + route_table_id: str, + gateway_id: Optional[str] = None, + subnet_id: Optional[str] = None, + ) -> str: # Idempotent if association already exists. route_tables_by_subnet = self.describe_route_tables( filters={"association.subnet-id": [subnet_id]} @@ -182,22 +295,24 @@ class RouteTableBackend: # Association does not yet exist, so create it. route_table = self.get_route_table(route_table_id) if gateway_id is None: - self.get_subnet(subnet_id) # Validate subnet exists + self.get_subnet(subnet_id) # type: ignore[attr-defined] # Validate subnet exists association_id = random_subnet_association_id() - route_table.associations[association_id] = subnet_id + route_table.associations[association_id] = subnet_id # type: ignore[assignment] return association_id - if subnet_id is None: + else: association_id = random_subnet_association_id() route_table.associations[association_id] = gateway_id return association_id - def disassociate_route_table(self, association_id): + def disassociate_route_table(self, association_id: str) -> Optional[str]: for route_table in self.route_tables.values(): if association_id in route_table.associations: return route_table.associations.pop(association_id, None) raise InvalidAssociationIdError(association_id) - def replace_route_table_association(self, association_id, route_table_id): + def replace_route_table_association( + self, association_id: str, route_table_id: str + ) -> str: # Idempotent if association already exists. new_route_table = self.get_route_table(route_table_id) if association_id in new_route_table.all_associations_ids: @@ -223,107 +338,22 @@ class RouteTableBackend: new_route_table.associations[new_association_id] = association_target_id return new_association_id - -# TODO: refractor to isloate class methods from backend logic -class Route(CloudFormationModel): - def __init__( - self, - route_table, - destination_cidr_block, - destination_ipv6_cidr_block, - destination_prefix_list=None, - local=False, - gateway=None, - instance=None, - nat_gateway=None, - egress_only_igw=None, - transit_gateway=None, - interface=None, - vpc_pcx=None, - carrier_gateway=None, - ): - self.id = generate_route_id( - route_table.id, - destination_cidr_block, - destination_ipv6_cidr_block, - destination_prefix_list.id if destination_prefix_list else None, - ) - self.route_table = route_table - self.destination_cidr_block = destination_cidr_block - self.destination_ipv6_cidr_block = destination_ipv6_cidr_block - self.destination_prefix_list = destination_prefix_list - self.local = local - self.gateway = gateway - self.instance = instance - self.nat_gateway = nat_gateway - self.egress_only_igw = egress_only_igw - self.transit_gateway = transit_gateway - self.interface = interface - self.vpc_pcx = vpc_pcx - self.carrier_gateway = carrier_gateway - - @property - def physical_resource_id(self): - return self.id - - @staticmethod - def cloudformation_name_type(): - return None - - @staticmethod - def cloudformation_type(): - # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-route.html - return "AWS::EC2::Route" - - @classmethod - def create_from_cloudformation_json( - cls, resource_name, cloudformation_json, account_id, region_name, **kwargs - ): - from ..models import ec2_backends - - properties = cloudformation_json["Properties"] - - gateway_id = properties.get("GatewayId") - instance_id = properties.get("InstanceId") - interface_id = properties.get("NetworkInterfaceId") - nat_gateway_id = properties.get("NatGatewayId") - egress_only_igw_id = properties.get("EgressOnlyInternetGatewayId") - transit_gateway_id = properties.get("TransitGatewayId") - pcx_id = properties.get("VpcPeeringConnectionId") - - route_table_id = properties["RouteTableId"] - ec2_backend = ec2_backends[account_id][region_name] - route_table = ec2_backend.create_route( - route_table_id=route_table_id, - destination_cidr_block=properties.get("DestinationCidrBlock"), - gateway_id=gateway_id, - instance_id=instance_id, - nat_gateway_id=nat_gateway_id, - egress_only_igw_id=egress_only_igw_id, - transit_gateway_id=transit_gateway_id, - interface_id=interface_id, - vpc_peering_connection_id=pcx_id, - ) - return route_table - - -class RouteBackend: def create_route( self, - route_table_id, - destination_cidr_block, - destination_ipv6_cidr_block=None, - destination_prefix_list_id=None, - local=False, - gateway_id=None, - instance_id=None, - nat_gateway_id=None, - egress_only_igw_id=None, - transit_gateway_id=None, - interface_id=None, - vpc_peering_connection_id=None, - carrier_gateway_id=None, - ): + route_table_id: str, + destination_cidr_block: Optional[str], + destination_ipv6_cidr_block: Optional[str] = None, + destination_prefix_list_id: Optional[str] = None, + local: bool = False, + gateway_id: Optional[str] = None, + instance_id: Optional[str] = None, + nat_gateway_id: Optional[str] = None, + egress_only_igw_id: Optional[str] = None, + transit_gateway_id: Optional[str] = None, + interface_id: Optional[str] = None, + vpc_peering_connection_id: Optional[str] = None, + carrier_gateway_id: Optional[str] = None, + ) -> Route: gateway = None nat_gateway = None transit_gateway = None @@ -336,16 +366,16 @@ class RouteBackend: if interface_id: # for validating interface Id whether it is valid or not. - interface = self.get_network_interface(interface_id) + interface = self.get_network_interface(interface_id) # type: ignore[attr-defined] else: if gateway_id: if EC2_RESOURCE_TO_PREFIX["vpn-gateway"] in gateway_id: - gateway = self.get_vpn_gateway(gateway_id) + gateway = self.get_vpn_gateway(gateway_id) # type: ignore[attr-defined] elif EC2_RESOURCE_TO_PREFIX["internet-gateway"] in gateway_id: - gateway = self.get_internet_gateway(gateway_id) + gateway = self.get_internet_gateway(gateway_id) # type: ignore[attr-defined] elif EC2_RESOURCE_TO_PREFIX["vpc-endpoint"] in gateway_id: - gateway = self.get_vpc_end_point(gateway_id) + gateway = self.get_vpc_end_point(gateway_id) # type: ignore[attr-defined] if destination_cidr_block: self.__validate_destination_cidr_block( @@ -353,17 +383,17 @@ class RouteBackend: ) if nat_gateway_id is not None: - nat_gateway = self.nat_gateways.get(nat_gateway_id) + nat_gateway = self.nat_gateways.get(nat_gateway_id) # type: ignore[attr-defined] if egress_only_igw_id is not None: - egress_only_igw = self.get_egress_only_igw(egress_only_igw_id) + egress_only_igw = self.get_egress_only_igw(egress_only_igw_id) # type: ignore[attr-defined] if transit_gateway_id is not None: - transit_gateway = self.transit_gateways.get(transit_gateway_id) + transit_gateway = self.transit_gateways.get(transit_gateway_id) # type: ignore[attr-defined] if destination_prefix_list_id is not None: - destination_prefix_list = self.managed_prefix_lists.get( + destination_prefix_list = self.managed_prefix_lists.get( # type: ignore[attr-defined] destination_prefix_list_id ) if carrier_gateway_id is not None: - carrier_gateway = self.carrier_gateways.get(carrier_gateway_id) + carrier_gateway = self.carrier_gateways.get(carrier_gateway_id) # type: ignore[attr-defined] route = Route( route_table, @@ -372,13 +402,13 @@ class RouteBackend: destination_prefix_list, local=local, gateway=gateway, - instance=self.get_instance(instance_id) if instance_id else None, + instance=self.get_instance(instance_id) if instance_id else None, # type: ignore[attr-defined] nat_gateway=nat_gateway, egress_only_igw=egress_only_igw, transit_gateway=transit_gateway, interface=interface, carrier_gateway=carrier_gateway, - vpc_pcx=self.get_vpc_peering_connection(vpc_peering_connection_id) + vpc_pcx=self.get_vpc_peering_connection(vpc_peering_connection_id) # type: ignore[attr-defined] if vpc_peering_connection_id else None, ) @@ -387,18 +417,18 @@ class RouteBackend: def replace_route( self, - route_table_id, - destination_cidr_block, - destination_ipv6_cidr_block=None, - destination_prefix_list_id=None, - nat_gateway_id=None, - egress_only_igw_id=None, - transit_gateway_id=None, - gateway_id=None, - instance_id=None, - interface_id=None, - vpc_peering_connection_id=None, - ): + route_table_id: str, + destination_cidr_block: str, + destination_ipv6_cidr_block: Optional[str] = None, + destination_prefix_list_id: Optional[str] = None, + nat_gateway_id: Optional[str] = None, + egress_only_igw_id: Optional[str] = None, + transit_gateway_id: Optional[str] = None, + gateway_id: Optional[str] = None, + instance_id: Optional[str] = None, + interface_id: Optional[str] = None, + vpc_peering_connection_id: Optional[str] = None, + ) -> Route: route_table = self.get_route_table(route_table_id) route_id = generate_route_id( route_table.id, destination_cidr_block, destination_ipv6_cidr_block @@ -406,7 +436,7 @@ class RouteBackend: route = route_table.routes[route_id] if interface_id: - self.raise_not_implemented_error("ReplaceRoute to NetworkInterfaceId") + self.raise_not_implemented_error("ReplaceRoute to NetworkInterfaceId") # type: ignore[attr-defined] route.gateway = None route.nat_gateway = None @@ -414,25 +444,25 @@ class RouteBackend: route.transit_gateway = None if gateway_id: if EC2_RESOURCE_TO_PREFIX["vpn-gateway"] in gateway_id: - route.gateway = self.get_vpn_gateway(gateway_id) + route.gateway = self.get_vpn_gateway(gateway_id) # type: ignore[attr-defined] elif EC2_RESOURCE_TO_PREFIX["internet-gateway"] in gateway_id: - route.gateway = self.get_internet_gateway(gateway_id) + route.gateway = self.get_internet_gateway(gateway_id) # type: ignore[attr-defined] if nat_gateway_id is not None: - route.nat_gateway = self.nat_gateways.get(nat_gateway_id) + route.nat_gateway = self.nat_gateways.get(nat_gateway_id) # type: ignore[attr-defined] if egress_only_igw_id is not None: - route.egress_only_igw = self.get_egress_only_igw(egress_only_igw_id) + route.egress_only_igw = self.get_egress_only_igw(egress_only_igw_id) # type: ignore[attr-defined] if transit_gateway_id is not None: - route.transit_gateway = self.transit_gateways.get(transit_gateway_id) + route.transit_gateway = self.transit_gateways.get(transit_gateway_id) # type: ignore[attr-defined] if destination_prefix_list_id is not None: - route.prefix_list = self.managed_prefix_lists.get( + route.prefix_list = self.managed_prefix_lists.get( # type: ignore[attr-defined] destination_prefix_list_id ) - route.instance = self.get_instance(instance_id) if instance_id else None + route.instance = self.get_instance(instance_id) if instance_id else None # type: ignore[attr-defined] route.interface = None route.vpc_pcx = ( - self.get_vpc_peering_connection(vpc_peering_connection_id) + self.get_vpc_peering_connection(vpc_peering_connection_id) # type: ignore[attr-defined] if vpc_peering_connection_id else None ) @@ -440,18 +470,13 @@ class RouteBackend: route_table.routes[route.id] = route return route - def get_route(self, route_id): - route_table_id, _ = split_route_id(route_id) - route_table = self.get_route_table(route_table_id) - return route_table.get(route_id) - def delete_route( self, - route_table_id, - destination_cidr_block, - destination_ipv6_cidr_block=None, - destination_prefix_list_id=None, - ): + route_table_id: str, + destination_cidr_block: str, + destination_ipv6_cidr_block: Optional[str] = None, + destination_prefix_list_id: Optional[str] = None, + ) -> Route: cidr = destination_cidr_block route_table = self.get_route_table(route_table_id) if destination_ipv6_cidr_block: @@ -464,7 +489,9 @@ class RouteBackend: raise InvalidRouteError(route_table_id, cidr) return deleted - def __validate_destination_cidr_block(self, destination_cidr_block, route_table): + def __validate_destination_cidr_block( + self, destination_cidr_block: str, route_table: RouteTable + ) -> None: """ Utility function to check the destination CIDR block Will validate the format and check for overlap with existing routes diff --git a/moto/ec2/utils.py b/moto/ec2/utils.py index 795467423..6624e989d 100644 --- a/moto/ec2/utils.py +++ b/moto/ec2/utils.py @@ -7,7 +7,7 @@ from datetime import datetime from cryptography.hazmat.primitives import serialization from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.asymmetric import rsa -from typing import Any, Dict, List, TypeVar, Optional +from typing import Any, Dict, List, TypeVar, Tuple, Optional from moto.iam import iam_backends from moto.moto_api._internal import mock_random as random @@ -122,7 +122,7 @@ def random_subnet_ipv6_cidr_block_association_id(): ) -def random_subnet_association_id(): +def random_subnet_association_id() -> str: return random_id(prefix=EC2_RESOURCE_TO_PREFIX["route-table-association"]) @@ -184,7 +184,7 @@ def random_egress_only_internet_gateway_id() -> str: ) -def random_route_table_id(): +def random_route_table_id() -> str: return random_id(prefix=EC2_RESOURCE_TO_PREFIX["route-table"]) @@ -281,7 +281,10 @@ def random_ipv6_cidr(): def generate_route_id( - route_table_id, cidr_block, ipv6_cidr_block=None, prefix_list=None + route_table_id: str, + cidr_block: Optional[str], + ipv6_cidr_block: Optional[str] = None, + prefix_list: Optional[str] = None, ): if ipv6_cidr_block and not cidr_block: cidr_block = ipv6_cidr_block @@ -309,7 +312,7 @@ def utc_date_and_time() -> str: return f"{x.year}-{x.month:02d}-{x.day:02d}T{x.hour:02d}:{x.minute:02d}:{x.second:02d}.000Z" -def split_route_id(route_id): +def split_route_id(route_id: str) -> Tuple[str, str]: values = route_id.split("~") return values[0], values[1] diff --git a/setup.cfg b/setup.cfg index c9ab54f7d..671d5df1c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -229,7 +229,7 @@ disable = W,C,R,E enable = anomalous-backslash-in-string, arguments-renamed, dangerous-default-value, deprecated-module, function-redefined, import-self, redefined-builtin, redefined-outer-name, reimported, pointless-statement, super-with-arguments, unused-argument, unused-import, unused-variable, useless-else-on-loop, wildcard-import [mypy] -files= moto/a*,moto/b*,moto/c*,moto/d*,moto/ebs/,moto/ec2/models/a*,moto/ec2/models/c*,moto/ec2/models/d*,moto/ec2/models/e*,moto/ec2/models/f*,moto/ec2/models/h*,moto/ec2/models/i*,moto/ec2/models/k*,moto/ec2/models/l*,moto/ec2/models/m*,moto/ec2/models/n*,moto/moto_api +files= moto/a*,moto/b*,moto/c*,moto/d*,moto/ebs/,moto/ec2/models/a*,moto/ec2/models/c*,moto/ec2/models/d*,moto/ec2/models/e*,moto/ec2/models/f*,moto/ec2/models/h*,moto/ec2/models/i*,moto/ec2/models/k*,moto/ec2/models/l*,moto/ec2/models/m*,moto/ec2/models/n*,moto/ec2/models/r*,moto/moto_api show_column_numbers=True show_error_codes = True disable_error_code=abstract