Example #1
0
 def get_cases(self) -> List[Tuple[Dict[str, Any], ...]]:
     logger.debug('Determining cases for IterativeRunner')
     cases_lol: List[List[Tuple[Dict[
         str, Any], ...]]] = manager.plm.hook.pyfileconf_iter_get_cases(
             config_updates=self.config_updates, runner=self)
     cases = list(itertools.chain(*cases_lol))
     manager.plm.hook.pyfileconf_iter_modify_cases(cases=cases, runner=self)
     logger.debug(f'Got {cases} for IterativeRunner.cases')
     return cases
Example #2
0
    def reset_option(self, attr: str):
        """
        Reset a particular option by name

        :param attr: Name of option
        :return:
        """
        logger.debug(f'Resetting option {attr}')
        opt: PyfileconfOption = getattr(self, attr)
        opt.reset()
Example #3
0
    def reset(self):
        """
        Undo all changes made through the options interface

        :return:
        """
        logger.debug(f"Resetting pyfileconf options")
        for attr in options.option_attrs:
            opt = getattr(self, attr)
            opt.reset()
Example #4
0
    def refresh(self, section_path_str: str):
        """
        Reloads from the existing file, then reapplies any config updates. Useful for when
        this config depends on the attribute of some other config which was updated.

        :param section_path_str: section path of item to be refreshed
        :return:
        """
        logger.info(f'Refreshing config for {section_path_str}')
        self.runner.refresh(section_path_str)
        logger.debug(f'Finished refreshing config for {section_path_str}')
Example #5
0
    def set_option(self, attr: str, value: Any):
        """
        Set a particular option by its name

        :param attr: Option name
        :param value: New option value
        :return:
        """
        logger.debug(f"Setting option {attr} to {value}")
        opt: PyfileconfOption = getattr(self, attr)
        opt.value = value
        return self
Example #6
0
 def get(self, section_path_str: str):
     logger.debug(f'Getting {section_path_str} in runner')
     func_or_collection = self._get_func_or_collection(section_path_str)
     if isinstance(func_or_collection, Collection):
         return self._get_section(section_path_str)
     elif self._is_specific_class(func_or_collection):
         return self._get_one_obj_with_config(section_path_str)
     elif inspect.isclass(func_or_collection):
         return self._get_one_obj_with_config(section_path_str)
     elif callable(func_or_collection):
         return self._get_one_func_with_config(section_path_str)
     else:
         raise ValueError(f'could not get section {section_path_str}. expected PipelineCollection or function,'
                          f'got {func_or_collection} of type {type(func_or_collection)}')
Example #7
0
    def reload(self) -> None:
        """
        Useful for getting file system changes without having to start a new Python session. Also resets
        any locally defined configuration.

        Reloads functions from pipeline dict, scaffolds config files for any new functions,
        and updates configuration from files.

        Returns: None

        """
        logger.info(f'Reloading {self.name}')
        self._wipe_loaded_modules()
        self.load()
        logger.debug(f'Finished reloading {self.name}')
Example #8
0
    def set_options(self, updates: Iterable[Tuple[str, Any]]):
        """
        Set multiple options at once by their name
        :param updates: Multiple option updates
        :return:

        :Examples:

        >>> import pyfileconf
        >>> pyfileconf.options.set_options([('log_stdout', True), ('log_folder', 'MyLogs')])

        """
        for attr, value in updates:
            logger.debug(f"Setting option {attr} to {value}")
            opt: PyfileconfOption = getattr(self, attr)
            opt.value = value
        return self
Example #9
0
    def reset(self,
              section_path_str_or_view: 'StrOrView',
              allow_create: bool = False):
        """
        Resets a function or section config to default.

        To reset all configs, use .reload() instead.

        :param section_path_str_or_view:
        :return:
        """
        logger.info(f'Resetting config for {section_path_str_or_view}')
        section_path_str = self._get_section_path_str_from_section_path_str_or_view(
            section_path_str_or_view)
        self.runner.reset(section_path_str, allow_create=allow_create)
        logger.debug(
            f'Finished resetting config for {section_path_str_or_view}')
Example #10
0
    def load(self) -> None:
        """
        Wrapper to track imported modules so that can reimport them upon reloading
        """
        logger.debug(f'Running load for {self.name}')
        self._import_tracker = ImportTracker()

        try:
            self._load_pipeline_config_and_runner()
        except Exception as e:
            # Reset loaded modules from import, completely canceling load so it can be tried again
            self._loaded_modules = self._import_tracker.imported_modules
            self._wipe_loaded_modules()
            self._loaded_modules = [
            ]  # modules have been wiped, must be sure they won't be wiped again
            raise e

        self._loaded_modules = self._import_tracker.imported_modules
        logger.debug(f'Finished running load for {self.name}')
Example #11
0
    def get_defaults(self) -> Dict[str, Dict[str, Any]]:
        logger.debug('Determining defaults for IterativeRunner')
        from pyfileconf import PipelineManager

        if not hasattr(self, 'cases'):
            raise ValueError('must set cases before calling get_defaults')
        case = self.cases[0]
        section_path_strs = [
            self._get_full_section_path_str(conf['section_path_str'])
            for conf in case
        ]
        defaults: Dict[str, Dict[str, Any]] = {}
        for sp_str in section_path_strs:
            pm = PipelineManager.get_manager_by_section_path_str(sp_str)
            sp = SectionPath(sp_str)
            relative_section_path_str = SectionPath(".".join(sp[1:])).path_str
            config = pm.config.get(relative_section_path_str)
            if config is not None:
                defaults[sp_str] = {**config}
        logger.debug(f'Got {defaults} for IterativeRunner.defaults')
        return defaults
Example #12
0
    def _update(self,
                d_: dict = None,
                section_path_str: str = None,
                pyfileconf_persist: bool = True,
                **kwargs):
        """
        Update the configuration for an item by section path

        :param d_: dictionary of updates
        :param section_path_str: section path of item to be updated
        :param pyfileconf_persist: whether to make changes last through refreshing config
        :param kwargs: kwarg updates
        :return:
        """
        from pyfileconf.selector.models.itemview import is_item_view

        all_updates = {}
        if d_ is not None:
            all_updates.update(d_)
        all_updates.update(kwargs)
        logger.info(f'Updating {section_path_str} with config: {all_updates}')

        if section_path_str:
            # If any of the updates are putting an ItemView as the value, then
            # record that this config is dependent on the config referenced
            # by the ItemView
            all_updates = {**kwargs}
            if d_ is not None:
                all_updates.update(d_)
            full_sp = SectionPath.join(self.name, section_path_str)
            for value in all_updates.values():
                if is_item_view(value):
                    context.add_config_dependency(full_sp, value)

        self.runner.update(d_,
                           section_path_str,
                           pyfileconf_persist=pyfileconf_persist,
                           **kwargs)
        logger.debug(
            f'Finished updating {section_path_str} with config: {all_updates}')
Example #13
0
 def reset(self):
     logger.debug(f"Resetting option {self.name}")
     self.value = self.default_value
Example #14
0
    def create(self,
               section_path_str: str,
               func_or_class: Optional[Union[Callable, Type]] = None):
        """
        Create a new configuration entry dynamically rather than manually modifying dict file

        :param func_or_class: function or class to use to generate config
        :param section_path_str: section path at which the config should be stored
        :return:
        """
        logger.info(f'Creating config for {section_path_str}')
        section_path = SectionPath(section_path_str)

        if section_path[0] in self.specific_class_names:
            # Got path for a specific class dict, add to specific class dict
            if len(section_path) < 3:
                raise ValueError(
                    'when targeting a specific class dict, section path must have minimum length of '
                    '3, e.g. example_class.thing.stuff')
            if func_or_class is not None:
                raise ValueError(
                    'only pass func_or_class when targeting main pipeline dict, not specific class dict'
                )
            self._create_specific_class_dict_entry(section_path)
            full_sp = section_path
            registrar = self._registrar_dict[section_path[0]]
            klass = registrar.collection.klass
            if klass is None:
                raise ValueError(
                    f'must have specific class set, got None for class in {registrar}'
                )
            key_attr = registrar.collection.key_attr
            registrar_obj = convert_to_empty_obj_if_necessary(
                section_path[-1], klass, key_attr=key_attr)
            set_section_path_str = SectionPath.from_section_str_list(
                section_path[1:-1]).path_str
            scaffold_path_str = SectionPath.from_section_str_list(
                section_path[1:]).path_str
        else:
            # Got path for main pipeline dict, add to main pipeline dict
            if func_or_class is None:
                raise ValueError(
                    'when adding creating item in main pipeline dict, must pass function or class'
                )
            self._create_pipeline_dict_entry(section_path, func_or_class)
            name = func_or_class.__name__
            full_sp = SectionPath.join(section_path, name)
            mod, import_base = get_module_and_name_imported_from(func_or_class)
            obj_import = ObjectImportStatement([name], import_base)
            item = ast.Name(id=name)
            imports = ImportStatementContainer([obj_import])
            registrar_obj = ObjectView.from_ast_and_imports(item, imports)
            if self._general_registrar is None:
                raise ValueError('general registrar must be defined')
            registrar = self._general_registrar
            set_section_path_str = section_path_str
            scaffold_path_str = full_sp.path_str

        registrar.set(set_section_path_str, registrar_obj)
        registrar.scaffold_config_for(scaffold_path_str)
        self.reset(full_sp.path_str, allow_create=True)
        logger.debug(f'Finished creating config for {section_path_str}')
Example #15
0
        """
        :param collect_results: Whether to aggregate and return results, set to False to save memory
            if results are stored in some other way
        :return:
        """
        from pyfileconf.main import PipelineManager
        logger.info(f'Running {self.run_items} with cases')
        all_results = []
        for case in self.cases:
            if not self.should_run(case):
                continue
            result = self._run_case(case)
            if collect_results:
                in_out_tup = (case, result)
                all_results.append(in_out_tup)
        logger.debug(
            f'Finished running {self.run_items} with cases {self.cases}')
        return all_results

    def run_gen(self) -> Iterator[IterativeResult]:
        logger.info(f'Running {self.run_items} with cases')
        for case in self.cases:
            if not self.should_run(case):
                continue
            result = self._run_case(case)
            in_out_tup = (case, result)
            yield in_out_tup

    def _run_case(self, case: Tuple[Dict[str, Any], ...]) -> Any:
        case_with_defaults = self._fill_case_with_defaults(case)
        manager.plm.hook.pyfileconf_iter_update_for_case(
            case=case_with_defaults, runner=self)