On Tue, Jun 20, 2017 at 10:18 AM, Steven D'Aprano <st...@pearwood.info> wrote:
> Apparently you heavily use properties, and __getattr__, and find that
> the two don't interact well together when the property getters and
> setters themselves raise AttributeError. I think that's relevant
> information that helps explain the problem you are hoping to fix.
>
> So I *think* this demonstrates the problem:
>
> class A(object):
>     eggs = "text"
>     def __getattr__(self, name):
>         if name == 'cheese':
>             return "cheddar"
>         raise AttributeError('%s missing' % name)
>     @property
>     def spam(self):
>         return self.eggs.uper() # Oops.

I'm quoting Steven's post, but I'm addressing the OP.


One good solution to this is a "guard point" around your property functions.

def noleak(*exc):
    def deco(func):
        @functools.wraps(func)
        def wrapper(*a, **kw):
            try: return func(*a, **kw)
            except exc: raise RuntimeError
        return wrapper
    return deco

@property
@noleak(AttributeError)
def spam(self):
    return self.eggs.uper()

In fact, you could make this into a self-wrapping system if you like:

def property(func, *, _=property):
    return _(noleak(AttributeError)(func))

Now, all your @property functions will be guarded: any AttributeErrors
they raise will actually bubble as RuntimeErrors instead.

Making this work with setters and deleters is left as an exercise for
the reader.

ChrisA
_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to