def __call__(self, parser, namespace, values, option_string=None): # figure out what options are set parse_files = hasattr(namespace, 'files') parse_phil = hasattr(namespace, 'phil') parse_dir = hasattr(namespace, 'dir') # get previous values or define default if ( parse_files and (getattr(namespace, 'files') is not None) ): files = namespace.files else: files = list() if ( parse_phil and (getattr(namespace, 'phil') is not None) ): phil = namespace.phil else: phil = list() if ( parse_dir and (getattr(namespace, 'dir') is not None) ): directory = namespace.dir else: directory = list() if ( hasattr(namespace, 'unknown') and (getattr(namespace, 'unknown') is not None) ): unknown = namespace.unknown else: unknown = list() # separate values for value in values: if (os.path.isfile(value)): files.append(value) elif ( (isinstance(value, str)) and ('=' in value) ): phil.append(value) elif (os.path.isdir(value)): directory.append(value) else: unknown.append(value) # update options if (parse_files): setattr(namespace, 'files', files) else: unknown.extend(files) if (parse_phil): setattr(namespace, 'phil', phil) else: unknown.extend(phil) if (parse_dir): setattr(namespace, 'dir', directory) else: unknown.extend(directory) # store unknown values for custom processing (if available) setattr(namespace, 'unknown', unknown)
def process_phil(self, phil_list): '''' Process PHIL arguments Currently only handles command-line changes Will add inclusion of PHIL files from data_manager first, then command-line options ''' print('Processing PHIL parameters:', file=self.logger) print('-' * self.text_width, file=self.logger) print('', file=self.logger) printed_something = False data_sources = list() sources = list() unused_phil = list() # PHIL files are processed in order from command-line if (self.data_manager.has_phils()): phil_names = self.data_manager.get_phil_names() phil = list() print(' Adding PHIL files:', file=self.logger) print(' ------------------', file=self.logger) for name in phil_names: # remove DataManager scope since input files are already loaded phil_scope = self.data_manager.get_phil(name) for phil_object in phil_scope.objects: if (phil_object.name == 'data_manager'): phil_scope.objects.remove(phil_object) phil.append(phil_scope) print(' %s' % name, file=self.logger) data_sources.extend(phil) print('', file=self.logger) printed_something = True # command-line PHIL arguments override any previous settings and are # processed in given order def custom_processor(arg): unused_phil.append(arg) return True if (len(phil_list) > 0): interpreter = self.master_phil.command_line_argument_interpreter( home_scope='') print(' Adding command-line PHIL:', file=self.logger) print(' -------------------------', file=self.logger) for phil in phil_list: print(' %s' % phil, file=self.logger) print('', file=self.logger) printed_something = True working = interpreter.process_args( phil_list, custom_processor=custom_processor) if (len(working) > 0): sources.extend(working) if (self.namespace.overwrite): # override overwrite if True sources.append(iotbx.phil.parse('output.overwrite=True')) if ((len(data_sources) + len(sources)) > 0): self.working_phil, more_unused_phil = self.master_phil.fetch( sources=data_sources + sources, track_unused_definitions=True) unused_phil.extend(more_unused_phil) else: self.working_phil = self.master_phil # show unrecognized parameters and abort if (len(unused_phil) > 0): print(' Unrecognized PHIL parameters:', file=self.logger) print(' -----------------------------', file=self.logger) for phil in unused_phil: print(' %s' % phil, file=self.logger) print('', file=self.logger) error_message = 'Some PHIL parameters are not recognized by %s.\n' % \ self.prog error_message += wordwrap( 'Please run this program with the --show-defaults option to see what parameters are available.', max_chars=self.text_width) + '\n' error_message += wordwrap( 'PHIL parameters in files should be fully specified (e.g. "output.overwrite" instead of just "overwrite")', max_chars=self.text_width) + '\n' raise Sorry(error_message) if (not printed_something): print(' No PHIL parameters found', file=self.logger) print('', file=self.logger)
def process_phil(self, phil_list): '''' Process PHIL arguments Also checks PHIL arguments (command line and files) for parameters that specify files (.type = path) ''' print('Processing PHIL parameters:', file=self.logger) print('-' * self.text_width, file=self.logger) print('', file=self.logger) printed_something = False data_sources = list() sources = list() unused_phil = list() # PHIL files are processed in order from command-line if (self.data_manager.has_phils()): phil_names = self.data_manager.get_phil_names() phil = list() print(' Adding PHIL files:', file=self.logger) print(' ------------------', file=self.logger) for name in phil_names: # remove DataManager scope since input files are already loaded phil_scope = self.data_manager.get_phil(name) for phil_object in phil_scope.objects: if (phil_object.name == 'data_manager'): phil_scope.objects.remove(phil_object) phil.append(phil_scope) print(' %s' % name, file=self.logger) data_sources.extend(phil) print('', file=self.logger) printed_something = True # command-line PHIL arguments override any previous settings and are # processed in given order def custom_processor(arg): unused_phil.append(arg) return True if (len(phil_list) > 0): interpreter = self.master_phil.command_line_argument_interpreter( home_scope='') print(' Adding command-line PHIL:', file=self.logger) print(' -------------------------', file=self.logger) for phil in phil_list: print(' %s' % phil, file=self.logger) print('', file=self.logger) printed_something = True working = interpreter.process_args( phil_list, custom_processor=custom_processor) if (len(working) > 0): sources.extend(working) if (self.namespace.overwrite): # override overwrite if True sources.append(iotbx.phil.parse('output.overwrite=True')) if ((len(data_sources) + len(sources)) > 0): self.working_phil, more_unused_phil = self.master_phil.fetch( sources=data_sources + sources, track_unused_definitions=True) unused_phil.extend(more_unused_phil) else: self.working_phil = self.master_phil.fetch() # show unrecognized parameters and abort if (len(unused_phil) > 0): print(' Unrecognized PHIL parameters:', file=self.logger) print(' -----------------------------', file=self.logger) for phil in unused_phil: print(' %s' % phil, file=self.logger) print('', file=self.logger) error_message = 'Some PHIL parameters are not recognized by %s.\n' % \ self.prog error_message += wordwrap( 'Please run this program with the --show-defaults option to see what parameters are available.', max_chars=self.text_width) + '\n' error_message += wordwrap( 'PHIL parameters in files should be fully specified (e.g. "output.overwrite" instead of just "overwrite")', max_chars=self.text_width) + '\n' raise Sorry(error_message) # process input phil for file/directory defintions and add to DataManager # Note: if a PHIL file is input as a PHIL parameter, the contents of the # file will NOT be parsed and validated. The PHIL file should be provided # as a command-line argument. This is mostly for finding data files # defined by PHIL parameters that should be added to the DataManager diff_phil = self.master_phil.fetch_diff(self.working_phil) paths = self.check_phil_for_paths(diff_phil) if (len(paths) > 0): files = list() dirs = list() for path in paths: if (path is not None): if (os.path.isfile(path)): files.append(path) elif (os.path.isdir(path)): dirs.append(path) if (self.parse_files): self.process_files(files, message='Processing files from PHIL:') if (self.parse_dir): self.process_dir(dirs, message='Processing directories from PHIL:') if (not printed_something): print(' No PHIL parameters found', file=self.logger) print('', file=self.logger)
def process_phil(self, phil_list): '''' Process PHIL arguments Currently only handles command-line changes Will add inclusion of PHIL files from data_manager first, then command-line options ''' print('Processing PHIL parameters:', file=self.logger) print('-' * 79, file=self.logger) print('', file=self.logger) printed_something = False data_sources = list() sources = list() unused_phil = list() # PHIL files are processed in order from command-line if (self.data_manager.has_phils()): phil_names = self.data_manager.get_phil_names() phil = list() for name in phil_names: phil.append(self.data_manager.get_phil(name)) data_sources.extend(phil) # command-line PHIL arguments override any previous settings def custom_processor(arg): unused_phil.append(arg) return True interpreter = self.master_phil.command_line_argument_interpreter( home_scope='') working = interpreter.process_args(phil_list, custom_processor=custom_processor) if (len(working) > 0): sources.extend(working) if (self.namespace.overwrite): # override overwrite if True sources.append(iotbx.phil.parse('output.overwrite=True')) self.working_phil, more_unused_phil = self.master_phil.fetch( sources=data_sources + sources, track_unused_definitions=True) unused_phil.extend(more_unused_phil) try: phil_diff = self.master_phil.fetch_diff(self.working_phil) except RuntimeError as err: raise Sorry(err) is_different = (len(phil_diff.as_str()) > 0) # show differences if (is_different): print(' Non-default PHIL parameters:', file=self.logger) print(' ----------------------------', file=self.logger) phil_diff.show(prefix=' ', out=self.logger) printed_something = True # write differences if (self.namespace.write_modified): if (is_different): self.data_manager.write_phil_file( self.modified_filename, phil_diff.as_str(), overwrite=self.namespace.overwrite) else: print(' No PHIL modifications to write', file=self.logger) printed_something = True # show unrecognized parameters and abort if (len(unused_phil) > 0): print('', file=self.logger) print(' Unrecognized PHIL parameters:', file=self.logger) print(' -----------------------------', file=self.logger) for phil in unused_phil: print(' %s' % phil, file=self.logger) print('', file=self.logger) error_message = 'Some PHIL parameters are not recognized by %s.\n' % \ self.prog error_message += 'Please run this program with the --show-defaults option to see what parameters are available.\n' error_message += 'PHIL parameters in files should be fully specified (e.g. "output.overwrite" instead of just "overwrite")' raise Sorry(error_message) if (not printed_something): print(' No PHIL parameters found', file=self.logger) print('', file=self.logger) # show final processed phil scope try: data_diff = self.data_manager.master_phil.fetch_diff( self.data_manager.export_phil_scope()) except RuntimeError as err: raise Sorry(err) is_different = ((len(data_diff.as_str()) + len(phil_diff.as_str())) > 0) if (is_different): print('Final processed PHIL parameters:') print('-' * 79, file=self.logger) data_diff.show(prefix=' ', out=self.logger) phil_diff.show(prefix=' ', out=self.logger) # write all parameters (DataManager + Program) if (self.namespace.write_all): all_phil = self.data_manager.export_phil_scope().as_str() all_phil += self.working_phil.as_str(expert_level=3) self.data_manager.write_phil_file( self.all_filename, all_phil, overwrite=self.namespace.overwrite) print('', file=self.logger)