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

Was it helpful?

Solution 2

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.

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'

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top