11import numpy as np
2- import os .path
3- import csv
42from functools import partial
5- from typing import Type , Optional , List , Any , Dict , Union
3+ from typing import Type , Optional , List , Union
64from pathlib import Path
75import pandas as pd
8- import time
96import logging
107
118from allensdk .api .cache import Cache
1512from allensdk .brain_observatory .behavior .internal .behavior_project_base \
1613 import BehaviorProjectBase
1714from allensdk .api .caching_utilities import one_file_call_caching , call_caching
18- from allensdk .core .exceptions import MissingDataError
1915from allensdk .core .authentication import DbCredentials
2016
2117BehaviorProjectApi = Type [BehaviorProjectBase ]
2218
2319
2420class BehaviorProjectCache (Cache ):
2521
26- MANIFEST_VERSION = "0.0.1-alpha"
22+ MANIFEST_VERSION = "0.0.1-alpha.1 "
2723 OPHYS_SESSIONS_KEY = "ophys_sessions"
2824 BEHAVIOR_SESSIONS_KEY = "behavior_sessions"
2925 OPHYS_EXPERIMENTS_KEY = "ophys_experiments"
3026
31- # Temporary way for scientists to keep track of analyses
32- OPHYS_ANALYSIS_LOG_KEY = "ophys_analysis_log"
33- BEHAVIOR_ANALYSIS_LOG_KEY = "behavior_analysis_log"
34-
3527 MANIFEST_CONFIG = {
3628 OPHYS_SESSIONS_KEY : {
3729 "spec" : f"{ OPHYS_SESSIONS_KEY } .csv" ,
@@ -47,18 +39,8 @@ class BehaviorProjectCache(Cache):
4739 "spec" : f"{ OPHYS_EXPERIMENTS_KEY } .csv" ,
4840 "parent_key" : "BASEDIR" ,
4941 "typename" : "file"
50- },
51- OPHYS_ANALYSIS_LOG_KEY : {
52- "spec" : f"{ OPHYS_ANALYSIS_LOG_KEY } .csv" ,
53- "parent_key" : "BASEDIR" ,
54- "typename" : "file"
55- },
56- BEHAVIOR_ANALYSIS_LOG_KEY : {
57- "spec" : f"{ BEHAVIOR_ANALYSIS_LOG_KEY } .csv" ,
58- "parent_key" : "BASEDIR" ,
59- "typename" : "file"
60- },
6142 }
43+ }
6244
6345 def __init__ (
6446 self ,
@@ -283,123 +265,45 @@ def get_behavior_session_table(
283265
284266 def get_session_data (self , ophys_experiment_id : int , fixed : bool = False ):
285267 """
286- Note -- This method mocks the behavior of a cache. No files are
287- actually downloaded for local access. Instead, it adds the
288- session id to a csv log. If the "fixed" parameter is true,
289- then the API will first check to ensure that the log is present
290- in the record before pulling the data .
268+ Note -- This method mocks the behavior of a cache. Future
269+ development will include an NWB reader to read from
270+ a true local cache (once nwb files are created).
271+ TODO: Using `fixed` will raise a NotImplementedError since there
272+ is no real cache .
291273 """
292- # TODO: Future development will include an NWB reader to read from
293- # a true local cache (once nwb files are created)
294- # For now just check the log if pass `fixed`
295- path = self .get_cache_path (None , self .OPHYS_ANALYSIS_LOG_KEY )
296274 if fixed :
297- self .logger .warning (
298- "Warning! Passing `fixed=True` does not ensure that the "
299- "underlying data has not changed, as no data are actually "
300- "cached locally. The log will be updated each time the data "
301- "are pulled from the database for tracking purposes." )
302- try :
303- record = pd .read_csv (path )
304- except FileNotFoundError :
305- raise MissingDataError (
306- "No analysis log found! Add to the log by getting "
307- "session data with fixed=False." )
308- if ophys_experiment_id not in record ["ophys_experiment_id" ].values :
309- raise MissingDataError (
310- f"Data for ophys experiment { ophys_experiment_id } not "
311- "found!" )
312-
275+ raise NotImplementedError
313276 fetch_session = partial (self .fetch_api .get_session_data ,
314277 ophys_experiment_id )
315- write_log = partial (_write_log , path = path ,
316- key_name = "ophys_experiment_id" ,
317- key_value = ophys_experiment_id )
318278 return call_caching (
319279 fetch_session ,
320- write_log ,
321- lazy = False ,
280+ lambda x : x , # not writing anything
281+ lazy = False , # can't actually read from file cache
322282 read = fetch_session
323283 )
324284
325285 def get_behavior_session_data (self , behavior_session_id : int ,
326286 fixed : bool = False ):
327287 """
328- Note -- This method mocks the behavior of a cache. No files are
329- actually downloaded for local access. Instead, it adds the
330- session id to a csv log. If the "fixed" parameter is true,
331- then the API will first check to ensure that the log is present
332- in the record before pulling the data .
288+ Note -- This method mocks the behavior of a cache. Future
289+ development will include an NWB reader to read from
290+ a true local cache (once nwb files are created).
291+ TODO: Using `fixed` will raise a NotImplementedError since there
292+ is no real cache .
333293 """
334- # TODO: Future development will include an NWB reader to read from
335- # a true local cache (once nwb files are created)
336- # For now just check the log if pass `fixed`
337- path = self .get_cache_path (None , self .BEHAVIOR_ANALYSIS_LOG_KEY )
338294 if fixed :
339- self .logger .warning (
340- "Warning! Passing `fixed=True` does not ensure that the "
341- "underlying data has not changed, as no data are actually "
342- "cached locally. The log will be updated each time the data "
343- "are pulled from the database for tracking purposes." )
344- try :
345- record = pd .read_csv (path )
346- except FileNotFoundError :
347- raise MissingDataError (
348- "No analysis log found! Add to the log by getting "
349- "session data with fixed=False." )
350- if behavior_session_id not in record ["behavior_session_id" ].values :
351- raise MissingDataError (
352- f"Data for ophys experiment { behavior_session_id } not "
353- "found!" )
295+ raise NotImplementedError
354296
355297 fetch_session = partial (self .fetch_api .get_behavior_only_session_data ,
356298 behavior_session_id )
357- write_log = partial (_write_log , path = path ,
358- key_name = "behavior_session_id" ,
359- key_value = behavior_session_id )
360299 return call_caching (
361300 fetch_session ,
362- write_log ,
301+ lambda x : x , # not writing anything
363302 lazy = False , # can't actually read from file cache
364303 read = fetch_session
365304 )
366305
367306
368- def _write_log (data : Any , path : str , key_name : str , key_value : Any ):
369- """
370- Helper method to create and add to a log. Invoked any time a session
371- object is created via BehaviorProjectCache.
372- :param data: Unused, required because call_caching method assumes
373- all writer functions have data as the first positional argument
374- :param path: Path to save the log file
375- :type path: str path
376- :param key_name: Name of the id used to track the session object.
377- Typically "behavior_session_id" or "ophys_session_id".
378- :type key_name: str
379- :param key_value: Value of the id used to track the session object.
380- Usually an int.
381- """
382- now = round (time .time ())
383- keys = [key_name , "created_at" , "updated_at" ]
384- values = [key_value , now , now ]
385- if os .path .exists (path ):
386- record = (pd .read_csv (path , index_col = key_name )
387- .to_dict (orient = "index" ))
388- experiment = record .get (key_value )
389- if experiment :
390- experiment .update ({"updated_at" : now })
391- else :
392- record .update ({key_value : dict (zip (keys [1 :], values [1 :]))})
393- (pd .DataFrame .from_dict (record , orient = "index" )
394- .rename_axis (index = key_name )
395- .to_csv (path ))
396- else :
397- with open (path , "w" ) as f :
398- w = csv .DictWriter (f , fieldnames = keys )
399- w .writeheader ()
400- w .writerow (dict (zip (keys , values )))
401-
402-
403307def _write_csv (path , df , array_fields = None ):
404308 """Private writer that encodes array fields into pipe-delimited strings
405309 for saving a csv.
0 commit comments