diff --git a/Makefile b/Makefile index c69818162d..8876d482b2 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ lint: # Linter performs static analysis to catch latent bugs ruff samcli # mypy performs type check - mypy --no-incremental setup.py samcli tests + mypy --exclude /testdata/ --exclude /init/templates/ --no-incremental setup.py samcli tests # Command to run everytime you make changes to verify everything works dev: lint test diff --git a/mypy.ini b/mypy.ini index 5a0be0e705..ba4e3fa9d1 100644 --- a/mypy.ini +++ b/mypy.ini @@ -5,7 +5,7 @@ warn_return_any=True warn_unused_configs=True no_implicit_optional=True warn_redundant_casts=True -warn_unused_ignores=True +warn_unused_ignores=False # @jfuss Done as a stop gap since different py versions have different errors warn_unreachable=True # diff --git a/requirements/base.txt b/requirements/base.txt index f2bb6a0f81..84eb44da14 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -3,21 +3,21 @@ click~=8.0 Flask<2.3 #Need to add Schemas latest SDK. boto3>=1.19.5,==1.* -jmespath~=0.10.0 -ruamel_yaml==0.17.21 +jmespath~=1.0.1 +ruamel_yaml~=0.17.21 PyYAML>=5.4.1,==5.* cookiecutter~=2.1.1 aws-sam-translator==1.68.0 #docker minor version updates can include breaking changes. Auto update micro version only. -docker~=4.2.0 +docker~=6.1.0 dateparser~=1.1 -requests==2.31.0 +requests~=2.31.0 serverlessrepo==0.1.10 aws_lambda_builders==1.33.0 tomlkit==0.11.8 watchdog==2.1.2 rich~=13.3.3 -pyopenssl==23.0.0 +pyopenssl~=23.0.0 # Needed for supporting Protocol in Python 3.7, Protocol class became public with python3.8 typing_extensions~=4.4.0 diff --git a/requirements/dev.txt b/requirements/dev.txt index ecb95dbcfa..f5dcf55592 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -1,22 +1,30 @@ -r pre-dev.txt -coverage==5.3 +coverage==7.2.7 pytest-cov==4.0.0 # type checking and related stubs # mypy adds new rules in new minor versions, which could cause our PR check to fail # here we fix its version and upgrade it manually in the future -mypy==0.790 +mypy==1.3.0 boto3-stubs[apigateway,cloudformation,ecr,iam,lambda,s3,schemas,secretsmanager,signer,stepfunctions,sts,xray]==1.26.131 types-pywin32==306.0.0.0 types-PyYAML==6.0.12 types-chevron==0.14.2.4 types-psutil==5.9.5.12 types-setuptools==65.4.0.0 +types-Pygments==2.15.0.1 +types-colorama==0.4.15.11 +types-dateparser==1.1.4.9 +types-docutils==0.20.0.1 +types-jsonschema==4.17.0.8 +types-pyOpenSSL==23.2.0.0 +types-requests==2.31.0.1 +types-urllib3==1.26.25.13 # Test requirements -pytest==7.2.2 +pytest~=7.2.2 parameterized==0.9.0 pytest-xdist==3.2.0 pytest-forked==1.6.0 diff --git a/requirements/reproducible-linux.txt b/requirements/reproducible-linux.txt index 7be7aa0656..e8faac8822 100644 --- a/requirements/reproducible-linux.txt +++ b/requirements/reproducible-linux.txt @@ -241,9 +241,9 @@ dateparser==1.1.8 \ --hash=sha256:070b29b5bbf4b1ec2cd51c96ea040dc68a614de703910a91ad1abba18f9f379f \ --hash=sha256:86b8b7517efcc558f085a142cdb7620f0921543fcabdb538c8a4c4001d8178e3 # via aws-sam-cli (setup.py) -docker==4.2.2 \ - --hash=sha256:03a46400c4080cb6f7aa997f881ddd84fef855499ece219d75fbdb53289c17ab \ - --hash=sha256:26eebadce7e298f55b76a88c4f8802476c5eaddbdbe38dbc6cce8781c47c9b54 +docker==6.1.3 \ + --hash=sha256:aa6d17830045ba5ef0168d5eaa34d37beeb113948c413affe1d5991fc11f9a20 \ + --hash=sha256:aecd2277b8bf8e506e484f6ab7aec39abe0038e29fa4a6d3ba86c3fe01844ed9 # via aws-sam-cli (setup.py) flask==2.2.5 \ --hash=sha256:58107ed83443e86067e41eff4631b058178191a355886f8e479e347fa1285fdf \ @@ -268,9 +268,9 @@ jinja2-time==0.2.0 \ --hash=sha256:d14eaa4d315e7688daa4969f616f226614350c48730bfa1692d2caebd8c90d40 \ --hash=sha256:d3eab6605e3ec8b7a0863df09cc1d23714908fa61aa6986a845c20ba488b4efa # via cookiecutter -jmespath==0.10.0 \ - --hash=sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9 \ - --hash=sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f +jmespath==1.0.1 \ + --hash=sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980 \ + --hash=sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe # via # aws-sam-cli (setup.py) # boto3 @@ -371,6 +371,10 @@ networkx==2.6.3 \ --hash=sha256:80b6b89c77d1dfb64a4c7854981b60aeea6360ac02c6d4e4913319e0a313abef \ --hash=sha256:c0946ed31d71f1b732b5aaa6da5a0388a345019af232ce2f49c766e2d6795c51 # via cfn-lint +packaging==23.1 \ + --hash=sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61 \ + --hash=sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f + # via docker pbr==5.11.1 \ --hash=sha256:567f09558bae2b3ab53cb3c1e2e33e726ff3338e7bae3db5dc954b3a44eef12b \ --hash=sha256:aefc51675b0b533d56bb5fd1c8c6c0522fe31896679882e1c4c63d5e4a0fccb3 @@ -630,7 +634,6 @@ six==1.16.0 \ --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 # via - # docker # junit-xml # python-dateutil # serverlessrepo @@ -664,6 +667,7 @@ urllib3==1.26.15 \ --hash=sha256:aa751d169e23c7479ce47a0cb0da579e3ede798f994f5816a74e4f4500dcea42 # via # botocore + # docker # requests watchdog==2.1.2 \ --hash=sha256:0237db4d9024859bea27d0efb59fe75eef290833fd988b8ead7a879b0308c2db \ diff --git a/requirements/reproducible-mac.txt b/requirements/reproducible-mac.txt index 0b47b91535..ee5072b94d 100644 --- a/requirements/reproducible-mac.txt +++ b/requirements/reproducible-mac.txt @@ -259,9 +259,9 @@ dateparser==1.1.8 \ --hash=sha256:070b29b5bbf4b1ec2cd51c96ea040dc68a614de703910a91ad1abba18f9f379f \ --hash=sha256:86b8b7517efcc558f085a142cdb7620f0921543fcabdb538c8a4c4001d8178e3 # via aws-sam-cli (setup.py) -docker==4.2.2 \ - --hash=sha256:03a46400c4080cb6f7aa997f881ddd84fef855499ece219d75fbdb53289c17ab \ - --hash=sha256:26eebadce7e298f55b76a88c4f8802476c5eaddbdbe38dbc6cce8781c47c9b54 +docker==6.1.3 \ + --hash=sha256:aa6d17830045ba5ef0168d5eaa34d37beeb113948c413affe1d5991fc11f9a20 \ + --hash=sha256:aecd2277b8bf8e506e484f6ab7aec39abe0038e29fa4a6d3ba86c3fe01844ed9 # via aws-sam-cli (setup.py) flask==2.2.5 \ --hash=sha256:58107ed83443e86067e41eff4631b058178191a355886f8e479e347fa1285fdf \ @@ -299,9 +299,9 @@ jinja2-time==0.2.0 \ --hash=sha256:d14eaa4d315e7688daa4969f616f226614350c48730bfa1692d2caebd8c90d40 \ --hash=sha256:d3eab6605e3ec8b7a0863df09cc1d23714908fa61aa6986a845c20ba488b4efa # via cookiecutter -jmespath==0.10.0 \ - --hash=sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9 \ - --hash=sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f +jmespath==1.0.1 \ + --hash=sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980 \ + --hash=sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe # via # aws-sam-cli (setup.py) # boto3 @@ -402,6 +402,10 @@ networkx==2.6.3 \ --hash=sha256:80b6b89c77d1dfb64a4c7854981b60aeea6360ac02c6d4e4913319e0a313abef \ --hash=sha256:c0946ed31d71f1b732b5aaa6da5a0388a345019af232ce2f49c766e2d6795c51 # via cfn-lint +packaging==23.1 \ + --hash=sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61 \ + --hash=sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f + # via docker pbr==5.11.1 \ --hash=sha256:567f09558bae2b3ab53cb3c1e2e33e726ff3338e7bae3db5dc954b3a44eef12b \ --hash=sha256:aefc51675b0b533d56bb5fd1c8c6c0522fe31896679882e1c4c63d5e4a0fccb3 @@ -703,7 +707,6 @@ six==1.16.0 \ --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 # via - # docker # junit-xml # python-dateutil # serverlessrepo @@ -742,6 +745,7 @@ urllib3==1.26.15 \ --hash=sha256:aa751d169e23c7479ce47a0cb0da579e3ede798f994f5816a74e4f4500dcea42 # via # botocore + # docker # requests watchdog==2.1.2 \ --hash=sha256:0237db4d9024859bea27d0efb59fe75eef290833fd988b8ead7a879b0308c2db \ diff --git a/samcli/cli/global_config.py b/samcli/cli/global_config.py index e9a105ae76..2542379432 100644 --- a/samcli/cli/global_config.py +++ b/samcli/cli/global_config.py @@ -163,7 +163,7 @@ def get_value( self, config_entry: ConfigEntry, default: Optional[T] = None, - value_type: Type[T] = T, + value_type: Type[T] = T, # type: ignore is_flag: bool = False, reload_config: bool = False, ) -> Optional[T]: diff --git a/samcli/cli/hidden_imports.py b/samcli/cli/hidden_imports.py index cde0e8368a..2d116d9fc8 100644 --- a/samcli/cli/hidden_imports.py +++ b/samcli/cli/hidden_imports.py @@ -2,17 +2,10 @@ Keeps list of hidden/dynamic imports that is being used in SAM CLI, so that pyinstaller can include these packages """ import pkgutil -from typing import cast +from types import ModuleType -from typing_extensions import Protocol - -class HasPathAndName(Protocol): - __path__: str - __name__: str - - -def walk_modules(module: HasPathAndName, visited: set) -> None: +def walk_modules(module: ModuleType, visited: set) -> None: """Recursively find all modules from a parent module""" for pkg in pkgutil.walk_packages(module.__path__, module.__name__ + "."): if pkg.name in visited: @@ -20,13 +13,11 @@ def walk_modules(module: HasPathAndName, visited: set) -> None: visited.add(pkg.name) if pkg.ispkg: submodule = __import__(pkg.name) - submodule = cast(HasPathAndName, submodule) walk_modules(submodule, visited) samcli_modules = set(["samcli"]) samcli = __import__("samcli") -samcli = cast(HasPathAndName, samcli) walk_modules(samcli, samcli_modules) SAM_CLI_HIDDEN_IMPORTS = list(samcli_modules) + [ diff --git a/samcli/commands/package/package_context.py b/samcli/commands/package/package_context.py index c030bf23b2..48b4b777df 100644 --- a/samcli/commands/package/package_context.py +++ b/samcli/commands/package/package_context.py @@ -22,6 +22,7 @@ import boto3 import click import docker +from docker.constants import DEFAULT_DOCKER_API_VERSION from samcli.commands.package.exceptions import PackageFailedError from samcli.lib.intrinsic_resolver.intrinsics_symbol_table import IntrinsicsSymbolTable @@ -120,7 +121,7 @@ def run(self): ) ecr_client = boto3.client("ecr", config=get_boto_config_with_user_agent(region_name=region_name)) - docker_client = docker.from_env() + docker_client = docker.from_env(version=DEFAULT_DOCKER_API_VERSION) s3_uploader = S3Uploader( s3_client, self.s3_bucket, self.s3_prefix, self.kms_key_id, self.force_upload, self.no_progressbar diff --git a/samcli/hook_packages/terraform/hooks/prepare/resource_linking.py b/samcli/hook_packages/terraform/hooks/prepare/resource_linking.py index 1cfeab8d5f..80dd302d41 100644 --- a/samcli/hook_packages/terraform/hooks/prepare/resource_linking.py +++ b/samcli/hook_packages/terraform/hooks/prepare/resource_linking.py @@ -243,7 +243,7 @@ def _link_using_terraform_config(self, source_tf_resource: TFResource, cfn_resou return for cfn_resource in cfn_resources: - self._resource_pair.cfn_resource_update_call_back_function(cfn_resource, dest_resources) # type: ignore + self._resource_pair.cfn_resource_update_call_back_function(cfn_resource, dest_resources) def _link_using_linking_fields(self, cfn_resource: Dict) -> None: """ @@ -298,7 +298,7 @@ def _link_using_linking_fields(self, cfn_resource: Dict) -> None: return LOG.debug("The value of the source resource linking field after mapping %s", dest_resources) - self._resource_pair.cfn_resource_update_call_back_function(cfn_resource, dest_resources) # type: ignore + self._resource_pair.cfn_resource_update_call_back_function(cfn_resource, dest_resources) def _process_resolved_resources( self, diff --git a/samcli/hook_packages/terraform/lib/utils.py b/samcli/hook_packages/terraform/lib/utils.py index 1ea7789f8d..888c9f809b 100644 --- a/samcli/hook_packages/terraform/lib/utils.py +++ b/samcli/hook_packages/terraform/lib/utils.py @@ -74,7 +74,7 @@ def _calculate_configuration_attribute_value_hash( else: sorted_references_list = sorted( configuration_attribute_value, - key=lambda x: x.value if isinstance(x, ConstantValue) else f"{x.module_address}.{x.value}", # type: ignore + key=lambda x: x.value if isinstance(x, ConstantValue) else f"{x.module_address}.{x.value}", ) for ref in sorted_references_list: md5.update( diff --git a/samcli/lib/build/app_builder.py b/samcli/lib/build/app_builder.py index c783e7e77e..5dbfcab965 100644 --- a/samcli/lib/build/app_builder.py +++ b/samcli/lib/build/app_builder.py @@ -8,6 +8,7 @@ import pathlib from typing import List, Optional, Dict, cast, NamedTuple import docker +from docker.constants import DEFAULT_DOCKER_API_VERSION import docker.errors from aws_lambda_builders import ( RPC_PROTOCOL_VERSION as lambda_builders_protocol_version, @@ -156,7 +157,7 @@ def __init__( self._parallel = parallel self._mode = mode self._stream_writer = stream_writer if stream_writer else StreamWriter(stream=osutils.stderr(), auto_flush=True) - self._docker_client = docker_client if docker_client else docker.from_env() + self._docker_client = docker_client if docker_client else docker.from_env(version=DEFAULT_DOCKER_API_VERSION) self._deprecated_runtimes = DEPRECATED_RUNTIMES self._colored = Colored() diff --git a/samcli/lib/build/workflows.py b/samcli/lib/build/workflows.py index 66d8529e4a..d97f83b99e 100644 --- a/samcli/lib/build/workflows.py +++ b/samcli/lib/build/workflows.py @@ -4,7 +4,7 @@ from typing import List CONFIG = namedtuple( - "Capability", + "CONFIG", [ "language", "dependency_manager", diff --git a/samcli/lib/deploy/deployer.py b/samcli/lib/deploy/deployer.py index 1426360d76..16e860c54c 100644 --- a/samcli/lib/deploy/deployer.py +++ b/samcli/lib/deploy/deployer.py @@ -624,7 +624,7 @@ def sync( msg = "" if exists: - kwargs["DisableRollback"] = disable_rollback + kwargs["DisableRollback"] = disable_rollback # type: ignore result = self.update_stack(**kwargs) self.wait_for_execute(stack_name, "UPDATE", disable_rollback, on_failure=on_failure) diff --git a/samcli/lib/hook/hook_config.py b/samcli/lib/hook/hook_config.py index 8a71a0993b..92908642de 100644 --- a/samcli/lib/hook/hook_config.py +++ b/samcli/lib/hook/hook_config.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Dict, NamedTuple, Optional, cast -import jsonschema # type: ignore +import jsonschema from .exceptions import InvalidHookPackageConfigException diff --git a/samcli/lib/iac/cdk/cdk_iac.py b/samcli/lib/iac/cdk/cdk_iac.py index 30fcd1c168..700c1ef3c3 100644 --- a/samcli/lib/iac/cdk/cdk_iac.py +++ b/samcli/lib/iac/cdk/cdk_iac.py @@ -19,13 +19,13 @@ class CdkIacImplementation(IaCPluginInterface): the CDK project type """ - def read_project(self, lookup_paths: List[LookupPath]) -> SamCliProject: + def read_project(self, lookup_paths: List[LookupPath]) -> SamCliProject: # type: ignore pass - def write_project(self, project: SamCliProject, build_dir: str) -> bool: + def write_project(self, project: SamCliProject, build_dir: str) -> bool: # type: ignore pass - def update_packaged_locations(self, stack: Stack) -> bool: + def update_packaged_locations(self, stack: Stack) -> bool: # type: ignore pass @staticmethod diff --git a/samcli/lib/iac/cfn/cfn_iac.py b/samcli/lib/iac/cfn/cfn_iac.py index a446ebae9c..7617af2f92 100644 --- a/samcli/lib/iac/cfn/cfn_iac.py +++ b/samcli/lib/iac/cfn/cfn_iac.py @@ -1,7 +1,6 @@ """ Provide a CFN implementation of IaCPluginInterface """ - import logging import os from typing import List, Optional @@ -72,11 +71,11 @@ def read_project(self, lookup_paths: List[LookupPath]) -> SamCliProject: stack = self._build_stack(self._template_file) return SamCliProject([stack]) - def write_project(self, project: SamCliProject, build_dir: str) -> bool: + def write_project(self, project: SamCliProject, build_dir: str) -> bool: # type: ignore # TODO pass - def update_packaged_locations(self, stack: Stack) -> bool: + def update_packaged_locations(self, stack: Stack) -> bool: # type: ignore # TODO pass diff --git a/samcli/lib/package/ecr_uploader.py b/samcli/lib/package/ecr_uploader.py index 334b2a4287..4c6e714b81 100644 --- a/samcli/lib/package/ecr_uploader.py +++ b/samcli/lib/package/ecr_uploader.py @@ -9,6 +9,7 @@ import botocore import click import docker +from docker.constants import DEFAULT_DOCKER_API_VERSION from docker.errors import APIError, BuildError from samcli.commands.package.exceptions import ( @@ -35,7 +36,7 @@ class ECRUploader: def __init__( self, docker_client, ecr_client, ecr_repo, ecr_repo_multi, no_progressbar=False, tag="latest", stream=stderr() ): - self.docker_client = docker_client if docker_client else docker.from_env() + self.docker_client = docker_client if docker_client else docker.from_env(version=DEFAULT_DOCKER_API_VERSION) self.ecr_client = ecr_client self.ecr_repo = ecr_repo self.ecr_repo_multi = ecr_repo_multi diff --git a/samcli/lib/package/image_utils.py b/samcli/lib/package/image_utils.py index ac86694a33..5fefbfcd53 100644 --- a/samcli/lib/package/image_utils.py +++ b/samcli/lib/package/image_utils.py @@ -2,6 +2,7 @@ Image artifacts based utilities """ import docker +from docker.constants import DEFAULT_DOCKER_API_VERSION from docker.errors import APIError, NullResource from samcli.commands.package.exceptions import DockerGetLocalImageFailedError @@ -35,7 +36,7 @@ def tag_translation(image, docker_image_id=None, gen_tag="latest"): if not docker_image_id: try: - docker_client = docker.from_env() + docker_client = docker.from_env(version=DEFAULT_DOCKER_API_VERSION) docker_image_id = docker_client.images.get(image).id except APIError as ex: raise DockerGetLocalImageFailedError(str(ex)) from ex diff --git a/samcli/lib/pipeline/bootstrap/stage.py b/samcli/lib/pipeline/bootstrap/stage.py index 314b6e4a48..06ab4fa6dc 100644 --- a/samcli/lib/pipeline/bootstrap/stage.py +++ b/samcli/lib/pipeline/bootstrap/stage.py @@ -13,7 +13,7 @@ import click import requests from botocore.exceptions import ClientError -from OpenSSL import SSL, crypto # type: ignore +from OpenSSL import SSL, crypto from samcli.commands.pipeline.bootstrap.guided_context import BITBUCKET, GITHUB_ACTIONS, GITLAB, OPEN_ID_CONNECT from samcli.commands.pipeline.bootstrap.pipeline_oidc_provider import PipelineOidcProvider @@ -222,7 +222,7 @@ def generate_thumbprint(oidc_provider_url: Optional[str]) -> Optional[str]: # If we attempt to get the cert chain without exchanging some traffic it will be empty c.sendall(str.encode("HEAD / HTTP/1.0\n\n")) peerCertChain = c.get_peer_cert_chain() - cert = peerCertChain[-1] + cert = peerCertChain[-1] # type: ignore # Dump the certificate in DER/ASN1 format so that its SHA1 hash can be computed dumped_cert = crypto.dump_certificate(crypto.FILETYPE_ASN1, cert) diff --git a/samcli/lib/providers/provider.py b/samcli/lib/providers/provider.py index c630f0ffcc..98e05051bf 100644 --- a/samcli/lib/providers/provider.py +++ b/samcli/lib/providers/provider.py @@ -466,9 +466,11 @@ def binary_media_types(self) -> List[str]: return list(self.binary_media_types_set) -_CorsTuple = namedtuple("Cors", ["allow_origin", "allow_methods", "allow_headers", "allow_credentials", "max_age"]) +_CorsTuple = namedtuple( + "_CorsTuple", ["allow_origin", "allow_methods", "allow_headers", "allow_credentials", "max_age"] +) -_CorsTuple.__new__.__defaults__ = ( # type: ignore +_CorsTuple.__new__.__defaults__ = ( None, # Allow Origin defaults to None None, # Allow Methods is optional and defaults to empty None, # Allow Headers is optional and defaults to empty diff --git a/samcli/lib/sync/flows/image_function_sync_flow.py b/samcli/lib/sync/flows/image_function_sync_flow.py index a284eeb191..cf9ff34871 100644 --- a/samcli/lib/sync/flows/image_function_sync_flow.py +++ b/samcli/lib/sync/flows/image_function_sync_flow.py @@ -5,6 +5,7 @@ import docker from docker.client import DockerClient +from docker.constants import DEFAULT_DOCKER_API_VERSION from samcli.lib.build.app_builder import ApplicationBuilder, ApplicationBuildResult from samcli.lib.package.ecr_uploader import ECRUploader @@ -69,7 +70,7 @@ def __init__( def _get_docker_client(self) -> DockerClient: """Lazy instantiates and returns the docker client""" if not self._docker_client: - self._docker_client = docker.from_env() + self._docker_client = docker.from_env(version=DEFAULT_DOCKER_API_VERSION) return self._docker_client def _get_ecr_client(self) -> Any: diff --git a/samcli/lib/utils/file_observer.py b/samcli/lib/utils/file_observer.py index 51f2450942..77928007ef 100644 --- a/samcli/lib/utils/file_observer.py +++ b/samcli/lib/utils/file_observer.py @@ -11,6 +11,7 @@ import docker from docker import DockerClient +from docker.constants import DEFAULT_DOCKER_API_VERSION from docker.errors import ImageNotFound from docker.types import CancellableStream from watchdog.events import FileSystemEvent, FileSystemEventHandler, PatternMatchingEventHandler @@ -257,7 +258,7 @@ def __init__(self, on_change: Callable) -> None: """ self._observed_images: Dict[str, str] = {} self._input_on_change: Callable = on_change - self.docker_client: DockerClient = docker.from_env() + self.docker_client: DockerClient = docker.from_env(version=DEFAULT_DOCKER_API_VERSION) self.events: CancellableStream = self.docker_client.events(filters={"type": "image"}, decode=True) self._images_observer_thread: Optional[Thread] = None self._lock: Lock = threading.Lock() diff --git a/samcli/lib/utils/lock_distributor.py b/samcli/lib/utils/lock_distributor.py index 94536b7a2f..2d4ad8dec0 100644 --- a/samcli/lib/utils/lock_distributor.py +++ b/samcli/lib/utils/lock_distributor.py @@ -72,7 +72,7 @@ def __init__( self._manager = manager self._dict_lock = self._create_new_lock() self._locks = ( - self._manager.dict() + self._manager.dict() # type: ignore if self._lock_type == LockDistributorType.PROCESS and self._manager is not None else dict() ) diff --git a/samcli/lib/utils/system_info.py b/samcli/lib/utils/system_info.py index 39dfe6d92e..03c6173b45 100644 --- a/samcli/lib/utils/system_info.py +++ b/samcli/lib/utils/system_info.py @@ -53,10 +53,11 @@ def _gather_docker_info() -> str: import contextlib import docker + from docker.constants import DEFAULT_DOCKER_API_VERSION from samcli.local.docker.utils import is_docker_reachable - with contextlib.closing(docker.from_env()) as client: + with contextlib.closing(docker.from_env(version=DEFAULT_DOCKER_API_VERSION)) as client: if is_docker_reachable(client): return cast(str, client.version().get("Version", "Not available")) return "Not available" diff --git a/samcli/local/docker/container.py b/samcli/local/docker/container.py index f3020cc51e..a6205c8e26 100644 --- a/samcli/local/docker/container.py +++ b/samcli/local/docker/container.py @@ -13,6 +13,7 @@ import docker import requests +from docker.constants import DEFAULT_DOCKER_API_VERSION from docker.errors import NotFound as DockerNetworkNotFound from samcli.lib.utils.retry import retry @@ -111,7 +112,7 @@ def __init__( self._logs_thread = None # Use the given Docker client or create new one - self.docker_client = docker_client or docker.from_env() + self.docker_client = docker_client or docker.from_env(version=DEFAULT_DOCKER_API_VERSION) # Runtime properties of the container. They won't have value until container is created or started self.id = None @@ -206,9 +207,6 @@ def create(self): # Ex: 128m => 128MB kwargs["mem_limit"] = "{}m".format(self._memory_limit_mb) - if self.network_id == "host": - kwargs["network_mode"] = self.network_id - real_container = self.docker_client.containers.create(self._image, **kwargs) self.id = real_container.id diff --git a/samcli/local/docker/lambda_image.py b/samcli/local/docker/lambda_image.py index 309ff91346..14ba00d06a 100644 --- a/samcli/local/docker/lambda_image.py +++ b/samcli/local/docker/lambda_image.py @@ -12,6 +12,7 @@ from typing import Optional import docker +from docker.constants import DEFAULT_DOCKER_API_VERSION from samcli.commands.local.cli_common.user_exceptions import ( DockerDistributionAPIError, @@ -123,7 +124,7 @@ def __init__(self, layer_downloader, skip_pull_image, force_image_build, docker_ self.layer_downloader = layer_downloader self.skip_pull_image = skip_pull_image self.force_image_build = force_image_build - self.docker_client = docker_client or docker.from_env() + self.docker_client = docker_client or docker.from_env(version=DEFAULT_DOCKER_API_VERSION) self.invoke_images = invoke_images def build(self, runtime, packagetype, image, layers, architecture, stream=None, function_name=None): diff --git a/samcli/local/docker/manager.py b/samcli/local/docker/manager.py index 50f7178021..45db09bce7 100644 --- a/samcli/local/docker/manager.py +++ b/samcli/local/docker/manager.py @@ -7,6 +7,7 @@ import threading import docker +from docker.constants import DEFAULT_DOCKER_API_VERSION from samcli.lib.utils.stream_writer import StreamWriter from samcli.local.docker import utils @@ -35,7 +36,7 @@ def __init__(self, docker_network_id=None, docker_client=None, skip_pull_image=F self.skip_pull_image = skip_pull_image self.docker_network_id = docker_network_id - self.docker_client = docker_client or docker.from_env() + self.docker_client = docker_client or docker.from_env(version=DEFAULT_DOCKER_API_VERSION) self.do_shutdown_event = do_shutdown_event self._lock = threading.Lock() diff --git a/samcli/local/lambdafn/runtime.py b/samcli/local/lambdafn/runtime.py index 770f3ef9e1..0272604656 100644 --- a/samcli/local/lambdafn/runtime.py +++ b/samcli/local/lambdafn/runtime.py @@ -331,7 +331,7 @@ class WarmLambdaRuntime(LambdaRuntime): warm containers life cycle. """ - def __init__(self, container_manager, image_builder): + def __init__(self, container_manager, image_builder, observer=None): """ Initialize the Local Lambda runtime @@ -347,7 +347,7 @@ def __init__(self, container_manager, image_builder): self._function_configs = {} self._containers = {} - self._observer = LambdaFunctionObserver(self._on_code_change) + self._observer = observer if observer else LambdaFunctionObserver(self._on_code_change) super().__init__(container_manager, image_builder) diff --git a/setup.py b/setup.py index 25d409f8db..792fed29f5 100644 --- a/setup.py +++ b/setup.py @@ -71,6 +71,7 @@ def read_version(): "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.11", "Topic :: Internet", "Topic :: Software Development :: Build Tools", "Topic :: Utilities", diff --git a/tests/integration/logs/test_logs_command.py b/tests/integration/logs/test_logs_command.py index 4bac06d740..22a15b8c72 100644 --- a/tests/integration/logs/test_logs_command.py +++ b/tests/integration/logs/test_logs_command.py @@ -2,7 +2,7 @@ import logging import time from pathlib import Path -from typing import List, Optional, Tuple +from typing import Any, Dict, List, Optional, Tuple import boto3 import pytest @@ -30,7 +30,7 @@ class LogsIntegTestCases(LogsIntegBase): test_template_folder = "" stack_name = "" - stack_resources = {} + stack_resources: Dict[Any, Any] = {} stack_info = None def setUp(self): @@ -76,7 +76,7 @@ def _get_physical_id(self, resource_path: str): return self.stack_resources[resource_path] def _get_output_value(self, key: str): - for output in self.stack_info.outputs: + for output in self.stack_info.outputs: # type: ignore if output.get("OutputKey", "") == key: return output.get("OutputValue", "") diff --git a/tests/integration/traces/test_traces_command.py b/tests/integration/traces/test_traces_command.py index cadca71c42..eb0a1d3fcc 100644 --- a/tests/integration/traces/test_traces_command.py +++ b/tests/integration/traces/test_traces_command.py @@ -1,7 +1,7 @@ import itertools import time from pathlib import Path -from typing import List +from typing import Any, List from unittest import skipIf import boto3 @@ -32,7 +32,7 @@ @skipIf(SKIP_TRACES_TESTS, "Skip traces tests in CI/CD only") @pytest.mark.xdist_group(name="sam_traces") class TestTracesCommand(TracesIntegBase): - stack_resources = [] + stack_resources: List[Any] = [] stack_name = "" def setUp(self): diff --git a/tests/unit/commands/deploy/test_command.py b/tests/unit/commands/deploy/test_command.py index bb96c16079..9f6a59d8e3 100644 --- a/tests/unit/commands/deploy/test_command.py +++ b/tests/unit/commands/deploy/test_command.py @@ -64,7 +64,7 @@ def setUp(self): def tearDown(self): self.companion_stack_manager_patch.stop() - @patch("os.environ", {**os.environ, "SAM_CLI_POLL_DELAY": 10}) + @patch("os.environ", {**os.environ, "SAM_CLI_POLL_DELAY": 10}) # type: ignore @patch("samcli.commands.package.command.click") @patch("samcli.commands.package.package_context.PackageContext") @patch("samcli.commands.deploy.command.click") diff --git a/tests/unit/commands/local/cli_common/test_invoke_context.py b/tests/unit/commands/local/cli_common/test_invoke_context.py index 052f265147..3cab08c82a 100644 --- a/tests/unit/commands/local/cli_common/test_invoke_context.py +++ b/tests/unit/commands/local/cli_common/test_invoke_context.py @@ -555,13 +555,20 @@ def test_must_raise_if_more_than_one_function(self): class TestInvokeContext_local_lambda_runner(TestCase): + @patch("samcli.local.lambdafn.runtime.LambdaFunctionObserver") @patch("samcli.commands.local.cli_common.invoke_context.LambdaImage") @patch("samcli.commands.local.cli_common.invoke_context.LayerDownloader") @patch("samcli.commands.local.cli_common.invoke_context.LambdaRuntime") @patch("samcli.commands.local.cli_common.invoke_context.LocalLambdaRunner") @patch("samcli.commands.local.cli_common.invoke_context.SamFunctionProvider") def test_must_create_runner( - self, SamFunctionProviderMock, LocalLambdaMock, LambdaRuntimeMock, download_layers_mock, lambda_image_patch + self, + SamFunctionProviderMock, + LocalLambdaMock, + LambdaRuntimeMock, + download_layers_mock, + lambda_image_patch, + LambdaFunctionObserver_patch, ): runtime_mock = Mock() LambdaRuntimeMock.return_value = runtime_mock @@ -575,6 +582,9 @@ def test_must_create_runner( image_mock = Mock() lambda_image_patch.return_value = image_mock + LambdaFunctionObserver_mock = Mock() + LambdaFunctionObserver_patch.return_value = LambdaFunctionObserver_mock + cwd = "cwd" self.context = InvokeContext( template_file="template_file", @@ -705,13 +715,20 @@ def test_must_create_runner_using_warm_containers( # assert that lambda runner is created only one time, and the cached version used in the second call self.assertEqual(LocalLambdaMock.call_count, 1) + @patch("samcli.local.lambdafn.runtime.LambdaFunctionObserver") @patch("samcli.commands.local.cli_common.invoke_context.LambdaImage") @patch("samcli.commands.local.cli_common.invoke_context.LayerDownloader") @patch("samcli.commands.local.cli_common.invoke_context.LambdaRuntime") @patch("samcli.commands.local.cli_common.invoke_context.LocalLambdaRunner") @patch("samcli.commands.local.cli_common.invoke_context.SamFunctionProvider") def test_must_create_runner_with_container_host_option( - self, SamFunctionProviderMock, LocalLambdaMock, LambdaRuntimeMock, download_layers_mock, lambda_image_patch + self, + SamFunctionProviderMock, + LocalLambdaMock, + LambdaRuntimeMock, + download_layers_mock, + lambda_image_patch, + LambdaFunctionObserver_patch, ): runtime_mock = Mock() LambdaRuntimeMock.return_value = runtime_mock @@ -725,6 +742,9 @@ def test_must_create_runner_with_container_host_option( image_mock = Mock() lambda_image_patch.return_value = image_mock + LambdaFunctionObserver_mock = Mock() + LambdaFunctionObserver_patch.return_value = LambdaFunctionObserver_mock + cwd = "cwd" self.context = InvokeContext( template_file="template_file", @@ -779,13 +799,20 @@ def test_must_create_runner_with_container_host_option( # assert that lambda runner is created only one time, and the cached version used in the second call self.assertEqual(LocalLambdaMock.call_count, 1) + @patch("samcli.local.lambdafn.runtime.LambdaFunctionObserver") @patch("samcli.commands.local.cli_common.invoke_context.LambdaImage") @patch("samcli.commands.local.cli_common.invoke_context.LayerDownloader") @patch("samcli.commands.local.cli_common.invoke_context.LambdaRuntime") @patch("samcli.commands.local.cli_common.invoke_context.LocalLambdaRunner") @patch("samcli.commands.local.cli_common.invoke_context.SamFunctionProvider") def test_must_create_runner_with_invoke_image_option( - self, SamFunctionProviderMock, LocalLambdaMock, LambdaRuntimeMock, download_layers_mock, lambda_image_patch + self, + SamFunctionProviderMock, + LocalLambdaMock, + LambdaRuntimeMock, + download_layers_mock, + lambda_image_patch, + LambdaFunctionObserver_patch, ): runtime_mock = Mock() LambdaRuntimeMock.return_value = runtime_mock @@ -799,6 +826,9 @@ def test_must_create_runner_with_invoke_image_option( image_mock = Mock() lambda_image_patch.return_value = image_mock + LambdaFunctionObserver_mock = Mock() + LambdaFunctionObserver_patch.return_value = LambdaFunctionObserver_mock + cwd = "cwd" self.context = InvokeContext( template_file="template_file", diff --git a/tests/unit/commands/sync/test_command.py b/tests/unit/commands/sync/test_command.py index 94f0dd118f..b0bcede4d0 100644 --- a/tests/unit/commands/sync/test_command.py +++ b/tests/unit/commands/sync/test_command.py @@ -68,7 +68,7 @@ def setUp(self): (False, False, False, False, True, InfraSyncResult(True)), ] ) - @patch("os.environ", {**os.environ, "SAM_CLI_POLL_DELAY": 10}) + @patch("os.environ", {**os.environ, "SAM_CLI_POLL_DELAY": 10}) # type: ignore @patch("samcli.commands.sync.command.click") @patch("samcli.commands.sync.command.execute_code_sync") @patch("samcli.commands.build.command.click") diff --git a/tests/unit/commands/validate/test_cli.py b/tests/unit/commands/validate/test_cli.py index b952de467f..c19f5d0377 100644 --- a/tests/unit/commands/validate/test_cli.py +++ b/tests/unit/commands/validate/test_cli.py @@ -11,8 +11,8 @@ from samcli.commands.validate.lib.exceptions import InvalidSamDocumentException from samcli.commands.validate.validate import do_cli, _read_sam_file, _lint -ctx_mock = namedtuple("ctx", ["profile", "region"]) -ctx_lint_mock = namedtuple("ctx", ["debug", "region"]) +ctx_mock = namedtuple("ctx_mock", ["profile", "region"]) +ctx_lint_mock = namedtuple("ctx_lint_mock", ["debug", "region"]) class TestValidateCli(TestCase): diff --git a/tests/unit/lib/build_module/test_app_builder.py b/tests/unit/lib/build_module/test_app_builder.py index 34f7cc5ae0..98b8006ad0 100644 --- a/tests/unit/lib/build_module/test_app_builder.py +++ b/tests/unit/lib/build_module/test_app_builder.py @@ -1418,8 +1418,7 @@ def setUp(self): def test_must_write_absolute_path_for_different_drives(self): def mock_new(cls, *args, **kwargs): cls = WindowsPath - self = cls._from_parts(args, init=False) - self._init() + self = cls._from_parts(args) return self def mock_resolve(self): diff --git a/tests/unit/lib/deploy/test_deployer.py b/tests/unit/lib/deploy/test_deployer.py index bd04722b03..9844366084 100644 --- a/tests/unit/lib/deploy/test_deployer.py +++ b/tests/unit/lib/deploy/test_deployer.py @@ -343,7 +343,7 @@ def test_wait_for_changeset(self): self.deployer._client.get_waiter = MagicMock(return_value=MockChangesetWaiter()) self.deployer.wait_for_changeset("test-id", "test-stack") - @patch("os.environ", {**os.environ, "SAM_CLI_POLL_DELAY": 10}) + @patch("os.environ", {**os.environ, "SAM_CLI_POLL_DELAY": 10}) # type: ignore def test_wait_for_changeset_client_sleep(self): deployer = Deployer(MagicMock().client("cloudformation"), client_sleep=os.getenv("SAM_CLI_POLL_DELAY", 0.5)) deployer._client.get_waiter = MagicMock(return_value=MockChangesetWaiter()) @@ -358,7 +358,7 @@ def test_wait_for_changeset_default_delay(self): ChangeSetName="test-id", StackName="test-stack", WaiterConfig={"Delay": 0.5} ) - @patch("os.environ", {**os.environ, "SAM_CLI_POLL_DELAY": 10}) + @patch("os.environ", {**os.environ, "SAM_CLI_POLL_DELAY": 10}) # type: ignore def test_wait_for_changeset_custom_delay(self): deployer = Deployer(MagicMock().client("cloudformation"), client_sleep=os.getenv("SAM_CLI_POLL_DELAY")) deployer.wait_for_changeset("test-id", "test-stack") diff --git a/tests/unit/lib/pipeline/bootstrap/test_environment.py b/tests/unit/lib/pipeline/bootstrap/test_environment.py index 3728c870d4..85eddc5fc8 100644 --- a/tests/unit/lib/pipeline/bootstrap/test_environment.py +++ b/tests/unit/lib/pipeline/bootstrap/test_environment.py @@ -2,7 +2,7 @@ from unittest import TestCase from unittest.mock import Mock, patch, call, MagicMock -import OpenSSL.SSL # type: ignore +import OpenSSL.SSL import requests from samcli.commands.pipeline.bootstrap.guided_context import GITHUB_ACTIONS diff --git a/tests/unit/local/apigw/test_lambda_authorizer.py b/tests/unit/local/apigw/test_lambda_authorizer.py index 41f81249a4..dc7ca00acb 100644 --- a/tests/unit/local/apigw/test_lambda_authorizer.py +++ b/tests/unit/local/apigw/test_lambda_authorizer.py @@ -25,7 +25,7 @@ def test_valid_header_identity_source(self): [ ({"headers": Headers({})},), # test empty headers ({},), # test no headers - ({"headers": Headers({"not here": 123})},), # test missing headers + ({"headers": Headers({"not here": 123})},), # type: ignore # test missing headers ({"validation_expression": "^123$"},), # test no headers, but provided validation ] ) diff --git a/tests/unit/local/docker/test_container.py b/tests/unit/local/docker/test_container.py index 61ccad4c9f..14f292c0ce 100644 --- a/tests/unit/local/docker/test_container.py +++ b/tests/unit/local/docker/test_container.py @@ -296,7 +296,6 @@ def test_must_connect_to_host_network_on_create(self): tty=False, use_config_proxy=True, volumes=expected_volumes, - network_mode="host", ) self.mock_docker_client.networks.get.assert_not_called() diff --git a/tests/unit/local/lambdafn/test_runtime.py b/tests/unit/local/lambdafn/test_runtime.py index 295b0c8d57..42087ebd00 100644 --- a/tests/unit/local/lambdafn/test_runtime.py +++ b/tests/unit/local/lambdafn/test_runtime.py @@ -939,10 +939,11 @@ def setUp(self): @patch("samcli.local.lambdafn.runtime.os") def test_must_return_same_path_if_path_is_not_compressed_file(self, os_mock): lambda_image_mock = Mock() + observer_mock = Mock() os_mock.path.isfile.return_value = False code_path = "path" - self.runtime = WarmLambdaRuntime(self.manager_mock, lambda_image_mock) + self.runtime = WarmLambdaRuntime(self.manager_mock, lambda_image_mock, observer_mock) res = self.runtime._get_code_dir(code_path) self.assertEqual(self.runtime._temp_uncompressed_paths_to_be_cleaned, []) self.assertEqual(res, code_path) @@ -951,12 +952,13 @@ def test_must_return_same_path_if_path_is_not_compressed_file(self, os_mock): @patch("samcli.local.lambdafn.runtime.os") def test_must_cache_temp_uncompressed_dirs_to_be_cleared_later(self, os_mock, _unzip_file_mock): lambda_image_mock = Mock() + observer_mock = Mock() os_mock.path.isfile.return_value = True uncompressed_dir_mock = Mock() _unzip_file_mock.return_value = uncompressed_dir_mock code_path = "path.zip" - self.runtime = WarmLambdaRuntime(self.manager_mock, lambda_image_mock) + self.runtime = WarmLambdaRuntime(self.manager_mock, lambda_image_mock, observer_mock) res = self.runtime._get_code_dir(code_path) self.assertEqual(self.runtime._temp_uncompressed_paths_to_be_cleaned, [uncompressed_dir_mock]) self.assertEqual(res, uncompressed_dir_mock) @@ -966,16 +968,16 @@ class TestWarmLambdaRuntime_clean_warm_containers_related_resources(TestCase): def setUp(self): self.manager_mock = Mock() lambda_image_mock = Mock() - self.runtime = WarmLambdaRuntime(self.manager_mock, lambda_image_mock) self.observer_mock = Mock() + self.observer_mock.is_alive.return_value = True + self.runtime = WarmLambdaRuntime(self.manager_mock, lambda_image_mock, self.observer_mock) + self.func1_container_mock = Mock() self.func2_container_mock = Mock() self.runtime._containers = { "func_name1": self.func1_container_mock, "func_name2": self.func2_container_mock, } - self.runtime._observer = self.observer_mock - self.runtime._observer.is_alive.return_value = True self.runtime._temp_uncompressed_paths_to_be_cleaned = ["path1", "path2"] @patch("samcli.local.lambdafn.runtime.shutil") @@ -1002,10 +1004,8 @@ class TestWarmLambdaRuntime_on_code_change(TestCase): def setUp(self): self.manager_mock = Mock() lambda_image_mock = Mock() - self.runtime = WarmLambdaRuntime(self.manager_mock, lambda_image_mock) - self.observer_mock = Mock() - self.runtime._observer = self.observer_mock + self.runtime = WarmLambdaRuntime(self.manager_mock, lambda_image_mock, self.observer_mock) self.lang = "runtime" self.handler = "handler"