I'm looking for a way performing some custom escaping whenever certain properties are set, and corresponding unescaping code when those properties are retrieved from one of my objects. I've looked at __setattr__, __getattr__ and __getattribute__ but can't see how they relate to properties.
For example I have a class such as:
class Bundle(object):
def __init__(self):
self.storage = Storage()
@property
def users_name(self):
"""
Get the user's name
"""
return self.storage.users_name
@users_name.setter
def users_name(self, users_name):
"""
Set the user's name
"""
# only permit letters and spaces.
if not re.match('^[A-Za-z ]+$', users_name):
msg = "'%s' is not a valid users_name. It must only contain letters and spaces" % users_name
log.fatal(msg)
raise ConfigurationError(msg)
self.storage.users_name = users_name
...
There are several such properties on the object.
What I want is a method that will only affect some of my properties (such as users_name, but not 'storage'), and will escape/unescape the value when set/retrieved.
- __getattr__ doesn't seem right because this code should be called for new and existing properties.
- __setattr__ might work but I don't understand how it fits in with my @property methods. For example, will __setattr__ always be called instead of my custom methods? How can I call my custom methods from within __setattr__? Is there an easy way of only affecting my @property properties without storing a list of properties to work on?
- __getattribute__ I tried using this but ended up in infinite loops. That aside, my questions are roughly the same as for __setattr__ regarding whether it's possible to delegate to the methods declared with @property (and how to do that?), and how best to say "only work for these properties and not just any property of this class.
What's the best way of approaching this?
-- update --
To elaborate: This particular 'Bundle' class acts as a proxy, storing config values in different backends - in this case a FileConfigBackend that wraps ConfigParser. ConfigParser uses '%' signs for interpolation. However, some of the values I want to set can legitimately contain percent signs so I need to escape them. However, instead of escaping them explicitly for every property, I want to have some sort of magic method that will be called every time a property is set. It will then run replace('%', '%%')
on the string. Similarly, I want a method that every time a property is retrieved will run replace('%%', '%')
on the value before returning it.
Also, since the majority of the properties in 'Bundle' are simply proxied to the backend storage, it'd be nice if there was a way to say 'if the property is in this list, just call self.storage.PROPERTY_NAME = VALUE
'. Sometimes though I want to be able to override that assignment, for example to run a regex on the value to set.
So really, I'm looking for a way of saying 'when a property is set, always call this method. Then if a concrete @property.setter exists, call that instead of doing self.storage.key = value
'.
(doh! I meant __getattr__ & __setattr__ not __get__ and __set__ - updated my question to reflect that)