pythonclasserror-handlingpython-requestscontextmanager

How to use a context manager to create an instance of a class?


I want to create a class that makes use of requests.Session(). Because of this, I want to use a context manager. However, when I try to access any of the functions or variables of the class, the context manager replies:

exception type:  <class 'AttributeError'>
exception value:  type object 'NoneType' has no attribute 'user'
exception trace:  <traceback object at 0x0000024CFAF30340>

My code:

Class request_session:
    def __init__(self, user="rwelch"):
        self.user = user
        self.session = (
            requests.Session()
        ) 

    def __enter__(self):
        print("Creating a new connection...")

    def __exit__(self, exception_type, exception_val, trace):
        print("Closing connection...")
        if exception_type:
            print(
                "exception type: ",
                exception_type,
                "\nexception value: ",
                exception_val,
                "\nexception trace: ",
                trace,
            )
            response = True
        else:
            response = False
        self.session.close()
        return response

...

with request_session() as request_session_handler:
   print(request_session_handler.user)

This type of implementation I got from examples using exclusively file management, so I'm sure there's something fundamental I'm missing here.

Thanks in advance


Solution

  • you should return the value of the session handler, otherwise it'll return None implicitly, leading to the error you see

    >>> def test():
    ...     """ implicitly returns None """
    ...     pass  # does nothing
    ... 
    >>> test().user
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'NoneType' object has no attribute 'user'
    

    alternatively, you can often avoid creating a custom context manager and decorate a function with @contextlib.contextmanager and yield from it

    class Foo:
        def __enter__(self):
            self.managed_resource = bar()
            return self.managed_resource
        def __exit__(self):
            self.managed_resource.close()
    
    @contextlib.contextmanager
    def my_contextmgr():
        resource = bar()
        try:
            yield resource
        finally:
            resource.close()