Skip to content

Commit b0ed50e

Browse files
AvasamAlexWaygoodJelleZijlstra
authored
Fix all fixable stubtest_allowlist entries in SQLAlchemy (#9596)
Co-authored-by: Alex Waygood <[email protected]> Co-authored-by: Jelle Zijlstra <[email protected]>
1 parent 08e6e4c commit b0ed50e

23 files changed

+379
-1268
lines changed

stubs/SQLAlchemy/@tests/stubtest_allowlist.txt

Lines changed: 22 additions & 1151 deletions
Large diffs are not rendered by default.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
from __future__ import annotations
2+
3+
from typing_extensions import assert_type
4+
5+
from sqlalchemy.orm.strategy_options import (
6+
Load,
7+
contains_eager,
8+
defaultload,
9+
defer,
10+
immediateload,
11+
joinedload,
12+
lazyload,
13+
load_only,
14+
loader_option,
15+
noload,
16+
raiseload,
17+
selectin_polymorphic,
18+
selectinload,
19+
subqueryload,
20+
undefer,
21+
undefer_group,
22+
with_expression,
23+
)
24+
25+
26+
def fn(loadopt: Load, *args: object) -> loader_option:
27+
return loader_option()
28+
29+
30+
# Testing that the function and return type of function are actually all instances of "loader_option"
31+
assert_type(contains_eager, loader_option)
32+
assert_type(contains_eager(fn), loader_option)
33+
assert_type(load_only, loader_option)
34+
assert_type(load_only(fn), loader_option)
35+
assert_type(joinedload, loader_option)
36+
assert_type(joinedload(fn), loader_option)
37+
assert_type(subqueryload, loader_option)
38+
assert_type(subqueryload(fn), loader_option)
39+
assert_type(selectinload, loader_option)
40+
assert_type(selectinload(fn), loader_option)
41+
assert_type(lazyload, loader_option)
42+
assert_type(lazyload(fn), loader_option)
43+
assert_type(immediateload, loader_option)
44+
assert_type(immediateload(fn), loader_option)
45+
assert_type(noload, loader_option)
46+
assert_type(noload(fn), loader_option)
47+
assert_type(raiseload, loader_option)
48+
assert_type(raiseload(fn), loader_option)
49+
assert_type(defaultload, loader_option)
50+
assert_type(defaultload(fn), loader_option)
51+
assert_type(defer, loader_option)
52+
assert_type(defer(fn), loader_option)
53+
assert_type(undefer, loader_option)
54+
assert_type(undefer(fn), loader_option)
55+
assert_type(undefer_group, loader_option)
56+
assert_type(undefer_group(fn), loader_option)
57+
assert_type(with_expression, loader_option)
58+
assert_type(with_expression(fn), loader_option)
59+
assert_type(selectin_polymorphic, loader_option)
60+
assert_type(selectin_polymorphic(fn), loader_option)
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
from __future__ import annotations
2+
3+
from _typeshed.dbapi import DBAPIConnection
4+
from typing import cast
5+
6+
from sqlalchemy.engine.base import Engine
7+
from sqlalchemy.engine.default import DefaultDialect
8+
from sqlalchemy.engine.url import URL
9+
from sqlalchemy.pool.base import Pool
10+
from sqlalchemy.testing import config as ConfigModule
11+
from sqlalchemy.testing.provision import (
12+
configure_follower,
13+
create_db,
14+
drop_all_schema_objects_post_tables,
15+
drop_all_schema_objects_pre_tables,
16+
drop_db,
17+
follower_url_from_main,
18+
generate_driver_url,
19+
get_temp_table_name,
20+
post_configure_engine,
21+
prepare_for_drop_tables,
22+
register,
23+
run_reap_dbs,
24+
set_default_schema_on_connection,
25+
stop_test_class_outside_fixtures,
26+
temp_table_keyword_args,
27+
update_db_opts,
28+
)
29+
from sqlalchemy.util import immutabledict
30+
31+
url = URL("", "", "", "", 0, "", immutabledict())
32+
engine = Engine(Pool(lambda: cast(DBAPIConnection, object())), DefaultDialect(), "")
33+
config = cast(ConfigModule.Config, object())
34+
unused = None
35+
36+
37+
class Foo:
38+
pass
39+
40+
41+
# Test that the decorator changes the first parameter to "cfg: str | URL | _ConfigProtocol"
42+
@register.init
43+
def no_args(__foo: Foo) -> None:
44+
pass
45+
46+
47+
no_args(cfg="")
48+
no_args(cfg=url)
49+
no_args(cfg=config)
50+
51+
# Test pre-decorated functions
52+
generate_driver_url(url, "", "")
53+
drop_all_schema_objects_pre_tables(url, unused)
54+
drop_all_schema_objects_post_tables(url, unused)
55+
create_db(url, engine, unused)
56+
drop_db(url, engine, unused)
57+
update_db_opts(url, unused)
58+
post_configure_engine(url, unused, unused)
59+
follower_url_from_main(url, "")
60+
configure_follower(url, unused)
61+
run_reap_dbs(url, unused)
62+
temp_table_keyword_args(url, engine)
63+
prepare_for_drop_tables(url, unused)
64+
stop_test_class_outside_fixtures(url, unused, type)
65+
get_temp_table_name(url, unused, "")
66+
set_default_schema_on_connection(ConfigModule, unused, unused)
67+
set_default_schema_on_connection(config, unused, unused)

stubs/SQLAlchemy/sqlalchemy/dialects/mssql/base.pyi

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,6 @@ class MSExecutionContext(default.DefaultExecutionContext):
197197
@property
198198
def rowcount(self): ...
199199
def handle_dbapi_exception(self, e) -> None: ...
200-
def get_result_cursor_strategy(self, result): ...
201200
def fire_sequence(self, seq, type_): ...
202201
def get_insert_default(self, column): ...
203202

stubs/SQLAlchemy/sqlalchemy/dialects/postgresql/base.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ class PGCompiler(compiler.SQLCompiler):
163163
class PGDDLCompiler(compiler.DDLCompiler):
164164
def get_column_specification(self, column, **kwargs): ...
165165
def visit_check_constraint(self, constraint): ...
166+
def visit_foreign_key_constraint(self, constraint) -> str: ... # type: ignore[override] # Different params
166167
def visit_drop_table_comment(self, drop): ...
167168
def visit_create_enum_type(self, create): ...
168169
def visit_drop_enum_type(self, drop): ...

stubs/SQLAlchemy/sqlalchemy/engine/interfaces.pyi

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@ class ExecutionContext:
116116
def pre_exec(self) -> None: ...
117117
def get_out_parameter_values(self, out_param_names) -> None: ...
118118
def post_exec(self) -> None: ...
119-
def get_result_cursor_strategy(self, result) -> None: ...
120119
def handle_dbapi_exception(self, e) -> None: ...
121120
def should_autocommit_text(self, statement) -> None: ...
122121
def lastrow_has_defaults(self) -> None: ...

stubs/SQLAlchemy/sqlalchemy/engine/url.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class _URLTuple(NamedTuple):
2222
_Query: TypeAlias = Mapping[str, str | Sequence[str]] | Sequence[tuple[str, str | Sequence[str]]]
2323

2424
class URL(_URLTuple):
25+
def __new__(self, *arg, **kw) -> Self | URL: ...
2526
@classmethod
2627
def create(
2728
cls,

stubs/SQLAlchemy/sqlalchemy/event/base.pyi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class _Dispatch:
1212
class _EventMeta(type):
1313
def __init__(cls, classname, bases, dict_) -> None: ...
1414

15-
class Events:
15+
class Events(metaclass=_EventMeta):
1616
dispatch: Any
1717

1818
class _JoinedDispatcher:

stubs/SQLAlchemy/sqlalchemy/orm/collections.pyi

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
1-
from _typeshed import Incomplete
2-
from typing import Any
1+
from _typeshed import Incomplete, SupportsKeysAndGetItem
2+
from collections.abc import Iterable
3+
from typing import Any, TypeVar, overload
4+
from typing_extensions import Literal, SupportsIndex
5+
6+
from ..orm.attributes import Event
7+
from ..util.langhelpers import _symbol, symbol
8+
9+
_T = TypeVar("_T")
10+
_KT = TypeVar("_KT")
11+
_VT = TypeVar("_VT")
312

413
class _PlainColumnGetter:
514
cols: Any
@@ -81,12 +90,41 @@ class CollectionAdapter:
8190
def fire_remove_event(self, item, initiator: Incomplete | None = None) -> None: ...
8291
def fire_pre_remove_event(self, initiator: Incomplete | None = None) -> None: ...
8392

84-
class InstrumentedList(list[Any]): ...
85-
class InstrumentedSet(set[Any]): ...
86-
class InstrumentedDict(dict[Any, Any]): ...
93+
class InstrumentedList(list[_T]):
94+
def append(self, item, _sa_initiator: Event | Literal[False] | None = None) -> None: ...
95+
def clear(self, index: SupportsIndex = -1) -> None: ...
96+
def extend(self, iterable: Iterable[_T]) -> None: ...
97+
def insert(self, index: SupportsIndex, value: _T) -> None: ...
98+
def pop(self, index: SupportsIndex = -1) -> _T: ...
99+
def remove(self, value: _T, _sa_initiator: Event | Literal[False] | None = None) -> None: ...
100+
101+
class InstrumentedSet(set[_T]):
102+
def add(self, value: _T, _sa_initiator: Event | Literal[False] | None = None) -> None: ...
103+
def difference_update(self, value: Iterable[_T]) -> None: ... # type: ignore[override]
104+
def discard(self, value: _T, _sa_initiator: Event | Literal[False] | None = None) -> None: ...
105+
def intersection_update(self, other: Iterable[_T]) -> None: ... # type: ignore[override]
106+
def remove(self, value: _T, _sa_initiator: Event | Literal[False] | None = None) -> None: ...
107+
def symmetric_difference_update(self, other: Iterable[_T]) -> None: ...
108+
def update(self, value: Iterable[_T]) -> None: ... # type: ignore[override]
109+
110+
class InstrumentedDict(dict[_KT, _VT]): ...
87111

88-
class MappedCollection(dict[Any, Any]):
112+
class MappedCollection(dict[_KT, _VT]):
89113
keyfunc: Any
90114
def __init__(self, keyfunc) -> None: ...
91-
def set(self, value, _sa_initiator: Incomplete | None = None) -> None: ...
92-
def remove(self, value, _sa_initiator: Incomplete | None = None) -> None: ...
115+
def set(self, value: _VT, _sa_initiator: Event | Literal[False] | None = None) -> None: ...
116+
def remove(self, value: _VT, _sa_initiator: Event | Literal[False] | None = None) -> None: ...
117+
def __delitem__(self, key: _KT, _sa_initiatorEvent: Event | Literal[False] | None = None) -> None: ...
118+
def __setitem__(self, key: _KT, value: _VT, _sa_initiator: Event | Literal[False] | None = None) -> None: ...
119+
@overload
120+
def pop(self, key: _KT) -> _VT: ...
121+
@overload
122+
def pop(self, key: _KT, default: _VT | _T | _symbol | symbol = ...) -> _VT | _T: ...
123+
@overload # type: ignore[override]
124+
def setdefault(self, key: _KT, default: _T) -> _VT | _T: ...
125+
@overload
126+
def setdefault(self, key: _KT, default: None = None) -> _VT | None: ...
127+
@overload
128+
def update(self, __other: SupportsKeysAndGetItem[_KT, _VT] = ..., **kwargs: _VT) -> None: ...
129+
@overload
130+
def update(self, __other: Iterable[tuple[_KT, _VT]] = ..., **kwargs: _VT) -> None: ...

stubs/SQLAlchemy/sqlalchemy/orm/decl_api.pyi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ _DeclT = TypeVar("_DeclT", bound=type[_DeclarativeBase])
1313

1414
# Dynamic class as created by registry.generate_base() via DeclarativeMeta
1515
# or another metaclass. This class does not exist at runtime.
16-
class _DeclarativeBase(Any): # super classes are dynamic
16+
class _DeclarativeBase(Any): # type: ignore[misc] # super classes are dynamic
1717
registry: ClassVar[registry]
1818
metadata: ClassVar[MetaData]
1919
__abstract__: ClassVar[bool]

0 commit comments

Comments
 (0)