Open bochecha opened 5 years ago
@bochecha @ilevkivskyi I'd like this feature too, and would like to help implement if I get some extra cycles soon! I think this is achievable through use of generics or a plugin, but not through simple stubs. Do we have a preference for how to implement this?
@ckarnell Yes, this would require some updates to the plugin. You can try submitting a PR.
Any updates on this feature request?
Is there at least a workaround to suppress these errors other than # type: ignore
for every single line?
You can specify exception in .mypy
configuration for this module or a file wide type ignore rather than line based
I also tried the following manual typing with runtime overload successfully
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.declarative.api import declared_attr
from sqlalchemy.schema import Column, ForeignKey
Base = declarative_base()
class TypedBaseModel:
"""typed base for mypy purposed"""
external_id: Column[str]
class BaseModel(TypedBaseModel):
"""
base Model
In order to defined common foreign key we need to declare it in a mixin class
"""
@declared_attr
def external_id(self):
return Column(String(512), nullable=False)
class Account(Base, BaseModel)
__tablename__ = "accounts"
name = Column(String(512), nullable=False)
You can built heritage with another layer of base class:
declared_attr
)declared_attr
I did three levels like this
@aydumoulin not sure how your example was supposed to work, if you try to set the @declared_attr property you get an error.
class Account(Base, BaseModel):
__tablename__ = "accounts"
name = Column(String(512), nullable=False)
def __init__(self):
self.external_id = "test"
~~~~~~~~~~~
Cannot assign member "external_id" for type "Account"
Property "external_id" has no defined setter - Pylance(reportGeneralTypeIssues)
EDIT: My apologies, this is using pyright with no plugin, not mypy with the plugin. That's probably the difference!
@wbobeirne thanks for trying it out and your feedback
As a sidenote In editor Pylance type checking sometimes produces errors due to lack of mypy plugin support. Is mypy producing the same errors when ran on this file?
This is an expunged version of the solution I use in our codebase. The following code runs in production and passes mypy and pylance.
from typing import TYPE_CHECKING, cast
from uuid import UUID
from sqlalchemy import Column
if TYPE_CHECKING:
CStr = Column[str]
CUUID = Column[UUID]
else:
CStr = str
CUUID = UUID
class _TypedBase:
"""typed base for mypy purposed"""
external_id: CStr
revision_id: CUUID
class _BaseModel(_TypedBase):
"""
In order to defined common foreign key we need to declare it in a mixin class
-> Columns with foreign keys to other columns must be declared as @declared_attr callables on declarative mixin classes.
"""
@declared_attr
def external_id(self):
return Column(String(512), nullable=False)
@declared_attr
def revision_id(self):
return cast(CUUID, Column(UUID, ForeignKey("revisions.id", ondelete="CASCADE"))
class User(Model, _BaseModel):
"""user"""
__tablename__ = "users"
email = Column(String, nullable=False)
first_name = Column(String(254), nullable=False)
last_name = Column(String(254), nullable=False)
deleted_at = Column(DateTime, nullable=True)
def __init__(self):
self.external_id = "test"
See the hover tooltip
I'm using SQLAlchemy's
declared_attr
decorator to add columns and relationships.However, the decorated columns and relationships are completely ignored.
Here is a very simplified reproducer:
This is what mypy says: