sqlalchemy2-stubs icon indicating copy to clipboard operation
sqlalchemy2-stubs copied to clipboard

hybrid_property: Name "my_property" already defined

Open kasium opened this issue 3 years ago • 5 comments

Describe the bug Using hybrid_property leads to several errors

  • redefinition of methods
  • incompatible assignment types

Expected behavior No errors are returned

To Reproduce

from sqlalchemy import Column, Date, Time
from sqlalchemy.ext.hybrid import hybrid_property
from datetime import datetime

class DummyTable:
    create_date = Column("create_date", Date)
    create_time = Column("create_time", Time)

    @hybrid_property
    def create_timestamp(self) -> datetime:
        """create time property"""
        return datetime.combine(self.create_date, self.create_time)

    @create_timestamp.setter
    def create_timestamp(self, value:datetime) -> None:
        """create time setter"""
        self.create_date = value.date()
        self.create_time = value.time()


DummyTable().create_timestamp = datetime.now()

Error

src/x.py:14:6: error: Name "create_timestamp" already defined on line 9  [no-redef]
        @create_timestamp.setter
         ^
src/x.py:21:1: error: Cannot assign to a method  [assignment]
    DummyTable().create_timestamp = datetime.now()
    ^
src/x.py:21:33: error: Incompatible types in assignment (expression has type "datetime", variable has type "Callable[..., Any]")  [assignment]
    DummyTable().create_timestamp = datetime.now()

Versions.

  • OS: Linux
  • Python: 3.7.1
  • SQLAlchemy: 1.4.22
  • mypy: 0.910
  • SQLAlchemy2-stubs: 0.0.2a6

kasium avatar Jul 29 '21 08:07 kasium

Hi,

This is working as expected if you correctly map DummyTable. Sadly to get rid of Cannot assign to a method [assignment] you need to change name of the setter function.

from sqlalchemy import Column, Date, Time
from sqlalchemy.ext.hybrid import hybrid_property
from datetime import datetime
from sqlalchemy.orm import declarative_base
Base = declarative_base()

class DummyTable(Base):
    create_date = Column("create_date", Date)
    create_time = Column("create_time", Time)

    @hybrid_property
    def create_timestamp(self) -> datetime:
        """create time property"""
        return datetime.combine(self.create_date, self.create_time)

    @create_timestamp.setter
    def _(self, value: datetime) -> None:
        """create time setter"""
        self.create_date = value.date()
        self.create_time = value.time()


DummyTable().create_timestamp = datetime.now()

CaselIT avatar Jul 30 '21 20:07 CaselIT

Thanks a lot!

kasium avatar Aug 02 '21 06:08 kasium

So, I just tried to rename the functions, but this doesn't work. It seems like that the function names must be same resulting in mypy issues: https://docs.sqlalchemy.org/en/14/orm/extensions/hybrid.html#defining-expression-behavior-distinct-from-attribute-behavior

kasium avatar Aug 02 '21 08:08 kasium

I've only checked if it fixed mypy error, I had not tried sqlalchemy.

I'm not sure if we can tell mypy to be happy about the name of the functions

CaselIT avatar Aug 02 '21 08:08 CaselIT

Also, if I just ignore the duplicate names (# type:ignore[no-redef]), then mypy still complains about overloaded functions. I guess, mypy can't figure out which function to use in which case. Mabye the easiest way is, to allow SQLAlchemy to use any function name

kasium avatar Aug 02 '21 08:08 kasium