def execute(self): """See base_runner.execute().""" import multiprocessing from libqtopensesame.misc import process, _ from libopensesame import misc, debug from StringIO import StringIO if os.name == u'nt': # Under Windows, the multiprocess runner assumes that there is a # file called `opensesame.py` or `opensesame.pyc`. If this file does # not exist, try to copy it from the main script (`opensesame`). If # this fails, provide an informative error message. os_folder = misc.opensesame_folder() if not os.path.exists(os.path.join(os_folder, u'opensesame.pyc')) \ and not os.path.exists(os.path.join(os_folder, u'opensesame.py')): import shutil try: shutil.copyfile(os.path.join(os_folder, u'opensesame'), \ os.path.join(os_folder, u'opensesame.py')) except Exception as e: return osexception( \ _(u'Failed to copy `opensesame` to `opensesame.py`, which is required for the multiprocess runner. Please copy the file manually, or select a different runner under Preferences.'), exception=e) self.channel = multiprocessing.Queue() self.exp_process = process.ExperimentProcess(self.experiment, \ self.channel) # Start process! self.exp_process.start() # Variables used for ugly hack to suppress 'None' print by Queue.get() _stdout = sys.stdout _pit = StringIO() # Wait for experiment to finish. # Listen for incoming messages in the meantime. while self.exp_process.is_alive() or not self.channel.empty(): QtGui.QApplication.processEvents() # Make sure None is not printed. Ugly hack for a bug in the Queue # class? sys.stdout = _pit # Wait for messages. Will throw Exception if no message is received # before timeout. try: msg = self.channel.get(True, 0.05) except: msg = None # Restore connection to stdout sys.stdout = _stdout # For standard print statements if isinstance(msg, basestring): sys.stdout.write(msg) # Errors arrive as a tuple with (Error object, traceback) elif isinstance(msg, Exception): return msg # Anything that is not a string, not an Exception, and not None is # unexpected elif msg != None: return osexception( \ u"Illegal message type received from child process: %s (%s)" \ % (msg, type(msg))) # Return None if experiment finished without problems return None
def run(self): """ Everything in this function is run in a new process, therefore all import statements are put in here. The function reroutes all output to stdin and stderr to the pipe to the main process so OpenSesame can handle all prints and errors. """ import os import sys from libopensesame import misc from libopensesame.experiment import experiment from libopensesame.exceptions import osexception # Under Windows, change the working directory to the OpenSesame folder, # so that the new process can find the main script. if os.name == u'nt': os.chdir(misc.opensesame_folder()) # Reroute output to OpenSesame main process, so everything will be # printed in the Debug window there. pipeToMainProcess = OutputChannel(self.output) sys.stdout = pipeToMainProcess sys.stderr = pipeToMainProcess # First initialize the experiment and catch any resulting Exceptions try: exp = experiment(string=self.script, pool_folder= self.pool_folder, experiment_path=self.experiment_path, fullscreen=self.fullscreen, auto_response=self.auto_response, subject_nr=self.subject_nr, logfile=self.logfile) except Exception as e: if not isinstance(e, osexception): e = osexception(u'Unexpected error', exception=e) # Communicate the exception and exit with error self.output.put(e) sys.exit(1) print(u'Starting experiment as %s' % self.name) # Run the experiment and catch any Exceptions. e_run = None exp.set_output_channel(self.output) try: exp.run() print('done!') except Exception as e_run: if not isinstance(e_run, osexception): e_run = osexception(u'Unexpected error', exception=e_run) exp.transmit_workspace() # End the experiment and catch any Exceptions. These exceptions are just # printed out and not explicitly passed on to the user, because they are # less important than the run-related exceptions. try: exp.end() except Exception as e_exp: print(u'An Exception occurred during exp.end(): %s' % e_exp) # Communicate the exception and exit with error if e_run is not None: self.output.put(e_run) sys.exit(1) # Exit with success sys.exit(0)
def run(self): """ Everything in this function is run in a new process, therefore all import statements are put in here. The function reroutes all output to stdin and stderr to the pipe to the main process so OpenSesame can handle all prints and errors. """ import os import sys from libopensesame import misc from libopensesame.experiment import experiment from libopensesame.exceptions import osexception # Under Windows, change the working directory to the OpenSesame folder, # so that the new process can find the main script. if os.name == u'nt': os.chdir(misc.opensesame_folder()) # Reroute output to OpenSesame main process, so everything will be # printed in the Debug window there. pipeToMainProcess = OutputChannel(self.output) sys.stdout = pipeToMainProcess sys.stderr = pipeToMainProcess # First initialize the experiment and catch any resulting Exceptions try: exp = experiment(string=self.script, pool_folder= \ self.pool_folder, experiment_path=self.experiment_path, \ fullscreen=self.fullscreen, auto_response=self.auto_response, \ subject_nr=self.subject_nr, logfile=self.logfile) except Exception as e: if not isinstance(e, osexception): e = osexception(u'Unexpected error', exception=e) # Communicate the exception and exit with error self.output.put(e) sys.exit(1) print(u'Starting experiment as %s' % self.name) # Run the experiment and catch any Exceptions. e_run = None try: exp.run() except Exception as e_run: if not isinstance(e_run, osexception): e_run = osexception(u'Unexpected error', exception=e_run) # End the experiment and catch any Exceptions. These exceptions are just # printed out and not explicitly passed on to the user, because they are # less important than the run-related exceptions. try: exp.end() except Exception as e_exp: print(u'An Exception occurred during exp.end(): %s' % e_exp) # Communicate the exception and exit with error if e_run != None: self.output.put(e_run) sys.exit(1) # Exit with success sys.exit(0)
def execute(self): """See base_runner.execute().""" import platform # In OS X the multiprocessing module is horribly broken, but a fixed # version has been released as the 'billiard' module if platform.system() == 'Darwin': import billiard as multiprocessing multiprocessing.forking_enable(0) else: import multiprocessing from libqtopensesame.misc import process, _ from libopensesame import misc self._workspace_globals = {} if os.name == u'nt' or (sys.platform == u'darwin' \ and not hasattr(sys,"frozen")): # Under Windows and OSX, the multiprocess runner assumes that there # is a file called `opensesame.py` or `opensesame.pyc`. If this file # does not exist, try to copy it from the main script # (`opensesame`). If this fails, provide an informative error # message. os_folder = misc.opensesame_folder() # misc.opensesame_folder() doesn't work for OSX and returns None then, # so determine OpenSesame's rootdir in another way if os_folder is None: os_folder = os.path.dirname( os.path.abspath(sys.modules['__main__'].__file__)) if not os.path.exists(os.path.join(os_folder, u'opensesame.pyc')) \ and not os.path.exists(os.path.join(os_folder, u'opensesame.py')): import shutil try: shutil.copyfile(os.path.join(os_folder, u'opensesame'), os.path.join(os_folder, u'opensesame.py')) except Exception as e: return osexception(_( u'Failed to copy `opensesame` to `opensesame.py`, which is required for the multiprocess runner. Please copy the file manually, or select a different runner under Preferences.' ), exception=e) self.channel = multiprocessing.Queue() try: self.exp_process = process.ExperimentProcess( self.experiment, self.channel) except Exception as e: return osexception(_(u'Failed to initialize experiment process'), exception=e) # Start process! self.exp_process.start() # Wait for experiment to finish. # Listen for incoming messages in the meantime. while self.exp_process.is_alive() or not self.channel.empty(): # We need to process the GUI. To make the GUI feel more responsive # during pauses, we refresh the GUI more often when paused. QtGui.QApplication.processEvents() if self.paused: for i in range(25): time.sleep(.01) QtGui.QApplication.processEvents() # Make sure None is not printed. Ugly hack for a bug in the Queue # class? self.console.suppress_stdout() # Wait for messages. Will throw Exception if no message is received # before timeout. try: msg = self.channel.get(True, 0.05) except: continue # Restore connection to stdout self.console.capture_stdout() if isinstance(msg, basestring): sys.stdout.write(safe_decode(msg, errors=u'ignore')) continue # Capture exceptions if isinstance(msg, Exception): return msg # The workspace globals are sent as a dict. A special __pause__ key # indicates whether the experiment should be paused or resumed. if isinstance(msg, dict): self._workspace_globals = msg if u'__heartbeat__' in msg: self.console.set_workspace_globals(msg) self.main_window.extension_manager.fire(u'heartbeat') elif u'__pause__' in msg: if msg[u'__pause__']: self.pause() else: self.resume() continue # Anything that is not a string, not an Exception, and not None is # unexpected return osexception( u"Illegal message type received from child process: %s (%s)" \ % (msg, type(msg))) # Return None if experiment finished without problems return None
def execute(self): """See base_runner.execute().""" import multiprocessing from libqtopensesame.misc import process, _ from libopensesame import misc, debug from StringIO import StringIO if os.name == u"nt": # Under Windows, the multiprocess runner assumes that there is a # file called `opensesame.py` or `opensesame.pyc`. If this file does # not exist, try to copy it from the main script (`opensesame`). If # this fails, provide an informative error message. os_folder = misc.opensesame_folder() if not os.path.exists(os.path.join(os_folder, u"opensesame.pyc")) and not os.path.exists( os.path.join(os_folder, u"opensesame.py") ): import shutil try: shutil.copyfile(os.path.join(os_folder, u"opensesame"), os.path.join(os_folder, u"opensesame.py")) except Exception as e: return osexception( _( u"Failed to copy `opensesame` to `opensesame.py`, which is required for the multiprocess runner. Please copy the file manually, or select a different runner under Preferences." ), exception=e, ) self.channel = multiprocessing.Queue() self.exp_process = process.ExperimentProcess(self.experiment, self.channel) # Start process! self.exp_process.start() # Variables used for ugly hack to suppress 'None' print by Queue.get() _stdout = sys.stdout _pit = StringIO() # Wait for experiment to finish. # Listen for incoming messages in the meantime. while self.exp_process.is_alive() or not self.channel.empty(): QtGui.QApplication.processEvents() # Make sure None is not printed. Ugly hack for a bug in the Queue # class? sys.stdout = _pit # Wait for messages. Will throw Exception if no message is received # before timeout. try: msg = self.channel.get(True, 0.05) except: msg = None # Restore connection to stdout sys.stdout = _stdout # For standard print statements if isinstance(msg, basestring): sys.stdout.write(msg) # Errors arrive as a tuple with (Error object, traceback) elif isinstance(msg, Exception): return msg # Anything that is not a string, not an Exception, and not None is # unexpected elif msg != None: return osexception(u"Illegal message type received from child process: %s (%s)" % (msg, type(msg))) # Return None if experiment finished without problems return None
def execute(self): """See base_runner.execute().""" import platform # In OS X the multiprocessing module is horribly broken, but a fixed # version has been released as the 'billiard' module if platform.system() == 'Darwin': import billiard as multiprocessing multiprocessing.forking_enable(0) else: import multiprocessing from libqtopensesame.misc import process, _ from libopensesame import misc, debug from StringIO import StringIO if os.name == u'nt' or (sys.platform == u'darwin' and not hasattr(sys,"frozen")): # Under Windows and OSX, the multiprocess runner assumes that there is a # file called `opensesame.py` or `opensesame.pyc`. If this file does # not exist, try to copy it from the main script (`opensesame`). If # this fails, provide an informative error message. os_folder = misc.opensesame_folder() # misc.opensesame_folder() doesn't work for OSX and returns None then, # so determine OpenSesame's rootdir in another way if os_folder is None: os_folder = os.path.dirname(os.path.abspath(sys.modules['__main__'].__file__)) if not os.path.exists(os.path.join(os_folder, u'opensesame.pyc')) \ and not os.path.exists(os.path.join(os_folder, u'opensesame.py')): import shutil try: shutil.copyfile(os.path.join(os_folder, u'opensesame'), \ os.path.join(os_folder, u'opensesame.py')) except Exception as e: return osexception( \ _(u'Failed to copy `opensesame` to `opensesame.py`, which is required for the multiprocess runner. Please copy the file manually, or select a different runner under Preferences.'), exception=e) self.channel = multiprocessing.Queue() self.exp_process = process.ExperimentProcess(self.experiment, \ self.channel) # Start process! self.exp_process.start() # Variables used for ugly hack to suppress 'None' print by Queue.get() _stdout = sys.stdout _pit = StringIO() # Wait for experiment to finish. # Listen for incoming messages in the meantime. while self.exp_process.is_alive() or not self.channel.empty(): QtGui.QApplication.processEvents() # Make sure None is not printed. Ugly hack for a bug in the Queue # class? sys.stdout = _pit # Wait for messages. Will throw Exception if no message is received # before timeout. try: msg = self.channel.get(True, 0.05) except: msg = None # Restore connection to stdout sys.stdout = _stdout # For standard print statements if isinstance(msg, basestring): sys.stdout.write(msg) # Errors arrive as a tuple with (Error object, traceback) elif isinstance(msg, Exception): return msg # Anything that is not a string, not an Exception, and not None is # unexpected elif msg != None: return osexception( \ u"Illegal message type received from child process: %s (%s)" \ % (msg, type(msg))) # Return None if experiment finished without problems return None
def execute(self): """See base_runner.execute().""" import platform # In OS X the multiprocessing module is horribly broken, but a fixed # version has been released as the 'billiard' module if platform.system() == 'Darwin': import billiard as multiprocessing multiprocessing.forking_enable(0) else: import multiprocessing from libqtopensesame.misc import process, _ from libopensesame import misc self._workspace_globals = {} if os.name == u'nt' or (sys.platform == u'darwin' \ and not hasattr(sys,"frozen")): # Under Windows and OSX, the multiprocess runner assumes that there # is a file called `opensesame.py` or `opensesame.pyc`. If this file # does not exist, try to copy it from the main script # (`opensesame`). If this fails, provide an informative error # message. os_folder = misc.opensesame_folder() # misc.opensesame_folder() doesn't work for OSX and returns None then, # so determine OpenSesame's rootdir in another way if os_folder is None: os_folder = os.path.dirname( os.path.abspath(sys.modules['__main__'].__file__)) if not os.path.exists(os.path.join(os_folder, u'opensesame.pyc')) \ and not os.path.exists(os.path.join(os_folder, u'opensesame.py')): import shutil try: shutil.copyfile(os.path.join(os_folder, u'opensesame'), os.path.join(os_folder, u'opensesame.py')) except Exception as e: return osexception( _(u'Failed to copy `opensesame` to `opensesame.py`, which is required for the multiprocess runner. Please copy the file manually, or select a different runner under Preferences.'), exception=e) self.channel = multiprocessing.Queue() try: self.exp_process = process.ExperimentProcess(self.experiment, self.channel) except Exception as e: return osexception(_(u'Failed to initialize experiment process'), exception=e) # Start process! self.exp_process.start() # Wait for experiment to finish. # Listen for incoming messages in the meantime. while self.exp_process.is_alive() or not self.channel.empty(): # We need to process the GUI. To make the GUI feel more responsive # during pauses, we refresh the GUI more often when paused. QtGui.QApplication.processEvents() if self.paused: for i in range(25): time.sleep(.01) QtGui.QApplication.processEvents() # Make sure None is not printed. Ugly hack for a bug in the Queue # class? self.console.suppress_stdout() # Wait for messages. Will throw Exception if no message is received # before timeout. try: msg = self.channel.get(True, 0.05) except: continue # Restore connection to stdout self.console.capture_stdout() if isinstance(msg, basestring): sys.stdout.write(safe_decode(msg, errors=u'ignore')) continue # Capture exceptions if isinstance(msg, Exception): return msg # The workspace globals are sent as a dict. A special __pause__ key # indicates whether the experiment should be paused or resumed. if isinstance(msg, dict): self._workspace_globals = msg if u'__heartbeat__' in msg: self.console.set_workspace_globals(msg) self.main_window.extension_manager.fire(u'heartbeat') elif u'__pause__' in msg: if msg[u'__pause__']: self.pause() else: self.resume() continue # Anything that is not a string, not an Exception, and not None is # unexpected return osexception( u"Illegal message type received from child process: %s (%s)" \ % (msg, type(msg))) # Return None if experiment finished without problems return None