Using context managers in a QCodes NI Daq driver (based on QDAC2 as reference) #5129
-
Hi, The QDAC2 source for the large part consists of context managers to, as I understand, enforce a clean allocation and deallocation of the dac's resources. The form it usually takes is: def sweep(self, *args, **kwargs):
return Sweep_Context(*args, **kwargs) where Sweep_Context is a class with an enter() and exit() methods. Non of the code uses a with statement and I don't understand how is clean up method ever called. I put together a mock script to illustrate: class Test_Context:
def __init__(self):
print("context init")
def __enter__(self):
print("context enter")
return self
def __exit__(self, exc_type, exc_obj, traceback):
print("context cleanup")
return False
class testClass:
def __init__(self):
print("class init")
def f(self):
return Test_Context()
t = testClass()
t.f() context cleanup and context enter are never printed out, unless I use Test_Context in a with statement. with Test_Context() as t:
pass thank you! |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments
-
hi @zibrov-zlobin ! hmm, qdac2 has quite a lot of example notebooks in the qcodes_contrib_drivers documentation, i'd be surprised if the sweep() is not shown/explained there. what about this page https://qcodes.github.io/Qcodes_contrib_drivers/examples/QDevil/QDAC2/Sweep.html and the to get back to your code snippet: the following would be euqivalent to the with test_class.f() as tce:
pass so, the true power of this contruct would come if arguments passed to class TestContext:
def __init__(self, message):
self.message = message
print("context init")
def __enter__(self):
print(f"context enter: {self.message}")
return self
def __exit__(self, exc_type, exc_obj, traceback):
print(f"context cleanup: {self.message}")
return False
class TestClass:
def __init__(self):
print("class init")
def f(self, message):
return TestContext(message)
t = TestClass()
with t.f("TestContext with a smile :)") as tc:
print(f"Test_Context is designed such that what is returned in `__enter__` is same instance, look: `t is tc` is {t is tc}") does this help? |
Beta Was this translation helpful? Give feedback.
-
@astafan8 Thank you for your response! I suppose I got a bit fixated on the 2D diode scan example, where the Sweep is run without a with statement, but I guess at the same time for the sweep context the exit() is used only to propagate errors. Could you please clarify further on how would you deal with nested contexts? arrangement = qdac.arrange(...)
sweep = arrangement.virtual_sweep2d(..) The clean way of running this example would've been nesting with statements? with qdac.arrange(...) as arrangement:
with arrangement.virtual_sweep2d(...) as sweep :
sweep.start() and if also a measurement is added, then a third with statement? thank you! |
Beta Was this translation helpful? Give feedback.
-
yes, i think that's how it would look like (i'm not a frequent used for QDAC2 though, so can't be 100% sure here). as a software dev i don't see problems with many nested contexts, i'd only suggest that the API should be good enough that typing all those contexts should be fast while keeping them readable. Also note that in python it's not necessary to nest the contexts, the with qdac.arrange(...) as arrangement, arrangement.virtual_sweep2d(...) as sweep:
sweep.start() |
Beta Was this translation helpful? Give feedback.
yes, i think that's how it would look like (i'm not a frequent used for QDAC2 though, so can't be 100% sure here). as a software dev i don't see problems with many nested contexts, i'd only suggest that the API should be good enough that typing all those contexts should be fast while keeping them readable. Also note that in python it's not necessary to nest the contexts, the
with
statement supports comma-separating the contexts like this: