def setup_class(cls): cls.exp = experiment.Experiment() # create once, not every test try: cls.tempDir = mkdtemp(dir=Path(__file__).root, prefix='psychopy-tests-app') except (PermissionError, OSError): # can't write to root on Linux cls.tempDir = mkdtemp(prefix='psychopy-tests-app')
def loadExperiment(self): """ Load the experiment object for the current psyexp file. Returns ------- PsychoPy Experiment object """ fileName = str(self.currentFile) if not os.path.exists(fileName): raise FileNotFoundError("File not found: {}".format(fileName)) # If not a Builder file, return if not fileName.endswith('.psyexp'): return None # Load experiment file exp = experiment.Experiment(prefs=self.app.prefs) try: exp.loadFromXML(fileName) except Exception: print(u"Failed to load {}. Please send the following to" u" the PsychoPy user list".format(fileName)) traceback.print_exc() return exp
def test_get_info(self): # List of values for expInfo fields, with expected compiled values for python and js cases = [ # Function call with multiple inputs { 'val': 'randint(0, 999)', 'py': "randint(0, 999)", 'js': "util.randint(0, 999)" } ] # Construct exp with one big expInfo string from cases exp = experiment.Experiment() exp.settings.params['Experiment info'].val = "{" i = 0 for case in cases: exp.settings.params[ 'Experiment info'].val += f"'{i}': '{case['val']}'," i += 1 exp.settings.params['Experiment info'].val += "}" # Compile to py pyScript = exp.writeScript(target="PsychoPy") # Check py expInfoStr = pyScript.split("expInfo = {")[1] expInfoStr = expInfoStr.split("}")[0] i = 0 for case in cases: wanted = f"'{i}': {case['py']}," assert wanted in expInfoStr, (f"Could not find `{wanted}` in ```\n" f"{expInfoStr}\n" f"```") i += 1
def test_handled_resources_removed(self): """ Check that resources handled by a static component are removed from the start of the experiment """ cases = [ # Resource handled by static component, no loop present { 'exp': "handledbystatic_noloop", 'seek': [], 'avoid': [ 'blue.png', 'white.png', 'yellow.png', 'groups.csv', 'groupA.csv', 'groupB.csv' ] }, # Resource handled by static component, loop defined by string { 'exp': "handledbystatic_strloop", 'seek': ['groupA.csv'], 'avoid': [ 'blue.png', 'white.png', 'yellow.png', 'groupB.csv', 'groups.csv' ] }, # Resource handled by static component, loop defined by constructed string { 'exp': "handledbystatic_constrloop", 'seek': ['groupA.csv', 'groupB.csv', 'groups.csv'], 'avoid': ['blue.png', 'white.png', 'yellow.png'] }, # Resource handled by static component, loop defined by constructed string from loop { 'exp': "handledbystatic_recurloop", 'seek': ['groupA.csv', 'groupB.csv', 'groups.csv'], 'avoid': ['blue.png', 'white.png', 'yellow.png'] }, ] exp = experiment.Experiment() for case in cases: # Load experiment exp.loadFromXML( Path(TESTS_DATA_PATH) / "test_get_resources" / (case['exp'] + ".psyexp")) # Write to JS script = exp.writeScript(target="PsychoJS") # Check that all "seek" phrases are included for phrase in case['seek']: assert _find_global_resource_in_js_experiment( script, phrase ), (f"'{phrase}' was not found in resources for {case['exp']}.psyexp" ) # Check that all "avoid" phrases are excluded for phrase in case['avoid']: assert not _find_global_resource_in_js_experiment( script, phrase ), (f"'{phrase}' was found in resources for {case['exp']}.psyexp" )
def test_stroop(self): #load experiment exp = experiment.Experiment() exp.loadFromXML(join(demosDir, 'builder', 'stroop', 'stroop.psyexp')) # try once packaging up the js libs exp.settings.params['JS libs'].val = 'remote' outFolder = join(self.temp_dir, 'stroopJS_remote/html') os.makedirs(outFolder) self.writeScript(exp, outFolder)
def test_blocked(self): # load experiment exp = experiment.Experiment() exp.loadFromXML(demosDir/'builder/understandingPsychopy/images_blocks/blockedTrials.psyexp') # try once packaging up the js libs exp.settings.params['JS libs'].val = 'packaged' outFolder = self.temp_dir/'blocked_packaged/html' os.makedirs(outFolder) self.writeScript(exp, outFolder) print("files in {}".format(outFolder))
def test_blocked(self): # load experiment exp = experiment.Experiment() exp.loadFromXML(demosDir/'builder'/'Design Templates'/'randomisedBlocks'/'randomisedBlocks.psyexp') # try once packaging up the js libs exp.settings.params['JS libs'].val = 'packaged' outFolder = self.temp_dir/'blocked_packaged/html' os.makedirs(outFolder) self.writeScript(exp, outFolder) print("files in {}".format(outFolder))
def test_blocked(self): # load experiment exp = experiment.Experiment() exp.loadFromXML(join(demosDir, 'builder', 'images_blocks', 'blockedTrials.psyexp')) # try once packaging up the js libs exp.settings.params['JS libs'].val = 'packaged' outFolder = join(self.temp_dir, 'blocked_packaged') self.writeScript(exp, outFolder) print("files in {}".format(outFolder))
def setup_class(cls): """ Load and run various experiments just once and use the objects / output in later tests """ # Setup temporary dir try: cls.tempDir = mkdtemp(dir=Path(__file__).root, prefix='psychopy-tests-loops') except (PermissionError, OSError): # can't write to root on Linux cls.tempDir = mkdtemp(prefix='psychopy-tests-loops') # List of filenames for experiments to run filenames = [ 'testLoopsBlocks', 'testStaircase', 'test_current_loop_attr' ] # Run each experiment to get data cls.cases = {} for filename in filenames: # Copy file to temp dir so it's in the same folder as we want data to output to ogExpFile = Path( TESTS_DATA_PATH) / "test_loops" / f"{filename}.psyexp" expFile = Path(cls.tempDir) / f"{filename}.psyexp" shutil.copy(ogExpFile, expFile) # Load experiment from file exp = experiment.Experiment() exp.loadFromXML(expFile) # Change data file output to temp dir datafile = (Path(cls.tempDir) / "data" / f"{filename}.csv") exp.settings.params[ 'Data filename'].val = f"'data' + os.sep + '{filename}'" # Write scripts pyScript = exp.writeScript(target="PsychoPy") # jsScript = exp.writeScript(target="PsychoJS") # disabled until all loops work in JS # Save Python script to temp dir pyScriptFile = Path(cls.tempDir) / f"{filename}.py" with codecs.open(str(pyScriptFile), 'w', 'utf-8-sig') as f: f.write(pyScript) # Run Python script to generate data file stdout, stderr = core.shellCall( [sys.executable, str(pyScriptFile)], stderr=True) # Load data file with open(datafile, "rb") as f: data = np.recfromcsv(f, case_sensitive=True) # Store cls.cases[filename] = { 'exp': exp, 'pyScript': pyScript, # 'jsScript': jsScript, # disabled until all loops work in JS 'data': data, 'stdout': stdout, 'stderr': stderr, }
def setup_class(cls): cls.expPy = experiment.Experiment() # create once, not every test cls.expJS = experiment.Experiment() cls.here = Path(__file__).parent cls.baselineProfile = cls.here / profile # should not need a wx.App with fetchIcons=False try: cls.allComp = getAllComponents(fetchIcons=False) except Exception: import wx if parse_version(wx.__version__) < parse_version('2.9'): tmpApp = wx.PySimpleApp() else: tmpApp = wx.App(False) try: from psychopy.app import localization except Exception: pass # not needed if can't import it cls.allComp = getAllComponents(fetchIcons=False)
def test_onlineExtraResources(self): """Open an experiment with resources in the format of 2020.5 (i.e. broken with \\ and with .. at start)""" expFile = (testsDataDir / 'broken2020_2_5_resources/broken_resources.psyexp') exp = experiment.Experiment() exp.loadFromXML(expFile) resList = exp.settings.params['Resources'].val print(resList) assert type(resList) == list assert (not resList[0].startswith('..'))
def setup(self): # Make blank experiment self.exp = experiment.Experiment() # Make blank routine self.routine = experiment.routines.Routine(name="testRoutine", exp=self.exp) self.exp.addRoutine("testRoutine", self.routine) self.exp.flow.addRoutine(self.routine, 0) # Make Resource Manager component self.comp = ResourceManagerComponent(exp=self.exp, parentName="testRoutine", name="testResourceManager") self.routine.addComponent(self.comp)
def setup(self): # Make blank experiment self.exp = experiment.Experiment() # Make blank routine self.routine = experiment.routines.Routine(name="testRoutine", exp=self.exp) self.exp.addRoutine("testRoutine", self.routine) self.exp.flow.addRoutine(self.routine, 0) # Make Static component self.comp = StaticComponent(exp=self.exp, parentName="testRoutine", name="testStatic") self.routine.addComponent(self.comp)
def test_stroop(self): #load experiment exp = experiment.Experiment() exp.loadFromXML(join(demosDir, 'builder','stroop','stroop.psyexp')) # try once packaging up the js libs exp.settings.params['JS libs'].val = 'packaged' outFolder = join(self.temp_dir, 'stroopJS_packaged') self.writeScript(exp, outFolder) # try once packaging up the js libs exp.settings.params['JS libs'].val = 'remote' outFolder = join(self.temp_dir, 'stroopJS_remote') self.writeScript(exp, outFolder) print("files in {}".format(outFolder))
def setup(self): # Make blank experiment self.exp = experiment.Experiment() # Make blank routine self.routine = Routine(name="testRoutine", exp=self.exp) self.exp.addRoutine("testRoutine", self.routine) self.exp.flow.addRoutine(self.routine, 0) # Add loop around routine self.loop = TrialHandler(exp=self.exp, name="testLoop") self.exp.flow.addLoop(self.loop, 0, -1) # Make Mouse component self.comp = CodeComponent(exp=self.exp, parentName="testRoutine", name="testCode") self.routine.addComponent(self.comp)
def test_JS_script_output(self): # Load experiment exp = experiment.Experiment() exp.loadFromXML(join(demosDir, 'builder', 'stroop', 'stroop.psyexp')) outFolder = join(self.temp_dir, 'stroopJS_output/html') outFile = os.path.join(outFolder, 'stroop.js') os.makedirs(outFolder) # Compile scripts assert(self.compileScript(infile=exp, version=None, outfile=outFile)) # Test whether files are written assert(os.path.isfile(os.path.join(outFolder, 'stroop.js'))) assert(os.path.isfile(os.path.join(outFolder, 'stroop-legacy-browsers.js'))) assert(os.path.isfile(os.path.join(outFolder, 'index.html'))) assert(os.path.isdir(os.path.join(outFolder, 'resources')))
def test_writing(self): # Create simple experiment with a Polygon exp = experiment.Experiment() rt = experiment.routines.Routine(name="testRoutine", exp=exp) exp.addRoutine("testRoutine", rt) exp.flow.addRoutine(rt, 0) comp = polygon.PolygonComponent(exp=exp, parentName="testRoutine") rt.addComponent(comp) # Set use version exp.settings.params['Use version'].val = "2021.1.4" # Save experiment exp.saveToXML(str(self.temp / "versionText.psyexp")) # --- Python --- # Write script scriptFile = str(self.temp / "versionText.py") generateScript( experimentPath=scriptFile, exp=exp, target="PsychoPy" ) # Read script with open(scriptFile, "r") as f: script = f.read() # Get args passed to comp args = script.split(f"{comp.name} = visual.ShapeStim(")[1] args = args.split(")")[0] # If using 2021.1.4, there shouldn't be any "anchor" arg in ShapeStim, as it wasn't implemented yet assert "anchor" not in args, ( "When compiling Py with useversion 2021.1.4, found 'anchor' argument in ShapeStim; this was not " "implemented in requested version." ) # --- JS --- # Write script scriptFile = str(self.temp / "versionText.js") generateScript( experimentPath=scriptFile, exp=exp, target="PsychoJS" ) # Read script with open(scriptFile, "r") as f: script = f.read() # Check for correct version import statement assert "import { PsychoJS } from './lib/core-2021.1.4.js'" in script, ( "When compiling JS with useversion 2021.1.4, could not find version-specific import statement." )
def _make_minimal_experiment(obj): """ Make a minimal experiment with just one routine, the same class as the current standalone routine but with all default params. """ # Skip whole test if required attributes aren't present if not hasattr(obj, "rt"): pytest.skip() # Make blank experiment exp = experiment.Experiment() # Create instance of this component with all default params rtClass = type(obj.rt) rt = rtClass(exp=exp, name=f"test{rtClass.__name__}") exp.addStandaloneRoutine(rt.name, rt) exp.flow.addRoutine(rt, 0) # Return experiment, routine and component return rt, exp
def setup(self): # Make a basic experiment with one routine self.exp = experiment.Experiment() self.rt = self.exp.addRoutine("testRoutine") self.exp.flow.addRoutine(self.rt, 0) # Add one of every component to that routine (default params) for compName, compClass in experiment.getAllComponents().items(): if compClass != SettingsComponent: comp = compClass(exp=self.exp, parentName=self.rt.name, name=f"test{compName}") self.rt.append(comp) # Add one of every standalone routine for rtName, rtClass in experiment.getAllStandaloneRoutines().items(): rt = rtClass(exp=self.exp, name=f"test{rtName}") self.exp.addStandaloneRoutine(rt.name, rt) # Add all routines to the flow for rt in self.exp.routines.values(): self.exp.flow.addRoutine(rt, 0)
def _make_minimal_experiment(obj): """ Make a minimal experiment with just one routine containing just one component, of the same class as the current component but with all default params. """ # Skip whole test if required attributes aren't present if not hasattr(obj, "comp"): pytest.skip() # Make blank experiment exp = experiment.Experiment() rt = exp.addRoutine(routineName='TestRoutine') exp.flow.addRoutine(rt, 0) # Create instance of this component with all default params compClass = type(obj.comp) comp = compClass(exp=exp, parentName='TestRoutine', name=f"test{compClass.__name__}") rt.append(comp) # Return experiment, routine and component return comp, rt, exp
def setup_class(cls): cls.exp = experiment.Experiment() # create once, not every test cls.here = os.path.abspath(os.path.dirname(__file__)) cls.baselineProfile = os.path.join(cls.here, profile) # should not need a wx.App with fetchIcons=False try: cls.allComp = getAllComponents(fetchIcons=False) except Exception: import wx if parse_version(wx.__version__) < parse_version('2.9'): tmpApp = wx.PySimpleApp() else: tmpApp = wx.App(False) try: from psychopy.app import localization except Exception: pass # not needed if can't import it cls.allComp = getAllComponents(fetchIcons=False) cls.origProjectCatalog = projects.projectCatalog projects.projectCatalog = {}
def test_xml(self): isTime = re.compile(r"\d+:\d+(:\d+)?( [AP]M)?") # Get all psyexp files in demos folder demosFolder = Path(self.exp.prefsPaths['demos']) / 'builder' for file in demosFolder.glob("**/*.psyexp"): # Create experiment and load from psyexp exp = experiment.Experiment() exp.loadFromXML(file) # Compile to get what script should look like target = exp.writeScript() # Save as XML temp = str(Path(self.tempDir) / "testXML.psyexp") exp.saveToXML(temp) # Load again exp.loadFromXML(temp) # Compile again test = exp.writeScript() # Remove any timestamps from script (these can cause false errors if compile takes longer than a second) test = re.sub(isTime, "", test) target = re.sub(isTime, "", target) # Compare two scripts to make sure saving and loading hasn't changed anything diff = difflib.unified_diff(target.splitlines(), test.splitlines()) assert list(diff) == []
def __init__(self, compClass): self.exp = experiment.Experiment() self.rt = experiment.routines.Routine(exp=self.exp, name="testRoutine") self.comp = compClass(exp=self.exp, parentName="testRoutine", name=f"test{compClass.__name__}")
#!/usr/bin/env python # -*- coding: utf-8 -*- # this script replaces hashtags with a sphinx URL string (to the github issues or pull request) # written by Jon with regex code by Jeremy from __future__ import absolute_import, print_function import os from psychopy import experiment, __version__ from pathlib import Path thisFolder = Path(__file__).parent nFiles = 0 for root, dirs, files in os.walk(thisFolder.parent / "psychopy/demos/builder"): for filename in files: if filename.endswith('.psyexp'): filepath = os.path.join(root, filename) exp = experiment.Experiment() exp.loadFromXML(filepath) origVersion = exp.psychopyVersion exp.psychopyVersion = __version__ exp.saveToXML(filepath) print("switching {} from {} to {}".format(filepath, origVersion, __version__))
def __init__(self, rtClass): self.exp = experiment.Experiment() self.rt = rtClass(exp=self.exp, name=f"test{rtClass.__name__}")
def test_flip_before_shutdown_in_settings_component(): exp = experiment.Experiment() script = exp.writeScript() assert 'Flip one final time' in script
def setup(self): # Create experiment self.exp = experiment.Experiment() self.exp.addRoutine( "testRoutine", experiment.routines.Routine("testRoutine", self.exp))
def setup_class(cls): cls.routines = experiment.getAllStandaloneRoutines() # Make basic experiments with one of each standalone routine cls.expPy = experiment.Experiment() cls.expJS = experiment.Experiment()
def setup(self): self.exp = experiment.Experiment() self.rt = EyetrackerCalibrationRoutine( exp=self.exp, name="testEyetrackerCalibrationRoutine")
def test_add_routine(self): exp = experiment.Experiment() # Test adding a regular routine rt = exp.addRoutine(f"testRoutine") # Check that the routine name is present assert rt.name in exp.routines # Check that the routine is a Routine assert isinstance( exp.routines[rt.name], experiment.routines.Routine ), (f"Routine {rt.name} should be Routine but was {type(exp.routines[rt.name]).__name__}" ) # Test adding standalone routines for rtName, rtClass in experiment.getAllStandaloneRoutines().items(): # Make and add standalone routine of this type rt = rtClass(exp=exp, name=f"test{rtClass.__name__}") exp.addStandaloneRoutine(rt.name, rt) # Check that the routine name is present assert rt.name in exp.routines, f"Could not find {rtClass.__name__} in experiment after adding" # Check that the routine is a Routine assert isinstance(exp.routines[rt.name], rtClass), ( f"Routine {rt.name} should be {rtClass.__name__} but was {type(exp.routines[rt.name]).__name__}" ) # Check that none of these routines are in the flow yet for rtName, rt in exp.routines.items(): assert rt not in exp.flow, ( f"Routine {rtName} of type {type(rt).__name__} found in experiment flow before being added" ) # Check that none of these routines appear in the compiled script yet pyScript = exp.writeScript(target="PsychoPy") jsScript = exp.writeScript(target="PsychoJS") for rtName, rt in exp.routines.items(): if "PsychoPy" in type(rt).targets: assert rtName not in pyScript, ( f"Routine {rtName} of type {type(rt).__name__} found in Python script before being added to flow" ) if "PsychoJS" in type(rt).targets: assert rtName not in jsScript, ( f"Routine {rtName} of type {type(rt).__name__} found in JS script before being added to flow" ) # Add routines to flow for rtName, rt in exp.routines.items(): exp.flow.addRoutine(rt, 0) # Check that they are in flow now for rtName, rt in exp.routines.items(): assert rt in exp.flow, ( f"Routine {rtName} of type {type(rt).__name__} not found in experiment flow after being added" ) # Check that all of these routines appear in the compiled script yet pyScript = exp.writeScript(target="PsychoPy") jsScript = exp.writeScript(target="PsychoJS") for rtName, rt in exp.routines.items(): if "PsychoPy" in type(rt).targets: assert rtName in pyScript, ( f"Routine {rtName} of type {type(rt).__name__} not found in Python script after being added to flow" ) if "PsychoJS" in type(rt).targets: assert rtName in jsScript, ( f"Routine {rtName} of type {type(rt).__name__} not found in JS script after being added to flow" )