Skip to content

Commit b0a041a

Browse files
Generic column operators and update Index signature. (#108)
* Make columnoperators generic in typeengine * Add ticket 82 test-case * Fix init of Index * tests: add index.__init__ with str expression.
1 parent e128507 commit b0a041a

File tree

7 files changed

+284
-119
lines changed

7 files changed

+284
-119
lines changed

sqlalchemy-stubs/sql/elements.pyi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ class ColumnElement(
126126
roles.DMLColumnRole,
127127
roles.DDLConstraintColumnRole,
128128
roles.DDLExpressionRole,
129-
operators.ColumnOperators,
129+
operators.ColumnOperators[_TE],
130130
ClauseElement,
131131
Generic[_TE],
132132
):

sqlalchemy-stubs/sql/operators.pyi

Lines changed: 107 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,21 @@ from operator import sub as sub
1919
from operator import truediv as truediv
2020
from typing import Any
2121
from typing import Callable
22+
from typing import Generic
23+
from typing import NoReturn
2224
from typing import Optional
2325
from typing import Type
2426
from typing import TypeVar
2527
from typing import Union
2628

29+
from . import sqltypes
2730
from .elements import ClauseElement
31+
from .elements import ColumnElement
2832
from .type_api import TypeEngine
2933

3034
_F = TypeVar("_F", bound=Callable[..., Any])
35+
_T = TypeVar("_T")
36+
_TE = TypeVar("_TE", bound=TypeEngine[Any])
3137

3238
div = truediv
3339

@@ -77,137 +83,123 @@ class custom_op:
7783
def __hash__(self) -> int: ...
7884
def __call__(self, left: Any, right: Any, **kw: Any) -> ClauseElement: ...
7985

80-
class ColumnOperators(Operators):
86+
class ColumnOperators(Operators, Generic[_TE]):
8187
timetuple: Any = ...
82-
def __lt__(self, other: Any) -> ClauseElement: ...
83-
def __le__(self, other: Any) -> ClauseElement: ...
84-
def __eq__(self, other: Any) -> ClauseElement: ... # type: ignore[override]
85-
def __ne__(self, other: Any) -> ClauseElement: ... # type: ignore[override]
86-
def is_distinct_from(self, other: Any) -> ClauseElement: ...
87-
def is_not_distinct_from(self, other: Any) -> ClauseElement: ...
88-
def isnot_distinct_from(self, other: Any) -> ClauseElement: ...
89-
def __gt__(self, other: Any) -> ClauseElement: ...
90-
def __ge__(self, other: Any) -> ClauseElement: ...
91-
def __neg__(self) -> ClauseElement: ...
92-
def __contains__(self, other: Any) -> ClauseElement: ...
93-
def __getitem__(self, index: Any) -> ClauseElement: ...
94-
def __lshift__(self, other: Any) -> ClauseElement: ...
95-
def __rshift__(self, other: Any) -> ClauseElement: ...
96-
def concat(self, other: Any) -> ClauseElement: ...
88+
# TODO https://github.com/sqlalchemy/sqlalchemy2-stubs/issues/114
89+
# Can we also limit the "other" parameter? Most should be
90+
# Same TypeEngine[_T] or _T, but in case of ORM expressions
91+
# _T is a Mapped type, can we extract the pure python type from
92+
# a TypeEngine bounded TypeVar?
93+
# def __lt__(
94+
# self, other: Union[ColumnElement[TypeEngine[_T]], _T]
95+
# ) -> ColumnElement[sqltypes.Boolean]: ...
96+
def __lt__(self, other: Any) -> ColumnElement[sqltypes.Boolean]: ...
97+
def __le__(self, other: Any) -> ColumnElement[sqltypes.Boolean]: ...
98+
def __eq__(self, other: Any) -> ColumnElement[sqltypes.Boolean]: ... # type: ignore[override]
99+
def __ne__(self, other: Any) -> ColumnElement[sqltypes.Boolean]: ... # type: ignore[override]
100+
def is_distinct_from(
101+
self, other: Any
102+
) -> ColumnElement[sqltypes.Boolean]: ...
103+
def is_not_distinct_from(
104+
self, other: Any
105+
) -> ColumnElement[sqltypes.Boolean]: ...
106+
def __gt__(self, other: Any) -> ColumnElement[sqltypes.Boolean]: ...
107+
def __ge__(self, other: Any) -> ColumnElement[sqltypes.Boolean]: ...
108+
def __neg__(self) -> ColumnElement[_TE]: ...
109+
def __contains__(self, other: Any) -> ColumnElement[sqltypes.Boolean]: ...
110+
# TODO __getitem__ is hard: Arrays return Random Types and Strings return Strings?
111+
def __getitem__(self, index: Any) -> ColumnElement[Any]: ...
112+
def __lshift__(self, other: Any) -> ColumnElement[_TE]: ...
113+
def __rshift__(self, other: Any) -> ColumnElement[_TE]: ...
114+
def concat(self, other: Any) -> ColumnElement[sqltypes.String]: ...
97115
def like(
98-
self, other: Any, escape: Optional[Any] = ...
99-
) -> ClauseElement: ...
116+
self, other: Any, escape: Optional[str] = ...
117+
) -> ColumnElement[sqltypes.Boolean]: ...
100118
def ilike(
101-
self, other: Any, escape: Optional[Any] = ...
102-
) -> ClauseElement: ...
103-
def in_(self, other: Any) -> ClauseElement: ...
104-
def not_in(self, other: Any) -> ClauseElement: ...
105-
def notin_(self, other: Any) -> ClauseElement: ...
119+
self, other: Any, escape: Optional[str] = ...
120+
) -> ColumnElement[sqltypes.Boolean]: ...
121+
def in_(self, other: Any) -> ColumnElement[sqltypes.Boolean]: ...
122+
def not_in(self, other: Any) -> ColumnElement[sqltypes.Boolean]: ...
106123
def not_like(
107-
self, other: Any, escape: Optional[Any] = ...
108-
) -> ClauseElement: ...
109-
def notlike(
110-
self, other: Any, escape: Optional[Any] = ...
111-
) -> ClauseElement: ...
124+
self, other: Any, escape: Optional[str] = ...
125+
) -> ColumnElement[sqltypes.Boolean]: ...
112126
def not_ilike(
113-
self, other: Any, escape: Optional[Any] = ...
114-
) -> ClauseElement: ...
115-
def notilike(
116-
self, other: Any, escape: Optional[Any] = ...
117-
) -> ClauseElement: ...
118-
def is_(self, other: Any) -> ClauseElement: ...
119-
def is_not(self, other: Any) -> ClauseElement: ...
120-
isnot: Any = ...
121-
def startswith(self, other: Any, **kwargs: Any) -> ClauseElement: ...
122-
def endswith(self, other: Any, **kwargs: Any) -> ClauseElement: ...
123-
def contains(self, other: Any, **kwargs: Any) -> ClauseElement: ...
124-
def match(self, other: Any, **kwargs: Any) -> ClauseElement: ...
127+
self, other: Any, escape: Optional[str] = ...
128+
) -> ColumnElement[sqltypes.Boolean]: ...
129+
def is_(self, other: Any) -> ColumnElement[sqltypes.Boolean]: ...
130+
def is_not(self, other: Any) -> ColumnElement[sqltypes.Boolean]: ...
131+
def startswith(
132+
self, other: Any, **kwargs: Any
133+
) -> ColumnElement[sqltypes.Boolean]: ...
134+
def endswith(
135+
self, other: Any, **kwargs: Any
136+
) -> ColumnElement[sqltypes.Boolean]: ...
137+
def contains(
138+
self, other: Any, **kwargs: Any
139+
) -> ColumnElement[sqltypes.Boolean]: ...
140+
def match(
141+
self, other: Any, **kwargs: Any
142+
) -> ColumnElement[sqltypes.Boolean]: ...
125143
def regexp_match(
126144
self, pattern: Any, flags: Optional[Any] = ...
127-
) -> ClauseElement: ...
145+
) -> ColumnElement[sqltypes.Boolean]: ...
128146
def regexp_replace(
129147
self, pattern: Any, replacement: Any, flags: Optional[Any] = ...
130-
) -> ClauseElement: ...
131-
def desc(self) -> ClauseElement: ...
132-
def asc(self) -> ClauseElement: ...
133-
def nulls_first(self) -> ClauseElement: ...
134-
def nullsfirst(self) -> ClauseElement: ...
135-
def nulls_last(self) -> ClauseElement: ...
136-
def nullslast(self) -> ClauseElement: ...
137-
def collate(self, collation: Any) -> ClauseElement: ...
138-
def __radd__(self, other: Any) -> ClauseElement: ...
139-
def __rsub__(self, other: Any) -> ClauseElement: ...
140-
def __rmul__(self, other: Any) -> ClauseElement: ...
141-
def __rdiv__(self, other: Any) -> ClauseElement: ...
142-
def __rmod__(self, other: Any) -> ClauseElement: ...
148+
) -> ColumnElement[sqltypes.String]: ...
149+
def desc(self) -> ColumnElement[sqltypes.NullType]: ...
150+
def asc(self) -> ColumnElement[sqltypes.NullType]: ...
151+
def nulls_first(self) -> ColumnElement[sqltypes.NullType]: ...
152+
def nulls_last(self) -> ColumnElement[sqltypes.NullType]: ...
153+
def collate(self, collation: str) -> ColumnElement[_TE]: ...
154+
def __radd__(self, other: Any) -> ColumnElement[_TE]: ...
155+
def __rsub__(self, other: Any) -> ColumnElement[_TE]: ...
156+
def __rmul__(self, other: Any) -> ColumnElement[_TE]: ...
157+
def __rdiv__(self, other: Any) -> ColumnElement[_TE]: ...
158+
def __rmod__(self, other: Any) -> ColumnElement[_TE]: ...
143159
def between(
144160
self, cleft: Any, cright: Any, symmetric: bool = ...
145-
) -> ClauseElement: ...
146-
def distinct(self) -> ClauseElement: ...
147-
def any_(self) -> ClauseElement: ...
148-
def all_(self) -> ClauseElement: ...
149-
def __add__(self, other: Any) -> ClauseElement: ...
150-
def __sub__(self, other: Any) -> ClauseElement: ...
151-
def __mul__(self, other: Any) -> ClauseElement: ...
152-
def __div__(self, other: Any) -> ClauseElement: ...
153-
def __mod__(self, other: Any) -> ClauseElement: ...
154-
def __truediv__(self, other: Any) -> ClauseElement: ...
155-
def __rtruediv__(self, other: Any) -> ClauseElement: ...
161+
) -> ColumnElement[sqltypes.Boolean]: ...
162+
def distinct(self) -> ColumnElement[_TE]: ...
163+
def any_(self) -> ColumnElement[sqltypes.NullType]: ...
164+
def all_(self) -> ColumnElement[sqltypes.NullType]: ...
165+
def __add__(self, other: Any) -> ColumnElement[_TE]: ...
166+
def __sub__(self, other: Any) -> ColumnElement[_TE]: ...
167+
def __mul__(self, other: Any) -> ColumnElement[_TE]: ...
168+
def __div__(self, other: Any) -> ColumnElement[_TE]: ...
169+
def __mod__(self, other: Any) -> ColumnElement[_TE]: ...
170+
def __truediv__(self, other: Any) -> ColumnElement[_TE]: ...
171+
def __rtruediv__(self, other: Any) -> ColumnElement[_TE]: ...
156172

157173
def commutative_op(fn: _F) -> _F: ...
158174
def comparison_op(fn: _F) -> _F: ...
159-
def from_() -> None: ...
160-
def function_as_comparison_op() -> None: ...
161-
def as_() -> None: ...
162-
def exists() -> None: ...
163-
def is_true(a: Any) -> None: ...
164-
165-
istrue = is_true
166-
167-
def is_false(a: Any) -> None: ...
168-
169-
isfalse = is_false
170-
175+
def from_() -> NoReturn: ...
176+
def function_as_comparison_op() -> NoReturn: ...
177+
def as_() -> NoReturn: ...
178+
def exists() -> NoReturn: ...
179+
def is_true(a: Any) -> NoReturn: ...
180+
def is_false(a: Any) -> NoReturn: ...
171181
def is_distinct_from(a: Any, b: Any) -> ClauseElement: ...
172182
def is_not_distinct_from(a: Any, b: Any) -> ClauseElement: ...
173-
174-
isnot_distinct_from = is_not_distinct_from
175-
176183
def is_(a: Any, b: Any) -> ClauseElement: ...
177184
def is_not(a: Any, b: Any) -> ClauseElement: ...
178-
179-
isnot = is_not
180-
181185
def collate(a: Any, b: Any) -> ClauseElement: ...
182186
def op(a: Any, opstring: str, b: Any) -> ClauseElement: ...
183187
def like_op(a: Any, b: Any, escape: Optional[Any] = ...) -> ClauseElement: ...
184188
def not_like_op(
185189
a: Any, b: Any, escape: Optional[Any] = ...
186190
) -> ClauseElement: ...
187-
188-
notlike_op = not_like_op
189-
190191
def ilike_op(a: Any, b: Any, escape: Optional[Any] = ...) -> ClauseElement: ...
191192
def not_ilike_op(
192193
a: Any, b: Any, escape: Optional[Any] = ...
193194
) -> ClauseElement: ...
194-
195-
notilike_op = not_ilike_op
196-
197195
def between_op(
198196
a: Any, b: Any, c: Any, symmetric: bool = ...
199197
) -> ClauseElement: ...
200198
def not_between_op(
201199
a: Any, b: Any, c: Any, symmetric: bool = ...
202200
) -> ClauseElement: ...
203-
204-
notbetween_op = not_between_op
205-
206201
def in_op(a: Any, b: Any) -> ClauseElement: ...
207202
def not_in_op(a: Any, b: Any) -> ClauseElement: ...
208-
209-
notin_op = not_in_op
210-
211203
def distinct_op(a: Any) -> ClauseElement: ...
212204
def any_op(a: Any) -> ClauseElement: ...
213205
def all_op(a: Any) -> ClauseElement: ...
@@ -217,27 +209,18 @@ def startswith_op(
217209
def not_startswith_op(
218210
a: Any, b: Any, escape: Optional[Any] = ..., autoescape: bool = ...
219211
) -> ClauseElement: ...
220-
221-
notstartswith_op = not_startswith_op
222-
223212
def endswith_op(
224213
a: Any, b: Any, escape: Optional[Any] = ..., autoescape: bool = ...
225214
) -> ClauseElement: ...
226215
def not_endswith_op(
227216
a: Any, b: Any, escape: Optional[Any] = ..., autoescape: bool = ...
228217
) -> ClauseElement: ...
229-
230-
notendswith_op = not_endswith_op
231-
232218
def contains_op(
233219
a: Any, b: Any, escape: Optional[Any] = ..., autoescape: bool = ...
234220
) -> ClauseElement: ...
235221
def not_contains_op(
236222
a: Any, b: Any, escape: Optional[Any] = ..., autoescape: bool = ...
237223
) -> ClauseElement: ...
238-
239-
notcontains_op = not_contains_op
240-
241224
def match_op(a: Any, b: Any, **kw: Any) -> ClauseElement: ...
242225
def regexp_match_op(
243226
a: Any, b: Any, flags: Optional[Any] = ...
@@ -249,24 +232,15 @@ def regexp_replace_op(
249232
a: Any, b: Any, replacement: Any, flags: Optional[Any] = ...
250233
) -> ClauseElement: ...
251234
def not_match_op(a: Any, b: Any, **kw: Any) -> ClauseElement: ...
252-
253-
notmatch_op = not_match_op
254-
255-
def comma_op(a: Any, b: Any) -> None: ...
256-
def filter_op(a: Any, b: Any) -> None: ...
235+
def comma_op(a: Any, b: Any) -> NoReturn: ...
236+
def filter_op(a: Any, b: Any) -> NoReturn: ...
257237
def concat_op(a: Any, b: Any) -> ClauseElement: ...
258238
def desc_op(a: Any) -> ClauseElement: ...
259239
def asc_op(a: Any) -> ClauseElement: ...
260240
def nulls_first_op(a: Any) -> ClauseElement: ...
261-
262-
nullsfirst_op = nulls_first_op
263-
264241
def nulls_last_op(a: Any) -> ClauseElement: ...
265-
266-
nullslast_op = nulls_last_op
267-
268-
def json_getitem_op(a: Any, b: Any) -> None: ...
269-
def json_path_getitem_op(a: Any, b: Any) -> None: ...
242+
def json_getitem_op(a: Any, b: Any) -> NoReturn: ...
243+
def json_path_getitem_op(a: Any, b: Any) -> NoReturn: ...
270244
def is_comparison(op: Any) -> bool: ...
271245
def is_commutative(op: Any) -> bool: ...
272246
def is_ordering_modifier(op: Any) -> bool: ...
@@ -275,3 +249,19 @@ def is_boolean(op: Any) -> bool: ...
275249
def mirror(op: Any) -> Any: ...
276250
def is_associative(op: Any) -> bool: ...
277251
def is_precedent(operator: Any, against: Any) -> bool: ...
252+
253+
# 1.4 deprecated; see sqlalchemy#5435
254+
istrue = is_true
255+
isfalse = is_false
256+
isnot_distinct_from = is_not_distinct_from
257+
isnot = is_not
258+
notlike_op = not_like_op
259+
notilike_op = not_ilike_op
260+
notbetween_op = not_between_op
261+
notin_op = not_in_op
262+
notstartswith_op = not_startswith_op
263+
notendswith_op = not_endswith_op
264+
notcontains_op = not_contains_op
265+
notmatch_op = not_match_op
266+
nullsfirst_op = nulls_first_op
267+
nullslast_op = nulls_last_op

sqlalchemy-stubs/sql/schema.pyi

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,10 @@ class Index(DialectKWArgs, ColumnCollectionMixin, SchemaItem):
545545
unique: bool = ...
546546
expressions: List[Column[Any]] = ...
547547
def __init__(
548-
self, name: str, *expressions: ColumnClause[Any], **kw: Any
548+
self,
549+
name: str,
550+
*expressions: Union[str, roles.DDLConstraintColumnRole],
551+
**kw: Any,
549552
) -> None: ...
550553
@property
551554
def bind(self) -> Optional[Union[Engine, Connection]]: ...

0 commit comments

Comments
 (0)