The original model was using the Classic Mapping style. Refactoring the model to use the Declarative Mapping style fixed the problem. I guess hybrid properties only work when the class is using the Declarative base.
SQLAlchemy hybrid_property error when setting
-
13-10-2022 - |
Question
I'm trying to use a hybrid_property decorator to define a getter/setter. Here's the code.
class Users(object):
def __init__(self, username, uid=None, password=None, group_uid=None):
self.uid = uid
self.username = username
self.password = password
self.group_uid = group_uid
def __repr__(self):
return "User(%(username)s)" % self.__dict__
@hybrid_property
def password(self):
return self._password
@password.setter
def set_password(self, password):
self._password = password
When looking at a user object, the getter works properly, ie user.password returns a string, but calling the setter yields the following
user.test('test')
Traceback (most recent call last):
File "--removed--", line 35, in exec_expr
exec code in self.namespace, self.globs
File "<web>", line 1, in <module>
TypeError: 'str' object is not callable
Any help pointing out what I'm missing would be greatly appreciated.
PS. Using SQLAlchemy version 0.9.1
Solution 2
OTHER TIPS
I haven't looked deeply enough in to the SQLAlchemy code to say definitively that this is the problem, but my bet is that you are using properties incorrectly. set_password
should just be called password
. I bet it will fix your problem, but even if it doesn't, you still need to do it that way. See this example.
You'll see a related error using the builtin @property
decorator. Remember, a decorator is just shorthand for assigning the result of a function that takes and returns a callable to the label of the decorated function in the local namespace. What you are doing here is creating 1 callable and assigning it to password
, then creating a new callable that wraps the password
callable and assigning it to set_password
. You mention in a comment that it works in an older version of SQLAlchemy. My bet is that they switched from modifying the wrapped callable object when using my_var.setter
to returning a new instance. If you were to use set_password
, it would most likely work as you expect password
to work.
The reason that this did not work is (I suspect) because you were testing the property as if it was a method. From your test code: user.test()
(I assume that in some version of your code password
was called test
.
If you do user.password('changeme')
then it will not work because user.password is not a method. Instead it should be: user.password = 'changeme'
I think it is likely that switching to the Declarative Base was just a coincidence.
I just want to put it here for anyone who might be interested... I also got this issue when trying to create a password in Airflow. It seems like a compatibility issue of the sqlalchemy version in Airflow. I installed this and it solved the issue: pip install 'sqlalchemy<1.2'