From 7ccde53cb0f59f757f5327a39cb0ccb159c77c18 Mon Sep 17 00:00:00 2001 From: Jan-Eric Nitschke <47750513+JanEricNitschke@users.noreply.github.com> Date: Mon, 15 Sep 2025 08:24:27 +0200 Subject: [PATCH 1/5] [PyMySQL] Fix stubs for pymysql.connections.Connection.__init__ --- stubs/PyMySQL/@tests/stubtest_allowlist.txt | 4 ---- stubs/PyMySQL/pymysql/connections.pyi | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/stubs/PyMySQL/@tests/stubtest_allowlist.txt b/stubs/PyMySQL/@tests/stubtest_allowlist.txt index 688b3058dbd2..e7a8053fb866 100644 --- a/stubs/PyMySQL/@tests/stubtest_allowlist.txt +++ b/stubs/PyMySQL/@tests/stubtest_allowlist.txt @@ -1,7 +1,3 @@ # DictCursorMixin changes method types of inherited classes, but doesn't contain much at runtime pymysql.cursors.DictCursorMixin.__iter__ pymysql.cursors.DictCursorMixin.fetch[a-z]* - -# FIXME: new stubtest errors from mypy v1.18.1 that need to be looked at more closely. -# See https://github.com/python/typeshed/pull/14699 -pymysql.connections.Connection.__init__ diff --git a/stubs/PyMySQL/pymysql/connections.pyi b/stubs/PyMySQL/pymysql/connections.pyi index 2fc19397c89e..ebdd0e764c37 100644 --- a/stubs/PyMySQL/pymysql/connections.pyi +++ b/stubs/PyMySQL/pymysql/connections.pyi @@ -76,7 +76,7 @@ class Connection(Generic[_C]): conv: dict[int | type[Any], Callable[[Any], str] | Callable[[str], Any]] | None = None, use_unicode: bool = True, client_flag: int = 0, - cursorclass: None = None, # different between overloads + cursorclass: type[Cursor] = Cursor, # different between overloads init_command: str | None = None, connect_timeout: float = 10, read_default_group: str | None = None, @@ -170,7 +170,7 @@ class Connection(Generic[_C]): conv: dict[int | type[Any], Callable[[Any], str] | Callable[[str], Any]] | None = None, use_unicode: bool = True, client_flag: int = 0, - cursorclass: None = None, # different between overloads + cursorclass: type[Cursor] = Cursor, # different between overloads init_command: str | None = None, connect_timeout: float = 10, read_default_group: str | None = None, From 4e26d008ef0b62c9712274399656fc058370987c Mon Sep 17 00:00:00 2001 From: Jan-Eric Nitschke <47750513+JanEricNitschke@users.noreply.github.com> Date: Mon, 15 Sep 2025 08:40:47 +0200 Subject: [PATCH 2/5] Set default as --- stubs/PyMySQL/pymysql/connections.pyi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stubs/PyMySQL/pymysql/connections.pyi b/stubs/PyMySQL/pymysql/connections.pyi index ebdd0e764c37..577a63afe617 100644 --- a/stubs/PyMySQL/pymysql/connections.pyi +++ b/stubs/PyMySQL/pymysql/connections.pyi @@ -76,7 +76,7 @@ class Connection(Generic[_C]): conv: dict[int | type[Any], Callable[[Any], str] | Callable[[str], Any]] | None = None, use_unicode: bool = True, client_flag: int = 0, - cursorclass: type[Cursor] = Cursor, # different between overloads + cursorclass: type[Cursor] = ..., # different between overloads init_command: str | None = None, connect_timeout: float = 10, read_default_group: str | None = None, @@ -170,7 +170,7 @@ class Connection(Generic[_C]): conv: dict[int | type[Any], Callable[[Any], str] | Callable[[str], Any]] | None = None, use_unicode: bool = True, client_flag: int = 0, - cursorclass: type[Cursor] = Cursor, # different between overloads + cursorclass: type[Cursor] = ..., # different between overloads init_command: str | None = None, connect_timeout: float = 10, read_default_group: str | None = None, From 95595d513c78095c4fdc8f0880a13044987278a0 Mon Sep 17 00:00:00 2001 From: Jan-Eric Nitschke <47750513+JanEricNitschke@users.noreply.github.com> Date: Mon, 15 Sep 2025 15:32:43 +0200 Subject: [PATCH 3/5] Use TypeVar default --- stubs/PyMySQL/pymysql/connections.pyi | 101 +------------------------- 1 file changed, 4 insertions(+), 97 deletions(-) diff --git a/stubs/PyMySQL/pymysql/connections.pyi b/stubs/PyMySQL/pymysql/connections.pyi index 577a63afe617..f6bbe3beb7dd 100644 --- a/stubs/PyMySQL/pymysql/connections.pyi +++ b/stubs/PyMySQL/pymysql/connections.pyi @@ -2,8 +2,8 @@ from _typeshed import FileDescriptorOrPath, Incomplete, Unused from collections.abc import Callable, Mapping from socket import _Address, socket as _socket from ssl import SSLContext, _PasswordType -from typing import Any, AnyStr, Generic, TypeVar, overload -from typing_extensions import Self, deprecated +from typing import Any, AnyStr, Generic, overload +from typing_extensions import Self, TypeVar, deprecated from .charset import charset_by_id as charset_by_id, charset_by_name as charset_by_name from .constants import CLIENT as CLIENT, COMMAND as COMMAND, FIELD_TYPE as FIELD_TYPE, SERVER_STATUS as SERVER_STATUS @@ -21,8 +21,8 @@ from .err import ( Warning, ) -_C = TypeVar("_C", bound=Cursor) -_C2 = TypeVar("_C2", bound=Cursor) +_C = TypeVar("_C", bound=Cursor, default=Cursor) +_C2 = TypeVar("_C2", bound=Cursor, default=Cursor) SSL_ENABLED: bool DEFAULT_USER: str | None @@ -59,52 +59,6 @@ class Connection(Generic[_C]): encoders: dict[type[Any], Callable[[Any], str]] # argument type depends on the key decoders: dict[int, Callable[[str], Any]] # return type depends on the key - @overload - def __init__( - self: Connection[Cursor], # different between overloads - *, - user: str | bytes | None = None, - password: str | bytes = "", - host: str | None = None, - database: str | bytes | None = None, - unix_socket: _Address | None = None, - port: int = 0, - charset: str = "", - collation: str | None = None, - sql_mode: str | None = None, - read_default_file: str | None = None, - conv: dict[int | type[Any], Callable[[Any], str] | Callable[[str], Any]] | None = None, - use_unicode: bool = True, - client_flag: int = 0, - cursorclass: type[Cursor] = ..., # different between overloads - init_command: str | None = None, - connect_timeout: float = 10, - read_default_group: str | None = None, - autocommit: bool | None = False, - local_infile: bool = False, - max_allowed_packet: int = 16_777_216, - defer_connect: bool = False, - auth_plugin_map: dict[str, Callable[[Connection[Any]], Any]] | None = None, - read_timeout: float | None = None, - write_timeout: float | None = None, - bind_address: str | None = None, - binary_prefix: bool = False, - program_name: str | None = None, - server_public_key: bytes | None = None, - ssl: dict[str, Incomplete] | SSLContext | None = None, - ssl_ca: str | None = None, - ssl_cert: str | None = None, - ssl_disabled: bool | None = None, - ssl_key: str | None = None, - ssl_key_password: _PasswordType | None = None, - ssl_verify_cert: bool | None = None, - ssl_verify_identity: bool | None = None, - compress: Unused = None, - named_pipe: Unused = None, - # different between overloads: - passwd: None = None, # deprecated - db: None = None, # deprecated - ) -> None: ... @overload def __init__( # different between overloads @@ -154,53 +108,6 @@ class Connection(Generic[_C]): ) -> None: ... @overload @deprecated("'passwd' and 'db' arguments are deprecated. Use 'password' and 'database' instead.") - def __init__( - self: Connection[Cursor], # different between overloads - *, - user: str | bytes | None = None, - password: str | bytes = "", - host: str | None = None, - database: str | bytes | None = None, - unix_socket: _Address | None = None, - port: int = 0, - charset: str = "", - collation: str | None = None, - sql_mode: str | None = None, - read_default_file: str | None = None, - conv: dict[int | type[Any], Callable[[Any], str] | Callable[[str], Any]] | None = None, - use_unicode: bool = True, - client_flag: int = 0, - cursorclass: type[Cursor] = ..., # different between overloads - init_command: str | None = None, - connect_timeout: float = 10, - read_default_group: str | None = None, - autocommit: bool | None = False, - local_infile: bool = False, - max_allowed_packet: int = 16_777_216, - defer_connect: bool = False, - auth_plugin_map: dict[str, Callable[[Connection[Any]], Any]] | None = None, - read_timeout: float | None = None, - write_timeout: float | None = None, - bind_address: str | None = None, - binary_prefix: bool = False, - program_name: str | None = None, - server_public_key: bytes | None = None, - ssl: dict[str, Incomplete] | SSLContext | None = None, - ssl_ca: str | None = None, - ssl_cert: str | None = None, - ssl_disabled: bool | None = None, - ssl_key: str | None = None, - ssl_key_password: _PasswordType | None = None, - ssl_verify_cert: bool | None = None, - ssl_verify_identity: bool | None = None, - compress: Unused = None, - named_pipe: Unused = None, - # different between overloads: - passwd: str | bytes | None = None, # deprecated - db: str | bytes | None = None, # deprecated - ) -> None: ... - @overload - @deprecated("'passwd' and 'db' arguments are deprecated. Use 'password' and 'database' instead.") def __init__( # different between overloads self: Connection[_C], # pyright: ignore[reportInvalidTypeVarUse] #11780 From 1bb85c025cf6b12c10ed70560efa22ff57a464f3 Mon Sep 17 00:00:00 2001 From: Jan-Eric Nitschke <47750513+JanEricNitschke@users.noreply.github.com> Date: Mon, 15 Sep 2025 16:22:50 +0200 Subject: [PATCH 4/5] Clean stubs and add regression tests --- .../PyMySQL/@tests/test_cases/check_connection.py | 14 ++++++++++++++ stubs/PyMySQL/pymysql/connections.pyi | 12 +++++------- 2 files changed, 19 insertions(+), 7 deletions(-) create mode 100644 stubs/PyMySQL/@tests/test_cases/check_connection.py diff --git a/stubs/PyMySQL/@tests/test_cases/check_connection.py b/stubs/PyMySQL/@tests/test_cases/check_connection.py new file mode 100644 index 000000000000..9a6fe8b0ba9b --- /dev/null +++ b/stubs/PyMySQL/@tests/test_cases/check_connection.py @@ -0,0 +1,14 @@ +from pymysql.connections import Connection +from pymysql.cursors import Cursor +from typing_extensions import assert_type + + +class MyCursor(Cursor): + pass + + +assert_type(Connection(), Connection[Cursor]) +assert_type(Connection(cursorclass=Cursor), Connection[Cursor]) +assert_type(Connection(cursorclass=MyCursor), Connection[MyCursor]) + +Connection(cursorclass=None) # type: ignore diff --git a/stubs/PyMySQL/pymysql/connections.pyi b/stubs/PyMySQL/pymysql/connections.pyi index f6bbe3beb7dd..32abdbf533df 100644 --- a/stubs/PyMySQL/pymysql/connections.pyi +++ b/stubs/PyMySQL/pymysql/connections.pyi @@ -22,7 +22,7 @@ from .err import ( ) _C = TypeVar("_C", bound=Cursor, default=Cursor) -_C2 = TypeVar("_C2", bound=Cursor, default=Cursor) +_C2 = TypeVar("_C2", bound=Cursor) SSL_ENABLED: bool DEFAULT_USER: str | None @@ -61,8 +61,7 @@ class Connection(Generic[_C]): @overload def __init__( - # different between overloads - self: Connection[_C], # pyright: ignore[reportInvalidTypeVarUse] #11780 + self, *, user: str | bytes | None = None, password: str | bytes = "", @@ -77,7 +76,7 @@ class Connection(Generic[_C]): conv: dict[int | type[Any], Callable[[Any], str] | Callable[[str], Any]] | None = None, use_unicode: bool = True, client_flag: int = 0, - cursorclass: type[_C] = ..., # different between overloads + cursorclass: type[_C] = ..., init_command: str | None = None, connect_timeout: float = 10, read_default_group: str | None = None, @@ -109,8 +108,7 @@ class Connection(Generic[_C]): @overload @deprecated("'passwd' and 'db' arguments are deprecated. Use 'password' and 'database' instead.") def __init__( - # different between overloads - self: Connection[_C], # pyright: ignore[reportInvalidTypeVarUse] #11780 + self, *, user: str | bytes | None = None, password: str | bytes = "", @@ -125,7 +123,7 @@ class Connection(Generic[_C]): conv: dict[int | type[Any], Callable[[Any], str] | Callable[[str], Any]] | None = None, use_unicode: bool = True, client_flag: int = 0, - cursorclass: type[_C] = ..., # different between overloads + cursorclass: type[_C] = ..., init_command: str | None = None, connect_timeout: float = 10, read_default_group: str | None = None, From c2dc1fc1f2ff1e0c5d8fa1433960d2c2784fc618 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 14:24:55 +0000 Subject: [PATCH 5/5] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stubs/PyMySQL/@tests/test_cases/check_connection.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stubs/PyMySQL/@tests/test_cases/check_connection.py b/stubs/PyMySQL/@tests/test_cases/check_connection.py index 9a6fe8b0ba9b..24d42664e3c7 100644 --- a/stubs/PyMySQL/@tests/test_cases/check_connection.py +++ b/stubs/PyMySQL/@tests/test_cases/check_connection.py @@ -1,6 +1,7 @@ +from typing_extensions import assert_type + from pymysql.connections import Connection from pymysql.cursors import Cursor -from typing_extensions import assert_type class MyCursor(Cursor):