I wrote a simple context manager in Python for handling unit tests (and to try to learn context managers):
class TestContext(object): test_count=1 def __init__(self): self.test_number = TestContext.test_count TestContext.test_count += 1 def __enter__(self): pass def __exit__(self, exc_type, exc_value, exc_traceback): if exc_value == None: print 'Test %d passed' %self.test_number else: print 'Test %d failed: %s' %(self.test_number, exc_value) return True
If I write a test as follows, everything works okay.
test = TestContext() with test: print 'running test %d....' %test.test_number raise Exception('this test failed')
However, if I try to use with...as, I don't get a reference to the TestContext() object. Running this:
with TestContext() as t: print t.test_number
Raises the exception 'NoneType' object has no attribute 'test_number'
.
Where am I going wrong?
__enter__() is provided which returns self while object. __exit__() is an abstract method which by default returns None . See also the definition of Context Manager Types. New in version 3.6.
You can also create custom function-based context managers using the contextlib. contextmanager decorator from the standard library and an appropriately coded generator function.
In Python, the with statement replaces a try-catch block with a concise shorthand. More importantly, it ensures closing resources right after processing them. A common example of using the with statement is reading or writing to a file. A function or class that supports the with statement is known as a context manager.
Assuming that you need to access the context manager created in the with
statement, __enter__
needs to return self
. If you don't need to access it, __enter__
can return whatever you would like.
The with statement will bind this method’s return value to the target(s) specified in the as clause of the statement, if any.
This will work.
class TestContext(object): test_count=1 def __init__(self): self.test_number = TestContext.test_count TestContext.test_count += 1 def __enter__(self): return self def __exit__(self, exc_type, exc_value, exc_traceback): if exc_value == None: print 'Test %d passed' % self.test_number else: print 'Test %d failed: %s' % (self.test_number, exc_value) return True
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With