diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2021-12-22 16:21:33 -0500 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2021-12-22 16:22:49 -0500 |
| commit | aded8b11d9eccbd1f2b645a94338e34a3d234bc9 (patch) | |
| tree | 13addfc556c77adc515e273d82d0fca04ea25c3f /lib/sqlalchemy | |
| parent | ab75ec2adb35b249ae6e700f965eb52c0340da69 (diff) | |
| download | sqlalchemy-aded8b11d9eccbd1f2b645a94338e34a3d234bc9.tar.gz | |
use fully qualified, locatable names for all use of api.named_type()
Fixed mypy regression where the release of mypy 0.930 added additional
internal checks to the format of "named types", requiring that they be
fully qualified and locatable. This broke the mypy plugin for SQLAlchemy,
raising an assertion error, as there was use of symbols such as
``__builtins__`` and other un-locatable or unqualified names that
previously had not raised any assertions.
Fixes: #7496
Change-Id: I037680606a1d51158ef6503508ec76c5d5adc946
Diffstat (limited to 'lib/sqlalchemy')
| -rw-r--r-- | lib/sqlalchemy/ext/mypy/apply.py | 9 | ||||
| -rw-r--r-- | lib/sqlalchemy/ext/mypy/decl_class.py | 2 | ||||
| -rw-r--r-- | lib/sqlalchemy/ext/mypy/infer.py | 10 | ||||
| -rw-r--r-- | lib/sqlalchemy/ext/mypy/names.py | 6 | ||||
| -rw-r--r-- | lib/sqlalchemy/ext/mypy/plugin.py | 4 |
5 files changed, 20 insertions, 11 deletions
diff --git a/lib/sqlalchemy/ext/mypy/apply.py b/lib/sqlalchemy/ext/mypy/apply.py index cf5b4fda2..b3af0560c 100644 --- a/lib/sqlalchemy/ext/mypy/apply.py +++ b/lib/sqlalchemy/ext/mypy/apply.py @@ -36,6 +36,7 @@ from mypy.types import UnionType from . import infer from . import util +from .names import NAMED_TYPE_SQLA_MAPPED def apply_mypy_mapped_attr( @@ -134,7 +135,7 @@ def re_apply_declarative_assignments( and isinstance(stmt.rvalue.callee.expr, NameExpr) and stmt.rvalue.callee.expr.node is not None and stmt.rvalue.callee.expr.node.fullname - == "sqlalchemy.orm.attributes.Mapped" + == NAMED_TYPE_SQLA_MAPPED and stmt.rvalue.callee.name == "_empty_constructor" and isinstance(stmt.rvalue.args[0], CallExpr) and isinstance(stmt.rvalue.args[0].callee, RefExpr) @@ -165,7 +166,7 @@ def re_apply_declarative_assignments( if python_type_for_type is not None: left_node.type = api.named_type( - "__sa_Mapped", [python_type_for_type] + NAMED_TYPE_SQLA_MAPPED, [python_type_for_type] ) if update_cls_metadata: @@ -202,12 +203,12 @@ def apply_type_to_mapped_statement( if left_hand_explicit_type is not None: left_node.type = api.named_type( - "__sa_Mapped", [left_hand_explicit_type] + NAMED_TYPE_SQLA_MAPPED, [left_hand_explicit_type] ) else: lvalue.is_inferred_def = False left_node.type = api.named_type( - "__sa_Mapped", + NAMED_TYPE_SQLA_MAPPED, [] if python_type_for_type is None else [python_type_for_type], ) diff --git a/lib/sqlalchemy/ext/mypy/decl_class.py b/lib/sqlalchemy/ext/mypy/decl_class.py index 0d7462d5b..c33c30e25 100644 --- a/lib/sqlalchemy/ext/mypy/decl_class.py +++ b/lib/sqlalchemy/ext/mypy/decl_class.py @@ -327,7 +327,7 @@ def _scan_declarative_decorator_stmt( ) left_node.node.type = api.named_type( - "__sa_Mapped", [left_hand_explicit_type] + names.NAMED_TYPE_SQLA_MAPPED, [left_hand_explicit_type] ) # this will ignore the rvalue entirely diff --git a/lib/sqlalchemy/ext/mypy/infer.py b/lib/sqlalchemy/ext/mypy/infer.py index 6d243b6ec..3cd946e04 100644 --- a/lib/sqlalchemy/ext/mypy/infer.py +++ b/lib/sqlalchemy/ext/mypy/infer.py @@ -147,7 +147,7 @@ def _infer_type_from_relationship( type_is_a_collection = True if python_type_for_type is not None: python_type_for_type = api.named_type( - "__builtins__.list", [python_type_for_type] + names.NAMED_TYPE_BUILTINS_LIST, [python_type_for_type] ) elif ( uselist_arg is None or api.parse_bool(uselist_arg) is True @@ -438,7 +438,7 @@ def _infer_type_from_left_and_inferred_right( if not is_subtype(left_hand_explicit_type, python_type_for_type): effective_type = api.named_type( - "__sa_Mapped", [orig_python_type_for_type] + names.NAMED_TYPE_SQLA_MAPPED, [orig_python_type_for_type] ) msg = ( @@ -507,7 +507,9 @@ def infer_type_from_left_hand_type_only( ) util.fail(api, msg.format(node.name), node) - return api.named_type("__sa_Mapped", [AnyType(TypeOfAny.special_form)]) + return api.named_type( + names.NAMED_TYPE_SQLA_MAPPED, [AnyType(TypeOfAny.special_form)] + ) else: # use type from the left hand side @@ -529,7 +531,7 @@ def extract_python_type_from_typeengine( return Instance(first_arg.node, []) # TODO: support other pep-435 types here else: - return api.named_type("__builtins__.str", []) + return api.named_type(names.NAMED_TYPE_BUILTINS_STR, []) assert node.has_base("sqlalchemy.sql.type_api.TypeEngine"), ( "could not extract Python type from node: %s" % node diff --git a/lib/sqlalchemy/ext/mypy/names.py b/lib/sqlalchemy/ext/mypy/names.py index 3dbfcc770..8ec15a6d4 100644 --- a/lib/sqlalchemy/ext/mypy/names.py +++ b/lib/sqlalchemy/ext/mypy/names.py @@ -47,6 +47,12 @@ AS_DECLARATIVE_BASE: int = util.symbol("AS_DECLARATIVE_BASE") # type: ignore DECLARATIVE_MIXIN: int = util.symbol("DECLARATIVE_MIXIN") # type: ignore QUERY_EXPRESSION: int = util.symbol("QUERY_EXPRESSION") # type: ignore +# names that must succeed with mypy.api.named_type +NAMED_TYPE_BUILTINS_OBJECT = "builtins.object" +NAMED_TYPE_BUILTINS_STR = "builtins.str" +NAMED_TYPE_BUILTINS_LIST = "builtins.list" +NAMED_TYPE_SQLA_MAPPED = "sqlalchemy.orm.attributes.Mapped" + _lookup: Dict[str, Tuple[int, Set[str]]] = { "Column": ( COLUMN, diff --git a/lib/sqlalchemy/ext/mypy/plugin.py b/lib/sqlalchemy/ext/mypy/plugin.py index 356b0d948..8687012a1 100644 --- a/lib/sqlalchemy/ext/mypy/plugin.py +++ b/lib/sqlalchemy/ext/mypy/plugin.py @@ -142,7 +142,7 @@ def _dynamic_class_hook(ctx: DynamicClassDefContext) -> None: ) info.bases = [Instance(cls_arg.node, [])] else: - obj = ctx.api.named_type("__builtins__.object") + obj = ctx.api.named_type(names.NAMED_TYPE_BUILTINS_OBJECT) info.bases = [obj] @@ -152,7 +152,7 @@ def _dynamic_class_hook(ctx: DynamicClassDefContext) -> None: util.fail( ctx.api, "Not able to calculate MRO for declarative base", ctx.call ) - obj = ctx.api.named_type("__builtins__.object") + obj = ctx.api.named_type(names.NAMED_TYPE_BUILTINS_OBJECT) info.bases = [obj] info.fallback_to_any = True |
