diff --git a/src/revpimodio2/io.py b/src/revpimodio2/io.py index b77e78d..f12467f 100644 --- a/src/revpimodio2/io.py +++ b/src/revpimodio2/io.py @@ -99,9 +99,11 @@ class IOList(object): When 'autorefresh=True' is used, all read or write actions in the background are performed automatically. """ - if self.__modio._looprunning: - raise RuntimeError("can not start multiple mainloop/cycleloop/with sessions") - self.__modio._looprunning = True + if not self.__modio._context_manager: + # If ModIO itself is in a context manager, it sets the _looprunning=True flag itself + if self.__modio._looprunning: + raise RuntimeError("can not enter context manager inside mainloop or cycleloop") + self.__modio._looprunning = True self.__modio.readprocimg() return self @@ -114,7 +116,9 @@ class IOList(object): outputs are automatically written in the background. """ self.__modio.writeprocimg() - self.__modio._looprunning = False + if self.__modio._context_manager: + # Do not reset if ModIO is in a context manager itself, it will handle that flag + self.__modio._looprunning = False def __getattr__(self, key): """ diff --git a/src/revpimodio2/modio.py b/src/revpimodio2/modio.py index 38bceb1..ff37f3a 100644 --- a/src/revpimodio2/modio.py +++ b/src/revpimodio2/modio.py @@ -70,6 +70,7 @@ class RevPiModIO(object): "_autorefresh", "_buffedwrite", "_configrsc", + "_context_manager", "_debug", "_devselect", "_exit", @@ -146,6 +147,7 @@ class RevPiModIO(object): self._autorefresh = autorefresh self._configrsc = configrsc + self._context_manager = False self._monitoring = monitoring self._procimg = "/dev/piControl0" if procimg is None else procimg self._set_device_based_cycle_time = True @@ -205,6 +207,22 @@ class RevPiModIO(object): if self._myfh is not None: self._myfh.close() + def __enter__(self): + if self._context_manager: + raise RuntimeError("can not use multiple context managers of same instance") + if self._looprunning: + raise RuntimeError("can not enter context manager with running mainloop or cycleloop") + self._context_manager = True + self._looprunning = True + + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.writeprocimg() + self.exit(full=True) + self._looprunning = False + self._context_manager = False + def __evt_exit(self, signum, sigframe) -> None: """ Eventhandler fuer Programmende. @@ -805,6 +823,9 @@ class RevPiModIO(object): :param blocking: Wenn False, blockiert das Programm hier NICHT :return: None or the return value of the cycle function """ + # Check for context manager + if self._context_manager: + raise RuntimeError("Can not start cycleloop inside a context manager (with statement)") # Prüfen ob ein Loop bereits läuft if self._looprunning: raise RuntimeError("can not start multiple loops mainloop/cycleloop") @@ -1060,6 +1081,9 @@ class RevPiModIO(object): :param blocking: Wenn False, blockiert das Programm hier NICHT """ + # Check for context manager + if self._context_manager: + raise RuntimeError("Can not start mainloop inside a context manager (with statement)") # Prüfen ob ein Loop bereits läuft if self._looprunning: raise RuntimeError("can not start multiple loops mainloop/cycleloop")