def saveSettings(self): """ Saves current configuration stored in the task object into AHF_task_*.jsn Call this function after modifying the contents of the task to save your changes :param: none :returns: nothing """ self.edited = True # get name for new config file and massage it a bit if self.fileName == '': promptStr = 'Enter a name to save task settings as file:' else: promptStr = 'Enter a name to save task settings, or enter to use current name, \'' + self.fileName + '\':' newConfig = input(promptStr) if self.fileName != '' and newConfig == '': newConfig = self.fileName else: if newConfig.startswith('AHF_config_'): newConfig = newConfig[9:] if newConfig.endswith('.jsn'): newConfig.rstrip('.jsn') newConfig = ''.join([ c for c in newConfig if c.isalpha() or c.isdigit() or c == '_' ]) self.fileName = newConfig CAD.Obj_fields_to_file(self, 'config', newConfig, '.jsn', 'AHF_config/')
def getConfigData(self, tag): """ returns saved dictionary for given tag """ return CAD.File_to_dict('mouse', '{:013}'.format(int(tag)), '.jsn', dir=self.configPath)
def storeConfig(self, tag, configDict, source=""): """ saves data to corresponding json text file, overwriting old file """ if tag is int: CAD.Dict_to_file(configDict, 'mouse', '{:013}'.format(int(tag)), '.jsn', dir=self.configPath)
def create_fillable_json(self): tags = self.miceDict.keys() self.miceDict = {} useOld = "" if len(tags) > 0: useOld = input("You have the following tags in your JSON: " + str(tags) + " Would you like to use these?") addMore = True if len(useOld) > 0 and useOld[0].lower() == 'y': for tag in tags: self.add(int(tag)) addMore = input("Add any more mice?") if len(addMore) > 0 and addMore[0].lower() == 'n': addMore = False if addMore: tempInput = input( 'Add the mice for your task.\n' 'Type A for adding a mouse with the tag number \n' 'Type T for using the RFID Tag reader ') moreMice = True while moreMice: self.add(tempInput[0]) stillmore = input('add another mouse? Y or N') if stillmore[0] == "n" or stillmore[0] == "N": moreMice = False print(self.miceDict) CAD.Dict_to_file(self.miceDict, "mice_fillable", self.jsonName, ".jsn", dir=configPath) input("Please edit the values in AHF_mice_fillable_" + self.jsonName + '.jsn now. Do not modify the structure.\n' + "Press enter when done") os.system("sudo cp AHF_mice_fillable_" + self.jsonName + ".jsn" + " AHF_mice_" + self.jsonName + ".jsn") self.miceDict = CAD.File_to_dict('mice', self.jsonName, '.jsn', dir=configPath)
def configGenerator(self): """ Each configuration file has config data for a single subject. This function loads data from all of them in turn, and returning each as a a tuple of(tagID, dictionary) """ for fname in listdir(self.configPath): if fname.startswith('AHF_mouse_') and fname.endswith('.jsn'): tagStr = fname[10:len(fname) - 4] yield (int(tagStr), CAD.File_to_dict('mouse', tagStr, '.jsn', dir=self.configPath))
def setup(self): # hardware.json subject.json self.settingsTuple = ('HeadFixer', 'Rewarder', 'Stimulator') self.loadConfigs = self.settingsDict.get('loadMiceConfigs') self.jsonName = self.settingsDict.get('jsonName') self.inChamberTimeLimit = self.settingsDict.get('inChamberTimeLimit') self.miceDict = {} self.resultsDict = {} if self.loadConfigs == "database" and hasattr( self.task, 'DataLogger' ): # try to load mice configuration from dataLogger dataLogger = self.task.DataLogger for configTuple in dataLogger.configGenerator("current_subjects"): self.miceDict.update(configTuple) elif self.loadConfigs == "provide_json": #check file, if not existing or not correct provide a fillable json, then update miceDict when user is ready try: direc = "" if os.getcwd() == "/root": with open("/home/pi/config.txt", "r") as file: configs = file.readlines() for config in configs: config = config.split("=") if config[0] == "path": direc = config[1].rstrip("\n") self.miceDict = CAD.File_to_dict('mice', self.jsonName, '.jsn', self.configPath) if self.check_miceDict(self.miceDict) == False: raise Exception('Could not confirm dictionary') except Exception as e: print( 'Unable to open and fully load subjects configuration, we will create a fillable json for you.\n' 'This file will be named AHF_mice_fillable' + self.jsonName + ".jsn\n") self.create_fillable_json() while self.check_miceDict(self.miceDict) == False: input( 'could not load json, please edit and try again. Press enter when done' ) for tag in self.miceDict.keys(): for source in self.miceDict.get(tag): self.task.DataLogger.storeConfig( int(tag), self.miceDict.get(tag).get(source), source)
def retireMouse(self, tag, reason): CAD.Remove_file('mouse', '{:013}'.format(int(tag)), '.jsn', dir=self.configPath) self.writeToLogFile(tag, "Retirement", {'reason': reason}, time())
def subjectSettings(self): """ Allows user to add mice to file, maybe use TagReader, give initial values to paramaters """ from time import sleep while True: inputStr = '\n************** Mouse Configuration ********************\nEnter:\n' inputStr += 'A to add a mouse, by its RFID Tag\n' inputStr += 'T to read a tag from the Tag Reader and add that mouse\n' inputStr += 'M to modify mouse information for a specific mouse\n' inputStr += 'R to remove a mouse from the list, by RFID Tag\n' inputStr += 'J to create a Json file for subject settings from Database\n' inputStr += 'E to exit :' event = input(inputStr) tag = 0 if event[0].lower() == 'm': mouse = input("Enter a tag, or leave blank for all mice: ") if len(mouse) > 0: mouse = self.get(mouse) if mouse is not None: for source in self.settingsTuple: reference = getattr(self.task, source) sourceDict = reference.config_user_subject_get( mouse.get(source, {})) mouse.update({source: sourceDict}) else: for tag, dict in self.get_all().items(): print("Tag:", tag) for source in self.settingsTuple: reference = getattr(self.task, source) sourceDict = reference.config_user_subject_get( dict.get(source, {})) dict.update({source: sourceDict}) elif event[0].lower() == 'r': # remove a mouse mice = self.task.DataLogger.getMice() tag = input( 'Mice currently known to be in the cage : {}.\n' 'Enter the RFID tag of the mouse to be removed: '.format( str(mice))) reason = input( 'Why do you want to retire the mouse(e.g. participation, window, health, finished): ' ) if tag != '' and tag in mice: self.task.DataLogger.retireMouse(tag, reason) mice = self.task.DataLogger.getMice() print('mice now in cage: {}'.format(str(mice))) else: print("wrong tag") elif event[0].lower() == 'j': default = input( 'Use CURRENT settings for each mouse for Json?(otherwise DEFAULT settings are used' ) if default[0] == 'y' or default[0] == 'Y': settings = "current_subjects" else: settings = "default_subjects" jsonDict = {} for config in self.task.DataLogger.configGenerator(settings): jsonDict.update(config) if len(jsonDict) > 0: nameStr = input( 'Chose a filename. Your file will be automatically named: AHF_mice_filename.json' ) configFile = 'AHF_mice' + nameStr + '.json' with open(configFile, 'w') as fp: fp.write( json.dumps(jsonDict, separators=('\n', '='), sort_keys=True, skipkeys=True)) fp.close() uid = pwd.getpwnam('pi').pw_uid gid = grp.getgrnam('pi').gr_gid os.chown( configFile, uid, gid ) # we may run as root for pi PWM, so we need to explicitly set ownership # TODO check this elif event[0].lower() == 'a' or event[0].lower( ) == 't': # other two choices are for adding a mouse by RFID Tag, either reading from Tag Reader, or typing it self.task.Reader.stopLogging() self.add(event) CAD.Dict_to_file(self.miceDict, "mice", self.jsonName, ".jsn", dir='AHF_config/') self.task.Reader.startLogging() else: break response = input( 'Save changes in settings to a json file, too?(recommended)') if response[0] == 'Y' or response[0] == 'y': CAD.Dict_to_file(self.miceDict, "mice", self.jsonName, ".jsn", dir='AHF_config/')
def userEdit(self): """ Allows user interaction to add and remove subjects, print out and edit individual configuration """ CAD.Edit_dict(self.miceDict, 'Mice')
def __init__(self, fileName='', object=None): """ Initializes a Task object with settings for various hardware, stimulator, and Subjects classes """ fileErr = False if fileName != '': # file name passed in may or may not start with AFH_task_ and end with .jsn self.fileName = fileName if self.fileName.startswith('AHF_config_'): self.fileName = self.filename[11:] if self.fileName.endswith('.jsn'): self.filename = self.fileName.rstrip('.jsn') if not CAD.File_exists('config', self.fileName, '.jsn'): self.fileName = '' else: self.fileName = '' # Initialization dictionary found from database if object is not None: for key, value in object.items(): if type(value) is str and key.endswith('Class'): if value.startswith("AHF_"): setattr( self, key, CAD.Class_from_file(value[4:], '', dirName='AHF_' + key[:-5])) else: setattr(self, key, None) else: setattr(self, key, value) # no file passed in, or passed in file could not be found. Get user to choose a file if object is None and self.fileName == '': try: self.fileName = CAD.File_from_user( 'config', 'Auto Head Fix task configuration', '.jsn', True) except FileNotFoundError: self.fileName = '' print('Let\'s configure a new task.\n') fileErr = True # if we found a file, try to load it if object is None and self.fileName != '': try: CAD.File_to_obj_fields('config', self.fileName, '.jsn', self, dir='AHF_config') except ValueError as e: print('Unable to open and fully load task configuration:' + str(e)) fileErr = True # check for any missing settings, all settings will be missing if making a new config, and call setting functions for # things like head fixer that are subclassable need some extra work , when either loaded from file or user queried ########## Head Fixer(obligatory) makes its own dictionary ################################# if not hasattr(self, 'HeadFixerClass') or not hasattr( self, 'HeadFixerDict'): self.HeadFixerClass = CAD.Class_from_file( 'HeadFixer', CAD.File_from_user('HeadFixer', 'Head Fixer Class', '.py'), dirName='AHF_HeadFixer') self.HeadFixerDict = self.HeadFixerClass.config_user_get() fileErr = True ################################ Stimulator(Obligatory) makes its own dictionary ####################### if not hasattr(self, 'StimulusClass') or not hasattr( self, 'StimulusDict'): self.StimulusClass = CAD.Class_from_file( 'Stimulus', CAD.File_from_user('Stimulus', 'Experiment Stimulus Class', '.py'), dirName='AHF_Stimulus') #requires a starter dict? self.StimulusDict = self.StimulusClass.config_user_get() fileErr = True ################################ Stimulator(Obligatory) makes its own dictionary ####################### if not hasattr(self, 'StimulatorClass') or not hasattr( self, 'StimulatorDict'): self.StimulatorClass = CAD.Class_from_file( 'Stimulator', CAD.File_from_user('Stimulator', 'Experiment Stimulator Class', '.py'), dirName='AHF_Stimulator') #requires a starter dict? self.StimulatorDict = self.StimulatorClass.config_user_get() fileErr = True ################################ Rewarder(Obligatory) class makes its own dictionary ####################### if not hasattr(self, 'RewarderClass') or not hasattr( self, 'RewarderDict'): self.RewarderClass = CAD.Class_from_file('Rewarder', CAD.File_from_user( 'Rewarder', 'Rewarder', '.py'), dirName='AHF_Rewarder') self.RewarderDict = self.RewarderClass.config_user_get() fileErr = True ############################ Reader(Obligatory) makes its own dictionary ############## if not hasattr(self, 'ReaderClass') or not hasattr(self, 'ReaderDict'): self.ReaderClass = CAD.Class_from_file( 'Reader', CAD.File_from_user('Reader', 'RFID-Tag Reader', '.py'), dirName='AHF_Reader') self.ReaderDict = self.ReaderClass.config_user_get() fileErr = True ################################ Camera(optional) makes its own dictionary of settings #################### if not hasattr(self, 'CameraClass') or not hasattr(self, 'CameraDict'): if object is not None: self.cameraClass = None self.cameraDict = None else: tempInput = input( 'Does this system have a main camera installed(Y or N):') if tempInput[0] == 'y' or tempInput[0] == 'Y': self.CameraClass = CAD.Class_from_file( 'Camera', CAD.File_from_user('Camera', 'main camera', '.py'), dirName='AHF_Camera') self.CameraDict = self.CameraClass.config_user_get() else: self.cameraClass = None self.cameraDict = None fileErr = True ############################# ContactCheck(Obligatory) makes its own dictionary of settings ################### if not hasattr(self, 'ContactCheckClass') or not hasattr( self, 'ContactCheckDict'): self.ContactCheckClass = CAD.Class_from_file( 'ContactCheck', CAD.File_from_user('ContactCheck', 'Contact Checker', '.py'), dirName='AHF_ContactCheck') self.ContactCheckDict = self.ContactCheckClass.config_user_get() fileErr = True ############################ NOT just A single GPIO pin for brain illumination, unless you want that ########### if not hasattr(self, 'BrainLightClass') or not hasattr( self, 'BrainLightDict'): self.BrainLightClass = CAD.Class_from_file( 'BrainLight', CAD.File_from_user('BrainLight', 'Brain illuminator', '.py'), dirName='AHF_BrainLight') self.BrainLightDict = self.BrainLightClass.config_user_get() fileErr = True ####################################### triggers for alerting other computers(Optional) only 1 subclass so far ######################3 if not hasattr(self, 'TriggerClass') or not hasattr( self, 'TriggerDict'): if object is not None: self.TriggerClass = None self.TriggerDict = None else: tempInput = input( 'Send triggers to start tasks on secondary computers(Y or N):' ) if tempInput[0] == 'y' or tempInput[0] == 'Y': self.TriggerClass = CAD.Class_from_file( 'Trigger', CAD.File_from_user('Trigger', 'Trigger', '.py'), dirName='AHF_Trigger') self.TriggerDict = self.TriggerClass.config_user_get() else: self.TriggerClass = None self.TriggerDict = None fileErr = True ############################## LickDetector(optional) only 1 subclass so far ############## if not hasattr(self, 'LickDetectorClass') or not hasattr( self, 'LickDetectorDict'): if object is not None: self.LickDetectorClass = None self.LickDetectorDict = None else: tempInput = input( 'Does this setup have a Lick Detector installed?(Y or N)') if tempInput[0] == 'y' or tempInput[0] == 'Y': self.LickDetectorClass = CAD.Class_from_file( 'LickDetector', CAD.File_from_user('LickDetector', 'Lick Detector', '.py'), dirName='AHF_LickDetector') self.LickDetectorDict = self.LickDetectorClass.config_user_get( ) else: self.LickDetectorClass = None self.LickDetectorDict = None fileErr = True ###################### DataLogger(Obligatory) for logging data in text files, or database of HD5,or .... ################# if not hasattr(self, 'DataLoggerClass') or not hasattr( self, 'DataLoggerDict'): self.DataLoggerClass = CAD.Class_from_file( 'DataLogger', CAD.File_from_user('DataLogger', 'Data Logger', '.py'), dirName='AHF_DataLogger') self.DataLoggerDict = self.DataLoggerClass.config_user_get() fileErr = True ############################ text messaging using textbelt service(Optional) only 1 subclass so far ###################### if not hasattr(self, 'NotifierClass') or not hasattr( self, 'NotifierDict'): if object is not None: self.NotifierClass = None self.NotifierDict = None else: tempInput = input( 'Send notifications if subject exceeds criterion time in chamber?(Y or N):' ) if tempInput[0] == 'y' or tempInput[0] == 'Y': self.NotifierClass = CAD.Class_from_file( 'Notifier', CAD.File_from_user('Notifier', 'Text Messaging Notifier', '.py'), dirName='AHF_Notifier') self.NotifierDict = self.NotifierClass.config_user_get() self.NotifierDict.update( {'cageID': self.DataLoggerDict.get('cageID')}) else: self.NotifierClass = None self.NotifierDict = None fileErr = True ############################## Subjects only 1 subclass so far(generic mice) ############## if not hasattr(self, 'SubjectsClass') or not hasattr( self, 'SubjectsDict'): self.SubjectsClass = CAD.Class_from_file( 'Subjects', CAD.File_from_user('Subjects', 'test subjects', '.py'), dirName='AHF_Subjects') self.SubjectsDict = self.SubjectsClass.config_user_get() fileErr = True ###################### things we track in the main program ################################# self.tag = 0 # RFIG tag number, 0 for no tag, updated by threaded callback self.contact = False # true if contact is true self.contactTime = 0 self.lastFixedTag = 0 self.lastFixedTime = 0 self.entryTime = 0.0 self.fixAgainTime = float('inf') self.fixed = False self.isFixTrial = False self.inChamberLimitExceeded = False self.edited = False self.logToFile = True # a flag for writing to the shell only, or to the shall and the log ################ if some of the paramaters were set by user, give option to save ############### if fileErr: response = input( 'Save new/updated settings to a task configuration file?') if response[0] == 'y' or response[0] == 'Y': self.saveSettings()
def editSettings(self): if (CAD.Edit_Obj_fields(self, 'Auto Head Fix Task', isTaskConfig=True)): response = input('Save changes in settings to a file? y/n') if response[0] == 'Y' or response[0] == 'y': self.saveSettings()