Skip to content

Commit 222c9ca

Browse files
fix: add PEP 561 py.typed markers for type checker support
Add py.typed marker files to core and all module packages to indicate type information is available. This enables type checkers like Pyright and mypy to recognize and validate type hints in testcontainers packages. Resolves "Stub file not found" errors when running type checkers on code that imports testcontainers modules.
1 parent 5853d32 commit 222c9ca

File tree

8 files changed

+28
-16
lines changed

8 files changed

+28
-16
lines changed

core/testcontainers/compose/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
# flake8: noqa: F401
21
from testcontainers.compose.compose import (
32
ComposeContainer,
43
DockerCompose,

modules/generic/example_basic.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def basic_example():
5959
print(f"\nPython container ID: {container_id}")
6060

6161
# Execute command in container
62-
exit_code, output = python.exec_run("python -c 'print(\"Hello from container!\")'")
62+
_exit_code, output = python.exec(["python", "-c", 'print("Hello from container!")'])
6363
print(f"Command output: {output.decode()}")
6464

6565
# Example 5: Container with health check

modules/mailpit/testcontainers/mailpit/py.typed

Whitespace-only changes.

modules/postgres/example_basic.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import pandas as pd
1+
import pandas as pd # type: ignore[import-untyped]
22
import sqlalchemy
33
from sqlalchemy import text
44

55
from testcontainers.postgres import PostgresContainer
66

77

8-
def basic_example():
8+
def basic_example() -> None:
99
with PostgresContainer() as postgres:
1010
# Get connection URL
1111
connection_url = postgres.get_connection_url()

modules/postgres/testcontainers/postgres/__init__.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
# License for the specific language governing permissions and limitations
1212
# under the License.
1313
import os
14-
from typing import Optional
14+
from typing import Any, Optional, Union, cast
1515

1616
from testcontainers.core.generic import DbContainer
1717
from testcontainers.core.utils import raise_for_deprecated_parameter
@@ -53,13 +53,14 @@ def __init__(
5353
password: Optional[str] = None,
5454
dbname: Optional[str] = None,
5555
driver: Optional[str] = "psycopg2",
56-
**kwargs,
56+
**kwargs: Any,
5757
) -> None:
5858
raise_for_deprecated_parameter(kwargs, "user", "username")
5959
super().__init__(image=image, **kwargs)
60-
self.username: str = username or os.environ.get("POSTGRES_USER", "test")
61-
self.password: str = password or os.environ.get("POSTGRES_PASSWORD", "test")
62-
self.dbname: str = dbname or os.environ.get("POSTGRES_DB", "test")
60+
# Ensure concrete str types while preserving "falsy" fallback semantics
61+
self.username: str = cast("str", username or os.environ.get("POSTGRES_USER", "test"))
62+
self.password: str = cast("str", password or os.environ.get("POSTGRES_PASSWORD", "test"))
63+
self.dbname: str = cast("str", dbname or os.environ.get("POSTGRES_DB", "test"))
6364
self.port = port
6465
self.driver = f"+{driver}" if driver else ""
6566

@@ -70,7 +71,7 @@ def _configure(self) -> None:
7071
self.with_env("POSTGRES_PASSWORD", self.password)
7172
self.with_env("POSTGRES_DB", self.dbname)
7273

73-
def get_connection_url(self, host: Optional[str] = None, driver: Optional[str] = _UNSET) -> str:
74+
def get_connection_url(self, host: Optional[str] = None, driver: Union[str, None, object] = _UNSET) -> str:
7475
"""Get a DB connection URL to connect to the PG DB.
7576
7677
If a driver is set in the constructor (defaults to psycopg2!), the URL will contain the

modules/postgres/tests/test_postgres.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from pathlib import Path
2+
from typing import TypedDict
23

34
import pytest
45
import sqlalchemy
@@ -70,7 +71,13 @@ def test_quoted_password():
7071
password = "p@$%25+0&%rd :/!=?"
7172
quoted_password = "p%40%24%2525+0%26%25rd %3A%2F%21%3D%3F"
7273
driver = "psycopg2"
73-
kwargs = {
74+
75+
class ConnKwargs(TypedDict, total=False):
76+
driver: str
77+
username: str
78+
password: str
79+
80+
kwargs: ConnKwargs = {
7481
"driver": driver,
7582
"username": user,
7683
"password": password,
@@ -106,15 +113,20 @@ def test_show_how_to_initialize_db_via_initdb_dir():
106113
with engine.begin() as connection:
107114
connection.execute(sqlalchemy.text(insert_query))
108115
result = connection.execute(sqlalchemy.text(select_query))
109-
result = result.fetchall()
110-
assert len(result) == 1
111-
assert result[0] == (1, "sally", "sells seashells")
116+
rows = result.fetchall()
117+
assert len(rows) == 1
118+
assert rows[0] == (1, "sally", "sells seashells")
112119

113120

114121
def test_none_driver_urls():
115122
user = "root"
116123
password = "pass"
117-
kwargs = {
124+
125+
class ConnKwargs(TypedDict, total=False):
126+
username: str
127+
password: str
128+
129+
kwargs: ConnKwargs = {
118130
"username": user,
119131
"password": password,
120132
}

modules/sftp/testcontainers/sftp/py.typed

Whitespace-only changes.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ mypy_path = [
354354
# "modules/openfga",
355355
# "modules/opensearch",
356356
# "modules/oracle",
357-
# "modules/postgres",
357+
"modules/postgres",
358358
# "modules/rabbitmq",
359359
# "modules/redis",
360360
# "modules/selenium"

0 commit comments

Comments
 (0)