markhern
markhern

Reputation: 43

Receiving AttributeError: __exit__ even when WITH object has EXIT defined

I'm receiving an error of AttributeError: __exit__ in the code below after finishing the with section. The Element object has is being returned in the with and it has __exit__ defined, so I'm baffled.

class Builder:
    def __init__(self):
        print("Builder init fires")

    def __getattr__(self, name):
        return Element(name, self)

class Element:
    def __init__(self, name, builder):
        self.name = name
        self.builder = builder
        print("Element init fires for name of", self.name)
    def __call__(*args, **kargs):
        print("CALL fires, now with attributes listed:")
        for attr, value in sorted(kargs.items()):
            print(' %s=>%s' % (attr, value))

    def __enter__(self):  
        return self

    def __exit__(self, type, value, traceback): 
        pass

aa = Builder()        
with aa.feed(xmlns='http://www.w3.org/2005/Atom'):
    print("INSIDE THE WITH")

Upvotes: 3

Views: 4067

Answers (1)

hynekcer
hynekcer

Reputation: 15548

The value of expression after with keyword must be a valid context manager. That means the value of the expresion must have attributes __enter__ and __exit__ and these must accept parameters described in docs With Statement Context Managers. You can easily verify that the part aa.feed would be acceptable, but the value of whole expression is None and it has no necessary attribute. A difference between Python 3.5 and 3.6 is that one fails on missing __exit__ and the latter on missing __enter__. Nothing unexpected.

You also forgot self in the line def __call__(self, *args, **kargs): that would be a problem if you will use args and it is a pythonic pattern also with unused args.

Upvotes: 1

Related Questions