Repository: connelldave/botocove (language: python)

Issue:
Add support for multiple regions
I find myself doing a lot of multi-region work these days.

So in all my multi-region botocove scripts I've started using a variation of helper functions like `run_across_org` and `run_in_each_region` in the demo script below.

When it works, it's great, because you can get the output from each region in each account's result key something like this.

```python
{'Exceptions': [],
 'FailedAssumeRole': [],
 'Results': [{'Arn': 'arn:aws:organizations::111111111111:account/o-aaaaaaaaaa/222222222222',
              'AssumeRoleSuccess': True,
              'Email': 'aws@example.com',
              'Id': '222222222222',
              'Name': 'Demo Account 1',
              'PolicyArns': [{'arn': 'arn:aws:iam::aws:policy/AmazonVPCReadOnlyAccess'}],
              'Result': [{'RegionName': 'eu-west-1',
                          'Result': 'vpc-22222222222222222'},
                         {'RegionName': 'us-east-1',
                          'Result': 'vpc-11111111111111111'}],
              'RoleName': 'OrganizationAccountAccessRole',
              'RoleSessionName': 'OrganizationAccountAccessRole',
              'Status': 'ACTIVE'},
```

```python
from botocove import cove
from pprint import pprint


def main():
    results = get_org_default_vpc_ids()
    pprint(results)


def get_org_default_vpc_ids():
    org_func = run_across_org(
        get_default_vpc_id,
        regions=["eu-west-1", "us-east-1"],
        policy_arns=[{"arn": "arn:aws:iam::aws:policy/AmazonVPCReadOnlyAccess"}],
    )
    return org_func()


def get_default_vpc_id(session, region):
    ec2 = session.client("ec2", region_name=region)
    resp = ec2.describe_vpcs(Filters=[{"Name": "is-default", "Values": ["true"]}])
    if len(resp["Vpcs"]) > 0:
        return resp["Vpcs"][0]["VpcId"]
    return None


def run_across_org(func, target_ids=None, regions=None, policy_arns=None):
    def _across_org(*args, **kwargs):
        return cove(
            run_in_each_region(func, regions),
            target_ids=target_ids,
            policy_arns=policy_arns,
        )(*args, **kwargs)
    return _across_org


def run_in_each_region(func, region_names):

    def _in_each_region(session, *args, **kwargs):

        return [
            {
                "RegionName": rn,
                "Result": func(session, rn, *args, **kwargs)
            }
            for rn in region_names
        ]

    return _in_each_region


if __name__ == "__main__":
    main()
```

The main problem with this implementation is that it's not very robust. An error in any region will scupper results from all the other regions and all you'll be left with is an exception.

A lesser problem is performance because each region is accessed serially, although this is probably mitigated by the account-level concurrency.

Another problem with this implementation (perhaps more theoretical than practical) is the lack of flexibility. It will always iterate over the cartesian product accounts and regions. It may be useful to be able to iterate over a different set of regions per account. (Perhaps using an input mapping of account IDs to region names.)

It would be great if the cove function would handle this automatically. So I'm sharing my rough implementation here to get some feedback in the hope that it can be improved upon and ultimately integrated into the library.

The `get_default_vpc_id` function in the demo code shows how new client code would work. The client function would take a session and a region, and it would be the client's responsibility to create a boto3 client with the correct region set. Botocove itself would be responsible for ensuring the function gets called once for all the account-region pairs.

To be backwards compatible with client code that doesn't pass any region info or a function that takes a region parameter, I suppose the default behavior would be to behave as before and use only the main boto3 session's region.
Add moto test harness
Add a more complex test harness for confidence using Moto


Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7a2e0a6..09ca415 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,7 +3,10 @@ All notable changes to this project will be documented in this file.
 
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-
+## [1.5.2] - 2022-23-02
+### Added
+- Botocove now supports a regions argument, allowing sessions to be run across
+one or many regions per account
 ## [1.5.1] - 2022-13-02
 ### Fixed
 - Reverted internal handling of output data to a dictionary rather than dataclass:
diff --git a/README.md b/README.md
index b912f58..307118a 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,9 @@
 # Botocove
 
 Run a function against a selection of AWS accounts, or all AWS accounts in an
-organization, concurrently. By default, opinionated to work with the standard
+organization, concurrently with thread safety. Run in one or multiple regions.
+
+By default, opinionated to work with the standard
 AWS Organization master/member configuration from an organization master
 account.
 
@@ -19,14 +21,16 @@ in every account required, gathering all results into a dictionary.
 at scale. **Test carefully and make idempotent changes**! Please read available
 arguments to understand safe experimentation with this package.
 
-## Requirements
+## Pre-requisites and Info
 
 An IAM user with `sts:assumerole` privilege, and accounts that have a trust
 relationship to the IAM user's account.
 
-By default, the IAM user is expected to be in an AWS Organization Master account
+By default, the IAM user is expected to be in an AWS Organization Master account. You can alter nearly all behaviour of Cove with appropriate [arguments](#arguments)
+
+Cove will not execute a function call in the account it's called from.
 
-Default (customisable if unsuitable) expectations are:
+Default requirements are:
 
 In the organization master account:
 * IAM permissions `sts:assumerole`, `sts:get-caller-identity` and
@@ -35,18 +39,19 @@ In the organization master account:
 In the organization accounts:
 * An `AccountOrganizationAccessRole` role
 
-See the Arguments section for how to change these defaults to work with any
-accounts.
+See the [arguments](#arguments) section for how to change these defaults to work with any
+account configuration, including running without an AWS Organization.
 
 ## Quickstart
-A function written to interact with a `boto3 session` can now be called with
-a `session` from every account required in your AWS organization, assuming
-a role in each account.
+A function written to interact with one
+[boto3 session](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/core/session.html)
+can now be called with a `session` from every account and region required by assuming a
+ role in for each account - except the host account you're running from.
 
 For example:
 
 A standard approach: this function takes a boto3 `session` and gets all IAM
-users from a single AWS account
+users from a single AWS account. You would then manually run it in each account.
 
 ```
 import boto3
@@ -92,49 +97,63 @@ def main():
     print(all_results["FailedAssumeRole"])
 ```
 
+Here's an example of a more customised Cove decorator:
+```
+@cove(
+    target_ids=["123456789101", "234567891011"],
+    rolename="AWSControlTowerExecution",
+    raise_exception=True,
+    regions=["eu-west-1", "eu-west-2", "us-east-1"],
+)
+def do_things(session):
+    # Cove will return six results of True, 2 accounts * 3 regions
+    return True
+```
 ## Arguments
 
 ### Cove
 `@cove()`:
 
-Uses boto3 credential chain to get every AWS account within the
-organization, assume the `OrganizationAccountAccessRole` in it and run the
-wrapped function with that role.
+Uses the standard boto3 credential chain to start with, assuming roles in every account
+required. Defaults to assuming the `OrganizationAccountAccessRole` in every account
+in an AWS organization.
 
 Equivalent to:
 `@cove(target_ids=None, ignore_ids=None, rolename=None, role_session_name=rolename,
     policy=None, policy_arns=None, assuming_session=None, raise_exception=False,
-    org_master=True)`
+    org_master=True, thread_workers=20, regions=None)`
 
-`target_ids`: Optional[List[str]]
+`target_ids`: List[str]
 
 A list of AWS accounts as strings to attempt to assume role in to. When unset,
 default attempts to use every available account ID in an AWS organization.
 
-`ignore_ids`: Optional[List[str]]
+`ignore_ids`: List[str]
 
 A list of AWS account ID's that will not attempt assumption in to. Allows IDs to
 be ignored.
 
-`rolename`: Optional[str]
+`rolename`: str
 
 An IAM role name that will be attempted to assume in all target accounts.
 Defaults to the AWS Organization default, `OrganizationAccountAccessRole`.
 
-`role_session_name`: Optional[str]
+`role_session_name`: str
 
 An IAM role session name that will be passed to each Cove session's `sts.assume_role()` call.
 Defaults to the name of the role being used if unset.
 
-`policy`: Optional[str]
+`policy`: str
 
-A policy document that will be used as a session policy in each Cove session's `sts.assume_role()` call. Unless the value is None, it is passed through via the Policy parameter.
+A policy document that will be used as a session policy in each Cove session's `sts.assume_role()`
+call. Unless the value is None, it is passed through via the Policy parameter.
 
-`policy_arns`: Optional[List[str]]
+`policy_arns`: List[str]
 
-A list of managed policy ARNs that will be used as a session policy in each Cove session's `sts.assume_role()` call. Unless the value is None, it is passed through via the PolicyArns parameter.
+A list of managed policy ARNs that will be used as a session policy in each Cove session's
+ `sts.assume_role()` call. Unless the value is None, it is passed through via the PolicyArns parameter.
 
-`assuming_session`: Optional[Session]
+`assuming_session`: Session
 
 A Boto3 `boto3.session.Session()` object that will be used to call `sts:assumerole`. If not
 provided, cove will instantiate one which will use the standard boto3 credential chain.
@@ -156,8 +175,7 @@ all accounts in the organization, and enrich each `CoveSession` with information
 available (`Id`, `Arn`, `Name`, `Status`, `Email`). Disabling this and providing your
 own full list of accounts may be a desirable optimisation if speed is an issue.
 
-`org_master=False` means `target_ids` must be provided (as no list of accounts
-can be created for you), as well as likely `rolename`. Only `Id` will be
+`org_master=False` means only `Id` will be
 available to `CoveSession`.
 
 `thread_workers`: int
@@ -166,6 +184,13 @@ Defaults to 20. Cove utilises a ThreadPoolWorker under the hood, which can be tu
 with this argument. Number of thread workers directly corrolates to memory usage: see
 [here](#is-botocove-thread-safe)
 
+`regions`: List[str]
+
+If not provided, Cove will respect your profile's default region via the boto credential chain.
+If provided, Cove will run the decorated function in every region named.
+
+You can get all regions with:
+`regions = [r['RegionName'] for r in boto3.client('ec2').describe_regions()['Regions']]`✨
 
 ### CoveSession
 
diff --git a/botocove/cove_decorator.py b/botocove/cove_decorator.py
index 5e5411e..c5583a8 100644
--- a/botocove/cove_decorator.py
+++ b/botocove/cove_decorator.py
@@ -23,7 +23,8 @@ def cove(
     assuming_session: Optional[Session] = None,
     raise_exception: bool = False,
     org_master: bool = True,
-    thread_workers: int = 20
+    thread_workers: int = 20,
+    regions: Optional[List[str]] = None
 ) -> Callable:
     def decorator(func: Callable[..., Any]) -> Callable[..., CoveOutput]:
         @functools.wraps(func)
@@ -38,6 +39,8 @@ def wrapper(*args: Any, **kwargs: Any) -> CoveOutput:
                 policy_arns=policy_arns,
                 org_master=org_master,
                 assuming_session=assuming_session,
+                thread_workers=thread_workers,
+                regions=regions,
             )
 
             runner = CoveRunner(
diff --git a/botocove/cove_host_account.py b/botocove/cove_host_account.py
index 21946eb..69e89f6 100644
--- a/botocove/cove_host_account.py
+++ b/botocove/cove_host_account.py
@@ -1,5 +1,5 @@
 import logging
-from typing import Any, List, Literal, Optional, Set, Union
+from typing import Any, Iterable, List, Literal, Optional, Sequence, Set, Union
 
 import boto3
 from boto3.session import Session
@@ -16,6 +16,8 @@
 
 
 class CoveHostAccount(object):
+    target_regions: Sequence[Optional[str]]
+
     def __init__(
         self,
         target_ids: Optional[List[str]],
@@ -26,11 +28,22 @@ def __init__(
         policy_arns: Optional[List[str]],
         assuming_session: Optional[Session],
         org_master: bool,
+        thread_workers: int,
+        regions: Optional[List[str]],
     ) -> None:
 
+        self.thread_workers = thread_workers
+
         self.sts_client = self._get_boto3_sts_client(assuming_session)
         self.org_client = self._get_boto3_org_client(assuming_session)
 
+        self.host_account_id = self.sts_client.get_caller_identity()["Account"]
+
+        if regions is None:
+            self.target_regions = [None]
+        else:
+            self.target_regions = regions
+
         self.provided_ignore_ids = ignore_ids
         self.target_accounts = self._resolve_target_accounts(target_ids)
         if not self.target_accounts:
@@ -45,33 +58,31 @@ def __init__(
 
         self.org_master = org_master
 
-    def get_cove_session_info(self) -> List[CoveSessionInformation]:
-        logger.info(
-            f"Getting session information: {self.role_to_assume=} "
-            f"{self.role_session_name=} {self.target_accounts=} "
-            f"{self.provided_ignore_ids=}"
-        )
+    def get_cove_sessions(self) -> List[CoveSessionInformation]:
+        logger.info(f"Getting session information for {self.target_accounts=}")
+        logger.info(f"Role: {self.role_to_assume=} {self.role_session_name=}")
         logger.info(f"Session policy: {self.policy_arns=} {self.policy=}")
-
-        sessions = []
-        for account_id in self.target_accounts:
-            account_details: CoveSessionInformation = CoveSessionInformation(
-                Id=account_id,
-                RoleName=self.role_to_assume,
-                RoleSessionName=self.role_session_name,
-                Policy=self.policy,
-                PolicyArns=self.policy_arns,
-                AssumeRoleSuccess=False,
-                ExceptionDetails=None,
-                Name=None,
-                Arn=None,
-                Email=None,
-                Status=None,
-                Result=None,
-            )
-            sessions.append(account_details)
-
-        return sessions
+        return list(self._generate_account_sessions())
+
+    def _generate_account_sessions(self) -> Iterable[CoveSessionInformation]:
+        for region in self.target_regions:
+            for account_id in self.target_accounts:
+                account_details: CoveSessionInformation = CoveSessionInformation(
+                    Id=account_id,
+                    RoleName=self.role_to_assume,
+                    RoleSessionName=self.role_session_name,
+                    Policy=self.policy,
+                    PolicyArns=self.policy_arns,
+                    AssumeRoleSuccess=False,
+                    Region=region,
+                    ExceptionDetails=None,
+                    Name=None,
+                    Arn=None,
+                    Email=None,
+                    Status=None,
+                    Result=None,
+                )
+                yield account_details
 
     def _get_boto3_client(
         self,
@@ -81,11 +92,13 @@ def _get_boto3_client(
         if assuming_session:
             logger.info(f"Using provided Boto3 session {assuming_session}")
             return assuming_session.client(
-                service_name=clientname, config=Config(max_pool_connections=20)
+                service_name=clientname,
+                config=Config(max_pool_connections=self.thread_workers),
             )
         logger.info("No Boto3 session argument: using credential chain")
         return boto3.client(
-            service_name=clientname, config=Config(max_pool_connections=20)
+            service_name=clientname,
+            config=Config(max_pool_connections=self.thread_workers),
         )
 
     def _get_boto3_org_client(
@@ -101,21 +114,23 @@ def _get_boto3_sts_client(self, assuming_session: Optional[Session]) -> STSClien
         return client
 
     def _resolve_target_accounts(self, target_ids: Optional[List[str]]) -> Set[str]:
+        # Ensure we never run botocove on the account it's being run from
+        validated_ignore_ids = {self.host_account_id}
+
         if self.provided_ignore_ids:
-            validated_ignore_ids = self._format_ignore_ids()
-        else:
-            validated_ignore_ids = set()
+            validated_ignore_ids.update(self._parse_ignore_ids())
+        logger.info(f"Ignoring account IDs: {validated_ignore_ids=}")
 
         if target_ids is None:
-            # No target_ids passed
-            target_accounts = self._gather_org_assume_targets()
+            # No target_ids passed, get all accounts in org
+            target_accounts = self._get_active_org_accounts()
         else:
             # Specific list of IDs passed
             target_accounts = set(target_ids)
 
         return target_accounts - validated_ignore_ids
 
-    def _format_ignore_ids(self) -> Set[str]:
+    def _parse_ignore_ids(self) -> Set[str]:
         if not isinstance(self.provided_ignore_ids, list):
             raise TypeError("ignore_ids must be a list of account IDs")
         for account_id in self.provided_ignore_ids:
@@ -132,19 +147,3 @@ def _get_active_org_accounts(self) -> Set[str]:
             .build_full_result()["Accounts"]
         )
         return {acc["Id"] for acc in all_org_accounts if acc["Status"] == "ACTIVE"}
-
-    def _build_account_ignore_list(self) -> Set[str]:
-        accounts_to_ignore: Set[str] = {
-            self.sts_client.get_caller_identity()["Account"]
-        }
-        if self.provided_ignore_ids:
-            accounts_to_ignore.update(self.provided_ignore_ids)
-
-        logger.info(f"{accounts_to_ignore=}")
-        return accounts_to_ignore
-
-    def _gather_org_assume_targets(self) -> Set[str]:
-        accounts_to_ignore = self._build_account_ignore_list()
-        active_accounts = self._get_active_org_accounts()
-        target_accounts = active_accounts - accounts_to_ignore
-        return target_accounts
diff --git a/botocove/cove_runner.py b/botocove/cove_runner.py
index 210c0c3..7b7c181 100644
--- a/botocove/cove_runner.py
+++ b/botocove/cove_runner.py
@@ -23,7 +23,7 @@ def __init__(
     ) -> None:
 
         self.host_account = host_account
-        self.sessions = host_account.get_cove_session_info()
+        self.sessions = host_account.get_cove_sessions()
 
         self.cove_wrapped_func = func
         self.raise_exception = raise_exception
diff --git a/botocove/cove_session.py b/botocove/cove_session.py
index 9468e8e..4012bfe 100644
--- a/botocove/cove_session.py
+++ b/botocove/cove_session.py
@@ -75,11 +75,19 @@ def activate_cove_session(self) -> "CoveSession":
                 if v is not None
             }
             creds = self.sts_client.assume_role(**assume_role_args)["Credentials"]  # type: ignore[arg-type] # noqa E501
-            self.initialize_boto_session(
-                aws_access_key_id=creds["AccessKeyId"],
-                aws_secret_access_key=creds["SecretAccessKey"],
-                aws_session_token=creds["SessionToken"],
-            )
+
+            init_session_args = {
+                k: v
+                for k, v in [
+                    ("aws_access_key_id", creds["AccessKeyId"]),
+                    ("aws_secret_access_key", creds["SecretAccessKey"]),
+                    ("aws_session_token", creds["SessionToken"]),
+                    ("region_name", self.session_information["Region"]),
+                ]
+                if v is not None
+            }
+
+            self.initialize_boto_session(**init_session_args)
             self.session_information["AssumeRoleSuccess"] = True
         except ClientError:
             logger.error(
diff --git a/botocove/cove_types.py b/botocove/cove_types.py
index 49c0702..0efc795 100644
--- a/botocove/cove_types.py
+++ b/botocove/cove_types.py
@@ -16,6 +16,7 @@ class CoveSessionInformation(TypedDict):
     PolicyArns: Optional[List[str]]
     Result: Any
     ExceptionDetails: Optional[Exception]
+    Region: Optional[str]
 
 
 CoveResults = List[CoveSessionInformation]
diff --git a/mypy.ini b/mypy.ini
index 07ca8b4..7407e93 100644
--- a/mypy.ini
+++ b/mypy.ini
@@ -27,4 +27,7 @@ warn_unused_ignores = False
 
 
 [mypy-tqdm.*]
+ignore_missing_imports = True
+
+[mypy-moto.*]
 ignore_missing_imports = True
\ No newline at end of file
diff --git a/poetry.lock b/poetry.lock
index 058f2dd..51a6df4 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -20,56 +20,38 @@ docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
 tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"]
 tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"]
 
-[[package]]
-name = "bandit"
-version = "1.7.1"
-description = "Security oriented static analyser for python code."
-category = "dev"
-optional = false
-python-versions = ">=3.5"
-
-[package.dependencies]
-colorama = {version = ">=0.3.9", markers = "platform_system == \"Windows\""}
-GitPython = ">=1.0.1"
-PyYAML = ">=5.3.1"
-stevedore = ">=1.20.0"
-
 [[package]]
 name = "black"
-version = "21.12b0"
+version = "22.1.0"
 description = "The uncompromising code formatter."
 category = "dev"
 optional = false
 python-versions = ">=3.6.2"
 
 [package.dependencies]
-click = ">=7.1.2"
+click = ">=8.0.0"
 mypy-extensions = ">=0.4.3"
-pathspec = ">=0.9.0,<1"
+pathspec = ">=0.9.0"
 platformdirs = ">=2"
-tomli = ">=0.2.6,<2.0.0"
-typing-extensions = [
-    {version = ">=3.10.0.0", markers = "python_version < \"3.10\""},
-    {version = "!=3.10.0.1", markers = "python_version >= \"3.10\""},
-]
+tomli = ">=1.1.0"
+typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}
 
 [package.extras]
 colorama = ["colorama (>=0.4.3)"]
 d = ["aiohttp (>=3.7.4)"]
 jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
-python2 = ["typed-ast (>=1.4.3)"]
 uvloop = ["uvloop (>=0.15.2)"]
 
 [[package]]
 name = "boto3"
-version = "1.20.41"
+version = "1.21.6"
 description = "The AWS SDK for Python"
 category = "main"
 optional = false
 python-versions = ">= 3.6"
 
 [package.dependencies]
-botocore = ">=1.23.41,<1.24.0"
+botocore = ">=1.24.6,<1.25.0"
 jmespath = ">=0.7.1,<1.0.0"
 s3transfer = ">=0.5.0,<0.6.0"
 
@@ -78,324 +60,324 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"]
 
 [[package]]
 name = "boto3-stubs"
-version = "1.20.40"
-description = "Type annotations for boto3 1.20.40, generated by mypy-boto3-builder 6.3.2"
+version = "1.21.6"
+description = "Type annotations for boto3 1.21.6 generated with mypy-boto3-builder 7.1.2"
 category = "main"
 optional = false
 python-versions = ">=3.6"
 
 [package.dependencies]
 botocore-stubs = "*"
-mypy-boto3-organizations = {version = ">=1.20.0", optional = true, markers = "extra == \"organizations\""}
-mypy-boto3-sts = {version = ">=1.20.0", optional = true, markers = "extra == \"sts\""}
+mypy-boto3-organizations = {version = ">=1.21.0", optional = true, markers = "extra == \"organizations\""}
+mypy-boto3-sts = {version = ">=1.21.0", optional = true, markers = "extra == \"sts\""}
 typing-extensions = {version = "*", markers = "python_version < \"3.9\""}
 
 [package.extras]
-accessanalyzer = ["mypy-boto3-accessanalyzer (>=1.20.0)"]
-account = ["mypy-boto3-account (>=1.20.0)"]
-acm = ["mypy-boto3-acm (>=1.20.0)"]
-acm-pca = ["mypy-boto3-acm-pca (>=1.20.0)"]
-alexaforbusiness = ["mypy-boto3-alexaforbusiness (>=1.20.0)"]
-all = ["mypy-boto3-accessanalyzer (>=1.20.0)", "mypy-boto3-account (>=1.20.0)", "mypy-boto3-acm (>=1.20.0)", "mypy-boto3-acm-pca (>=1.20.0)", "mypy-boto3-alexaforbusiness (>=1.20.0)", "mypy-boto3-amp (>=1.20.0)", "mypy-boto3-amplify (>=1.20.0)", "mypy-boto3-amplifybackend (>=1.20.0)", "mypy-boto3-amplifyuibuilder (>=1.20.0)", "mypy-boto3-apigateway (>=1.20.0)", "mypy-boto3-apigatewaymanagementapi (>=1.20.0)", "mypy-boto3-apigatewayv2 (>=1.20.0)", "mypy-boto3-appconfig (>=1.20.0)", "mypy-boto3-appconfigdata (>=1.20.0)", "mypy-boto3-appflow (>=1.20.0)", "mypy-boto3-appintegrations (>=1.20.0)", "mypy-boto3-application-autoscaling (>=1.20.0)", "mypy-boto3-application-insights (>=1.20.0)", "mypy-boto3-applicationcostprofiler (>=1.20.0)", "mypy-boto3-appmesh (>=1.20.0)", "mypy-boto3-apprunner (>=1.20.0)", "mypy-boto3-appstream (>=1.20.0)", "mypy-boto3-appsync (>=1.20.0)", "mypy-boto3-athena (>=1.20.0)", "mypy-boto3-auditmanager (>=1.20.0)", "mypy-boto3-autoscaling (>=1.20.0)", "mypy-boto3-autoscaling-plans (>=1.20.0)", "mypy-boto3-backup (>=1.20.0)", "mypy-boto3-backup-gateway (>=1.20.0)", "mypy-boto3-batch (>=1.20.0)", "mypy-boto3-braket (>=1.20.0)", "mypy-boto3-budgets (>=1.20.0)", "mypy-boto3-ce (>=1.20.0)", "mypy-boto3-chime (>=1.20.0)", "mypy-boto3-chime-sdk-identity (>=1.20.0)", "mypy-boto3-chime-sdk-meetings (>=1.20.0)", "mypy-boto3-chime-sdk-messaging (>=1.20.0)", "mypy-boto3-cloud9 (>=1.20.0)", "mypy-boto3-cloudcontrol (>=1.20.0)", "mypy-boto3-clouddirectory (>=1.20.0)", "mypy-boto3-cloudformation (>=1.20.0)", "mypy-boto3-cloudfront (>=1.20.0)", "mypy-boto3-cloudhsm (>=1.20.0)", "mypy-boto3-cloudhsmv2 (>=1.20.0)", "mypy-boto3-cloudsearch (>=1.20.0)", "mypy-boto3-cloudsearchdomain (>=1.20.0)", "mypy-boto3-cloudtrail (>=1.20.0)", "mypy-boto3-cloudwatch (>=1.20.0)", "mypy-boto3-codeartifact (>=1.20.0)", "mypy-boto3-codebuild (>=1.20.0)", "mypy-boto3-codecommit (>=1.20.0)", "mypy-boto3-codedeploy (>=1.20.0)", "mypy-boto3-codeguru-reviewer (>=1.20.0)", "mypy-boto3-codeguruprofiler (>=1.20.0)", "mypy-boto3-codepipeline (>=1.20.0)", "mypy-boto3-codestar (>=1.20.0)", "mypy-boto3-codestar-connections (>=1.20.0)", "mypy-boto3-codestar-notifications (>=1.20.0)", "mypy-boto3-cognito-identity (>=1.20.0)", "mypy-boto3-cognito-idp (>=1.20.0)", "mypy-boto3-cognito-sync (>=1.20.0)", "mypy-boto3-comprehend (>=1.20.0)", "mypy-boto3-comprehendmedical (>=1.20.0)", "mypy-boto3-compute-optimizer (>=1.20.0)", "mypy-boto3-config (>=1.20.0)", "mypy-boto3-connect (>=1.20.0)", "mypy-boto3-connect-contact-lens (>=1.20.0)", "mypy-boto3-connectparticipant (>=1.20.0)", "mypy-boto3-cur (>=1.20.0)", "mypy-boto3-customer-profiles (>=1.20.0)", "mypy-boto3-databrew (>=1.20.0)", "mypy-boto3-dataexchange (>=1.20.0)", "mypy-boto3-datapipeline (>=1.20.0)", "mypy-boto3-datasync (>=1.20.0)", "mypy-boto3-dax (>=1.20.0)", "mypy-boto3-detective (>=1.20.0)", "mypy-boto3-devicefarm (>=1.20.0)", "mypy-boto3-devops-guru (>=1.20.0)", "mypy-boto3-directconnect (>=1.20.0)", "mypy-boto3-discovery (>=1.20.0)", "mypy-boto3-dlm (>=1.20.0)", "mypy-boto3-dms (>=1.20.0)", "mypy-boto3-docdb (>=1.20.0)", "mypy-boto3-drs (>=1.20.0)", "mypy-boto3-ds (>=1.20.0)", "mypy-boto3-dynamodb (>=1.20.0)", "mypy-boto3-dynamodbstreams (>=1.20.0)", "mypy-boto3-ebs (>=1.20.0)", "mypy-boto3-ec2 (>=1.20.0)", "mypy-boto3-ec2-instance-connect (>=1.20.0)", "mypy-boto3-ecr (>=1.20.0)", "mypy-boto3-ecr-public (>=1.20.0)", "mypy-boto3-ecs (>=1.20.0)", "mypy-boto3-efs (>=1.20.0)", "mypy-boto3-eks (>=1.20.0)", "mypy-boto3-elastic-inference (>=1.20.0)", "mypy-boto3-elasticache (>=1.20.0)", "mypy-boto3-elasticbeanstalk (>=1.20.0)", "mypy-boto3-elastictranscoder (>=1.20.0)", "mypy-boto3-elb (>=1.20.0)", "mypy-boto3-elbv2 (>=1.20.0)", "mypy-boto3-emr (>=1.20.0)", "mypy-boto3-emr-containers (>=1.20.0)", "mypy-boto3-es (>=1.20.0)", "mypy-boto3-events (>=1.20.0)", "mypy-boto3-evidently (>=1.20.0)", "mypy-boto3-finspace (>=1.20.0)", "mypy-boto3-finspace-data (>=1.20.0)", "mypy-boto3-firehose (>=1.20.0)", "mypy-boto3-fis (>=1.20.0)", "mypy-boto3-fms (>=1.20.0)", "mypy-boto3-forecast (>=1.20.0)", "mypy-boto3-forecastquery (>=1.20.0)", "mypy-boto3-frauddetector (>=1.20.0)", "mypy-boto3-fsx (>=1.20.0)", "mypy-boto3-gamelift (>=1.20.0)", "mypy-boto3-glacier (>=1.20.0)", "mypy-boto3-globalaccelerator (>=1.20.0)", "mypy-boto3-glue (>=1.20.0)", "mypy-boto3-grafana (>=1.20.0)", "mypy-boto3-greengrass (>=1.20.0)", "mypy-boto3-greengrassv2 (>=1.20.0)", "mypy-boto3-groundstation (>=1.20.0)", "mypy-boto3-guardduty (>=1.20.0)", "mypy-boto3-health (>=1.20.0)", "mypy-boto3-healthlake (>=1.20.0)", "mypy-boto3-honeycode (>=1.20.0)", "mypy-boto3-iam (>=1.20.0)", "mypy-boto3-identitystore (>=1.20.0)", "mypy-boto3-imagebuilder (>=1.20.0)", "mypy-boto3-importexport (>=1.20.0)", "mypy-boto3-inspector (>=1.20.0)", "mypy-boto3-inspector2 (>=1.20.0)", "mypy-boto3-iot (>=1.20.0)", "mypy-boto3-iot-data (>=1.20.0)", "mypy-boto3-iot-jobs-data (>=1.20.0)", "mypy-boto3-iot1click-devices (>=1.20.0)", "mypy-boto3-iot1click-projects (>=1.20.0)", "mypy-boto3-iotanalytics (>=1.20.0)", "mypy-boto3-iotdeviceadvisor (>=1.20.0)", "mypy-boto3-iotevents (>=1.20.0)", "mypy-boto3-iotevents-data (>=1.20.0)", "mypy-boto3-iotfleethub (>=1.20.0)", "mypy-boto3-iotsecuretunneling (>=1.20.0)", "mypy-boto3-iotsitewise (>=1.20.0)", "mypy-boto3-iotthingsgraph (>=1.20.0)", "mypy-boto3-iottwinmaker (>=1.20.0)", "mypy-boto3-iotwireless (>=1.20.0)", "mypy-boto3-ivs (>=1.20.0)", "mypy-boto3-kafka (>=1.20.0)", "mypy-boto3-kafkaconnect (>=1.20.0)", "mypy-boto3-kendra (>=1.20.0)", "mypy-boto3-kinesis (>=1.20.0)", "mypy-boto3-kinesis-video-archived-media (>=1.20.0)", "mypy-boto3-kinesis-video-media (>=1.20.0)", "mypy-boto3-kinesis-video-signaling (>=1.20.0)", "mypy-boto3-kinesisanalytics (>=1.20.0)", "mypy-boto3-kinesisanalyticsv2 (>=1.20.0)", "mypy-boto3-kinesisvideo (>=1.20.0)", "mypy-boto3-kms (>=1.20.0)", "mypy-boto3-lakeformation (>=1.20.0)", "mypy-boto3-lambda (>=1.20.0)", "mypy-boto3-lex-models (>=1.20.0)", "mypy-boto3-lex-runtime (>=1.20.0)", "mypy-boto3-lexv2-models (>=1.20.0)", "mypy-boto3-lexv2-runtime (>=1.20.0)", "mypy-boto3-license-manager (>=1.20.0)", "mypy-boto3-lightsail (>=1.20.0)", "mypy-boto3-location (>=1.20.0)", "mypy-boto3-logs (>=1.20.0)", "mypy-boto3-lookoutequipment (>=1.20.0)", "mypy-boto3-lookoutmetrics (>=1.20.0)", "mypy-boto3-lookoutvision (>=1.20.0)", "mypy-boto3-machinelearning (>=1.20.0)", "mypy-boto3-macie (>=1.20.0)", "mypy-boto3-macie2 (>=1.20.0)", "mypy-boto3-managedblockchain (>=1.20.0)", "mypy-boto3-marketplace-catalog (>=1.20.0)", "mypy-boto3-marketplace-entitlement (>=1.20.0)", "mypy-boto3-marketplacecommerceanalytics (>=1.20.0)", "mypy-boto3-mediaconnect (>=1.20.0)", "mypy-boto3-mediaconvert (>=1.20.0)", "mypy-boto3-medialive (>=1.20.0)", "mypy-boto3-mediapackage (>=1.20.0)", "mypy-boto3-mediapackage-vod (>=1.20.0)", "mypy-boto3-mediastore (>=1.20.0)", "mypy-boto3-mediastore-data (>=1.20.0)", "mypy-boto3-mediatailor (>=1.20.0)", "mypy-boto3-memorydb (>=1.20.0)", "mypy-boto3-meteringmarketplace (>=1.20.0)", "mypy-boto3-mgh (>=1.20.0)", "mypy-boto3-mgn (>=1.20.0)", "mypy-boto3-migration-hub-refactor-spaces (>=1.20.0)", "mypy-boto3-migrationhub-config (>=1.20.0)", "mypy-boto3-migrationhubstrategy (>=1.20.0)", "mypy-boto3-mobile (>=1.20.0)", "mypy-boto3-mq (>=1.20.0)", "mypy-boto3-mturk (>=1.20.0)", "mypy-boto3-mwaa (>=1.20.0)", "mypy-boto3-neptune (>=1.20.0)", "mypy-boto3-network-firewall (>=1.20.0)", "mypy-boto3-networkmanager (>=1.20.0)", "mypy-boto3-nimble (>=1.20.0)", "mypy-boto3-opensearch (>=1.20.0)", "mypy-boto3-opsworks (>=1.20.0)", "mypy-boto3-opsworkscm (>=1.20.0)", "mypy-boto3-organizations (>=1.20.0)", "mypy-boto3-outposts (>=1.20.0)", "mypy-boto3-panorama (>=1.20.0)", "mypy-boto3-personalize (>=1.20.0)", "mypy-boto3-personalize-events (>=1.20.0)", "mypy-boto3-personalize-runtime (>=1.20.0)", "mypy-boto3-pi (>=1.20.0)", "mypy-boto3-pinpoint (>=1.20.0)", "mypy-boto3-pinpoint-email (>=1.20.0)", "mypy-boto3-pinpoint-sms-voice (>=1.20.0)", "mypy-boto3-polly (>=1.20.0)", "mypy-boto3-pricing (>=1.20.0)", "mypy-boto3-proton (>=1.20.0)", "mypy-boto3-qldb (>=1.20.0)", "mypy-boto3-qldb-session (>=1.20.0)", "mypy-boto3-quicksight (>=1.20.0)", "mypy-boto3-ram (>=1.20.0)", "mypy-boto3-rbin (>=1.20.0)", "mypy-boto3-rds (>=1.20.0)", "mypy-boto3-rds-data (>=1.20.0)", "mypy-boto3-redshift (>=1.20.0)", "mypy-boto3-redshift-data (>=1.20.0)", "mypy-boto3-rekognition (>=1.20.0)", "mypy-boto3-resiliencehub (>=1.20.0)", "mypy-boto3-resource-groups (>=1.20.0)", "mypy-boto3-resourcegroupstaggingapi (>=1.20.0)", "mypy-boto3-robomaker (>=1.20.0)", "mypy-boto3-route53 (>=1.20.0)", "mypy-boto3-route53-recovery-cluster (>=1.20.0)", "mypy-boto3-route53-recovery-control-config (>=1.20.0)", "mypy-boto3-route53-recovery-readiness (>=1.20.0)", "mypy-boto3-route53domains (>=1.20.0)", "mypy-boto3-route53resolver (>=1.20.0)", "mypy-boto3-rum (>=1.20.0)", "mypy-boto3-s3 (>=1.20.0)", "mypy-boto3-s3control (>=1.20.0)", "mypy-boto3-s3outposts (>=1.20.0)", "mypy-boto3-sagemaker (>=1.20.0)", "mypy-boto3-sagemaker-a2i-runtime (>=1.20.0)", "mypy-boto3-sagemaker-edge (>=1.20.0)", "mypy-boto3-sagemaker-featurestore-runtime (>=1.20.0)", "mypy-boto3-sagemaker-runtime (>=1.20.0)", "mypy-boto3-savingsplans (>=1.20.0)", "mypy-boto3-schemas (>=1.20.0)", "mypy-boto3-sdb (>=1.20.0)", "mypy-boto3-secretsmanager (>=1.20.0)", "mypy-boto3-securityhub (>=1.20.0)", "mypy-boto3-serverlessrepo (>=1.20.0)", "mypy-boto3-service-quotas (>=1.20.0)", "mypy-boto3-servicecatalog (>=1.20.0)", "mypy-boto3-servicecatalog-appregistry (>=1.20.0)", "mypy-boto3-servicediscovery (>=1.20.0)", "mypy-boto3-ses (>=1.20.0)", "mypy-boto3-sesv2 (>=1.20.0)", "mypy-boto3-shield (>=1.20.0)", "mypy-boto3-signer (>=1.20.0)", "mypy-boto3-sms (>=1.20.0)", "mypy-boto3-sms-voice (>=1.20.0)", "mypy-boto3-snow-device-management (>=1.20.0)", "mypy-boto3-snowball (>=1.20.0)", "mypy-boto3-sns (>=1.20.0)", "mypy-boto3-sqs (>=1.20.0)", "mypy-boto3-ssm (>=1.20.0)", "mypy-boto3-ssm-contacts (>=1.20.0)", "mypy-boto3-ssm-incidents (>=1.20.0)", "mypy-boto3-sso (>=1.20.0)", "mypy-boto3-sso-admin (>=1.20.0)", "mypy-boto3-sso-oidc (>=1.20.0)", "mypy-boto3-stepfunctions (>=1.20.0)", "mypy-boto3-storagegateway (>=1.20.0)", "mypy-boto3-sts (>=1.20.0)", "mypy-boto3-support (>=1.20.0)", "mypy-boto3-swf (>=1.20.0)", "mypy-boto3-synthetics (>=1.20.0)", "mypy-boto3-textract (>=1.20.0)", "mypy-boto3-timestream-query (>=1.20.0)", "mypy-boto3-timestream-write (>=1.20.0)", "mypy-boto3-transcribe (>=1.20.0)", "mypy-boto3-transfer (>=1.20.0)", "mypy-boto3-translate (>=1.20.0)", "mypy-boto3-voice-id (>=1.20.0)", "mypy-boto3-waf (>=1.20.0)", "mypy-boto3-waf-regional (>=1.20.0)", "mypy-boto3-wafv2 (>=1.20.0)", "mypy-boto3-wellarchitected (>=1.20.0)", "mypy-boto3-wisdom (>=1.20.0)", "mypy-boto3-workdocs (>=1.20.0)", "mypy-boto3-worklink (>=1.20.0)", "mypy-boto3-workmail (>=1.20.0)", "mypy-boto3-workmailmessageflow (>=1.20.0)", "mypy-boto3-workspaces (>=1.20.0)", "mypy-boto3-workspaces-web (>=1.20.0)", "mypy-boto3-xray (>=1.20.0)"]
-amp = ["mypy-boto3-amp (>=1.20.0)"]
-amplify = ["mypy-boto3-amplify (>=1.20.0)"]
-amplifybackend = ["mypy-boto3-amplifybackend (>=1.20.0)"]
-amplifyuibuilder = ["mypy-boto3-amplifyuibuilder (>=1.20.0)"]
-apigateway = ["mypy-boto3-apigateway (>=1.20.0)"]
-apigatewaymanagementapi = ["mypy-boto3-apigatewaymanagementapi (>=1.20.0)"]
-apigatewayv2 = ["mypy-boto3-apigatewayv2 (>=1.20.0)"]
-appconfig = ["mypy-boto3-appconfig (>=1.20.0)"]
-appconfigdata = ["mypy-boto3-appconfigdata (>=1.20.0)"]
-appflow = ["mypy-boto3-appflow (>=1.20.0)"]
-appintegrations = ["mypy-boto3-appintegrations (>=1.20.0)"]
-application-autoscaling = ["mypy-boto3-application-autoscaling (>=1.20.0)"]
-application-insights = ["mypy-boto3-application-insights (>=1.20.0)"]
-applicationcostprofiler = ["mypy-boto3-applicationcostprofiler (>=1.20.0)"]
-appmesh = ["mypy-boto3-appmesh (>=1.20.0)"]
-apprunner = ["mypy-boto3-apprunner (>=1.20.0)"]
-appstream = ["mypy-boto3-appstream (>=1.20.0)"]
-appsync = ["mypy-boto3-appsync (>=1.20.0)"]
-athena = ["mypy-boto3-athena (>=1.20.0)"]
-auditmanager = ["mypy-boto3-auditmanager (>=1.20.0)"]
-autoscaling = ["mypy-boto3-autoscaling (>=1.20.0)"]
-autoscaling-plans = ["mypy-boto3-autoscaling-plans (>=1.20.0)"]
-backup = ["mypy-boto3-backup (>=1.20.0)"]
-backup-gateway = ["mypy-boto3-backup-gateway (>=1.20.0)"]
-batch = ["mypy-boto3-batch (>=1.20.0)"]
-braket = ["mypy-boto3-braket (>=1.20.0)"]
-budgets = ["mypy-boto3-budgets (>=1.20.0)"]
-ce = ["mypy-boto3-ce (>=1.20.0)"]
-chime = ["mypy-boto3-chime (>=1.20.0)"]
-chime-sdk-identity = ["mypy-boto3-chime-sdk-identity (>=1.20.0)"]
-chime-sdk-meetings = ["mypy-boto3-chime-sdk-meetings (>=1.20.0)"]
-chime-sdk-messaging = ["mypy-boto3-chime-sdk-messaging (>=1.20.0)"]
-cloud9 = ["mypy-boto3-cloud9 (>=1.20.0)"]
-cloudcontrol = ["mypy-boto3-cloudcontrol (>=1.20.0)"]
-clouddirectory = ["mypy-boto3-clouddirectory (>=1.20.0)"]
-cloudformation = ["mypy-boto3-cloudformation (>=1.20.0)"]
-cloudfront = ["mypy-boto3-cloudfront (>=1.20.0)"]
-cloudhsm = ["mypy-boto3-cloudhsm (>=1.20.0)"]
-cloudhsmv2 = ["mypy-boto3-cloudhsmv2 (>=1.20.0)"]
-cloudsearch = ["mypy-boto3-cloudsearch (>=1.20.0)"]
-cloudsearchdomain = ["mypy-boto3-cloudsearchdomain (>=1.20.0)"]
-cloudtrail = ["mypy-boto3-cloudtrail (>=1.20.0)"]
-cloudwatch = ["mypy-boto3-cloudwatch (>=1.20.0)"]
-codeartifact = ["mypy-boto3-codeartifact (>=1.20.0)"]
-codebuild = ["mypy-boto3-codebuild (>=1.20.0)"]
-codecommit = ["mypy-boto3-codecommit (>=1.20.0)"]
-codedeploy = ["mypy-boto3-codedeploy (>=1.20.0)"]
-codeguru-reviewer = ["mypy-boto3-codeguru-reviewer (>=1.20.0)"]
-codeguruprofiler = ["mypy-boto3-codeguruprofiler (>=1.20.0)"]
-codepipeline = ["mypy-boto3-codepipeline (>=1.20.0)"]
-codestar = ["mypy-boto3-codestar (>=1.20.0)"]
-codestar-connections = ["mypy-boto3-codestar-connections (>=1.20.0)"]
-codestar-notifications = ["mypy-boto3-codestar-notifications (>=1.20.0)"]
-cognito-identity = ["mypy-boto3-cognito-identity (>=1.20.0)"]
-cognito-idp = ["mypy-boto3-cognito-idp (>=1.20.0)"]
-cognito-sync = ["mypy-boto3-cognito-sync (>=1.20.0)"]
-comprehend = ["mypy-boto3-comprehend (>=1.20.0)"]
-comprehendmedical = ["mypy-boto3-comprehendmedical (>=1.20.0)"]
-compute-optimizer = ["mypy-boto3-compute-optimizer (>=1.20.0)"]
-config = ["mypy-boto3-config (>=1.20.0)"]
-connect = ["mypy-boto3-connect (>=1.20.0)"]
-connect-contact-lens = ["mypy-boto3-connect-contact-lens (>=1.20.0)"]
-connectparticipant = ["mypy-boto3-connectparticipant (>=1.20.0)"]
-cur = ["mypy-boto3-cur (>=1.20.0)"]
-customer-profiles = ["mypy-boto3-customer-profiles (>=1.20.0)"]
-databrew = ["mypy-boto3-databrew (>=1.20.0)"]
-dataexchange = ["mypy-boto3-dataexchange (>=1.20.0)"]
-datapipeline = ["mypy-boto3-datapipeline (>=1.20.0)"]
-datasync = ["mypy-boto3-datasync (>=1.20.0)"]
-dax = ["mypy-boto3-dax (>=1.20.0)"]
-detective = ["mypy-boto3-detective (>=1.20.0)"]
-devicefarm = ["mypy-boto3-devicefarm (>=1.20.0)"]
-devops-guru = ["mypy-boto3-devops-guru (>=1.20.0)"]
-directconnect = ["mypy-boto3-directconnect (>=1.20.0)"]
-discovery = ["mypy-boto3-discovery (>=1.20.0)"]
-dlm = ["mypy-boto3-dlm (>=1.20.0)"]
-dms = ["mypy-boto3-dms (>=1.20.0)"]
-docdb = ["mypy-boto3-docdb (>=1.20.0)"]
-drs = ["mypy-boto3-drs (>=1.20.0)"]
-ds = ["mypy-boto3-ds (>=1.20.0)"]
-dynamodb = ["mypy-boto3-dynamodb (>=1.20.0)"]
-dynamodbstreams = ["mypy-boto3-dynamodbstreams (>=1.20.0)"]
-ebs = ["mypy-boto3-ebs (>=1.20.0)"]
-ec2 = ["mypy-boto3-ec2 (>=1.20.0)"]
-ec2-instance-connect = ["mypy-boto3-ec2-instance-connect (>=1.20.0)"]
-ecr = ["mypy-boto3-ecr (>=1.20.0)"]
-ecr-public = ["mypy-boto3-ecr-public (>=1.20.0)"]
-ecs = ["mypy-boto3-ecs (>=1.20.0)"]
-efs = ["mypy-boto3-efs (>=1.20.0)"]
-eks = ["mypy-boto3-eks (>=1.20.0)"]
-elastic-inference = ["mypy-boto3-elastic-inference (>=1.20.0)"]
-elasticache = ["mypy-boto3-elasticache (>=1.20.0)"]
-elasticbeanstalk = ["mypy-boto3-elasticbeanstalk (>=1.20.0)"]
-elastictranscoder = ["mypy-boto3-elastictranscoder (>=1.20.0)"]
-elb = ["mypy-boto3-elb (>=1.20.0)"]
-elbv2 = ["mypy-boto3-elbv2 (>=1.20.0)"]
-emr = ["mypy-boto3-emr (>=1.20.0)"]
-emr-containers = ["mypy-boto3-emr-containers (>=1.20.0)"]
-es = ["mypy-boto3-es (>=1.20.0)"]
-essential = ["mypy-boto3-cloudformation (>=1.20.0)", "mypy-boto3-dynamodb (>=1.20.0)", "mypy-boto3-ec2 (>=1.20.0)", "mypy-boto3-lambda (>=1.20.0)", "mypy-boto3-rds (>=1.20.0)", "mypy-boto3-s3 (>=1.20.0)", "mypy-boto3-sqs (>=1.20.0)"]
-events = ["mypy-boto3-events (>=1.20.0)"]
-evidently = ["mypy-boto3-evidently (>=1.20.0)"]
-finspace = ["mypy-boto3-finspace (>=1.20.0)"]
-finspace-data = ["mypy-boto3-finspace-data (>=1.20.0)"]
-firehose = ["mypy-boto3-firehose (>=1.20.0)"]
-fis = ["mypy-boto3-fis (>=1.20.0)"]
-fms = ["mypy-boto3-fms (>=1.20.0)"]
-forecast = ["mypy-boto3-forecast (>=1.20.0)"]
-forecastquery = ["mypy-boto3-forecastquery (>=1.20.0)"]
-frauddetector = ["mypy-boto3-frauddetector (>=1.20.0)"]
-fsx = ["mypy-boto3-fsx (>=1.20.0)"]
-gamelift = ["mypy-boto3-gamelift (>=1.20.0)"]
-glacier = ["mypy-boto3-glacier (>=1.20.0)"]
-globalaccelerator = ["mypy-boto3-globalaccelerator (>=1.20.0)"]
-glue = ["mypy-boto3-glue (>=1.20.0)"]
-grafana = ["mypy-boto3-grafana (>=1.20.0)"]
-greengrass = ["mypy-boto3-greengrass (>=1.20.0)"]
-greengrassv2 = ["mypy-boto3-greengrassv2 (>=1.20.0)"]
-groundstation = ["mypy-boto3-groundstation (>=1.20.0)"]
-guardduty = ["mypy-boto3-guardduty (>=1.20.0)"]
-health = ["mypy-boto3-health (>=1.20.0)"]
-healthlake = ["mypy-boto3-healthlake (>=1.20.0)"]
-honeycode = ["mypy-boto3-honeycode (>=1.20.0)"]
-iam = ["mypy-boto3-iam (>=1.20.0)"]
-identitystore = ["mypy-boto3-identitystore (>=1.20.0)"]
-imagebuilder = ["mypy-boto3-imagebuilder (>=1.20.0)"]
-importexport = ["mypy-boto3-importexport (>=1.20.0)"]
-inspector = ["mypy-boto3-inspector (>=1.20.0)"]
-inspector2 = ["mypy-boto3-inspector2 (>=1.20.0)"]
-iot = ["mypy-boto3-iot (>=1.20.0)"]
-iot-data = ["mypy-boto3-iot-data (>=1.20.0)"]
-iot-jobs-data = ["mypy-boto3-iot-jobs-data (>=1.20.0)"]
-iot1click-devices = ["mypy-boto3-iot1click-devices (>=1.20.0)"]
-iot1click-projects = ["mypy-boto3-iot1click-projects (>=1.20.0)"]
-iotanalytics = ["mypy-boto3-iotanalytics (>=1.20.0)"]
-iotdeviceadvisor = ["mypy-boto3-iotdeviceadvisor (>=1.20.0)"]
-iotevents = ["mypy-boto3-iotevents (>=1.20.0)"]
-iotevents-data = ["mypy-boto3-iotevents-data (>=1.20.0)"]
-iotfleethub = ["mypy-boto3-iotfleethub (>=1.20.0)"]
-iotsecuretunneling = ["mypy-boto3-iotsecuretunneling (>=1.20.0)"]
-iotsitewise = ["mypy-boto3-iotsitewise (>=1.20.0)"]
-iotthingsgraph = ["mypy-boto3-iotthingsgraph (>=1.20.0)"]
-iottwinmaker = ["mypy-boto3-iottwinmaker (>=1.20.0)"]
-iotwireless = ["mypy-boto3-iotwireless (>=1.20.0)"]
-ivs = ["mypy-boto3-ivs (>=1.20.0)"]
-kafka = ["mypy-boto3-kafka (>=1.20.0)"]
-kafkaconnect = ["mypy-boto3-kafkaconnect (>=1.20.0)"]
-kendra = ["mypy-boto3-kendra (>=1.20.0)"]
-kinesis = ["mypy-boto3-kinesis (>=1.20.0)"]
-kinesis-video-archived-media = ["mypy-boto3-kinesis-video-archived-media (>=1.20.0)"]
-kinesis-video-media = ["mypy-boto3-kinesis-video-media (>=1.20.0)"]
-kinesis-video-signaling = ["mypy-boto3-kinesis-video-signaling (>=1.20.0)"]
-kinesisanalytics = ["mypy-boto3-kinesisanalytics (>=1.20.0)"]
-kinesisanalyticsv2 = ["mypy-boto3-kinesisanalyticsv2 (>=1.20.0)"]
-kinesisvideo = ["mypy-boto3-kinesisvideo (>=1.20.0)"]
-kms = ["mypy-boto3-kms (>=1.20.0)"]
-lakeformation = ["mypy-boto3-lakeformation (>=1.20.0)"]
-lambda = ["mypy-boto3-lambda (>=1.20.0)"]
-lex-models = ["mypy-boto3-lex-models (>=1.20.0)"]
-lex-runtime = ["mypy-boto3-lex-runtime (>=1.20.0)"]
-lexv2-models = ["mypy-boto3-lexv2-models (>=1.20.0)"]
-lexv2-runtime = ["mypy-boto3-lexv2-runtime (>=1.20.0)"]
-license-manager = ["mypy-boto3-license-manager (>=1.20.0)"]
-lightsail = ["mypy-boto3-lightsail (>=1.20.0)"]
-location = ["mypy-boto3-location (>=1.20.0)"]
-logs = ["mypy-boto3-logs (>=1.20.0)"]
-lookoutequipment = ["mypy-boto3-lookoutequipment (>=1.20.0)"]
-lookoutmetrics = ["mypy-boto3-lookoutmetrics (>=1.20.0)"]
-lookoutvision = ["mypy-boto3-lookoutvision (>=1.20.0)"]
-machinelearning = ["mypy-boto3-machinelearning (>=1.20.0)"]
-macie = ["mypy-boto3-macie (>=1.20.0)"]
-macie2 = ["mypy-boto3-macie2 (>=1.20.0)"]
-managedblockchain = ["mypy-boto3-managedblockchain (>=1.20.0)"]
-marketplace-catalog = ["mypy-boto3-marketplace-catalog (>=1.20.0)"]
-marketplace-entitlement = ["mypy-boto3-marketplace-entitlement (>=1.20.0)"]
-marketplacecommerceanalytics = ["mypy-boto3-marketplacecommerceanalytics (>=1.20.0)"]
-mediaconnect = ["mypy-boto3-mediaconnect (>=1.20.0)"]
-mediaconvert = ["mypy-boto3-mediaconvert (>=1.20.0)"]
-medialive = ["mypy-boto3-medialive (>=1.20.0)"]
-mediapackage = ["mypy-boto3-mediapackage (>=1.20.0)"]
-mediapackage-vod = ["mypy-boto3-mediapackage-vod (>=1.20.0)"]
-mediastore = ["mypy-boto3-mediastore (>=1.20.0)"]
-mediastore-data = ["mypy-boto3-mediastore-data (>=1.20.0)"]
-mediatailor = ["mypy-boto3-mediatailor (>=1.20.0)"]
-memorydb = ["mypy-boto3-memorydb (>=1.20.0)"]
-meteringmarketplace = ["mypy-boto3-meteringmarketplace (>=1.20.0)"]
-mgh = ["mypy-boto3-mgh (>=1.20.0)"]
-mgn = ["mypy-boto3-mgn (>=1.20.0)"]
-migration-hub-refactor-spaces = ["mypy-boto3-migration-hub-refactor-spaces (>=1.20.0)"]
-migrationhub-config = ["mypy-boto3-migrationhub-config (>=1.20.0)"]
-migrationhubstrategy = ["mypy-boto3-migrationhubstrategy (>=1.20.0)"]
-mobile = ["mypy-boto3-mobile (>=1.20.0)"]
-mq = ["mypy-boto3-mq (>=1.20.0)"]
-mturk = ["mypy-boto3-mturk (>=1.20.0)"]
-mwaa = ["mypy-boto3-mwaa (>=1.20.0)"]
-neptune = ["mypy-boto3-neptune (>=1.20.0)"]
-network-firewall = ["mypy-boto3-network-firewall (>=1.20.0)"]
-networkmanager = ["mypy-boto3-networkmanager (>=1.20.0)"]
-nimble = ["mypy-boto3-nimble (>=1.20.0)"]
-opensearch = ["mypy-boto3-opensearch (>=1.20.0)"]
-opsworks = ["mypy-boto3-opsworks (>=1.20.0)"]
-opsworkscm = ["mypy-boto3-opsworkscm (>=1.20.0)"]
-organizations = ["mypy-boto3-organizations (>=1.20.0)"]
-outposts = ["mypy-boto3-outposts (>=1.20.0)"]
-panorama = ["mypy-boto3-panorama (>=1.20.0)"]
-personalize = ["mypy-boto3-personalize (>=1.20.0)"]
-personalize-events = ["mypy-boto3-personalize-events (>=1.20.0)"]
-personalize-runtime = ["mypy-boto3-personalize-runtime (>=1.20.0)"]
-pi = ["mypy-boto3-pi (>=1.20.0)"]
-pinpoint = ["mypy-boto3-pinpoint (>=1.20.0)"]
-pinpoint-email = ["mypy-boto3-pinpoint-email (>=1.20.0)"]
-pinpoint-sms-voice = ["mypy-boto3-pinpoint-sms-voice (>=1.20.0)"]
-polly = ["mypy-boto3-polly (>=1.20.0)"]
-pricing = ["mypy-boto3-pricing (>=1.20.0)"]
-proton = ["mypy-boto3-proton (>=1.20.0)"]
-qldb = ["mypy-boto3-qldb (>=1.20.0)"]
-qldb-session = ["mypy-boto3-qldb-session (>=1.20.0)"]
-quicksight = ["mypy-boto3-quicksight (>=1.20.0)"]
-ram = ["mypy-boto3-ram (>=1.20.0)"]
-rbin = ["mypy-boto3-rbin (>=1.20.0)"]
-rds = ["mypy-boto3-rds (>=1.20.0)"]
-rds-data = ["mypy-boto3-rds-data (>=1.20.0)"]
-redshift = ["mypy-boto3-redshift (>=1.20.0)"]
-redshift-data = ["mypy-boto3-redshift-data (>=1.20.0)"]
-rekognition = ["mypy-boto3-rekognition (>=1.20.0)"]
-resiliencehub = ["mypy-boto3-resiliencehub (>=1.20.0)"]
-resource-groups = ["mypy-boto3-resource-groups (>=1.20.0)"]
-resourcegroupstaggingapi = ["mypy-boto3-resourcegroupstaggingapi (>=1.20.0)"]
-robomaker = ["mypy-boto3-robomaker (>=1.20.0)"]
-route53 = ["mypy-boto3-route53 (>=1.20.0)"]
-route53-recovery-cluster = ["mypy-boto3-route53-recovery-cluster (>=1.20.0)"]
-route53-recovery-control-config = ["mypy-boto3-route53-recovery-control-config (>=1.20.0)"]
-route53-recovery-readiness = ["mypy-boto3-route53-recovery-readiness (>=1.20.0)"]
-route53domains = ["mypy-boto3-route53domains (>=1.20.0)"]
-route53resolver = ["mypy-boto3-route53resolver (>=1.20.0)"]
-rum = ["mypy-boto3-rum (>=1.20.0)"]
-s3 = ["mypy-boto3-s3 (>=1.20.0)"]
-s3control = ["mypy-boto3-s3control (>=1.20.0)"]
-s3outposts = ["mypy-boto3-s3outposts (>=1.20.0)"]
-sagemaker = ["mypy-boto3-sagemaker (>=1.20.0)"]
-sagemaker-a2i-runtime = ["mypy-boto3-sagemaker-a2i-runtime (>=1.20.0)"]
-sagemaker-edge = ["mypy-boto3-sagemaker-edge (>=1.20.0)"]
-sagemaker-featurestore-runtime = ["mypy-boto3-sagemaker-featurestore-runtime (>=1.20.0)"]
-sagemaker-runtime = ["mypy-boto3-sagemaker-runtime (>=1.20.0)"]
-savingsplans = ["mypy-boto3-savingsplans (>=1.20.0)"]
-schemas = ["mypy-boto3-schemas (>=1.20.0)"]
-sdb = ["mypy-boto3-sdb (>=1.20.0)"]
-secretsmanager = ["mypy-boto3-secretsmanager (>=1.20.0)"]
-securityhub = ["mypy-boto3-securityhub (>=1.20.0)"]
-serverlessrepo = ["mypy-boto3-serverlessrepo (>=1.20.0)"]
-service-quotas = ["mypy-boto3-service-quotas (>=1.20.0)"]
-servicecatalog = ["mypy-boto3-servicecatalog (>=1.20.0)"]
-servicecatalog-appregistry = ["mypy-boto3-servicecatalog-appregistry (>=1.20.0)"]
-servicediscovery = ["mypy-boto3-servicediscovery (>=1.20.0)"]
-ses = ["mypy-boto3-ses (>=1.20.0)"]
-sesv2 = ["mypy-boto3-sesv2 (>=1.20.0)"]
-shield = ["mypy-boto3-shield (>=1.20.0)"]
-signer = ["mypy-boto3-signer (>=1.20.0)"]
-sms = ["mypy-boto3-sms (>=1.20.0)"]
-sms-voice = ["mypy-boto3-sms-voice (>=1.20.0)"]
-snow-device-management = ["mypy-boto3-snow-device-management (>=1.20.0)"]
-snowball = ["mypy-boto3-snowball (>=1.20.0)"]
-sns = ["mypy-boto3-sns (>=1.20.0)"]
-sqs = ["mypy-boto3-sqs (>=1.20.0)"]
-ssm = ["mypy-boto3-ssm (>=1.20.0)"]
-ssm-contacts = ["mypy-boto3-ssm-contacts (>=1.20.0)"]
-ssm-incidents = ["mypy-boto3-ssm-incidents (>=1.20.0)"]
-sso = ["mypy-boto3-sso (>=1.20.0)"]
-sso-admin = ["mypy-boto3-sso-admin (>=1.20.0)"]
-sso-oidc = ["mypy-boto3-sso-oidc (>=1.20.0)"]
-stepfunctions = ["mypy-boto3-stepfunctions (>=1.20.0)"]
-storagegateway = ["mypy-boto3-storagegateway (>=1.20.0)"]
-sts = ["mypy-boto3-sts (>=1.20.0)"]
-support = ["mypy-boto3-support (>=1.20.0)"]
-swf = ["mypy-boto3-swf (>=1.20.0)"]
-synthetics = ["mypy-boto3-synthetics (>=1.20.0)"]
-textract = ["mypy-boto3-textract (>=1.20.0)"]
-timestream-query = ["mypy-boto3-timestream-query (>=1.20.0)"]
-timestream-write = ["mypy-boto3-timestream-write (>=1.20.0)"]
-transcribe = ["mypy-boto3-transcribe (>=1.20.0)"]
-transfer = ["mypy-boto3-transfer (>=1.20.0)"]
-translate = ["mypy-boto3-translate (>=1.20.0)"]
-voice-id = ["mypy-boto3-voice-id (>=1.20.0)"]
-waf = ["mypy-boto3-waf (>=1.20.0)"]
-waf-regional = ["mypy-boto3-waf-regional (>=1.20.0)"]
-wafv2 = ["mypy-boto3-wafv2 (>=1.20.0)"]
-wellarchitected = ["mypy-boto3-wellarchitected (>=1.20.0)"]
-wisdom = ["mypy-boto3-wisdom (>=1.20.0)"]
-workdocs = ["mypy-boto3-workdocs (>=1.20.0)"]
-worklink = ["mypy-boto3-worklink (>=1.20.0)"]
-workmail = ["mypy-boto3-workmail (>=1.20.0)"]
-workmailmessageflow = ["mypy-boto3-workmailmessageflow (>=1.20.0)"]
-workspaces = ["mypy-boto3-workspaces (>=1.20.0)"]
-workspaces-web = ["mypy-boto3-workspaces-web (>=1.20.0)"]
-xray = ["mypy-boto3-xray (>=1.20.0)"]
+accessanalyzer = ["mypy-boto3-accessanalyzer (>=1.21.0)"]
+account = ["mypy-boto3-account (>=1.21.0)"]
+acm = ["mypy-boto3-acm (>=1.21.0)"]
+acm-pca = ["mypy-boto3-acm-pca (>=1.21.0)"]
+alexaforbusiness = ["mypy-boto3-alexaforbusiness (>=1.21.0)"]
+all = ["mypy-boto3-accessanalyzer (>=1.21.0)", "mypy-boto3-account (>=1.21.0)", "mypy-boto3-acm (>=1.21.0)", "mypy-boto3-acm-pca (>=1.21.0)", "mypy-boto3-alexaforbusiness (>=1.21.0)", "mypy-boto3-amp (>=1.21.0)", "mypy-boto3-amplify (>=1.21.0)", "mypy-boto3-amplifybackend (>=1.21.0)", "mypy-boto3-amplifyuibuilder (>=1.21.0)", "mypy-boto3-apigateway (>=1.21.0)", "mypy-boto3-apigatewaymanagementapi (>=1.21.0)", "mypy-boto3-apigatewayv2 (>=1.21.0)", "mypy-boto3-appconfig (>=1.21.0)", "mypy-boto3-appconfigdata (>=1.21.0)", "mypy-boto3-appflow (>=1.21.0)", "mypy-boto3-appintegrations (>=1.21.0)", "mypy-boto3-application-autoscaling (>=1.21.0)", "mypy-boto3-application-insights (>=1.21.0)", "mypy-boto3-applicationcostprofiler (>=1.21.0)", "mypy-boto3-appmesh (>=1.21.0)", "mypy-boto3-apprunner (>=1.21.0)", "mypy-boto3-appstream (>=1.21.0)", "mypy-boto3-appsync (>=1.21.0)", "mypy-boto3-athena (>=1.21.0)", "mypy-boto3-auditmanager (>=1.21.0)", "mypy-boto3-autoscaling (>=1.21.0)", "mypy-boto3-autoscaling-plans (>=1.21.0)", "mypy-boto3-backup (>=1.21.0)", "mypy-boto3-backup-gateway (>=1.21.0)", "mypy-boto3-batch (>=1.21.0)", "mypy-boto3-braket (>=1.21.0)", "mypy-boto3-budgets (>=1.21.0)", "mypy-boto3-ce (>=1.21.0)", "mypy-boto3-chime (>=1.21.0)", "mypy-boto3-chime-sdk-identity (>=1.21.0)", "mypy-boto3-chime-sdk-meetings (>=1.21.0)", "mypy-boto3-chime-sdk-messaging (>=1.21.0)", "mypy-boto3-cloud9 (>=1.21.0)", "mypy-boto3-cloudcontrol (>=1.21.0)", "mypy-boto3-clouddirectory (>=1.21.0)", "mypy-boto3-cloudformation (>=1.21.0)", "mypy-boto3-cloudfront (>=1.21.0)", "mypy-boto3-cloudhsm (>=1.21.0)", "mypy-boto3-cloudhsmv2 (>=1.21.0)", "mypy-boto3-cloudsearch (>=1.21.0)", "mypy-boto3-cloudsearchdomain (>=1.21.0)", "mypy-boto3-cloudtrail (>=1.21.0)", "mypy-boto3-cloudwatch (>=1.21.0)", "mypy-boto3-codeartifact (>=1.21.0)", "mypy-boto3-codebuild (>=1.21.0)", "mypy-boto3-codecommit (>=1.21.0)", "mypy-boto3-codedeploy (>=1.21.0)", "mypy-boto3-codeguru-reviewer (>=1.21.0)", "mypy-boto3-codeguruprofiler (>=1.21.0)", "mypy-boto3-codepipeline (>=1.21.0)", "mypy-boto3-codestar (>=1.21.0)", "mypy-boto3-codestar-connections (>=1.21.0)", "mypy-boto3-codestar-notifications (>=1.21.0)", "mypy-boto3-cognito-identity (>=1.21.0)", "mypy-boto3-cognito-idp (>=1.21.0)", "mypy-boto3-cognito-sync (>=1.21.0)", "mypy-boto3-comprehend (>=1.21.0)", "mypy-boto3-comprehendmedical (>=1.21.0)", "mypy-boto3-compute-optimizer (>=1.21.0)", "mypy-boto3-config (>=1.21.0)", "mypy-boto3-connect (>=1.21.0)", "mypy-boto3-connect-contact-lens (>=1.21.0)", "mypy-boto3-connectparticipant (>=1.21.0)", "mypy-boto3-cur (>=1.21.0)", "mypy-boto3-customer-profiles (>=1.21.0)", "mypy-boto3-databrew (>=1.21.0)", "mypy-boto3-dataexchange (>=1.21.0)", "mypy-boto3-datapipeline (>=1.21.0)", "mypy-boto3-datasync (>=1.21.0)", "mypy-boto3-dax (>=1.21.0)", "mypy-boto3-detective (>=1.21.0)", "mypy-boto3-devicefarm (>=1.21.0)", "mypy-boto3-devops-guru (>=1.21.0)", "mypy-boto3-directconnect (>=1.21.0)", "mypy-boto3-discovery (>=1.21.0)", "mypy-boto3-dlm (>=1.21.0)", "mypy-boto3-dms (>=1.21.0)", "mypy-boto3-docdb (>=1.21.0)", "mypy-boto3-drs (>=1.21.0)", "mypy-boto3-ds (>=1.21.0)", "mypy-boto3-dynamodb (>=1.21.0)", "mypy-boto3-dynamodbstreams (>=1.21.0)", "mypy-boto3-ebs (>=1.21.0)", "mypy-boto3-ec2 (>=1.21.0)", "mypy-boto3-ec2-instance-connect (>=1.21.0)", "mypy-boto3-ecr (>=1.21.0)", "mypy-boto3-ecr-public (>=1.21.0)", "mypy-boto3-ecs (>=1.21.0)", "mypy-boto3-efs (>=1.21.0)", "mypy-boto3-eks (>=1.21.0)", "mypy-boto3-elastic-inference (>=1.21.0)", "mypy-boto3-elasticache (>=1.21.0)", "mypy-boto3-elasticbeanstalk (>=1.21.0)", "mypy-boto3-elastictranscoder (>=1.21.0)", "mypy-boto3-elb (>=1.21.0)", "mypy-boto3-elbv2 (>=1.21.0)", "mypy-boto3-emr (>=1.21.0)", "mypy-boto3-emr-containers (>=1.21.0)", "mypy-boto3-es (>=1.21.0)", "mypy-boto3-events (>=1.21.0)", "mypy-boto3-evidently (>=1.21.0)", "mypy-boto3-finspace (>=1.21.0)", "mypy-boto3-finspace-data (>=1.21.0)", "mypy-boto3-firehose (>=1.21.0)", "mypy-boto3-fis (>=1.21.0)", "mypy-boto3-fms (>=1.21.0)", "mypy-boto3-forecast (>=1.21.0)", "mypy-boto3-forecastquery (>=1.21.0)", "mypy-boto3-frauddetector (>=1.21.0)", "mypy-boto3-fsx (>=1.21.0)", "mypy-boto3-gamelift (>=1.21.0)", "mypy-boto3-glacier (>=1.21.0)", "mypy-boto3-globalaccelerator (>=1.21.0)", "mypy-boto3-glue (>=1.21.0)", "mypy-boto3-grafana (>=1.21.0)", "mypy-boto3-greengrass (>=1.21.0)", "mypy-boto3-greengrassv2 (>=1.21.0)", "mypy-boto3-groundstation (>=1.21.0)", "mypy-boto3-guardduty (>=1.21.0)", "mypy-boto3-health (>=1.21.0)", "mypy-boto3-healthlake (>=1.21.0)", "mypy-boto3-honeycode (>=1.21.0)", "mypy-boto3-iam (>=1.21.0)", "mypy-boto3-identitystore (>=1.21.0)", "mypy-boto3-imagebuilder (>=1.21.0)", "mypy-boto3-importexport (>=1.21.0)", "mypy-boto3-inspector (>=1.21.0)", "mypy-boto3-inspector2 (>=1.21.0)", "mypy-boto3-iot (>=1.21.0)", "mypy-boto3-iot-data (>=1.21.0)", "mypy-boto3-iot-jobs-data (>=1.21.0)", "mypy-boto3-iot1click-devices (>=1.21.0)", "mypy-boto3-iot1click-projects (>=1.21.0)", "mypy-boto3-iotanalytics (>=1.21.0)", "mypy-boto3-iotdeviceadvisor (>=1.21.0)", "mypy-boto3-iotevents (>=1.21.0)", "mypy-boto3-iotevents-data (>=1.21.0)", "mypy-boto3-iotfleethub (>=1.21.0)", "mypy-boto3-iotsecuretunneling (>=1.21.0)", "mypy-boto3-iotsitewise (>=1.21.0)", "mypy-boto3-iotthingsgraph (>=1.21.0)", "mypy-boto3-iottwinmaker (>=1.21.0)", "mypy-boto3-iotwireless (>=1.21.0)", "mypy-boto3-ivs (>=1.21.0)", "mypy-boto3-kafka (>=1.21.0)", "mypy-boto3-kafkaconnect (>=1.21.0)", "mypy-boto3-kendra (>=1.21.0)", "mypy-boto3-kinesis (>=1.21.0)", "mypy-boto3-kinesis-video-archived-media (>=1.21.0)", "mypy-boto3-kinesis-video-media (>=1.21.0)", "mypy-boto3-kinesis-video-signaling (>=1.21.0)", "mypy-boto3-kinesisanalytics (>=1.21.0)", "mypy-boto3-kinesisanalyticsv2 (>=1.21.0)", "mypy-boto3-kinesisvideo (>=1.21.0)", "mypy-boto3-kms (>=1.21.0)", "mypy-boto3-lakeformation (>=1.21.0)", "mypy-boto3-lambda (>=1.21.0)", "mypy-boto3-lex-models (>=1.21.0)", "mypy-boto3-lex-runtime (>=1.21.0)", "mypy-boto3-lexv2-models (>=1.21.0)", "mypy-boto3-lexv2-runtime (>=1.21.0)", "mypy-boto3-license-manager (>=1.21.0)", "mypy-boto3-lightsail (>=1.21.0)", "mypy-boto3-location (>=1.21.0)", "mypy-boto3-logs (>=1.21.0)", "mypy-boto3-lookoutequipment (>=1.21.0)", "mypy-boto3-lookoutmetrics (>=1.21.0)", "mypy-boto3-lookoutvision (>=1.21.0)", "mypy-boto3-machinelearning (>=1.21.0)", "mypy-boto3-macie (>=1.21.0)", "mypy-boto3-macie2 (>=1.21.0)", "mypy-boto3-managedblockchain (>=1.21.0)", "mypy-boto3-marketplace-catalog (>=1.21.0)", "mypy-boto3-marketplace-entitlement (>=1.21.0)", "mypy-boto3-marketplacecommerceanalytics (>=1.21.0)", "mypy-boto3-mediaconnect (>=1.21.0)", "mypy-boto3-mediaconvert (>=1.21.0)", "mypy-boto3-medialive (>=1.21.0)", "mypy-boto3-mediapackage (>=1.21.0)", "mypy-boto3-mediapackage-vod (>=1.21.0)", "mypy-boto3-mediastore (>=1.21.0)", "mypy-boto3-mediastore-data (>=1.21.0)", "mypy-boto3-mediatailor (>=1.21.0)", "mypy-boto3-memorydb (>=1.21.0)", "mypy-boto3-meteringmarketplace (>=1.21.0)", "mypy-boto3-mgh (>=1.21.0)", "mypy-boto3-mgn (>=1.21.0)", "mypy-boto3-migration-hub-refactor-spaces (>=1.21.0)", "mypy-boto3-migrationhub-config (>=1.21.0)", "mypy-boto3-migrationhubstrategy (>=1.21.0)", "mypy-boto3-mobile (>=1.21.0)", "mypy-boto3-mq (>=1.21.0)", "mypy-boto3-mturk (>=1.21.0)", "mypy-boto3-mwaa (>=1.21.0)", "mypy-boto3-neptune (>=1.21.0)", "mypy-boto3-network-firewall (>=1.21.0)", "mypy-boto3-networkmanager (>=1.21.0)", "mypy-boto3-nimble (>=1.21.0)", "mypy-boto3-opensearch (>=1.21.0)", "mypy-boto3-opsworks (>=1.21.0)", "mypy-boto3-opsworkscm (>=1.21.0)", "mypy-boto3-organizations (>=1.21.0)", "mypy-boto3-outposts (>=1.21.0)", "mypy-boto3-panorama (>=1.21.0)", "mypy-boto3-personalize (>=1.21.0)", "mypy-boto3-personalize-events (>=1.21.0)", "mypy-boto3-personalize-runtime (>=1.21.0)", "mypy-boto3-pi (>=1.21.0)", "mypy-boto3-pinpoint (>=1.21.0)", "mypy-boto3-pinpoint-email (>=1.21.0)", "mypy-boto3-pinpoint-sms-voice (>=1.21.0)", "mypy-boto3-polly (>=1.21.0)", "mypy-boto3-pricing (>=1.21.0)", "mypy-boto3-proton (>=1.21.0)", "mypy-boto3-qldb (>=1.21.0)", "mypy-boto3-qldb-session (>=1.21.0)", "mypy-boto3-quicksight (>=1.21.0)", "mypy-boto3-ram (>=1.21.0)", "mypy-boto3-rbin (>=1.21.0)", "mypy-boto3-rds (>=1.21.0)", "mypy-boto3-rds-data (>=1.21.0)", "mypy-boto3-redshift (>=1.21.0)", "mypy-boto3-redshift-data (>=1.21.0)", "mypy-boto3-rekognition (>=1.21.0)", "mypy-boto3-resiliencehub (>=1.21.0)", "mypy-boto3-resource-groups (>=1.21.0)", "mypy-boto3-resourcegroupstaggingapi (>=1.21.0)", "mypy-boto3-robomaker (>=1.21.0)", "mypy-boto3-route53 (>=1.21.0)", "mypy-boto3-route53-recovery-cluster (>=1.21.0)", "mypy-boto3-route53-recovery-control-config (>=1.21.0)", "mypy-boto3-route53-recovery-readiness (>=1.21.0)", "mypy-boto3-route53domains (>=1.21.0)", "mypy-boto3-route53resolver (>=1.21.0)", "mypy-boto3-rum (>=1.21.0)", "mypy-boto3-s3 (>=1.21.0)", "mypy-boto3-s3control (>=1.21.0)", "mypy-boto3-s3outposts (>=1.21.0)", "mypy-boto3-sagemaker (>=1.21.0)", "mypy-boto3-sagemaker-a2i-runtime (>=1.21.0)", "mypy-boto3-sagemaker-edge (>=1.21.0)", "mypy-boto3-sagemaker-featurestore-runtime (>=1.21.0)", "mypy-boto3-sagemaker-runtime (>=1.21.0)", "mypy-boto3-savingsplans (>=1.21.0)", "mypy-boto3-schemas (>=1.21.0)", "mypy-boto3-sdb (>=1.21.0)", "mypy-boto3-secretsmanager (>=1.21.0)", "mypy-boto3-securityhub (>=1.21.0)", "mypy-boto3-serverlessrepo (>=1.21.0)", "mypy-boto3-service-quotas (>=1.21.0)", "mypy-boto3-servicecatalog (>=1.21.0)", "mypy-boto3-servicecatalog-appregistry (>=1.21.0)", "mypy-boto3-servicediscovery (>=1.21.0)", "mypy-boto3-ses (>=1.21.0)", "mypy-boto3-sesv2 (>=1.21.0)", "mypy-boto3-shield (>=1.21.0)", "mypy-boto3-signer (>=1.21.0)", "mypy-boto3-sms (>=1.21.0)", "mypy-boto3-sms-voice (>=1.21.0)", "mypy-boto3-snow-device-management (>=1.21.0)", "mypy-boto3-snowball (>=1.21.0)", "mypy-boto3-sns (>=1.21.0)", "mypy-boto3-sqs (>=1.21.0)", "mypy-boto3-ssm (>=1.21.0)", "mypy-boto3-ssm-contacts (>=1.21.0)", "mypy-boto3-ssm-incidents (>=1.21.0)", "mypy-boto3-sso (>=1.21.0)", "mypy-boto3-sso-admin (>=1.21.0)", "mypy-boto3-sso-oidc (>=1.21.0)", "mypy-boto3-stepfunctions (>=1.21.0)", "mypy-boto3-storagegateway (>=1.21.0)", "mypy-boto3-sts (>=1.21.0)", "mypy-boto3-support (>=1.21.0)", "mypy-boto3-swf (>=1.21.0)", "mypy-boto3-synthetics (>=1.21.0)", "mypy-boto3-textract (>=1.21.0)", "mypy-boto3-timestream-query (>=1.21.0)", "mypy-boto3-timestream-write (>=1.21.0)", "mypy-boto3-transcribe (>=1.21.0)", "mypy-boto3-transfer (>=1.21.0)", "mypy-boto3-translate (>=1.21.0)", "mypy-boto3-voice-id (>=1.21.0)", "mypy-boto3-waf (>=1.21.0)", "mypy-boto3-waf-regional (>=1.21.0)", "mypy-boto3-wafv2 (>=1.21.0)", "mypy-boto3-wellarchitected (>=1.21.0)", "mypy-boto3-wisdom (>=1.21.0)", "mypy-boto3-workdocs (>=1.21.0)", "mypy-boto3-worklink (>=1.21.0)", "mypy-boto3-workmail (>=1.21.0)", "mypy-boto3-workmailmessageflow (>=1.21.0)", "mypy-boto3-workspaces (>=1.21.0)", "mypy-boto3-workspaces-web (>=1.21.0)", "mypy-boto3-xray (>=1.21.0)"]
+amp = ["mypy-boto3-amp (>=1.21.0)"]
+amplify = ["mypy-boto3-amplify (>=1.21.0)"]
+amplifybackend = ["mypy-boto3-amplifybackend (>=1.21.0)"]
+amplifyuibuilder = ["mypy-boto3-amplifyuibuilder (>=1.21.0)"]
+apigateway = ["mypy-boto3-apigateway (>=1.21.0)"]
+apigatewaymanagementapi = ["mypy-boto3-apigatewaymanagementapi (>=1.21.0)"]
+apigatewayv2 = ["mypy-boto3-apigatewayv2 (>=1.21.0)"]
+appconfig = ["mypy-boto3-appconfig (>=1.21.0)"]
+appconfigdata = ["mypy-boto3-appconfigdata (>=1.21.0)"]
+appflow = ["mypy-boto3-appflow (>=1.21.0)"]
+appintegrations = ["mypy-boto3-appintegrations (>=1.21.0)"]
+application-autoscaling = ["mypy-boto3-application-autoscaling (>=1.21.0)"]
+application-insights = ["mypy-boto3-application-insights (>=1.21.0)"]
+applicationcostprofiler = ["mypy-boto3-applicationcostprofiler (>=1.21.0)"]
+appmesh = ["mypy-boto3-appmesh (>=1.21.0)"]
+apprunner = ["mypy-boto3-apprunner (>=1.21.0)"]
+appstream = ["mypy-boto3-appstream (>=1.21.0)"]
+appsync = ["mypy-boto3-appsync (>=1.21.0)"]
+athena = ["mypy-boto3-athena (>=1.21.0)"]
+auditmanager = ["mypy-boto3-auditmanager (>=1.21.0)"]
+autoscaling = ["mypy-boto3-autoscaling (>=1.21.0)"]
+autoscaling-plans = ["mypy-boto3-autoscaling-plans (>=1.21.0)"]
+backup = ["mypy-boto3-backup (>=1.21.0)"]
+backup-gateway = ["mypy-boto3-backup-gateway (>=1.21.0)"]
+batch = ["mypy-boto3-batch (>=1.21.0)"]
+braket = ["mypy-boto3-braket (>=1.21.0)"]
+budgets = ["mypy-boto3-budgets (>=1.21.0)"]
+ce = ["mypy-boto3-ce (>=1.21.0)"]
+chime = ["mypy-boto3-chime (>=1.21.0)"]
+chime-sdk-identity = ["mypy-boto3-chime-sdk-identity (>=1.21.0)"]
+chime-sdk-meetings = ["mypy-boto3-chime-sdk-meetings (>=1.21.0)"]
+chime-sdk-messaging = ["mypy-boto3-chime-sdk-messaging (>=1.21.0)"]
+cloud9 = ["mypy-boto3-cloud9 (>=1.21.0)"]
+cloudcontrol = ["mypy-boto3-cloudcontrol (>=1.21.0)"]
+clouddirectory = ["mypy-boto3-clouddirectory (>=1.21.0)"]
+cloudformation = ["mypy-boto3-cloudformation (>=1.21.0)"]
+cloudfront = ["mypy-boto3-cloudfront (>=1.21.0)"]
+cloudhsm = ["mypy-boto3-cloudhsm (>=1.21.0)"]
+cloudhsmv2 = ["mypy-boto3-cloudhsmv2 (>=1.21.0)"]
+cloudsearch = ["mypy-boto3-cloudsearch (>=1.21.0)"]
+cloudsearchdomain = ["mypy-boto3-cloudsearchdomain (>=1.21.0)"]
+cloudtrail = ["mypy-boto3-cloudtrail (>=1.21.0)"]
+cloudwatch = ["mypy-boto3-cloudwatch (>=1.21.0)"]
+codeartifact = ["mypy-boto3-codeartifact (>=1.21.0)"]
+codebuild = ["mypy-boto3-codebuild (>=1.21.0)"]
+codecommit = ["mypy-boto3-codecommit (>=1.21.0)"]
+codedeploy = ["mypy-boto3-codedeploy (>=1.21.0)"]
+codeguru-reviewer = ["mypy-boto3-codeguru-reviewer (>=1.21.0)"]
+codeguruprofiler = ["mypy-boto3-codeguruprofiler (>=1.21.0)"]
+codepipeline = ["mypy-boto3-codepipeline (>=1.21.0)"]
+codestar = ["mypy-boto3-codestar (>=1.21.0)"]
+codestar-connections = ["mypy-boto3-codestar-connections (>=1.21.0)"]
+codestar-notifications = ["mypy-boto3-codestar-notifications (>=1.21.0)"]
+cognito-identity = ["mypy-boto3-cognito-identity (>=1.21.0)"]
+cognito-idp = ["mypy-boto3-cognito-idp (>=1.21.0)"]
+cognito-sync = ["mypy-boto3-cognito-sync (>=1.21.0)"]
+comprehend = ["mypy-boto3-comprehend (>=1.21.0)"]
+comprehendmedical = ["mypy-boto3-comprehendmedical (>=1.21.0)"]
+compute-optimizer = ["mypy-boto3-compute-optimizer (>=1.21.0)"]
+config = ["mypy-boto3-config (>=1.21.0)"]
+connect = ["mypy-boto3-connect (>=1.21.0)"]
+connect-contact-lens = ["mypy-boto3-connect-contact-lens (>=1.21.0)"]
+connectparticipant = ["mypy-boto3-connectparticipant (>=1.21.0)"]
+cur = ["mypy-boto3-cur (>=1.21.0)"]
+customer-profiles = ["mypy-boto3-customer-profiles (>=1.21.0)"]
+databrew = ["mypy-boto3-databrew (>=1.21.0)"]
+dataexchange = ["mypy-boto3-dataexchange (>=1.21.0)"]
+datapipeline = ["mypy-boto3-datapipeline (>=1.21.0)"]
+datasync = ["mypy-boto3-datasync (>=1.21.0)"]
+dax = ["mypy-boto3-dax (>=1.21.0)"]
+detective = ["mypy-boto3-detective (>=1.21.0)"]
+devicefarm = ["mypy-boto3-devicefarm (>=1.21.0)"]
+devops-guru = ["mypy-boto3-devops-guru (>=1.21.0)"]
+directconnect = ["mypy-boto3-directconnect (>=1.21.0)"]
+discovery = ["mypy-boto3-discovery (>=1.21.0)"]
+dlm = ["mypy-boto3-dlm (>=1.21.0)"]
+dms = ["mypy-boto3-dms (>=1.21.0)"]
+docdb = ["mypy-boto3-docdb (>=1.21.0)"]
+drs = ["mypy-boto3-drs (>=1.21.0)"]
+ds = ["mypy-boto3-ds (>=1.21.0)"]
+dynamodb = ["mypy-boto3-dynamodb (>=1.21.0)"]
+dynamodbstreams = ["mypy-boto3-dynamodbstreams (>=1.21.0)"]
+ebs = ["mypy-boto3-ebs (>=1.21.0)"]
+ec2 = ["mypy-boto3-ec2 (>=1.21.0)"]
+ec2-instance-connect = ["mypy-boto3-ec2-instance-connect (>=1.21.0)"]
+ecr = ["mypy-boto3-ecr (>=1.21.0)"]
+ecr-public = ["mypy-boto3-ecr-public (>=1.21.0)"]
+ecs = ["mypy-boto3-ecs (>=1.21.0)"]
+efs = ["mypy-boto3-efs (>=1.21.0)"]
+eks = ["mypy-boto3-eks (>=1.21.0)"]
+elastic-inference = ["mypy-boto3-elastic-inference (>=1.21.0)"]
+elasticache = ["mypy-boto3-elasticache (>=1.21.0)"]
+elasticbeanstalk = ["mypy-boto3-elasticbeanstalk (>=1.21.0)"]
+elastictranscoder = ["mypy-boto3-elastictranscoder (>=1.21.0)"]
+elb = ["mypy-boto3-elb (>=1.21.0)"]
+elbv2 = ["mypy-boto3-elbv2 (>=1.21.0)"]
+emr = ["mypy-boto3-emr (>=1.21.0)"]
+emr-containers = ["mypy-boto3-emr-containers (>=1.21.0)"]
+es = ["mypy-boto3-es (>=1.21.0)"]
+essential = ["mypy-boto3-cloudformation (>=1.21.0)", "mypy-boto3-dynamodb (>=1.21.0)", "mypy-boto3-ec2 (>=1.21.0)", "mypy-boto3-lambda (>=1.21.0)", "mypy-boto3-rds (>=1.21.0)", "mypy-boto3-s3 (>=1.21.0)", "mypy-boto3-sqs (>=1.21.0)"]
+events = ["mypy-boto3-events (>=1.21.0)"]
+evidently = ["mypy-boto3-evidently (>=1.21.0)"]
+finspace = ["mypy-boto3-finspace (>=1.21.0)"]
+finspace-data = ["mypy-boto3-finspace-data (>=1.21.0)"]
+firehose = ["mypy-boto3-firehose (>=1.21.0)"]
+fis = ["mypy-boto3-fis (>=1.21.0)"]
+fms = ["mypy-boto3-fms (>=1.21.0)"]
+forecast = ["mypy-boto3-forecast (>=1.21.0)"]
+forecastquery = ["mypy-boto3-forecastquery (>=1.21.0)"]
+frauddetector = ["mypy-boto3-frauddetector (>=1.21.0)"]
+fsx = ["mypy-boto3-fsx (>=1.21.0)"]
+gamelift = ["mypy-boto3-gamelift (>=1.21.0)"]
+glacier = ["mypy-boto3-glacier (>=1.21.0)"]
+globalaccelerator = ["mypy-boto3-globalaccelerator (>=1.21.0)"]
+glue = ["mypy-boto3-glue (>=1.21.0)"]
+grafana = ["mypy-boto3-grafana (>=1.21.0)"]
+greengrass = ["mypy-boto3-greengrass (>=1.21.0)"]
+greengrassv2 = ["mypy-boto3-greengrassv2 (>=1.21.0)"]
+groundstation = ["mypy-boto3-groundstation (>=1.21.0)"]
+guardduty = ["mypy-boto3-guardduty (>=1.21.0)"]
+health = ["mypy-boto3-health (>=1.21.0)"]
+healthlake = ["mypy-boto3-healthlake (>=1.21.0)"]
+honeycode = ["mypy-boto3-honeycode (>=1.21.0)"]
+iam = ["mypy-boto3-iam (>=1.21.0)"]
+identitystore = ["mypy-boto3-identitystore (>=1.21.0)"]
+imagebuilder = ["mypy-boto3-imagebuilder (>=1.21.0)"]
+importexport = ["mypy-boto3-importexport (>=1.21.0)"]
+inspector = ["mypy-boto3-inspector (>=1.21.0)"]
+inspector2 = ["mypy-boto3-inspector2 (>=1.21.0)"]
+iot = ["mypy-boto3-iot (>=1.21.0)"]
+iot-data = ["mypy-boto3-iot-data (>=1.21.0)"]
+iot-jobs-data = ["mypy-boto3-iot-jobs-data (>=1.21.0)"]
+iot1click-devices = ["mypy-boto3-iot1click-devices (>=1.21.0)"]
+iot1click-projects = ["mypy-boto3-iot1click-projects (>=1.21.0)"]
+iotanalytics = ["mypy-boto3-iotanalytics (>=1.21.0)"]
+iotdeviceadvisor = ["mypy-boto3-iotdeviceadvisor (>=1.21.0)"]
+iotevents = ["mypy-boto3-iotevents (>=1.21.0)"]
+iotevents-data = ["mypy-boto3-iotevents-data (>=1.21.0)"]
+iotfleethub = ["mypy-boto3-iotfleethub (>=1.21.0)"]
+iotsecuretunneling = ["mypy-boto3-iotsecuretunneling (>=1.21.0)"]
+iotsitewise = ["mypy-boto3-iotsitewise (>=1.21.0)"]
+iotthingsgraph = ["mypy-boto3-iotthingsgraph (>=1.21.0)"]
+iottwinmaker = ["mypy-boto3-iottwinmaker (>=1.21.0)"]
+iotwireless = ["mypy-boto3-iotwireless (>=1.21.0)"]
+ivs = ["mypy-boto3-ivs (>=1.21.0)"]
+kafka = ["mypy-boto3-kafka (>=1.21.0)"]
+kafkaconnect = ["mypy-boto3-kafkaconnect (>=1.21.0)"]
+kendra = ["mypy-boto3-kendra (>=1.21.0)"]
+kinesis = ["mypy-boto3-kinesis (>=1.21.0)"]
+kinesis-video-archived-media = ["mypy-boto3-kinesis-video-archived-media (>=1.21.0)"]
+kinesis-video-media = ["mypy-boto3-kinesis-video-media (>=1.21.0)"]
+kinesis-video-signaling = ["mypy-boto3-kinesis-video-signaling (>=1.21.0)"]
+kinesisanalytics = ["mypy-boto3-kinesisanalytics (>=1.21.0)"]
+kinesisanalyticsv2 = ["mypy-boto3-kinesisanalyticsv2 (>=1.21.0)"]
+kinesisvideo = ["mypy-boto3-kinesisvideo (>=1.21.0)"]
+kms = ["mypy-boto3-kms (>=1.21.0)"]
+lakeformation = ["mypy-boto3-lakeformation (>=1.21.0)"]
+lambda = ["mypy-boto3-lambda (>=1.21.0)"]
+lex-models = ["mypy-boto3-lex-models (>=1.21.0)"]
+lex-runtime = ["mypy-boto3-lex-runtime (>=1.21.0)"]
+lexv2-models = ["mypy-boto3-lexv2-models (>=1.21.0)"]
+lexv2-runtime = ["mypy-boto3-lexv2-runtime (>=1.21.0)"]
+license-manager = ["mypy-boto3-license-manager (>=1.21.0)"]
+lightsail = ["mypy-boto3-lightsail (>=1.21.0)"]
+location = ["mypy-boto3-location (>=1.21.0)"]
+logs = ["mypy-boto3-logs (>=1.21.0)"]
+lookoutequipment = ["mypy-boto3-lookoutequipment (>=1.21.0)"]
+lookoutmetrics = ["mypy-boto3-lookoutmetrics (>=1.21.0)"]
+lookoutvision = ["mypy-boto3-lookoutvision (>=1.21.0)"]
+machinelearning = ["mypy-boto3-machinelearning (>=1.21.0)"]
+macie = ["mypy-boto3-macie (>=1.21.0)"]
+macie2 = ["mypy-boto3-macie2 (>=1.21.0)"]
+managedblockchain = ["mypy-boto3-managedblockchain (>=1.21.0)"]
+marketplace-catalog = ["mypy-boto3-marketplace-catalog (>=1.21.0)"]
+marketplace-entitlement = ["mypy-boto3-marketplace-entitlement (>=1.21.0)"]
+marketplacecommerceanalytics = ["mypy-boto3-marketplacecommerceanalytics (>=1.21.0)"]
+mediaconnect = ["mypy-boto3-mediaconnect (>=1.21.0)"]
+mediaconvert = ["mypy-boto3-mediaconvert (>=1.21.0)"]
+medialive = ["mypy-boto3-medialive (>=1.21.0)"]
+mediapackage = ["mypy-boto3-mediapackage (>=1.21.0)"]
+mediapackage-vod = ["mypy-boto3-mediapackage-vod (>=1.21.0)"]
+mediastore = ["mypy-boto3-mediastore (>=1.21.0)"]
+mediastore-data = ["mypy-boto3-mediastore-data (>=1.21.0)"]
+mediatailor = ["mypy-boto3-mediatailor (>=1.21.0)"]
+memorydb = ["mypy-boto3-memorydb (>=1.21.0)"]
+meteringmarketplace = ["mypy-boto3-meteringmarketplace (>=1.21.0)"]
+mgh = ["mypy-boto3-mgh (>=1.21.0)"]
+mgn = ["mypy-boto3-mgn (>=1.21.0)"]
+migration-hub-refactor-spaces = ["mypy-boto3-migration-hub-refactor-spaces (>=1.21.0)"]
+migrationhub-config = ["mypy-boto3-migrationhub-config (>=1.21.0)"]
+migrationhubstrategy = ["mypy-boto3-migrationhubstrategy (>=1.21.0)"]
+mobile = ["mypy-boto3-mobile (>=1.21.0)"]
+mq = ["mypy-boto3-mq (>=1.21.0)"]
+mturk = ["mypy-boto3-mturk (>=1.21.0)"]
+mwaa = ["mypy-boto3-mwaa (>=1.21.0)"]
+neptune = ["mypy-boto3-neptune (>=1.21.0)"]
+network-firewall = ["mypy-boto3-network-firewall (>=1.21.0)"]
+networkmanager = ["mypy-boto3-networkmanager (>=1.21.0)"]
+nimble = ["mypy-boto3-nimble (>=1.21.0)"]
+opensearch = ["mypy-boto3-opensearch (>=1.21.0)"]
+opsworks = ["mypy-boto3-opsworks (>=1.21.0)"]
+opsworkscm = ["mypy-boto3-opsworkscm (>=1.21.0)"]
+organizations = ["mypy-boto3-organizations (>=1.21.0)"]
+outposts = ["mypy-boto3-outposts (>=1.21.0)"]
+panorama = ["mypy-boto3-panorama (>=1.21.0)"]
+personalize = ["mypy-boto3-personalize (>=1.21.0)"]
+personalize-events = ["mypy-boto3-personalize-events (>=1.21.0)"]
+personalize-runtime = ["mypy-boto3-personalize-runtime (>=1.21.0)"]
+pi = ["mypy-boto3-pi (>=1.21.0)"]
+pinpoint = ["mypy-boto3-pinpoint (>=1.21.0)"]
+pinpoint-email = ["mypy-boto3-pinpoint-email (>=1.21.0)"]
+pinpoint-sms-voice = ["mypy-boto3-pinpoint-sms-voice (>=1.21.0)"]
+polly = ["mypy-boto3-polly (>=1.21.0)"]
+pricing = ["mypy-boto3-pricing (>=1.21.0)"]
+proton = ["mypy-boto3-proton (>=1.21.0)"]
+qldb = ["mypy-boto3-qldb (>=1.21.0)"]
+qldb-session = ["mypy-boto3-qldb-session (>=1.21.0)"]
+quicksight = ["mypy-boto3-quicksight (>=1.21.0)"]
+ram = ["mypy-boto3-ram (>=1.21.0)"]
+rbin = ["mypy-boto3-rbin (>=1.21.0)"]
+rds = ["mypy-boto3-rds (>=1.21.0)"]
+rds-data = ["mypy-boto3-rds-data (>=1.21.0)"]
+redshift = ["mypy-boto3-redshift (>=1.21.0)"]
+redshift-data = ["mypy-boto3-redshift-data (>=1.21.0)"]
+rekognition = ["mypy-boto3-rekognition (>=1.21.0)"]
+resiliencehub = ["mypy-boto3-resiliencehub (>=1.21.0)"]
+resource-groups = ["mypy-boto3-resource-groups (>=1.21.0)"]
+resourcegroupstaggingapi = ["mypy-boto3-resourcegroupstaggingapi (>=1.21.0)"]
+robomaker = ["mypy-boto3-robomaker (>=1.21.0)"]
+route53 = ["mypy-boto3-route53 (>=1.21.0)"]
+route53-recovery-cluster = ["mypy-boto3-route53-recovery-cluster (>=1.21.0)"]
+route53-recovery-control-config = ["mypy-boto3-route53-recovery-control-config (>=1.21.0)"]
+route53-recovery-readiness = ["mypy-boto3-route53-recovery-readiness (>=1.21.0)"]
+route53domains = ["mypy-boto3-route53domains (>=1.21.0)"]
+route53resolver = ["mypy-boto3-route53resolver (>=1.21.0)"]
+rum = ["mypy-boto3-rum (>=1.21.0)"]
+s3 = ["mypy-boto3-s3 (>=1.21.0)"]
+s3control = ["mypy-boto3-s3control (>=1.21.0)"]
+s3outposts = ["mypy-boto3-s3outposts (>=1.21.0)"]
+sagemaker = ["mypy-boto3-sagemaker (>=1.21.0)"]
+sagemaker-a2i-runtime = ["mypy-boto3-sagemaker-a2i-runtime (>=1.21.0)"]
+sagemaker-edge = ["mypy-boto3-sagemaker-edge (>=1.21.0)"]
+sagemaker-featurestore-runtime = ["mypy-boto3-sagemaker-featurestore-runtime (>=1.21.0)"]
+sagemaker-runtime = ["mypy-boto3-sagemaker-runtime (>=1.21.0)"]
+savingsplans = ["mypy-boto3-savingsplans (>=1.21.0)"]
+schemas = ["mypy-boto3-schemas (>=1.21.0)"]
+sdb = ["mypy-boto3-sdb (>=1.21.0)"]
+secretsmanager = ["mypy-boto3-secretsmanager (>=1.21.0)"]
+securityhub = ["mypy-boto3-securityhub (>=1.21.0)"]
+serverlessrepo = ["mypy-boto3-serverlessrepo (>=1.21.0)"]
+service-quotas = ["mypy-boto3-service-quotas (>=1.21.0)"]
+servicecatalog = ["mypy-boto3-servicecatalog (>=1.21.0)"]
+servicecatalog-appregistry = ["mypy-boto3-servicecatalog-appregistry (>=1.21.0)"]
+servicediscovery = ["mypy-boto3-servicediscovery (>=1.21.0)"]
+ses = ["mypy-boto3-ses (>=1.21.0)"]
+sesv2 = ["mypy-boto3-sesv2 (>=1.21.0)"]
+shield = ["mypy-boto3-shield (>=1.21.0)"]
+signer = ["mypy-boto3-signer (>=1.21.0)"]
+sms = ["mypy-boto3-sms (>=1.21.0)"]
+sms-voice = ["mypy-boto3-sms-voice (>=1.21.0)"]
+snow-device-management = ["mypy-boto3-snow-device-management (>=1.21.0)"]
+snowball = ["mypy-boto3-snowball (>=1.21.0)"]
+sns = ["mypy-boto3-sns (>=1.21.0)"]
+sqs = ["mypy-boto3-sqs (>=1.21.0)"]
+ssm = ["mypy-boto3-ssm (>=1.21.0)"]
+ssm-contacts = ["mypy-boto3-ssm-contacts (>=1.21.0)"]
+ssm-incidents = ["mypy-boto3-ssm-incidents (>=1.21.0)"]
+sso = ["mypy-boto3-sso (>=1.21.0)"]
+sso-admin = ["mypy-boto3-sso-admin (>=1.21.0)"]
+sso-oidc = ["mypy-boto3-sso-oidc (>=1.21.0)"]
+stepfunctions = ["mypy-boto3-stepfunctions (>=1.21.0)"]
+storagegateway = ["mypy-boto3-storagegateway (>=1.21.0)"]
+sts = ["mypy-boto3-sts (>=1.21.0)"]
+support = ["mypy-boto3-support (>=1.21.0)"]
+swf = ["mypy-boto3-swf (>=1.21.0)"]
+synthetics = ["mypy-boto3-synthetics (>=1.21.0)"]
+textract = ["mypy-boto3-textract (>=1.21.0)"]
+timestream-query = ["mypy-boto3-timestream-query (>=1.21.0)"]
+timestream-write = ["mypy-boto3-timestream-write (>=1.21.0)"]
+transcribe = ["mypy-boto3-transcribe (>=1.21.0)"]
+transfer = ["mypy-boto3-transfer (>=1.21.0)"]
+translate = ["mypy-boto3-translate (>=1.21.0)"]
+voice-id = ["mypy-boto3-voice-id (>=1.21.0)"]
+waf = ["mypy-boto3-waf (>=1.21.0)"]
+waf-regional = ["mypy-boto3-waf-regional (>=1.21.0)"]
+wafv2 = ["mypy-boto3-wafv2 (>=1.21.0)"]
+wellarchitected = ["mypy-boto3-wellarchitected (>=1.21.0)"]
+wisdom = ["mypy-boto3-wisdom (>=1.21.0)"]
+workdocs = ["mypy-boto3-workdocs (>=1.21.0)"]
+worklink = ["mypy-boto3-worklink (>=1.21.0)"]
+workmail = ["mypy-boto3-workmail (>=1.21.0)"]
+workmailmessageflow = ["mypy-boto3-workmailmessageflow (>=1.21.0)"]
+workspaces = ["mypy-boto3-workspaces (>=1.21.0)"]
+workspaces-web = ["mypy-boto3-workspaces-web (>=1.21.0)"]
+xray = ["mypy-boto3-xray (>=1.21.0)"]
 
 [[package]]
 name = "botocore"
-version = "1.23.41"
+version = "1.24.6"
 description = "Low-level, data-driven core of boto 3."
 category = "main"
 optional = false
@@ -411,8 +393,8 @@ crt = ["awscrt (==0.12.5)"]
 
 [[package]]
 name = "botocore-stubs"
-version = "1.23.40"
-description = "Type annotations for botocore 1.23.40, generated by mypy-boto3-builder 6.3.2"
+version = "1.24.6"
+description = "Type annotations for botocore 1.24.6 generated with mypy-boto3-builder 7.1.2"
 category = "main"
 optional = false
 python-versions = ">=3.6"
@@ -420,6 +402,25 @@ python-versions = ">=3.6"
 [package.dependencies]
 typing-extensions = {version = "*", markers = "python_version < \"3.9\""}
 
+[[package]]
+name = "certifi"
+version = "2021.10.8"
+description = "Python package for providing Mozilla's CA Bundle."
+category = "dev"
+optional = false
+python-versions = "*"
+
+[[package]]
+name = "cffi"
+version = "1.15.0"
+description = "Foreign Function Interface for Python calling C code."
+category = "dev"
+optional = false
+python-versions = "*"
+
+[package.dependencies]
+pycparser = "*"
+
 [[package]]
 name = "cfgv"
 version = "3.3.1"
@@ -428,9 +429,20 @@ category = "dev"
 optional = false
 python-versions = ">=3.6.1"
 
+[[package]]
+name = "charset-normalizer"
+version = "2.0.12"
+description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
+category = "dev"
+optional = false
+python-versions = ">=3.5.0"
+
+[package.extras]
+unicode_backport = ["unicodedata2"]
+
 [[package]]
 name = "click"
-version = "8.0.3"
+version = "8.0.4"
 description = "Composable command line interface toolkit"
 category = "dev"
 optional = false
@@ -447,6 +459,25 @@ category = "main"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
 
+[[package]]
+name = "cryptography"
+version = "36.0.1"
+description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
+[package.dependencies]
+cffi = ">=1.12"
+
+[package.extras]
+docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"]
+docstest = ["pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"]
+pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"]
+sdist = ["setuptools_rust (>=0.11.4)"]
+ssh = ["bcrypt (>=3.1.5)"]
+test = ["pytest (>=6.2.0)", "pytest-cov", "pytest-subtests", "pytest-xdist", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,!=3.79.2)"]
+
 [[package]]
 name = "distlib"
 version = "0.3.4"
@@ -457,11 +488,11 @@ python-versions = "*"
 
 [[package]]
 name = "entrypoints"
-version = "0.3"
+version = "0.4"
 description = "Discover and load entry points from installed packages."
 category = "dev"
 optional = false
-python-versions = ">=2.7"
+python-versions = ">=3.6"
 
 [[package]]
 name = "eradicate"
@@ -473,7 +504,7 @@ python-versions = "*"
 
 [[package]]
 name = "filelock"
-version = "3.4.2"
+version = "3.6.0"
 description = "A platform independent file lock."
 category = "dev"
 optional = false
@@ -496,20 +527,6 @@ mccabe = ">=0.6.0,<0.7.0"
 pycodestyle = ">=2.8.0,<2.9.0"
 pyflakes = ">=2.4.0,<2.5.0"
 
-[[package]]
-name = "flake8-bandit"
-version = "2.1.2"
-description = "Automated security testing with bandit and flake8."
-category = "dev"
-optional = false
-python-versions = "*"
-
-[package.dependencies]
-bandit = "*"
-flake8 = "*"
-flake8-polyfill = "*"
-pycodestyle = "*"
-
 [[package]]
 name = "flake8-bugbear"
 version = "22.1.11"
@@ -635,56 +652,41 @@ flake8-plugin-utils = ">=1.3.2,<2.0.0"
 
 [[package]]
 name = "flakeheaven"
-version = "0.11.0"
-description = "Flake8 wrapper to make it nice and configurable"
+version = "0.11.1"
+description = "FlakeHeaven is a [Flake8](https://gitlab.com/pycqa/flake8) wrapper to make it cool."
 category = "dev"
 optional = false
-python-versions = ">=3.5"
+python-versions = ">=3.6.2,<4.0.0"
 
 [package.dependencies]
 colorama = "*"
 entrypoints = "*"
-flake8 = ">=4.0.1"
+flake8 = ">=4.0.1,<5.0.0"
 pygments = "*"
 toml = "*"
 urllib3 = "*"
 
 [package.extras]
-dev = ["dlint", "flake8-2020", "flake8-aaa", "flake8-absolute-import", "flake8-alfred", "flake8-annotations-complexity", "flake8-bandit", "flake8-black", "flake8-broken-line", "flake8-bugbear", "flake8-builtins", "flake8-coding", "flake8-cognitive-complexity", "flake8-commas", "flake8-comprehensions", "flake8-debugger", "flake8-django", "flake8-docstrings", "flake8-eradicate", "flake8-executable", "flake8-expression-complexity", "flake8-fixme", "flake8-functions", "flake8-future-import", "flake8-import-order", "flake8-isort", "flake8-logging-format", "flake8-mock", "flake8-mutable", "flake8-mypy", "flake8-pep3101", "flake8-pie", "flake8-print", "flake8-printf-formatting", "flake8-pyi", "flake8-pytest-style", "flake8-pytest", "flake8-quotes", "flake8-requirements", "flake8-rst-docstrings", "flake8-scrapy", "flake8-spellcheck", "flake8-sql", "flake8-strict", "black (==21.10b0)", "flake8-string-format", "flake8-tidy-imports", "flake8-todo", "flake8-use-fstring", "flake8-variables-names", "mccabe", "pandas-vet", "pep8-naming", "pylint", "typing-extensions", "wemake-python-styleguide", "mypy", "pytest", "isort"]
 docs = ["alabaster", "pygments-github-lexers", "recommonmark", "sphinx"]
 
 [[package]]
-name = "gitdb"
-version = "4.0.9"
-description = "Git Object Database"
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-
-[package.dependencies]
-smmap = ">=3.0.1,<6"
-
-[[package]]
-name = "gitpython"
-version = "3.1.26"
-description = "GitPython is a python library used to interact with Git repositories"
+name = "identify"
+version = "2.4.11"
+description = "File identification library for Python"
 category = "dev"
 optional = false
 python-versions = ">=3.7"
 
-[package.dependencies]
-gitdb = ">=4.0.1,<5"
+[package.extras]
+license = ["ukkonen"]
 
 [[package]]
-name = "identify"
-version = "2.4.4"
-description = "File identification library for Python"
+name = "idna"
+version = "3.3"
+description = "Internationalized Domain Names in Applications (IDNA)"
 category = "dev"
 optional = false
-python-versions = ">=3.6.1"
-
-[package.extras]
-license = ["ukkonen"]
+python-versions = ">=3.5"
 
 [[package]]
 name = "iniconfig"
@@ -708,6 +710,20 @@ requirements_deprecated_finder = ["pipreqs", "pip-api"]
 colors = ["colorama (>=0.4.3,<0.5.0)"]
 plugins = ["setuptools"]
 
+[[package]]
+name = "jinja2"
+version = "3.0.3"
+description = "A very fast and expressive template engine."
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
+[package.dependencies]
+MarkupSafe = ">=2.0"
+
+[package.extras]
+i18n = ["Babel (>=2.7)"]
+
 [[package]]
 name = "jmespath"
 version = "0.10.0"
@@ -716,6 +732,14 @@ category = "main"
 optional = false
 python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
 
+[[package]]
+name = "markupsafe"
+version = "2.1.0"
+description = "Safely add untrusted strings to HTML/XML markup."
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+
 [[package]]
 name = "mccabe"
 version = "0.6.1"
@@ -724,6 +748,48 @@ category = "dev"
 optional = false
 python-versions = "*"
 
+[[package]]
+name = "moto"
+version = "3.0.4"
+description = "A library that allows your python tests to easily mock out the boto library"
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
+[package.dependencies]
+boto3 = ">=1.9.201"
+botocore = ">=1.12.201"
+cryptography = ">=3.3.1"
+Jinja2 = ">=2.10.1"
+MarkupSafe = "!=2.0.0a1"
+python-dateutil = ">=2.1,<3.0.0"
+pytz = "*"
+requests = ">=2.5"
+responses = ">=0.9.0"
+werkzeug = "*"
+xmltodict = "*"
+
+[package.extras]
+all = ["PyYAML (>=5.1)", "python-jose[cryptography] (>=3.1.0,<4.0.0)", "ecdsa (!=0.15)", "docker (>=2.5.1)", "graphql-core", "jsondiff (>=1.1.2)", "aws-xray-sdk (>=0.93,!=0.96)", "idna (>=2.5,<4)", "cfn-lint (>=0.4.0)", "sshpubkeys (>=3.1.0)", "setuptools"]
+apigateway = ["PyYAML (>=5.1)", "python-jose[cryptography] (>=3.1.0,<4.0.0)", "ecdsa (!=0.15)"]
+apigatewayv2 = ["PyYAML (>=5.1)"]
+appsync = ["graphql-core"]
+awslambda = ["docker (>=2.5.1)"]
+batch = ["docker (>=2.5.1)"]
+cloudformation = ["docker (>=2.5.1)", "PyYAML (>=5.1)", "cfn-lint (>=0.4.0)"]
+cognitoidp = ["python-jose[cryptography] (>=3.1.0,<4.0.0)", "ecdsa (!=0.15)"]
+ds = ["sshpubkeys (>=3.1.0)"]
+dynamodb2 = ["docker (>=2.5.1)"]
+dynamodbstreams = ["docker (>=2.5.1)"]
+ec2 = ["sshpubkeys (>=3.1.0)"]
+efs = ["sshpubkeys (>=3.1.0)"]
+iotdata = ["jsondiff (>=1.1.2)"]
+route53resolver = ["sshpubkeys (>=3.1.0)"]
+s3 = ["PyYAML (>=5.1)"]
+server = ["PyYAML (>=5.1)", "python-jose[cryptography] (>=3.1.0,<4.0.0)", "ecdsa (!=0.15)", "docker (>=2.5.1)", "graphql-core", "jsondiff (>=1.1.2)", "aws-xray-sdk (>=0.93,!=0.96)", "idna (>=2.5,<4)", "cfn-lint (>=0.4.0)", "sshpubkeys (>=3.1.0)", "setuptools", "flask", "flask-cors"]
+ssm = ["PyYAML (>=5.1)", "dataclasses"]
+xray = ["aws-xray-sdk (>=0.93,!=0.96)", "setuptools"]
+
 [[package]]
 name = "mypy"
 version = "0.931"
@@ -743,8 +809,8 @@ python2 = ["typed-ast (>=1.4.0,<2)"]
 
 [[package]]
 name = "mypy-boto3-organizations"
-version = "1.20.35.post1"
-description = "Type annotations for boto3.Organizations 1.20.35 service, generated by mypy-boto3-builder 6.3.2"
+version = "1.21.0"
+description = "Type annotations for boto3.Organizations 1.21.0 service generated by mypy-boto3-builder 7.0.4"
 category = "main"
 optional = false
 python-versions = ">=3.6"
@@ -754,8 +820,8 @@ typing-extensions = {version = "*", markers = "python_version < \"3.9\""}
 
 [[package]]
 name = "mypy-boto3-sts"
-version = "1.20.35.post1"
-description = "Type annotations for boto3.STS 1.20.35 service, generated by mypy-boto3-builder 6.3.2"
+version = "1.21.0"
+description = "Type annotations for boto3.STS 1.21.0 service generated by mypy-boto3-builder 7.0.4"
 category = "main"
 optional = false
 python-versions = ">=3.6"
@@ -798,14 +864,6 @@ category = "dev"
 optional = false
 python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
 
-[[package]]
-name = "pbr"
-version = "5.8.0"
-description = "Python Build Reasonableness"
-category = "dev"
-optional = false
-python-versions = ">=2.6"
-
 [[package]]
 name = "pep8-naming"
 version = "0.12.1"
@@ -820,7 +878,7 @@ flake8-polyfill = ">=1.0.2,<2"
 
 [[package]]
 name = "platformdirs"
-version = "2.4.1"
+version = "2.5.1"
 description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
 category = "dev"
 optional = false
@@ -874,6 +932,14 @@ category = "dev"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
 
+[[package]]
+name = "pycparser"
+version = "2.21"
+description = "C parser in Python"
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
 [[package]]
 name = "pyflakes"
 version = "2.4.0"
@@ -903,7 +969,7 @@ diagrams = ["jinja2", "railroad-diagrams"]
 
 [[package]]
 name = "pytest"
-version = "6.2.5"
+version = "7.0.1"
 description = "pytest: simple powerful testing with Python"
 category = "dev"
 optional = false
@@ -917,18 +983,18 @@ iniconfig = "*"
 packaging = "*"
 pluggy = ">=0.12,<2.0"
 py = ">=1.8.2"
-toml = "*"
+tomli = ">=1.0.0"
 
 [package.extras]
-testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
+testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"]
 
 [[package]]
 name = "pytest-mock"
-version = "3.6.1"
+version = "3.7.0"
 description = "Thin-wrapper around the mock package for easier use with pytest"
 category = "dev"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
 
 [package.dependencies]
 pytest = ">=5.0"
@@ -947,6 +1013,14 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
 [package.dependencies]
 six = ">=1.5"
 
+[[package]]
+name = "pytz"
+version = "2021.3"
+description = "World timezone definitions, modern and historical"
+category = "dev"
+optional = false
+python-versions = "*"
+
 [[package]]
 name = "pyyaml"
 version = "6.0"
@@ -955,9 +1029,42 @@ category = "dev"
 optional = false
 python-versions = ">=3.6"
 
+[[package]]
+name = "requests"
+version = "2.27.1"
+description = "Python HTTP for Humans."
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
+
+[package.dependencies]
+certifi = ">=2017.4.17"
+charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""}
+idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""}
+urllib3 = ">=1.21.1,<1.27"
+
+[package.extras]
+socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"]
+use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"]
+
+[[package]]
+name = "responses"
+version = "0.18.0"
+description = "A utility library for mocking out the `requests` Python library."
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+
+[package.dependencies]
+requests = ">=2.0,<3.0"
+urllib3 = ">=1.25.10"
+
+[package.extras]
+tests = ["pytest (>=4.6)", "coverage (>=6.0.0)", "pytest-cov", "pytest-localserver", "flake8", "types-mock", "types-requests", "mypy"]
+
 [[package]]
 name = "s3transfer"
-version = "0.5.0"
+version = "0.5.1"
 description = "An Amazon S3 Transfer Manager"
 category = "main"
 optional = false
@@ -977,25 +1084,6 @@ category = "main"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
 
-[[package]]
-name = "smmap"
-version = "5.0.0"
-description = "A pure Python implementation of a sliding window memory map manager"
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-
-[[package]]
-name = "stevedore"
-version = "3.5.0"
-description = "Manage dynamic plugins for Python applications"
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-
-[package.dependencies]
-pbr = ">=2.0.0,<2.1.0 || >2.1.0"
-
 [[package]]
 name = "testfixtures"
 version = "6.18.3"
@@ -1019,11 +1107,11 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
 
 [[package]]
 name = "tomli"
-version = "1.2.3"
+version = "2.0.1"
 description = "A lil' TOML parser"
 category = "dev"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
 
 [[package]]
 name = "tqdm"
@@ -1043,7 +1131,7 @@ telegram = ["requests"]
 
 [[package]]
 name = "typing-extensions"
-version = "4.0.1"
+version = "4.1.1"
 description = "Backported and Experimental Type Hints for Python 3.6+"
 category = "main"
 optional = false
@@ -1064,7 +1152,7 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
 
 [[package]]
 name = "virtualenv"
-version = "20.13.0"
+version = "20.13.1"
 description = "Virtual Python Environment builder"
 category = "dev"
 optional = false
@@ -1080,10 +1168,29 @@ six = ">=1.9.0,<2"
 docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=21.3)"]
 testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "packaging (>=20.0)"]
 
+[[package]]
+name = "werkzeug"
+version = "2.0.3"
+description = "The comprehensive WSGI web application library."
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
+[package.extras]
+watchdog = ["watchdog"]
+
+[[package]]
+name = "xmltodict"
+version = "0.12.0"
+description = "Makes working with XML feel like you are working with JSON"
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
 [metadata]
 lock-version = "1.1"
 python-versions = "^3.8"
-content-hash = "77f63aae84d92ce55be9aab5e019f8fc53cf3945c923f645470356780c02a9bd"
+content-hash = "b7414e86a15b81926dceb2c1ea325e4881cc1dcc1a6a74451f7f768377bcad7f"
 
 [metadata.files]
 atomicwrites = [
@@ -1094,64 +1201,160 @@ attrs = [
     {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"},
     {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"},
 ]
-bandit = [
-    {file = "bandit-1.7.1-py3-none-any.whl", hash = "sha256:f5acd838e59c038a159b5c621cf0f8270b279e884eadd7b782d7491c02add0d4"},
-    {file = "bandit-1.7.1.tar.gz", hash = "sha256:a81b00b5436e6880fa8ad6799bc830e02032047713cbb143a12939ac67eb756c"},
-]
 black = [
-    {file = "black-21.12b0-py3-none-any.whl", hash = "sha256:a615e69ae185e08fdd73e4715e260e2479c861b5740057fde6e8b4e3b7dd589f"},
-    {file = "black-21.12b0.tar.gz", hash = "sha256:77b80f693a569e2e527958459634f18df9b0ba2625ba4e0c2d5da5be42e6f2b3"},
+    {file = "black-22.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1297c63b9e1b96a3d0da2d85d11cd9bf8664251fd69ddac068b98dc4f34f73b6"},
+    {file = "black-22.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2ff96450d3ad9ea499fc4c60e425a1439c2120cbbc1ab959ff20f7c76ec7e866"},
+    {file = "black-22.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e21e1f1efa65a50e3960edd068b6ae6d64ad6235bd8bfea116a03b21836af71"},
+    {file = "black-22.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2f69158a7d120fd641d1fa9a921d898e20d52e44a74a6fbbcc570a62a6bc8ab"},
+    {file = "black-22.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:228b5ae2c8e3d6227e4bde5920d2fc66cc3400fde7bcc74f480cb07ef0b570d5"},
+    {file = "black-22.1.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b1a5ed73ab4c482208d20434f700d514f66ffe2840f63a6252ecc43a9bc77e8a"},
+    {file = "black-22.1.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35944b7100af4a985abfcaa860b06af15590deb1f392f06c8683b4381e8eeaf0"},
+    {file = "black-22.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:7835fee5238fc0a0baf6c9268fb816b5f5cd9b8793423a75e8cd663c48d073ba"},
+    {file = "black-22.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dae63f2dbf82882fa3b2a3c49c32bffe144970a573cd68d247af6560fc493ae1"},
+    {file = "black-22.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fa1db02410b1924b6749c245ab38d30621564e658297484952f3d8a39fce7e8"},
+    {file = "black-22.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c8226f50b8c34a14608b848dc23a46e5d08397d009446353dad45e04af0c8e28"},
+    {file = "black-22.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2d6f331c02f0f40aa51a22e479c8209d37fcd520c77721c034517d44eecf5912"},
+    {file = "black-22.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:742ce9af3086e5bd07e58c8feb09dbb2b047b7f566eb5f5bc63fd455814979f3"},
+    {file = "black-22.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fdb8754b453fb15fad3f72cd9cad3e16776f0964d67cf30ebcbf10327a3777a3"},
+    {file = "black-22.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5660feab44c2e3cb24b2419b998846cbb01c23c7fe645fee45087efa3da2d61"},
+    {file = "black-22.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:6f2f01381f91c1efb1451998bd65a129b3ed6f64f79663a55fe0e9b74a5f81fd"},
+    {file = "black-22.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:efbadd9b52c060a8fc3b9658744091cb33c31f830b3f074422ed27bad2b18e8f"},
+    {file = "black-22.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8871fcb4b447206904932b54b567923e5be802b9b19b744fdff092bd2f3118d0"},
+    {file = "black-22.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccad888050f5393f0d6029deea2a33e5ae371fd182a697313bdbd835d3edaf9c"},
+    {file = "black-22.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07e5c049442d7ca1a2fc273c79d1aecbbf1bc858f62e8184abe1ad175c4f7cc2"},
+    {file = "black-22.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:373922fc66676133ddc3e754e4509196a8c392fec3f5ca4486673e685a421321"},
+    {file = "black-22.1.0-py3-none-any.whl", hash = "sha256:3524739d76b6b3ed1132422bf9d82123cd1705086723bc3e235ca39fd21c667d"},
+    {file = "black-22.1.0.tar.gz", hash = "sha256:a7c0192d35635f6fc1174be575cb7915e92e5dd629ee79fdaf0dcfa41a80afb5"},
 ]
 boto3 = [
-    {file = "boto3-1.20.41-py3-none-any.whl", hash = "sha256:aaddf6cf93568b734ad62fd96991775bccc7f016e93ff4e98dc1aa4f7586440c"},
-    {file = "boto3-1.20.41.tar.gz", hash = "sha256:fb02467a6e8109c7db994ba77fa2e8381ed129ce312988d8ef23edf6e3a3c7f1"},
+    {file = "boto3-1.21.6-py3-none-any.whl", hash = "sha256:0e8d4d814f94031947035a4c2bb2c23832d5de941a6a492fb85794a02bafc44d"},
+    {file = "boto3-1.21.6.tar.gz", hash = "sha256:95d9b5b6fe3383fbf8f33d58f62258d3b3ea138d4369017031339b60fd5b8887"},
 ]
 boto3-stubs = [
-    {file = "boto3-stubs-1.20.40.tar.gz", hash = "sha256:24f23e14de15d29a85e301b5beb144d2c778ed350e0c08a2136a978c8105e3c9"},
-    {file = "boto3_stubs-1.20.40-py3-none-any.whl", hash = "sha256:2e940afd4a47688bb536155b10bdc65cc99390217bfcb392f4fc8c188646a65f"},
+    {file = "boto3-stubs-1.21.6.tar.gz", hash = "sha256:0934f2d034a41df075480c76dd4b1fd1cc5e31e5ac0ebfafb90e83849424dbc1"},
+    {file = "boto3_stubs-1.21.6-py3-none-any.whl", hash = "sha256:0cca34ae2210074c3eabcfdf3c828279f7bd19eaf87ae3ce6c8202fe711680cc"},
 ]
 botocore = [
-    {file = "botocore-1.23.41-py3-none-any.whl", hash = "sha256:41104e1c976c9c410387b3c7d265466b314f287a1c13fd4b543768135301058a"},
-    {file = "botocore-1.23.41.tar.gz", hash = "sha256:9137c59c4eb1dee60ae3c710e94f56119a1b33b0b17ff3ad878fc2f4ce77843a"},
+    {file = "botocore-1.24.6-py3-none-any.whl", hash = "sha256:69aaa5a78ac7371f573e463be51fb962213c42fab08ef82380e84b9a87386949"},
+    {file = "botocore-1.24.6.tar.gz", hash = "sha256:359b9ea3870a1f8264113cb0b1216baa94bf1e8cee5d5d8af63a2e7ca6e7b33c"},
 ]
 botocore-stubs = [
-    {file = "botocore-stubs-1.23.40.tar.gz", hash = "sha256:48529a2b7e14c6e3dd4544c21d4cf342ad512e2a526f5262c565357683d78787"},
-    {file = "botocore_stubs-1.23.40-py3-none-any.whl", hash = "sha256:b5762895175cbacfa989b7ff313ca20f30f82137fcfd8a389cfe4a920cb57e73"},
+    {file = "botocore-stubs-1.24.6.tar.gz", hash = "sha256:fc860c8735ed1999261f986cf7eedc21a0c1d347881fbd7d42bc9fc985d47f24"},
+    {file = "botocore_stubs-1.24.6-py3-none-any.whl", hash = "sha256:85bdc35ffd0b008fbf3b94cc3ab5e3d51b59a1f2eab3c67f697c6a0e9a550f16"},
+]
+certifi = [
+    {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"},
+    {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"},
+]
+cffi = [
+    {file = "cffi-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962"},
+    {file = "cffi-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0"},
+    {file = "cffi-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14"},
+    {file = "cffi-1.15.0-cp27-cp27m-win32.whl", hash = "sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474"},
+    {file = "cffi-1.15.0-cp27-cp27m-win_amd64.whl", hash = "sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6"},
+    {file = "cffi-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27"},
+    {file = "cffi-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023"},
+    {file = "cffi-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2"},
+    {file = "cffi-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e"},
+    {file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7"},
+    {file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3"},
+    {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c"},
+    {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962"},
+    {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382"},
+    {file = "cffi-1.15.0-cp310-cp310-win32.whl", hash = "sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55"},
+    {file = "cffi-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0"},
+    {file = "cffi-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e"},
+    {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39"},
+    {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc"},
+    {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032"},
+    {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8"},
+    {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605"},
+    {file = "cffi-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e"},
+    {file = "cffi-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc"},
+    {file = "cffi-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636"},
+    {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4"},
+    {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997"},
+    {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b"},
+    {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2"},
+    {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7"},
+    {file = "cffi-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66"},
+    {file = "cffi-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029"},
+    {file = "cffi-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880"},
+    {file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20"},
+    {file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024"},
+    {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e"},
+    {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728"},
+    {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6"},
+    {file = "cffi-1.15.0-cp38-cp38-win32.whl", hash = "sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c"},
+    {file = "cffi-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443"},
+    {file = "cffi-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a"},
+    {file = "cffi-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37"},
+    {file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a"},
+    {file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e"},
+    {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796"},
+    {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df"},
+    {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8"},
+    {file = "cffi-1.15.0-cp39-cp39-win32.whl", hash = "sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a"},
+    {file = "cffi-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139"},
+    {file = "cffi-1.15.0.tar.gz", hash = "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954"},
 ]
 cfgv = [
     {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"},
     {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"},
 ]
+charset-normalizer = [
+    {file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"},
+    {file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"},
+]
 click = [
-    {file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"},
-    {file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"},
+    {file = "click-8.0.4-py3-none-any.whl", hash = "sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1"},
+    {file = "click-8.0.4.tar.gz", hash = "sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb"},
 ]
 colorama = [
     {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
     {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
 ]
+cryptography = [
+    {file = "cryptography-36.0.1-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:73bc2d3f2444bcfeac67dd130ff2ea598ea5f20b40e36d19821b4df8c9c5037b"},
+    {file = "cryptography-36.0.1-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:2d87cdcb378d3cfed944dac30596da1968f88fb96d7fc34fdae30a99054b2e31"},
+    {file = "cryptography-36.0.1-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74d6c7e80609c0f4c2434b97b80c7f8fdfaa072ca4baab7e239a15d6d70ed73a"},
+    {file = "cryptography-36.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:6c0c021f35b421ebf5976abf2daacc47e235f8b6082d3396a2fe3ccd537ab173"},
+    {file = "cryptography-36.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d59a9d55027a8b88fd9fd2826c4392bd487d74bf628bb9d39beecc62a644c12"},
+    {file = "cryptography-36.0.1-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a817b961b46894c5ca8a66b599c745b9a3d9f822725221f0e0fe49dc043a3a3"},
+    {file = "cryptography-36.0.1-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:94ae132f0e40fe48f310bba63f477f14a43116f05ddb69d6fa31e93f05848ae2"},
+    {file = "cryptography-36.0.1-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:7be0eec337359c155df191d6ae00a5e8bbb63933883f4f5dffc439dac5348c3f"},
+    {file = "cryptography-36.0.1-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:e0344c14c9cb89e76eb6a060e67980c9e35b3f36691e15e1b7a9e58a0a6c6dc3"},
+    {file = "cryptography-36.0.1-cp36-abi3-win32.whl", hash = "sha256:4caa4b893d8fad33cf1964d3e51842cd78ba87401ab1d2e44556826df849a8ca"},
+    {file = "cryptography-36.0.1-cp36-abi3-win_amd64.whl", hash = "sha256:391432971a66cfaf94b21c24ab465a4cc3e8bf4a939c1ca5c3e3a6e0abebdbcf"},
+    {file = "cryptography-36.0.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bb5829d027ff82aa872d76158919045a7c1e91fbf241aec32cb07956e9ebd3c9"},
+    {file = "cryptography-36.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ebc15b1c22e55c4d5566e3ca4db8689470a0ca2babef8e3a9ee057a8b82ce4b1"},
+    {file = "cryptography-36.0.1-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:596f3cd67e1b950bc372c33f1a28a0692080625592ea6392987dba7f09f17a94"},
+    {file = "cryptography-36.0.1-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:30ee1eb3ebe1644d1c3f183d115a8c04e4e603ed6ce8e394ed39eea4a98469ac"},
+    {file = "cryptography-36.0.1-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec63da4e7e4a5f924b90af42eddf20b698a70e58d86a72d943857c4c6045b3ee"},
+    {file = "cryptography-36.0.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca238ceb7ba0bdf6ce88c1b74a87bffcee5afbfa1e41e173b1ceb095b39add46"},
+    {file = "cryptography-36.0.1-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:ca28641954f767f9822c24e927ad894d45d5a1e501767599647259cbf030b903"},
+    {file = "cryptography-36.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:39bdf8e70eee6b1c7b289ec6e5d84d49a6bfa11f8b8646b5b3dfe41219153316"},
+    {file = "cryptography-36.0.1.tar.gz", hash = "sha256:53e5c1dc3d7a953de055d77bef2ff607ceef7a2aac0353b5d630ab67f7423638"},
+]
 distlib = [
     {file = "distlib-0.3.4-py2.py3-none-any.whl", hash = "sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b"},
     {file = "distlib-0.3.4.zip", hash = "sha256:e4b58818180336dc9c529bfb9a0b58728ffc09ad92027a3f30b7cd91e3458579"},
 ]
 entrypoints = [
-    {file = "entrypoints-0.3-py2.py3-none-any.whl", hash = "sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19"},
-    {file = "entrypoints-0.3.tar.gz", hash = "sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"},
+    {file = "entrypoints-0.4-py3-none-any.whl", hash = "sha256:f174b5ff827504fd3cd97cc3f8649f3693f51538c7e4bdf3ef002c8429d42f9f"},
+    {file = "entrypoints-0.4.tar.gz", hash = "sha256:b706eddaa9218a19ebcd67b56818f05bb27589b1ca9e8d797b74affad4ccacd4"},
 ]
 eradicate = [
     {file = "eradicate-2.0.0.tar.gz", hash = "sha256:27434596f2c5314cc9b31410c93d8f7e8885747399773cd088d3adea647a60c8"},
 ]
 filelock = [
-    {file = "filelock-3.4.2-py3-none-any.whl", hash = "sha256:cf0fc6a2f8d26bd900f19bf33915ca70ba4dd8c56903eeb14e1e7a2fd7590146"},
-    {file = "filelock-3.4.2.tar.gz", hash = "sha256:38b4f4c989f9d06d44524df1b24bd19e167d851f19b50bf3e3559952dddc5b80"},
+    {file = "filelock-3.6.0-py3-none-any.whl", hash = "sha256:f8314284bfffbdcfa0ff3d7992b023d4c628ced6feb957351d4c48d059f56bc0"},
+    {file = "filelock-3.6.0.tar.gz", hash = "sha256:9cd540a9352e432c7246a48fe4e8712b10acb1df2ad1f30e8c070b82ae1fed85"},
 ]
 flake8 = [
     {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"},
     {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"},
 ]
-flake8-bandit = [
-    {file = "flake8_bandit-2.1.2.tar.gz", hash = "sha256:687fc8da2e4a239b206af2e54a90093572a60d0954f3054e23690739b0b0de3b"},
-]
 flake8-bugbear = [
     {file = "flake8-bugbear-22.1.11.tar.gz", hash = "sha256:4c2a4136bd4ecb8bf02d5159af302ffc067642784c9d0488b33ce4610da825ee"},
     {file = "flake8_bugbear-22.1.11-py3-none-any.whl", hash = "sha256:ce7ae44aaaf67ef192b8a6de94a5ac617144e1675ad0654fdea556f48dc18d9b"},
@@ -1193,20 +1396,16 @@ flake8-pytest-style = [
     {file = "flake8_pytest_style-1.6.0-py3-none-any.whl", hash = "sha256:5fedb371a950e9fe0e0e6bfc854be7d99151271208f34cd2cc517681ece27780"},
 ]
 flakeheaven = [
-    {file = "flakeheaven-0.11.0-py3-none-any.whl", hash = "sha256:7c13bce95cfa496c47e46532f4ed0a020a6532d88f037e79bb9e342d9446992d"},
-    {file = "flakeheaven-0.11.0.tar.gz", hash = "sha256:002f2de2bbc2ae72c2920cfc91cf068c89b7a561c61f63efe4a06c4af146c2dd"},
-]
-gitdb = [
-    {file = "gitdb-4.0.9-py3-none-any.whl", hash = "sha256:8033ad4e853066ba6ca92050b9df2f89301b8fc8bf7e9324d412a63f8bf1a8fd"},
-    {file = "gitdb-4.0.9.tar.gz", hash = "sha256:bac2fd45c0a1c9cf619e63a90d62bdc63892ef92387424b855792a6cabe789aa"},
-]
-gitpython = [
-    {file = "GitPython-3.1.26-py3-none-any.whl", hash = "sha256:26ac35c212d1f7b16036361ca5cff3ec66e11753a0d677fb6c48fa4e1a9dd8d6"},
-    {file = "GitPython-3.1.26.tar.gz", hash = "sha256:fc8868f63a2e6d268fb25f481995ba185a85a66fcad126f039323ff6635669ee"},
+    {file = "flakeheaven-0.11.1-py3-none-any.whl", hash = "sha256:5614165d95bf26c46af22db4e0ccc90e475c286f902c473de16730fad4735e5d"},
+    {file = "flakeheaven-0.11.1.tar.gz", hash = "sha256:20f5a573b8e85be5a73fed2e3967f7ab8b5e77714a5898d8b634dd31a0b75f9b"},
 ]
 identify = [
-    {file = "identify-2.4.4-py2.py3-none-any.whl", hash = "sha256:aa68609c7454dbcaae60a01ff6b8df1de9b39fe6e50b1f6107ec81dcda624aa6"},
-    {file = "identify-2.4.4.tar.gz", hash = "sha256:6b4b5031f69c48bf93a646b90de9b381c6b5f560df4cbe0ed3cf7650ae741e4d"},
+    {file = "identify-2.4.11-py2.py3-none-any.whl", hash = "sha256:fd906823ed1db23c7a48f9b176a1d71cb8abede1e21ebe614bac7bdd688d9213"},
+    {file = "identify-2.4.11.tar.gz", hash = "sha256:2986942d3974c8f2e5019a190523b0b0e2a07cb8e89bf236727fb4b26f27f8fd"},
+]
+idna = [
+    {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"},
+    {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"},
 ]
 iniconfig = [
     {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
@@ -1216,14 +1415,64 @@ isort = [
     {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"},
     {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"},
 ]
+jinja2 = [
+    {file = "Jinja2-3.0.3-py3-none-any.whl", hash = "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8"},
+    {file = "Jinja2-3.0.3.tar.gz", hash = "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7"},
+]
 jmespath = [
     {file = "jmespath-0.10.0-py2.py3-none-any.whl", hash = "sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f"},
     {file = "jmespath-0.10.0.tar.gz", hash = "sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9"},
 ]
+markupsafe = [
+    {file = "MarkupSafe-2.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3028252424c72b2602a323f70fbf50aa80a5d3aa616ea6add4ba21ae9cc9da4c"},
+    {file = "MarkupSafe-2.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:290b02bab3c9e216da57c1d11d2ba73a9f73a614bbdcc027d299a60cdfabb11a"},
+    {file = "MarkupSafe-2.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e104c0c2b4cd765b4e83909cde7ec61a1e313f8a75775897db321450e928cce"},
+    {file = "MarkupSafe-2.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24c3be29abb6b34052fd26fc7a8e0a49b1ee9d282e3665e8ad09a0a68faee5b3"},
+    {file = "MarkupSafe-2.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:204730fd5fe2fe3b1e9ccadb2bd18ba8712b111dcabce185af0b3b5285a7c989"},
+    {file = "MarkupSafe-2.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d3b64c65328cb4cd252c94f83e66e3d7acf8891e60ebf588d7b493a55a1dbf26"},
+    {file = "MarkupSafe-2.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:96de1932237abe0a13ba68b63e94113678c379dca45afa040a17b6e1ad7ed076"},
+    {file = "MarkupSafe-2.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:75bb36f134883fdbe13d8e63b8675f5f12b80bb6627f7714c7d6c5becf22719f"},
+    {file = "MarkupSafe-2.1.0-cp310-cp310-win32.whl", hash = "sha256:4056f752015dfa9828dce3140dbadd543b555afb3252507348c493def166d454"},
+    {file = "MarkupSafe-2.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:d4e702eea4a2903441f2735799d217f4ac1b55f7d8ad96ab7d4e25417cb0827c"},
+    {file = "MarkupSafe-2.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f0eddfcabd6936558ec020130f932d479930581171368fd728efcfb6ef0dd357"},
+    {file = "MarkupSafe-2.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ddea4c352a488b5e1069069f2f501006b1a4362cb906bee9a193ef1245a7a61"},
+    {file = "MarkupSafe-2.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09c86c9643cceb1d87ca08cdc30160d1b7ab49a8a21564868921959bd16441b8"},
+    {file = "MarkupSafe-2.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a0a0abef2ca47b33fb615b491ce31b055ef2430de52c5b3fb19a4042dbc5cadb"},
+    {file = "MarkupSafe-2.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:736895a020e31b428b3382a7887bfea96102c529530299f426bf2e636aacec9e"},
+    {file = "MarkupSafe-2.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:679cbb78914ab212c49c67ba2c7396dc599a8479de51b9a87b174700abd9ea49"},
+    {file = "MarkupSafe-2.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:84ad5e29bf8bab3ad70fd707d3c05524862bddc54dc040982b0dbcff36481de7"},
+    {file = "MarkupSafe-2.1.0-cp37-cp37m-win32.whl", hash = "sha256:8da5924cb1f9064589767b0f3fc39d03e3d0fb5aa29e0cb21d43106519bd624a"},
+    {file = "MarkupSafe-2.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:454ffc1cbb75227d15667c09f164a0099159da0c1f3d2636aa648f12675491ad"},
+    {file = "MarkupSafe-2.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:142119fb14a1ef6d758912b25c4e803c3ff66920635c44078666fe7cc3f8f759"},
+    {file = "MarkupSafe-2.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b2a5a856019d2833c56a3dcac1b80fe795c95f401818ea963594b345929dffa7"},
+    {file = "MarkupSafe-2.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d1fb9b2eec3c9714dd936860850300b51dbaa37404209c8d4cb66547884b7ed"},
+    {file = "MarkupSafe-2.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62c0285e91414f5c8f621a17b69fc0088394ccdaa961ef469e833dbff64bd5ea"},
+    {file = "MarkupSafe-2.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fc3150f85e2dbcf99e65238c842d1cfe69d3e7649b19864c1cc043213d9cd730"},
+    {file = "MarkupSafe-2.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f02cf7221d5cd915d7fa58ab64f7ee6dd0f6cddbb48683debf5d04ae9b1c2cc1"},
+    {file = "MarkupSafe-2.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d5653619b3eb5cbd35bfba3c12d575db2a74d15e0e1c08bf1db788069d410ce8"},
+    {file = "MarkupSafe-2.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7d2f5d97fcbd004c03df8d8fe2b973fe2b14e7bfeb2cfa012eaa8759ce9a762f"},
+    {file = "MarkupSafe-2.1.0-cp38-cp38-win32.whl", hash = "sha256:3cace1837bc84e63b3fd2dfce37f08f8c18aeb81ef5cf6bb9b51f625cb4e6cd8"},
+    {file = "MarkupSafe-2.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:fabbe18087c3d33c5824cb145ffca52eccd053061df1d79d4b66dafa5ad2a5ea"},
+    {file = "MarkupSafe-2.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:023af8c54fe63530545f70dd2a2a7eed18d07a9a77b94e8bf1e2ff7f252db9a3"},
+    {file = "MarkupSafe-2.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d66624f04de4af8bbf1c7f21cc06649c1c69a7f84109179add573ce35e46d448"},
+    {file = "MarkupSafe-2.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c532d5ab79be0199fa2658e24a02fce8542df196e60665dd322409a03db6a52c"},
+    {file = "MarkupSafe-2.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67ec74fada3841b8c5f4c4f197bea916025cb9aa3fe5abf7d52b655d042f956"},
+    {file = "MarkupSafe-2.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30c653fde75a6e5eb814d2a0a89378f83d1d3f502ab710904ee585c38888816c"},
+    {file = "MarkupSafe-2.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:961eb86e5be7d0973789f30ebcf6caab60b844203f4396ece27310295a6082c7"},
+    {file = "MarkupSafe-2.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:598b65d74615c021423bd45c2bc5e9b59539c875a9bdb7e5f2a6b92dfcfc268d"},
+    {file = "MarkupSafe-2.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:599941da468f2cf22bf90a84f6e2a65524e87be2fce844f96f2dd9a6c9d1e635"},
+    {file = "MarkupSafe-2.1.0-cp39-cp39-win32.whl", hash = "sha256:e6f7f3f41faffaea6596da86ecc2389672fa949bd035251eab26dc6697451d05"},
+    {file = "MarkupSafe-2.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:b8811d48078d1cf2a6863dafb896e68406c5f513048451cd2ded0473133473c7"},
+    {file = "MarkupSafe-2.1.0.tar.gz", hash = "sha256:80beaf63ddfbc64a0452b841d8036ca0611e049650e20afcb882f5d3c266d65f"},
+]
 mccabe = [
     {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
     {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
 ]
+moto = [
+    {file = "moto-3.0.4-py2.py3-none-any.whl", hash = "sha256:79646213d8438385182f4eea79e28725f94b3d0d3dc9a3eda81db47e0ebef6cc"},
+    {file = "moto-3.0.4.tar.gz", hash = "sha256:168b8a3cb4dd8a6df8e51d582761cefa9657b9f45ac7e1eb24dae394ebc9e000"},
+]
 mypy = [
     {file = "mypy-0.931-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3c5b42d0815e15518b1f0990cff7a705805961613e701db60387e6fb663fe78a"},
     {file = "mypy-0.931-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c89702cac5b302f0c5d33b172d2b55b5df2bede3344a2fbed99ff96bddb2cf00"},
@@ -1247,12 +1496,12 @@ mypy = [
     {file = "mypy-0.931.tar.gz", hash = "sha256:0038b21890867793581e4cb0d810829f5fd4441aa75796b53033af3aa30430ce"},
 ]
 mypy-boto3-organizations = [
-    {file = "mypy-boto3-organizations-1.20.35.post1.tar.gz", hash = "sha256:0353afc1161227e16c2199a6c6c98483db0afcf9066479b21b293127e3cd01bd"},
-    {file = "mypy_boto3_organizations-1.20.35.post1-py3-none-any.whl", hash = "sha256:7dc3872d468f37f03ded0437af06b4e84c4b1d737be92c919894654150f2e00c"},
+    {file = "mypy-boto3-organizations-1.21.0.tar.gz", hash = "sha256:99b3896308431dbbf9ba004c47d2d3619424768ccc043debcbe0cd8232af2d29"},
+    {file = "mypy_boto3_organizations-1.21.0-py3-none-any.whl", hash = "sha256:3cb3ad72ac9e41a419ff4b37254fe39dffe0cfaf4540b7fe7bd148be54cac050"},
 ]
 mypy-boto3-sts = [
-    {file = "mypy-boto3-sts-1.20.35.post1.tar.gz", hash = "sha256:fde6deb8e91e9519c13ee409f36b0671cdfce8b6799b4cf2330eeb010ce36eab"},
-    {file = "mypy_boto3_sts-1.20.35.post1-py3-none-any.whl", hash = "sha256:0c22f42af0d79d4cce1940a904d77828ec36644475a665155b5320e55abbe8c1"},
+    {file = "mypy-boto3-sts-1.21.0.tar.gz", hash = "sha256:4365430ab02116922350422552b5faae1e9fb4c89dadf1dac2ff31d5c74658aa"},
+    {file = "mypy_boto3_sts-1.21.0-py3-none-any.whl", hash = "sha256:67168d7405aa96dadb7770d69ad7466f162c7d087ab1406fee1fc0baa07e6cbb"},
 ]
 mypy-extensions = [
     {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
@@ -1270,17 +1519,13 @@ pathspec = [
     {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"},
     {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"},
 ]
-pbr = [
-    {file = "pbr-5.8.0-py2.py3-none-any.whl", hash = "sha256:176e8560eaf61e127817ef93d8a844803abb27a4d4637f0ff3bb783129be2e0a"},
-    {file = "pbr-5.8.0.tar.gz", hash = "sha256:672d8ebee84921862110f23fcec2acea191ef58543d34dfe9ef3d9f13c31cddf"},
-]
 pep8-naming = [
     {file = "pep8-naming-0.12.1.tar.gz", hash = "sha256:bb2455947757d162aa4cad55dba4ce029005cd1692f2899a21d51d8630ca7841"},
     {file = "pep8_naming-0.12.1-py2.py3-none-any.whl", hash = "sha256:4a8daeaeb33cfcde779309fc0c9c0a68a3bbe2ad8a8308b763c5068f86eb9f37"},
 ]
 platformdirs = [
-    {file = "platformdirs-2.4.1-py3-none-any.whl", hash = "sha256:1d7385c7db91728b83efd0ca99a5afb296cab9d0ed8313a45ed8ba17967ecfca"},
-    {file = "platformdirs-2.4.1.tar.gz", hash = "sha256:440633ddfebcc36264232365d7840a970e75e1018d15b4327d11f91909045fda"},
+    {file = "platformdirs-2.5.1-py3-none-any.whl", hash = "sha256:bcae7cab893c2d310a711b70b24efb93334febe65f8de776ee320b517471e227"},
+    {file = "platformdirs-2.5.1.tar.gz", hash = "sha256:7535e70dfa32e84d4b34996ea99c5e432fa29a708d0f4e394bbcb2a8faa4f16d"},
 ]
 pluggy = [
     {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
@@ -1298,6 +1543,10 @@ pycodestyle = [
     {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"},
     {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"},
 ]
+pycparser = [
+    {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"},
+    {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"},
+]
 pyflakes = [
     {file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"},
     {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"},
@@ -1311,17 +1560,21 @@ pyparsing = [
     {file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"},
 ]
 pytest = [
-    {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"},
-    {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"},
+    {file = "pytest-7.0.1-py3-none-any.whl", hash = "sha256:9ce3ff477af913ecf6321fe337b93a2c0dcf2a0a1439c43f5452112c1e4280db"},
+    {file = "pytest-7.0.1.tar.gz", hash = "sha256:e30905a0c131d3d94b89624a1cc5afec3e0ba2fbdb151867d8e0ebd49850f171"},
 ]
 pytest-mock = [
-    {file = "pytest-mock-3.6.1.tar.gz", hash = "sha256:40217a058c52a63f1042f0784f62009e976ba824c418cced42e88d5f40ab0e62"},
-    {file = "pytest_mock-3.6.1-py3-none-any.whl", hash = "sha256:30c2f2cc9759e76eee674b81ea28c9f0b94f8f0445a1b87762cadf774f0df7e3"},
+    {file = "pytest-mock-3.7.0.tar.gz", hash = "sha256:5112bd92cc9f186ee96e1a92efc84969ea494939c3aead39c50f421c4cc69534"},
+    {file = "pytest_mock-3.7.0-py3-none-any.whl", hash = "sha256:6cff27cec936bf81dc5ee87f07132b807bcda51106b5ec4b90a04331cba76231"},
 ]
 python-dateutil = [
     {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
     {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
 ]
+pytz = [
+    {file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"},
+    {file = "pytz-2021.3.tar.gz", hash = "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"},
+]
 pyyaml = [
     {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"},
     {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"},
@@ -1357,22 +1610,22 @@ pyyaml = [
     {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"},
     {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"},
 ]
+requests = [
+    {file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"},
+    {file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"},
+]
+responses = [
+    {file = "responses-0.18.0-py3-none-any.whl", hash = "sha256:15c63ad16de13ee8e7182d99c9334f64fd81f1ee79f90748d527c28f7ca9dd51"},
+    {file = "responses-0.18.0.tar.gz", hash = "sha256:380cad4c1c1dc942e5e8a8eaae0b4d4edf708f4f010db8b7bcfafad1fcd254ff"},
+]
 s3transfer = [
-    {file = "s3transfer-0.5.0-py3-none-any.whl", hash = "sha256:9c1dc369814391a6bda20ebbf4b70a0f34630592c9aa520856bf384916af2803"},
-    {file = "s3transfer-0.5.0.tar.gz", hash = "sha256:50ed823e1dc5868ad40c8dc92072f757aa0e653a192845c94a3b676f4a62da4c"},
+    {file = "s3transfer-0.5.1-py3-none-any.whl", hash = "sha256:25c140f5c66aa79e1ac60be50dcd45ddc59e83895f062a3aab263b870102911f"},
+    {file = "s3transfer-0.5.1.tar.gz", hash = "sha256:69d264d3e760e569b78aaa0f22c97e955891cd22e32b10c51f784eeda4d9d10a"},
 ]
 six = [
     {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
     {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
 ]
-smmap = [
-    {file = "smmap-5.0.0-py3-none-any.whl", hash = "sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94"},
-    {file = "smmap-5.0.0.tar.gz", hash = "sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936"},
-]
-stevedore = [
-    {file = "stevedore-3.5.0-py3-none-any.whl", hash = "sha256:a547de73308fd7e90075bb4d301405bebf705292fa90a90fc3bcf9133f58616c"},
-    {file = "stevedore-3.5.0.tar.gz", hash = "sha256:f40253887d8712eaa2bb0ea3830374416736dc8ec0e22f5a65092c1174c44335"},
-]
 testfixtures = [
     {file = "testfixtures-6.18.3-py2.py3-none-any.whl", hash = "sha256:6ddb7f56a123e1a9339f130a200359092bd0a6455e31838d6c477e8729bb7763"},
     {file = "testfixtures-6.18.3.tar.gz", hash = "sha256:2600100ae96ffd082334b378e355550fef8b4a529a6fa4c34f47130905c7426d"},
@@ -1382,22 +1635,30 @@ toml = [
     {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
 ]
 tomli = [
-    {file = "tomli-1.2.3-py3-none-any.whl", hash = "sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c"},
-    {file = "tomli-1.2.3.tar.gz", hash = "sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f"},
+    {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
+    {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
 ]
 tqdm = [
     {file = "tqdm-4.62.3-py2.py3-none-any.whl", hash = "sha256:8dd278a422499cd6b727e6ae4061c40b48fce8b76d1ccbf5d34fca9b7f925b0c"},
     {file = "tqdm-4.62.3.tar.gz", hash = "sha256:d359de7217506c9851b7869f3708d8ee53ed70a1b8edbba4dbcb47442592920d"},
 ]
 typing-extensions = [
-    {file = "typing_extensions-4.0.1-py3-none-any.whl", hash = "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b"},
-    {file = "typing_extensions-4.0.1.tar.gz", hash = "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e"},
+    {file = "typing_extensions-4.1.1-py3-none-any.whl", hash = "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"},
+    {file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"},
 ]
 urllib3 = [
     {file = "urllib3-1.26.8-py2.py3-none-any.whl", hash = "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed"},
     {file = "urllib3-1.26.8.tar.gz", hash = "sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c"},
 ]
 virtualenv = [
-    {file = "virtualenv-20.13.0-py2.py3-none-any.whl", hash = "sha256:339f16c4a86b44240ba7223d0f93a7887c3ca04b5f9c8129da7958447d079b09"},
-    {file = "virtualenv-20.13.0.tar.gz", hash = "sha256:d8458cf8d59d0ea495ad9b34c2599487f8a7772d796f9910858376d1600dd2dd"},
+    {file = "virtualenv-20.13.1-py2.py3-none-any.whl", hash = "sha256:45e1d053cad4cd453181ae877c4ffc053546ae99e7dd049b9ff1d9be7491abf7"},
+    {file = "virtualenv-20.13.1.tar.gz", hash = "sha256:e0621bcbf4160e4e1030f05065c8834b4e93f4fcc223255db2a823440aca9c14"},
+]
+werkzeug = [
+    {file = "Werkzeug-2.0.3-py3-none-any.whl", hash = "sha256:1421ebfc7648a39a5c58c601b154165d05cf47a3cd0ccb70857cbdacf6c8f2b8"},
+    {file = "Werkzeug-2.0.3.tar.gz", hash = "sha256:b863f8ff057c522164b6067c9e28b041161b4be5ba4d0daceeaa50a163822d3c"},
+]
+xmltodict = [
+    {file = "xmltodict-0.12.0-py2.py3-none-any.whl", hash = "sha256:8bbcb45cc982f48b2ca8fe7e7827c5d792f217ecf1792626f808bf41c3b86051"},
+    {file = "xmltodict-0.12.0.tar.gz", hash = "sha256:50d8c638ed7ecb88d90561beedbf720c9b4e851a9fa6c47ebd64e99d166d8a21"},
 ]
diff --git a/pyproject.toml b/pyproject.toml
index de82358..aafa835 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "botocove"
-version = "1.5.1"
+version = "1.5.2"
 description = "A decorator to allow running a function against all AWS accounts in an organization"
 authors = ["Dave Connell <daveconn41@gmail.com>"]
 license = "LGPL-3.0-or-later"
@@ -31,6 +31,7 @@ flake8-print = "*"
 mypy = "*"
 pre-commit = "*"
 flakeheaven = "*"
+moto = {extras = ["organizations", "sts"], version = "*"}
 
 
 [build-system]


Test patch:
diff --git a/tests/conftest.py b/tests/conftest.py
index 7f32d88..7820ab8 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,8 +1,13 @@
 import logging
+from typing import Iterator
 
+import boto3
 import pytest
 from _pytest.logging import LogCaptureFixture
 from _pytest.monkeypatch import MonkeyPatch
+from moto import mock_organizations, mock_sts
+
+from tests.moto_mock_org.moto_models import LargeOrg, SmallOrg
 
 
 @pytest.fixture(autouse=True)
@@ -17,3 +22,24 @@ def _clean_env(monkeypatch: MonkeyPatch) -> None:
     # https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html#configuring-credentials
     for env_var in env_vars:
         monkeypatch.setenv(env_var, "broken_not_real_profile")
+
+
+# We tear down each fixture in the default function scope as Moto isn't thread-safe
+# Maintaining Moto mocks between tests means shared state mutation
+# We could just use one mock org instead - option for future.
+@pytest.fixture()
+def mock_small_org() -> Iterator[SmallOrg]:
+    """Uses moto mocking library to allow creation of fake AWS environment."""
+    with mock_sts():
+        with mock_organizations():
+            session = boto3.session.Session()
+            yield SmallOrg(session=session)
+
+
+@pytest.fixture()
+def mock_large_org() -> Iterator[LargeOrg]:
+    """Uses moto mocking library to allow creation of fake AWS environment."""
+    with mock_sts():
+        with mock_organizations():
+            session = boto3.session.Session()
+            yield LargeOrg(session=session)
diff --git a/tests/moto_mock_org/__init__.py b/tests/moto_mock_org/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/moto_mock_org/moto_models.py b/tests/moto_mock_org/moto_models.py
new file mode 100644
index 0000000..75bd334
--- /dev/null
+++ b/tests/moto_mock_org/moto_models.py
@@ -0,0 +1,116 @@
+from typing import List
+
+import boto3
+from mypy_boto3_organizations import OrganizationsClient
+
+
+class SmallOrg:
+    def __init__(self, session: boto3.Session):
+        mock_org_client = session.client("organizations")
+
+        # create org
+        self.master_acc_id = mock_org_client.create_organization(
+            FeatureSet="CONSOLIDATED_BILLING"
+        )["Organization"]["MasterAccountId"]
+        # Create 3 deep org nest
+        # root -> 1 -> 2 -> 3
+        # root -> 4
+        root_id = mock_org_client.list_roots()["Roots"][0]["Id"]
+
+        self.new_org1 = mock_org_client.create_organizational_unit(
+            ParentId=root_id,
+            Name="ou-1",
+        )["OrganizationalUnit"]["Id"]
+        self.new_org2 = mock_org_client.create_organizational_unit(
+            ParentId=self.new_org1,
+            Name="ou-2",
+        )["OrganizationalUnit"]["Id"]
+        self.new_org3 = mock_org_client.create_organizational_unit(
+            ParentId=self.new_org2,
+            Name="ou-3",
+        )["OrganizationalUnit"]["Id"]
+
+        # Create a second fork from root
+        self.new_org4 = mock_org_client.create_organizational_unit(
+            ParentId=root_id,
+            Name="ou-4",
+        )["OrganizationalUnit"]["Id"]
+
+        self.account_group_one = create_accounts_in_ou(
+            mock_org_client, 0, 3, root_id, self.new_org3
+        )
+        self.account_group_two = create_accounts_in_ou(
+            mock_org_client, 4, 5, root_id, self.new_org4
+        )
+
+        self.all_accounts = self.account_group_one + self.account_group_two
+
+
+class LargeOrg:
+    def __init__(self, session: boto3.Session):
+        mock_org_client: OrganizationsClient = session.client("organizations")
+
+        # create org
+        # root - A -> B
+        #         \-> C
+        # root - D
+        self.master_acc_id = mock_org_client.create_organization(
+            FeatureSet="CONSOLIDATED_BILLING"
+        )["Organization"]["MasterAccountId"]
+
+        # Create 3 deep org nest
+        root_id = mock_org_client.list_roots()["Roots"][0]["Id"]
+
+        # Member of root
+        self.ou_A = mock_org_client.create_organizational_unit(
+            ParentId=root_id,
+            Name="ou-a",
+        )["OrganizationalUnit"]["Id"]
+        # Members of A
+        self.ou_B = mock_org_client.create_organizational_unit(
+            ParentId=self.ou_A,
+            Name="ou-b",
+        )["OrganizationalUnit"]["Id"]
+        self.ou_C = mock_org_client.create_organizational_unit(
+            ParentId=self.ou_A,
+            Name="ou-c",
+        )["OrganizationalUnit"]["Id"]
+        # Member of root
+        self.ou_D = mock_org_client.create_organizational_unit(
+            ParentId=root_id,
+            Name="ou-d",
+        )["OrganizationalUnit"]["Id"]
+
+        self.account_group_one = create_accounts_in_ou(
+            mock_org_client, 0, 500, root_id, self.ou_B
+        )
+
+        self.account_group_two = create_accounts_in_ou(
+            mock_org_client, 500, 1000, root_id, self.ou_C
+        )
+
+        self.account_group_three = create_accounts_in_ou(
+            mock_org_client, 1000, 1500, root_id, self.ou_D
+        )
+
+        self.all_accounts = (
+            self.account_group_one + self.account_group_two + self.account_group_three
+        )
+
+
+def create_accounts_in_ou(
+    client: OrganizationsClient, start: int, stop: int, root_id: str, target_ou: str
+) -> List[str]:
+    account_ids = []
+    for i in range(start, stop):
+        acc_id = client.create_account(
+            Email=f"mock{i}@mock.com", AccountName=f"mock{i}"
+        )["CreateAccountStatus"]["AccountId"]
+        # Move account to bottom of OU tree
+        client.move_account(
+            AccountId=acc_id,
+            SourceParentId=root_id,
+            DestinationParentId=target_ou,
+        )
+        account_ids.append(acc_id)
+    return account_ids
diff --git a/tests/moto_mock_org/test_botocove/__init__.py b/tests/moto_mock_org/test_botocove/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/moto_mock_org/test_botocove/test_botocove.py b/tests/moto_mock_org/test_botocove/test_botocove.py
new file mode 100644
index 0000000..6f1eaad
--- /dev/null
+++ b/tests/moto_mock_org/test_botocove/test_botocove.py
@@ -0,0 +1,12 @@
+from botocove import CoveSession, cove
+from tests.moto_mock_org.moto_models import SmallOrg
+
+
+def test_decorated_simple_func(mock_small_org: SmallOrg) -> None:
+    @cove()
+    def simple_func(session: CoveSession) -> str:
+        return "hello"
+
+    cove_output = simple_func()
+    # Two simple_func calls == two mock AWS accounts
+    assert len(cove_output["Results"]) == 4
diff --git a/tests/moto_mock_org/test_host_account/__init__.py b/tests/moto_mock_org/test_host_account/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/moto_mock_org/test_host_account/test_regions.py b/tests/moto_mock_org/test_host_account/test_regions.py
new file mode 100644
index 0000000..01d3b0d
--- /dev/null
+++ b/tests/moto_mock_org/test_host_account/test_regions.py
@@ -0,0 +1,47 @@
+from botocove.cove_host_account import CoveHostAccount
+from tests.moto_mock_org.moto_models import SmallOrg
+
+
+def test_regions(mock_small_org: SmallOrg) -> None:
+
+    host_account = CoveHostAccount(
+        target_ids=None,
+        ignore_ids=None,
+        rolename=None,
+        role_session_name=None,
+        policy=None,
+        policy_arns=None,
+        org_master=True,
+        assuming_session=None,
+        regions=["eu-west-1", "eu-west-2"],
+        thread_workers=20,
+    )
+    sessions = host_account.get_cove_sessions()
+    account_ids = [acc_id["Id"] for acc_id in sessions]
+    assert len(account_ids) == len(host_account.target_accounts) * 2
+
+    regions = [acc_id["Region"] for acc_id in sessions]
+    assert "eu-west-1" in regions
+    assert "eu-west-2" in regions
+
+
+def test_no_regions(mock_small_org: SmallOrg) -> None:
+
+    host_account = CoveHostAccount(
+        target_ids=None,
+        ignore_ids=None,
+        rolename=None,
+        role_session_name=None,
+        policy=None,
+        policy_arns=None,
+        org_master=True,
+        assuming_session=None,
+        regions=None,
+        thread_workers=20,
+    )
+    sessions = host_account.get_cove_sessions()
+    account_ids = [acc_id["Id"] for acc_id in sessions]
+    assert set(account_ids) == set(mock_small_org.all_accounts)
+
+    for s in sessions:
+        assert s.get("Region", None) is None
diff --git a/tests/moto_mock_org/test_host_account/test_resolve_targets.py b/tests/moto_mock_org/test_host_account/test_resolve_targets.py
new file mode 100644
index 0000000..1f70ad0
--- /dev/null
+++ b/tests/moto_mock_org/test_host_account/test_resolve_targets.py
@@ -0,0 +1,91 @@
+from botocove.cove_host_account import CoveHostAccount
+from tests.moto_mock_org.moto_models import SmallOrg
+
+
+def test_target_all_in_org(mock_small_org: SmallOrg) -> None:
+
+    host_account = CoveHostAccount(
+        target_ids=None,
+        ignore_ids=None,
+        rolename=None,
+        role_session_name=None,
+        policy=None,
+        policy_arns=None,
+        org_master=True,
+        assuming_session=None,
+        regions=None,
+        thread_workers=20,
+    )
+    sessions = host_account.get_cove_sessions()
+    account_ids = [acc_id["Id"] for acc_id in sessions]
+    assert set(account_ids) == set(mock_small_org.all_accounts)
+    assert mock_small_org.master_acc_id not in account_ids
+
+
+def test_target_all_in_org_ignore_one(mock_small_org: SmallOrg) -> None:
+
+    ignore_acc = mock_small_org.all_accounts[0]
+
+    host_account = CoveHostAccount(
+        target_ids=None,
+        ignore_ids=[ignore_acc],
+        rolename=None,
+        role_session_name=None,
+        policy=None,
+        policy_arns=None,
+        org_master=True,
+        assuming_session=None,
+        regions=None,
+        thread_workers=20,
+    )
+    sessions = host_account.get_cove_sessions()
+    account_ids = [acc_id["Id"] for acc_id in sessions]
+
+    assert set(account_ids) == set(mock_small_org.all_accounts[1:])
+    assert ignore_acc not in account_ids
+
+
+def test_target_targets_and_ignores(mock_small_org: SmallOrg) -> None:
+
+    target_accs = mock_small_org.all_accounts[1:]
+    ignore_acc = mock_small_org.all_accounts[0]
+
+    host_account = CoveHostAccount(
+        target_ids=target_accs,
+        ignore_ids=[ignore_acc],
+        rolename=None,
+        role_session_name=None,
+        policy=None,
+        policy_arns=None,
+        org_master=True,
+        assuming_session=None,
+        regions=None,
+        thread_workers=20,
+    )
+    sessions = host_account.get_cove_sessions()
+    account_ids = [acc_id["Id"] for acc_id in sessions]
+
+    assert set(account_ids) == set(mock_small_org.all_accounts[1:])
+    assert ignore_acc not in account_ids
+
+
+def test_target_just_targets(mock_small_org: SmallOrg) -> None:
+
+    target_accs = mock_small_org.all_accounts[0:2]
+
+    host_account = CoveHostAccount(
+        target_ids=target_accs,
+        ignore_ids=None,
+        rolename=None,
+        role_session_name=None,
+        policy=None,
+        policy_arns=None,
+        org_master=True,
+        assuming_session=None,
+        regions=None,
+        thread_workers=20,
+    )
+    sessions = host_account.get_cove_sessions()
+    account_ids = [acc_id["Id"] for acc_id in sessions]
+
+    assert set(account_ids) == set(mock_small_org.all_accounts[0:2])
diff --git a/tests/moto_mock_org/test_moto.py b/tests/moto_mock_org/test_moto.py
new file mode 100644
index 0000000..2e13344
--- /dev/null
+++ b/tests/moto_mock_org/test_moto.py
@@ -0,0 +1,37 @@
+from botocove.cove_host_account import CoveHostAccount
+from tests.moto_mock_org.moto_models import LargeOrg, SmallOrg
+
+
+def test_small_org(mock_small_org: SmallOrg) -> None:
+    host_account = CoveHostAccount(
+        target_ids=None,
+        ignore_ids=None,
+        rolename=None,
+        role_session_name=None,
+        policy=None,
+        policy_arns=None,
+        org_master=True,
+        assuming_session=None,
+        regions=None,
+        thread_workers=20,
+    )
+    assert mock_small_org.master_acc_id == host_account.host_account_id
+    assert set(mock_small_org.all_accounts) == host_account.target_accounts
+
+
+def test_large_org(mock_large_org: LargeOrg) -> None:
+
+    host_account = CoveHostAccount(
+        target_ids=None,
+        ignore_ids=None,
+        rolename=None,
+        role_session_name=None,
+        policy=None,
+        policy_arns=None,
+        org_master=True,
+        assuming_session=None,
+        regions=None,
+        thread_workers=20,
+    )
+    assert mock_large_org.master_acc_id == host_account.host_account_id
+    assert set(mock_large_org.all_accounts) == host_account.target_accounts
diff --git a/tests/test_decorator.py b/tests/test_decorator.py
index 3fdf201..466cf66 100644
--- a/tests/test_decorator.py
+++ b/tests/test_decorator.py
@@ -143,7 +143,7 @@ def simple_func(session: CoveSession, arg1: int, arg2: int, arg3: int) -> int:
             "RoleSessionName": "OrganizationAccountAccessRole",
         }
     ]
-    # Two simple_func calls == two mock AWS accounts
+
     assert cove_output["Results"] == expected