--- /dev/null
+.. change::
+ :tags: bug, mypy
+ :tickets: 7496
+
+ 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.
+
from . import infer
from . import util
+from .names import NAMED_TYPE_SQLA_MAPPED
def apply_mypy_mapped_attr(
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)
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:
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],
)
)
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
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
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 = (
)
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
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
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,
)
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]
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