From 352b4c4b6635becc02af04d656121ef93e5511be Mon Sep 17 00:00:00 2001 From: TEParsons Date: Thu, 10 Oct 2024 15:18:14 +0100 Subject: [PATCH] NF: Allow Mic and Camera Components to be automatically saved when the experiment data saves --- psychopy/data/experiment.py | 28 +++++++++++++++++++ .../experiment/components/camera/__init__.py | 2 ++ .../components/microphone/__init__.py | 2 ++ 3 files changed, 32 insertions(+) diff --git a/psychopy/data/experiment.py b/psychopy/data/experiment.py index c6452af027..72e2f6eb0d 100644 --- a/psychopy/data/experiment.py +++ b/psychopy/data/experiment.py @@ -110,6 +110,8 @@ def __init__(self, self.status = constants.NOT_STARTED # dict of filenames to collision method to be used next time it's saved self._nextSaveCollision = {} + # list of call profiles for connected save methods + self.connectedSaveMethods = [] if dataFileName in ['', None]: logging.warning('ExperimentHandler created with no dataFileName' @@ -633,6 +635,29 @@ def queueNextCollision(self, fileCollisionMethod, fileName=None): # queue collision self._nextSaveCollision[fileName] = fileCollisionMethod + def connectSaveMethod(self, fcn, *args, **kwargs): + """ + Tell this experiment handler to call the given function with the given arguments and + keyword arguments whenever it saves its own data. + + Parameters + ---------- + fcn : function + Function to call + *args + Positional arguments to be given to the function when it's called + **kwargs + Keyword arguments to be given to the function when it's called + """ + # create a call profile for the given function + profile = { + 'fcn': fcn, + 'args': args, + 'kwargs': kwargs + } + # connect it + self.connectedSaveMethods.append(profile) + def save(self): """ Work out from own settings how to save, then use the appropriate method (saveAsWideText, @@ -651,6 +676,9 @@ def save(self): logging.warn( "ExperimentHandler.save was called on an ExperimentHandler with no dataFileName set." ) + # call connected save functions + for profile in self.connectedSaveMethods: + profile['fcn'](*profile['args'], **profile['kwargs']) return savedName diff --git a/psychopy/experiment/components/camera/__init__.py b/psychopy/experiment/components/camera/__init__.py index cea93f24af..084465ce91 100644 --- a/psychopy/experiment/components/camera/__init__.py +++ b/psychopy/experiment/components/camera/__init__.py @@ -474,6 +474,8 @@ def writeInitCode(self, buff): code = ( "# get camera object\n" "%(name)s = deviceManager.getDevice(%(deviceLabel)s)\n" + "# connect camera save method to experiment handler so it's called when data saves\n" + "thisExp.connectSaveMethod(%(name)s.save)\n" ) buff.writeIndentedLines(code % inits) diff --git a/psychopy/experiment/components/microphone/__init__.py b/psychopy/experiment/components/microphone/__init__.py index e3fea07bb3..4fff413fae 100644 --- a/psychopy/experiment/components/microphone/__init__.py +++ b/psychopy/experiment/components/microphone/__init__.py @@ -410,6 +410,8 @@ def writeInitCode(self, buff): "# tell the experiment handler to save this Microphone's clips if the experiment is " "force ended\n" "runAtExit.append(%(name)s.saveClips)\n" + "# connect camera save method to experiment handler so it's called when data saves\n" + "thisExp.connectSaveMethod(%(name)s.saveClips)\n" ) buff.writeIndentedLines(code % inits)