Sup*_*oot 5 python typechecking flask-sqlalchemy mypy python-typing
当尝试从作为实例属性的类继承时,就会出现问题。这个 mcve 重现了它,我将把下面问题的其余部分留给后代:
class A:
class SubA:
pass
a = A()
class B(a.SubA):
pass
Run Code Online (Sandbox Code Playgroud)
mypy输出:
Name 'a.SubA' is not defined
Run Code Online (Sandbox Code Playgroud)
这通过:
Name 'a.SubA' is not defined
Run Code Online (Sandbox Code Playgroud)
本相关问题中的示例几乎正是在命名空间Flask-SQLAlchemy下提供声明性基类的内容db。在该问题中,mypy维护者声称他们不会支持该模式。
我的问题是,上述模式有什么不正确以至于mypy不支持它?特别是在大型项目(例如Flask-SQLAlchemy.
此外,用户Flask-SQLAlchemy和mypy在项目中管理此内容的最佳方式是什么?
这个问题与缺少存根无关Flask-SQLAlchemy。接受这一点后,我遇到了这个问题。
请帮助我理解为什么以下内容不能按我的预期工作。
在我的环境中我只安装Flask-SQLAlchemy了mypy。
我已经mypy配置了ignore_missing_imports = True.
跳过mypy以下内容:
class A:
class SubA:
pass
class B(A.SubA):
pass
Run Code Online (Sandbox Code Playgroud)
揭示了:
error: Name 'db.Model' is not defined
Run Code Online (Sandbox Code Playgroud)
因此,我尝试子类化SQLAlchemy以提供 的注释Model,该注释显示在__annotations__对象上,但mypy模块的分析不会改变:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Widget(db.Model):
id = db.Column(db.Integer, primary_key=True)
Run Code Online (Sandbox Code Playgroud)
当我执行该文件时,print(db.__annotations__)命令显示{'Model': <class 'flask_sqlalchemy.model.DefaultMeta'>},但仍然mypy出现相同的错误:
error: Name 'db.Model' is not defined
Run Code Online (Sandbox Code Playgroud)
我希望提供注释应该db.Model可以使该错误消失。
我最初误解了该错误,因为它并不表明该属性Model不存在于 上db,而是表明该名称db.Model在命名空间中不存在。但为什么它会被视为db.Model全名,而不是db本地定义的名称及其Model属性呢?这与尝试从类变量继承有关吗?
另外,我的注释不正确,应该是:
error: Name 'db.Model' is not defined
Run Code Online (Sandbox Code Playgroud)
你应该使用A.SubA.
mypy据我所知,从角度来看,不允许通过实例变量访问嵌套类。因为派生类A可以覆盖嵌套类,并且 mypy 无法识别这种情况,如下所示:
class A:
class SubA:
pass
class C(A):
class SubA:
pass
def foo(a: A):
class B(a.SubA): # What SubA here ?
pass
foo(C())
Run Code Online (Sandbox Code Playgroud)
更新:
对于 Flask-SQLAlchemy,本次讨论中建议了以下解决方法:
from app import db
from sqlalchemy.ext.declarative import DeclarativeMeta
BaseModel: DeclarativeMeta = db.Model
class MyModel(BaseModel): ...
Run Code Online (Sandbox Code Playgroud)
如果您使用flask_sqlalchemy,那么您可以使用 from
flask_sqlalchemy.model import DefaultMeta而不是DeclarativeMeta。