"""Utilities functions for setting up test fixtures."""importtempfilefrompathlibimportPathimportshutilimportjsonfromuuidimportuuid4importpandasaspdfromiblutil.io.parquetimportstr2npfromiblutil.io.paramsimportset_hiddenimportone.paramsfromone.alf.cacheimportQC_TYPEfromone.convertersimportsession_record2path
[docs]defset_up_env()->tempfile.TemporaryDirectory:"""Create a temporary directory and copy cache fixtures over. Returns ------- tempfile.TemporaryDirectory The temporary directory containing the test ONE caches """fixture=Path(__file__).parent.joinpath('fixtures')tempdir=tempfile.TemporaryDirectory()# Copy cache files to temporary directoryforcache_filein('sessions','datasets'):filename=shutil.copy(fixture/f'{cache_file}.pqt',tempdir.name)assertPath(filename).exists()# Copy cached rest responsessetup_rest_cache(tempdir.name)returntempdir
[docs]defsetup_rest_cache(cache_dir):"""Copy REST cache fixtures to the .one parameter directory. Parameters ---------- cache_dir : str, pathlib.Path The location of the ONE cache directory (e.g. ~/Downloads/ONE/alyx.example.com) """fixture=Path(__file__).parent.joinpath('fixtures')rest_cache_dir=Path(cache_dir).joinpath('.rest')# Ensure emptyshutil.rmtree(rest_cache_dir,ignore_errors=True)rest_cache_dir.mkdir(parents=True,exist_ok=True)set_hidden(rest_cache_dir,True)# Copy over fixturesforfileinfixture.joinpath('rest_responses').glob('*'):filename=shutil.copy(file,rest_cache_dir)assertPath(filename).exists()
[docs]defcreate_file_tree(one):"""Touch all the files in the datasets table. Parameters ---------- one : one.api.One An instance of One containing cache tables to use. """# Create dset files from cachefor(eid,_),rel_pathinone._cache.datasets['rel_path'].items():session_path=session_record2path(one._cache.sessions.loc[eid])filepath=Path(one.cache_dir).joinpath(session_path,rel_path)filepath.parent.mkdir(exist_ok=True,parents=True)filepath.touch()
[docs]defsetup_test_params(token=False,cache_dir=None):"""Copy cache parameter fixture to .one directory. Parameters ---------- token : bool If true, save a token file so that client doesn't hit auth endpoint cache_dir : str, pathlib.Path The cache_dir to save """params_dir=Path(one.params.get_params_dir())params_dir.mkdir(exist_ok=True)fixture=Path(__file__).parent.joinpath('fixtures')test_pars='.test.alyx.internationalbrainlab.org'ifnotnext(params_dir.glob(test_pars),None):filename=shutil.copy(fixture/'params'/test_pars,params_dir/test_pars)assertPath(filename).exists()# Add to cache mapmap_file=params_dir/'.caches'ifnotmap_file.exists():shutil.copy(fixture/'params'/'.caches',map_file)assertPath(filename).exists()withopen(map_file,'r+')asf:data=json.load(f)data['CLIENT_MAP'][test_pars[1:]]=str(cache_diror'')f.seek(0)json.dump(data,f)f.truncate()# Add token to file so db not hitiftoken:pars=one.params.get(client=test_pars[1:])ifnotgetattr(pars,'TOKEN',False):one.params.save(pars.set('TOKEN',{'token':'T0k3N'}),test_pars[1:])
[docs]defrevisions_datasets_table(collections=('','alf/probe00','alf/probe01'),revisions=('','2020-01-08','2021-07-06'),object='spikes',attributes=('times','waveforems'),touch_path=None):"""Return a datasets cache DataFrame containing datasets with revision folders. As there are no revised datasets on the test databases, this function acts as a fixture for testing the filtering of datasets by a revision. Parameters ---------- collections : tuple A list of collections revisions : tuple A list of revisions object : str An ALF object attributes : tuple A list of ALF attributes touch_path : pathlib.Path, str If provided, files are created in this directory. Returns ------- pd.DataFrame A datasets cache table containing datasets made from the input names. """rel_path=[]forattrinattributes:forcollecincollections:forrevin(f'#{x}#'ifxelse''forxinrevisions):rel_path.append('/'.join(xforxin(collec,rev,f'{object}.{attr}.npy')ifx))d={'rel_path':rel_path,'file_size':0,'hash':None,'exists':True,'qc':'NOT_SET','eid':uuid4(),'id':(uuid4()for_inrel_path)}iftouch_path:forpinrel_path:path=Path(touch_path).joinpath(p)path.parent.mkdir(parents=True,exist_ok=True)path.touch()returnpd.DataFrame(data=d).astype({'qc':QC_TYPE}).set_index(['eid','id'])
[docs]defcreate_schema_cache(param_dir=None):"""Save REST cache file for docs/ endpoint. Ensures the database isn't hit when the rest_schemas property is accessed. Parameters ---------- param_dir : str, pathlib.Path The location of the parameter directory. If None, the default one is used. """actions=dict.fromkeys(['list','read','create','update','partial_update','delete'])endpoints=['cache','dataset-types','datasets','downloads','insertions','sessions']path_parts=('.rest','test.alyx.internationalbrainlab.org','https')rest_cache_dir=Path(param_dirorone.params.get_params_dir()).joinpath(*path_parts)withopen(rest_cache_dir/'1baff95c2d0e31059720a3716ad5b5a34b61a207','r')asf:json.dump({k:actionsforkinendpoints},f)
[docs]defget_file(root:str,str_id:str)->str:"""A stub function for `iblutil.io.params.getfile`. Allows the injection of a different param dir. Parameters ---------- root : str, pathlib.Path The root directory of the new parameters str_id : str The parameter string identifier Returns ------- str The parameter file path """parts=['.'+pifnotp.startswith('.')elsepforpinPath(str_id).parts]pfile=Path(root,*parts).as_posix()returnpfile
[docs]defcaches_str2int(caches):"""Convert str ids to int ids for cache tables. Parameters ---------- caches : Bunch A bunch of cache tables (from One._cache) """fortablein('sessions','datasets'):index=caches[table].indexnames=(index.name,)ifindex.nameelseindex.namescache=caches[table].reset_index()fornameinnames:fori,colinenumerate(str2np(cache.pop(name).values).T):cache[f'{name}_{i}']=colint_cols=cache.filter(regex=r'_\d{1}$').columns.sort_values().tolist()caches[table]=cache.set_index(int_cols)