diff --git a/Makefile b/Makefile index 9a4fd6f9..499c3035 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,9 @@ coverage: ## Target to combine and report coverage. lint: ## Lint all files in the project, which we also run in pre-commit poetry run pre-commit run -a +mypy-core-report: + poetry run mypy --config-file pyproject.toml core | poetry run python scripts/mypy_report.py + image: ## Make the docker image for dind tests poetry export -f requirements.txt -o build/requirements.txt docker build --build-arg PYTHON_VERSION=${PYTHON_VERSION} -t ${IMAGE} . diff --git a/core/testcontainers/core/generic.py b/core/testcontainers/core/generic.py index b2cd3010..5c6b6c4b 100644 --- a/core/testcontainers/core/generic.py +++ b/core/testcontainers/core/generic.py @@ -10,7 +10,7 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. -from typing import Optional +from typing import Any, Optional from urllib.parse import quote from testcontainers.core.container import DockerContainer @@ -55,7 +55,7 @@ def _create_connection_url( host: Optional[str] = None, port: Optional[int] = None, dbname: Optional[str] = None, - **kwargs, + **kwargs: Any, ) -> str: if raise_for_deprecated_parameter(kwargs, "db_name", "dbname"): raise ValueError(f"Unexpected arguments: {','.join(kwargs)}") diff --git a/core/testcontainers/core/network.py b/core/testcontainers/core/network.py index d149d5e4..b9bd670f 100644 --- a/core/testcontainers/core/network.py +++ b/core/testcontainers/core/network.py @@ -11,7 +11,7 @@ # License for the specific language governing permissions and limitations # under the License. import uuid -from typing import Optional +from typing import Any, Optional from testcontainers.core.docker_client import DockerClient @@ -21,12 +21,14 @@ class Network: Network context manager for programmatically connecting containers. """ - def __init__(self, docker_client_kw: Optional[dict] = None, docker_network_kw: Optional[dict] = None) -> None: + def __init__( + self, docker_client_kw: Optional[dict[str, Any]] = None, docker_network_kw: Optional[dict[str, Any]] = None + ): self.name = str(uuid.uuid4()) self._docker = DockerClient(**(docker_client_kw or {})) self._docker_network_kw = docker_network_kw or {} - def connect(self, container_id: str, network_aliases: Optional[list] = None): + def connect(self, container_id: str, network_aliases: Optional[list[str]] = None) -> None: self._network.connect(container_id, aliases=network_aliases) def remove(self) -> None: @@ -40,5 +42,5 @@ def create(self) -> "Network": def __enter__(self) -> "Network": return self.create() - def __exit__(self, exc_type, exc_val, exc_tb) -> None: + def __exit__(self, exc_type, exc_val, exc_tb) -> None: # type: ignore[no-untyped-def] self.remove() diff --git a/core/tests/conftest.py b/core/tests/conftest.py index 4f69565f..148f0d49 100644 --- a/core/tests/conftest.py +++ b/core/tests/conftest.py @@ -1,6 +1,6 @@ import pytest from typing import Callable -from testcontainers.core.container import DockerClient +from testcontainers.core.docker_client import DockerClient @pytest.fixture diff --git a/core/tests/test_docker_client.py b/core/tests/test_docker_client.py index 6bfe388d..83f730b3 100644 --- a/core/tests/test_docker_client.py +++ b/core/tests/test_docker_client.py @@ -38,8 +38,8 @@ def test_docker_client_login(): mock_parse_docker_auth_config = MagicMock(spec=parse_docker_auth_config) mock_utils = MagicMock() mock_utils.parse_docker_auth_config = mock_parse_docker_auth_config - TestAuth = namedtuple("Auth", "value") - mock_parse_docker_auth_config.return_value = [TestAuth("test")] + Auth = namedtuple("Auth", "value") + mock_parse_docker_auth_config.return_value = [Auth("test")] with ( mock.patch.object(c, "_docker_auth_config", "test"), diff --git a/core/tests/test_labels.py b/core/tests/test_labels.py index 425aee7d..c67b2406 100644 --- a/core/tests/test_labels.py +++ b/core/tests/test_labels.py @@ -10,7 +10,7 @@ from testcontainers.core.config import RYUK_IMAGE -def assert_in_with_value(labels: dict, label: str, value: str, known_before_test_time: bool) -> None: +def assert_in_with_value(labels: dict[str, str], label: str, value: str, known_before_test_time: bool): assert label in labels if known_before_test_time: assert labels[label] == value diff --git a/core/tests/test_network.py b/core/tests/test_network.py index 868032e2..d579bed0 100644 --- a/core/tests/test_network.py +++ b/core/tests/test_network.py @@ -90,6 +90,6 @@ def test_network_has_labels(): try: network.create() network = network._docker.client.networks.get(network_id=network.id) - assert LABEL_SESSION_ID in network.attrs.get("Labels") + assert LABEL_SESSION_ID in network.attrs.get("Labels") # type: ignore[attr-defined] finally: network.remove() diff --git a/poetry.lock b/poetry.lock index e0d17ea6..2cb8f663 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2078,44 +2078,44 @@ files = [ [[package]] name = "mypy" -version = "1.7.1" +version = "1.11.2" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:12cce78e329838d70a204293e7b29af9faa3ab14899aec397798a4b41be7f340"}, - {file = "mypy-1.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1484b8fa2c10adf4474f016e09d7a159602f3239075c7bf9f1627f5acf40ad49"}, - {file = "mypy-1.7.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31902408f4bf54108bbfb2e35369877c01c95adc6192958684473658c322c8a5"}, - {file = "mypy-1.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f2c2521a8e4d6d769e3234350ba7b65ff5d527137cdcde13ff4d99114b0c8e7d"}, - {file = "mypy-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:fcd2572dd4519e8a6642b733cd3a8cfc1ef94bafd0c1ceed9c94fe736cb65b6a"}, - {file = "mypy-1.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4b901927f16224d0d143b925ce9a4e6b3a758010673eeded9b748f250cf4e8f7"}, - {file = "mypy-1.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2f7f6985d05a4e3ce8255396df363046c28bea790e40617654e91ed580ca7c51"}, - {file = "mypy-1.7.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:944bdc21ebd620eafefc090cdf83158393ec2b1391578359776c00de00e8907a"}, - {file = "mypy-1.7.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9c7ac372232c928fff0645d85f273a726970c014749b924ce5710d7d89763a28"}, - {file = "mypy-1.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:f6efc9bd72258f89a3816e3a98c09d36f079c223aa345c659622f056b760ab42"}, - {file = "mypy-1.7.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6dbdec441c60699288adf051f51a5d512b0d818526d1dcfff5a41f8cd8b4aaf1"}, - {file = "mypy-1.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4fc3d14ee80cd22367caaaf6e014494415bf440980a3045bf5045b525680ac33"}, - {file = "mypy-1.7.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c6e4464ed5f01dc44dc9821caf67b60a4e5c3b04278286a85c067010653a0eb"}, - {file = "mypy-1.7.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:d9b338c19fa2412f76e17525c1b4f2c687a55b156320acb588df79f2e6fa9fea"}, - {file = "mypy-1.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:204e0d6de5fd2317394a4eff62065614c4892d5a4d1a7ee55b765d7a3d9e3f82"}, - {file = "mypy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:84860e06ba363d9c0eeabd45ac0fde4b903ad7aa4f93cd8b648385a888e23200"}, - {file = "mypy-1.7.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8c5091ebd294f7628eb25ea554852a52058ac81472c921150e3a61cdd68f75a7"}, - {file = "mypy-1.7.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40716d1f821b89838589e5b3106ebbc23636ffdef5abc31f7cd0266db936067e"}, - {file = "mypy-1.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5cf3f0c5ac72139797953bd50bc6c95ac13075e62dbfcc923571180bebb662e9"}, - {file = "mypy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:78e25b2fd6cbb55ddfb8058417df193f0129cad5f4ee75d1502248e588d9e0d7"}, - {file = "mypy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:75c4d2a6effd015786c87774e04331b6da863fc3fc4e8adfc3b40aa55ab516fe"}, - {file = "mypy-1.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2643d145af5292ee956aa0a83c2ce1038a3bdb26e033dadeb2f7066fb0c9abce"}, - {file = "mypy-1.7.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75aa828610b67462ffe3057d4d8a4112105ed211596b750b53cbfe182f44777a"}, - {file = "mypy-1.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ee5d62d28b854eb61889cde4e1dbc10fbaa5560cb39780c3995f6737f7e82120"}, - {file = "mypy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:72cf32ce7dd3562373f78bd751f73c96cfb441de147cc2448a92c1a308bd0ca6"}, - {file = "mypy-1.7.1-py3-none-any.whl", hash = "sha256:f7c5d642db47376a0cc130f0de6d055056e010debdaf0707cd2b0fc7e7ef30ea"}, - {file = "mypy-1.7.1.tar.gz", hash = "sha256:fcb6d9afb1b6208b4c712af0dafdc650f518836065df0d4fb1d800f5d6773db2"}, + {file = "mypy-1.11.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d42a6dd818ffce7be66cce644f1dff482f1d97c53ca70908dff0b9ddc120b77a"}, + {file = "mypy-1.11.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:801780c56d1cdb896eacd5619a83e427ce436d86a3bdf9112527f24a66618fef"}, + {file = "mypy-1.11.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41ea707d036a5307ac674ea172875f40c9d55c5394f888b168033177fce47383"}, + {file = "mypy-1.11.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6e658bd2d20565ea86da7d91331b0eed6d2eee22dc031579e6297f3e12c758c8"}, + {file = "mypy-1.11.2-cp310-cp310-win_amd64.whl", hash = "sha256:478db5f5036817fe45adb7332d927daa62417159d49783041338921dcf646fc7"}, + {file = "mypy-1.11.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75746e06d5fa1e91bfd5432448d00d34593b52e7e91a187d981d08d1f33d4385"}, + {file = "mypy-1.11.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a976775ab2256aadc6add633d44f100a2517d2388906ec4f13231fafbb0eccca"}, + {file = "mypy-1.11.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd953f221ac1379050a8a646585a29574488974f79d8082cedef62744f0a0104"}, + {file = "mypy-1.11.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:57555a7715c0a34421013144a33d280e73c08df70f3a18a552938587ce9274f4"}, + {file = "mypy-1.11.2-cp311-cp311-win_amd64.whl", hash = "sha256:36383a4fcbad95f2657642a07ba22ff797de26277158f1cc7bd234821468b1b6"}, + {file = "mypy-1.11.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e8960dbbbf36906c5c0b7f4fbf2f0c7ffb20f4898e6a879fcf56a41a08b0d318"}, + {file = "mypy-1.11.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:06d26c277962f3fb50e13044674aa10553981ae514288cb7d0a738f495550b36"}, + {file = "mypy-1.11.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e7184632d89d677973a14d00ae4d03214c8bc301ceefcdaf5c474866814c987"}, + {file = "mypy-1.11.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3a66169b92452f72117e2da3a576087025449018afc2d8e9bfe5ffab865709ca"}, + {file = "mypy-1.11.2-cp312-cp312-win_amd64.whl", hash = "sha256:969ea3ef09617aff826885a22ece0ddef69d95852cdad2f60c8bb06bf1f71f70"}, + {file = "mypy-1.11.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:37c7fa6121c1cdfcaac97ce3d3b5588e847aa79b580c1e922bb5d5d2902df19b"}, + {file = "mypy-1.11.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4a8a53bc3ffbd161b5b2a4fff2f0f1e23a33b0168f1c0778ec70e1a3d66deb86"}, + {file = "mypy-1.11.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ff93107f01968ed834f4256bc1fc4475e2fecf6c661260066a985b52741ddce"}, + {file = "mypy-1.11.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:edb91dded4df17eae4537668b23f0ff6baf3707683734b6a818d5b9d0c0c31a1"}, + {file = "mypy-1.11.2-cp38-cp38-win_amd64.whl", hash = "sha256:ee23de8530d99b6db0573c4ef4bd8f39a2a6f9b60655bf7a1357e585a3486f2b"}, + {file = "mypy-1.11.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:801ca29f43d5acce85f8e999b1e431fb479cb02d0e11deb7d2abb56bdaf24fd6"}, + {file = "mypy-1.11.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af8d155170fcf87a2afb55b35dc1a0ac21df4431e7d96717621962e4b9192e70"}, + {file = "mypy-1.11.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7821776e5c4286b6a13138cc935e2e9b6fde05e081bdebf5cdb2bb97c9df81d"}, + {file = "mypy-1.11.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:539c570477a96a4e6fb718b8d5c3e0c0eba1f485df13f86d2970c91f0673148d"}, + {file = "mypy-1.11.2-cp39-cp39-win_amd64.whl", hash = "sha256:3f14cd3d386ac4d05c5a39a51b84387403dadbd936e17cb35882134d4f8f0d24"}, + {file = "mypy-1.11.2-py3-none-any.whl", hash = "sha256:b499bc07dbdcd3de92b0a8b29fdf592c111276f6a12fe29c30f6c417dd546d12"}, + {file = "mypy-1.11.2.tar.gz", hash = "sha256:7f9993ad3e0ffdc95c2a14b66dee63729f021968bff8ad911867579c65d13a79"}, ] [package.dependencies] mypy-extensions = ">=1.0.0" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = ">=4.1.0" +typing-extensions = ">=4.6.0" [package.extras] dmypy = ["psutil (>=4.0)"] @@ -4677,4 +4677,4 @@ weaviate = ["weaviate-client"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<4.0" -content-hash = "7ffcf39257e1ac79d951b7ccb2cdb972beaaef35d0cd1f722d2964c5bdced674" +content-hash = "3668cd6d7ad70ac83d03024607d9bff43447206b40033113dd2a69189acb6406" diff --git a/pyproject.toml b/pyproject.toml index 990bb672..b2e76eea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -166,7 +166,7 @@ chroma = ["chromadb-client"] trino = ["trino"] [tool.poetry.group.dev.dependencies] -mypy = "1.7.1" +mypy = "1.11.2" pre-commit = "^3.6" pytest = "7.4.3" pytest-cov = "4.1.0" @@ -280,8 +280,9 @@ namespace_packages = true explicit_package_bases = true pretty = true show_error_codes = true +warn_return_any = true strict = true -fast_module_lookup = true +# fast_module_lookup = true modules = ["testcontainers.core"] mypy_path = [ "core", diff --git a/scripts/mypy_report.py b/scripts/mypy_report.py new file mode 100755 index 00000000..7bc12474 --- /dev/null +++ b/scripts/mypy_report.py @@ -0,0 +1,35 @@ +# Description: This script reads the output of mypy and generates a summary of errors by file. + +import re +import sys + +from rich.console import Console +from rich.table import Table + +# Regular expression to match file path and error count +pattern = r"(.*\.py:\d+):\s+error: (.*)" + +error_dict = {} + +for line in sys.stdin: + match = re.search(pattern, line) + if match: + # Extract file path and error message + file_path, _ = match.group(1).split(":") + error_message = match.group(2) + + if file_path not in error_dict: + error_dict[file_path] = 1 + else: + error_dict[file_path] += 1 + +table = Table(title="Error Summary") +table.add_column("File Path") +table.add_column("Errors", justify="left") + +for file_path, error_count in error_dict.items(): + table.add_row(file_path, str(error_count)) + +console = Console() +console.print(table) +console.print(f"[red]Found {sum(error_dict.values())} errors in {len(error_dict)} files.[/red]")