summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
authormike bayer <mike_mp@zzzcomputing.com>2021-11-18 16:13:16 +0000
committerGerrit Code Review <gerrit@ci3.zzzcomputing.com>2021-11-18 16:13:16 +0000
commitd6199ae445ed0c21716b58f8f9f4f96ef9ee34a6 (patch)
treeaba6eb2255683cd532e4fd7b680cb337d4660f88 /lib/sqlalchemy
parentc0b0bf8ab81ac966a8c5a428a45cddbafaaf6e18 (diff)
parent836902bc8438a800d2c9cf1452da31d3ca967f3b (diff)
downloadsqlalchemy-d6199ae445ed0c21716b58f8f9f4f96ef9ee34a6.tar.gz
Merge "handle dunder names in @declared_attr separately" into main
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/ext/mypy/decl_class.py15
-rw-r--r--lib/sqlalchemy/ext/mypy/util.py5
2 files changed, 19 insertions, 1 deletions
diff --git a/lib/sqlalchemy/ext/mypy/decl_class.py b/lib/sqlalchemy/ext/mypy/decl_class.py
index b85ec0f69..0d7462d5b 100644
--- a/lib/sqlalchemy/ext/mypy/decl_class.py
+++ b/lib/sqlalchemy/ext/mypy/decl_class.py
@@ -241,7 +241,20 @@ def _scan_declarative_decorator_stmt(
left_hand_explicit_type: Optional[ProperType] = None
- if isinstance(stmt.func.type, CallableType):
+ if util.name_is_dunder(stmt.name):
+ # for dunder names like __table_args__, __tablename__,
+ # __mapper_args__ etc., rewrite these as simple assignment
+ # statements; otherwise mypy doesn't like if the decorated
+ # function has an annotation like ``cls: Type[Foo]`` because
+ # it isn't @classmethod
+ any_ = AnyType(TypeOfAny.special_form)
+ left_node = NameExpr(stmt.var.name)
+ left_node.node = stmt.var
+ new_stmt = AssignmentStmt([left_node], TempNode(any_))
+ new_stmt.type = left_node.node.type
+ cls.defs.body[dec_index] = new_stmt
+ return
+ elif isinstance(stmt.func.type, CallableType):
func_type = stmt.func.type.ret_type
if isinstance(func_type, UnboundType):
type_id = names.type_id_for_unbound_type(func_type, cls, api)
diff --git a/lib/sqlalchemy/ext/mypy/util.py b/lib/sqlalchemy/ext/mypy/util.py
index a3825f175..4d55cb728 100644
--- a/lib/sqlalchemy/ext/mypy/util.py
+++ b/lib/sqlalchemy/ext/mypy/util.py
@@ -1,3 +1,4 @@
+import re
from typing import Any
from typing import Iterable
from typing import Iterator
@@ -82,6 +83,10 @@ class SQLAlchemyAttribute:
return cls(typ=typ, info=info, **data)
+def name_is_dunder(name):
+ return bool(re.match(r"^__.+?__$", name))
+
+
def _set_info_metadata(info: TypeInfo, key: str, data: Any) -> None:
info.metadata.setdefault("sqlalchemy", {})[key] = data