-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
"Already defined" + "not defined" errors with SQLAlchemy 1.2 hybrid_property #4430
Comments
Can you include the content of test.py? |
Oh sorry, it's just exactly the same as that example code (only the first class def):
I had the wrong line numbers on the error above (edited now), the error is on line 11, |
I guess this is because mypy doesn't understand that Also possibly you may have to take this up with https://github.com/JelleZijlstra/sqlalchemy-stubs. |
Since there are no stubs for More generally, |
Guido suggested in #220 that someone could try to build hybrid property support on top of mypy's descriptor support. I was able to get this going by defining a typed_hybrid_property generic class (in a pyi file), parameterized by python type and sql type. I had to define my hybrid properties as separate functions with different names (like I have so far been unable to convince mypy to type-check the multipart definition (using It would be super-nice if mypy provided a way to "get the @Property behavior" for additional decorators not named in the mypy source. |
@lincolnq This is something that probably can be done by a plugin. We currently have a plugin hook for classes decorated with a given decorator. We can probably just add a similar hook for functions. Btw, we are currently working on SQLAlchemy stubs (and soon mypy plugins) at https://github.com/dropbox/sqlalchemy-stubs |
@ilevkivskyi Do you have an idea of how a plugin could be used to silence these errors mentioned above if you use a
It sounds like the support for |
I was running into the same problem with two hybrid fields. Original: class Channel(db.Model):
__tablename__ = 'Channel'
id = db.Column('id', db.Integer, nullable=False, primary_key=True)
names = db.relationship(
ChannelName,
primaryjoin=ChannelName.channel_id == id,
backref='channel',
order_by="desc(ChannelName.default)"
)
@hybrid_property
def name(self) -> Optional[ChannelName]:
return self.names[0] if len(self.names) else None
@name.expression
def name(cls):
return select([ChannelName.name]) \
.where(ChannelName.channel_id == cls.id) \
.limit(1) \
.label('name')
@hybrid_property
def aliases(self) -> List[ChannelName]:
return self.names[1:]
@aliases.expression
def aliases(cls):
return select([ChannelName.name]) \
.where(ChannelName.channel_id == cls.id) \
.offset(1) \
.label('aliases')
def on_change(channel: Channel):
if channel.name:
channel.name.default = True
for alias in model.aliases:
alias.default = False Error;
Modified to: class Channel(db.Model):
__tablename__ = 'Channel'
id = db.Column('id', db.Integer, nullable=False, primary_key=True)
names = db.relationship(
ChannelName,
primaryjoin=ChannelName.channel_id == id,
backref='channel',
order_by="desc(ChannelName.default)"
)
@hybrid_property # type: ignore
def name(self) -> Optional[ChannelName]:
return self.names[0] if len(self.names) else None
@hybrid_property # type: ignore
def aliases(self) -> List[ChannelName]:
return self.names[1:]
@name.expression # type: ignore
def name(cls):
return select([ChannelName.name]) \
.where(ChannelName.channel_id == cls.id) \
.limit(1) \
.label('name')
@aliases.expression # type: ignore
def aliases(cls):
return select([ChannelName.name]) \
.where(ChannelName.channel_id == cls.id) \
.offset(1) \
.label('aliases')
def on_change(channel: Channel):
if channel.name:
channel.name.default = True
for alias in model.aliases:
alias.default = False Result:
|
Proper fix pending in python/mypy#4430
Another solution that I found and that doesn't require using from sqlalchemy import Base, Column, String
if TYPE_CHECKING:
# This makes hybrid_property's have the same typing as normal property until stubs are improved.
hybrid_property = property
else:
from sqlalchemy.ext.hybrid import hybrid_property
class FirstNameOnly(Base):
first_name = Column(String)
@hybrid_property
def name(self):
return self.first_name
@name.setter
def name(self, value):
self.first_name = value |
@ennnas I'm getting error: Name "TYPE_CHECKING" is not defined back. How do you get this variable? |
|
Thank you! :) |
It seems that sqlalchemy is deprecating their mypy plugin. Unfortunately, that means it is unlikely for this issue to be solvable in a neat way. That being said, another plugin could eventual implement either #7468 or #6760, to fix this. That being said, I don't think this issue is actionable beyond the above plugin issues, so I am going to close it. |
SQLAlchemy 1.2 was recently released, and changed its behavior of
hybrid_property
a bit to line up with how Python's@property
works. Specifically, it's now necessary to use the same method name for both the getter and setter, as seen in the example here (both aredef name(...)
): http://docs.sqlalchemy.org/en/latest/changelog/migration_12.html#hybrid-attributes-support-reuse-among-subclasses-redefinition-of-getterThis is causing mypy to error though, it now emits two (contradictory?) errors on the
@name.setter
line:The text was updated successfully, but these errors were encountered: