summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql/coercions.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2022-01-02 17:35:43 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2022-01-12 10:29:30 -0500
commit43f6ae639ca0186f4802255861acdc20f19e702f (patch)
tree311d908ba5b72b0fcb751d682f56ccd73710d41b /lib/sqlalchemy/sql/coercions.py
parenta869dc8fe3cd579ed9bab665d215a6c3e3d8a4ca (diff)
downloadsqlalchemy-43f6ae639ca0186f4802255861acdc20f19e702f.tar.gz
initial reorganize for static typing
start applying foundational annotations to key elements. two main elements addressed here: 1. removal of public_factory() and replacement with explicit functions. this just works much better with typing. 2. typing support for column expressions and operators. The biggest part of this involves stubbing out all the ColumnOperators methods under ColumnElement in a TYPE_CHECKING section. Took me a while to see this method vs. much more complicated things I thought I needed. Also for this version implementing #7519, ColumnElement types against the Python type and not TypeEngine. it is hoped this leads to easier transferrence between ORM/Core as well as eventual support for result set typing. Not clear yet how well this approach will work and what new issues it may introduce. given the current approach we now get full, rich typing for scenarios like this: from sqlalchemy import column, Integer, String, Boolean c1 = column('a', String) c2 = column('a', Integer) expr1 = c2.in_([1, 2, 3]) expr2 = c2 / 5 expr3 = -c2 expr4_a = ~(c2 == 5) expr4_b = ~column('q', Boolean) expr5 = c1 + 'x' expr6 = c2 + 10 Fixes: #7519 Fixes: #6810 Change-Id: I078d9f57955549f6f7868314287175f6c61c44cb
Diffstat (limited to 'lib/sqlalchemy/sql/coercions.py')
-rw-r--r--lib/sqlalchemy/sql/coercions.py124
1 files changed, 111 insertions, 13 deletions
diff --git a/lib/sqlalchemy/sql/coercions.py b/lib/sqlalchemy/sql/coercions.py
index fe2b498c8..3bec73f7d 100644
--- a/lib/sqlalchemy/sql/coercions.py
+++ b/lib/sqlalchemy/sql/coercions.py
@@ -8,6 +8,14 @@
import collections.abc as collections_abc
import numbers
import re
+import typing
+from typing import Any
+from typing import Callable
+from typing import Optional
+from typing import overload
+from typing import Type
+from typing import TypeVar
+from typing import Union
from . import operators
from . import roles
@@ -20,13 +28,24 @@ from .. import exc
from .. import inspection
from .. import util
+if not typing.TYPE_CHECKING:
+ elements = None
+ lambdas = None
+ schema = None
+ selectable = None
+ traversals = None
-elements = None
-lambdas = None
-schema = None
-selectable = None
-sqltypes = None
-traversals = None
+if typing.TYPE_CHECKING:
+ from . import elements
+ from . import lambdas
+ from . import schema
+ from . import selectable
+ from . import traversals
+ from .elements import ClauseElement
+ from .elements import ColumnElement
+
+_SR = TypeVar("_SR", bound=roles.SQLRole)
+_StringOnlyR = TypeVar("_StringOnlyR", bound=roles.StringRole)
def _is_literal(element):
@@ -110,14 +129,93 @@ def _expression_collection_was_a_list(attrname, fnname, args):
return args
+@overload
def expect(
- role,
- element,
- apply_propagate_attrs=None,
- argname=None,
- post_inspect=False,
- **kw,
-):
+ role: Type[roles.InElementRole],
+ element: Any,
+ *,
+ apply_propagate_attrs: Optional["ClauseElement"] = None,
+ argname: Optional[str] = None,
+ post_inspect: bool = False,
+ **kw: Any,
+) -> Union["elements.ColumnElement", "selectable.Select"]:
+ ...
+
+
+@overload
+def expect(
+ role: Type[roles.HasCTERole],
+ element: Any,
+ *,
+ apply_propagate_attrs: Optional["ClauseElement"] = None,
+ argname: Optional[str] = None,
+ post_inspect: bool = False,
+ **kw: Any,
+) -> "selectable.HasCTE":
+ ...
+
+
+@overload
+def expect(
+ role: Type[roles.ExpressionElementRole],
+ element: Any,
+ *,
+ apply_propagate_attrs: Optional["ClauseElement"] = None,
+ argname: Optional[str] = None,
+ post_inspect: bool = False,
+ **kw: Any,
+) -> "ColumnElement":
+ ...
+
+
+@overload
+def expect(
+ role: "Type[_StringOnlyR]",
+ element: Any,
+ *,
+ apply_propagate_attrs: Optional["ClauseElement"] = None,
+ argname: Optional[str] = None,
+ post_inspect: bool = False,
+ **kw: Any,
+) -> str:
+ ...
+
+
+@overload
+def expect(
+ role: Type[_SR],
+ element: Any,
+ *,
+ apply_propagate_attrs: Optional["ClauseElement"] = None,
+ argname: Optional[str] = None,
+ post_inspect: bool = False,
+ **kw: Any,
+) -> _SR:
+ ...
+
+
+@overload
+def expect(
+ role: Type[_SR],
+ element: Callable[..., Any],
+ *,
+ apply_propagate_attrs: Optional["ClauseElement"] = None,
+ argname: Optional[str] = None,
+ post_inspect: bool = False,
+ **kw: Any,
+) -> "lambdas.LambdaElement":
+ ...
+
+
+def expect(
+ role: Type[_SR],
+ element: Any,
+ *,
+ apply_propagate_attrs: Optional["ClauseElement"] = None,
+ argname: Optional[str] = None,
+ post_inspect: bool = False,
+ **kw: Any,
+) -> Union[str, _SR, "lambdas.LambdaElement"]:
if (
role.allows_lambda
# note callable() will not invoke a __getattr__() method, whereas