diff --git a/autoconf/__init__.py b/autoconf/__init__.py index c8ecd6a..faffad3 100644 --- a/autoconf/__init__.py +++ b/autoconf/__init__.py @@ -1,5 +1,6 @@ from . import exc from .tools.decorators import cached_property +from .tools.decorators import lazy_property from .conf import Config from .conf import instance from .json_prior.config import default_prior diff --git a/autoconf/class_path.py b/autoconf/class_path.py index 3c257c0..5d3f185 100644 --- a/autoconf/class_path.py +++ b/autoconf/class_path.py @@ -1,61 +1,61 @@ -import builtins -import importlib -import re -from typing import List, Type - - -def get_class_path(cls: type) -> str: - """ - The full import path of the type - """ - if hasattr(cls, "__class_path__"): - cls = cls.__class_path__ - return re.search("'(.*)'", str(cls))[1] - - -def get_class(class_path: str) -> Type[object]: - return GetClass(class_path).cls - - -class GetClass: - def __init__(self, class_path): - self.class_path = class_path - - @property - def _class_path_array(self) -> List[str]: - """ - A list of strings describing the module and class of the - real object represented here - """ - return self.class_path.split(".") - - @property - def _class_name(self) -> str: - """ - The name of the real class - """ - return self._class_path_array[-1] - - @property - def _module_path(self) -> str: - """ - The path of the module containing the real class - """ - return ".".join(self._class_path_array[:-1]) - - @property - def _module(self): - """ - The module containing the real class - """ - try: - return importlib.import_module(self._module_path) - except ValueError: - return builtins - - @property - def cls(self) -> Type[object]: - """ - The class of the real object - """ - return getattr(self._module, self._class_name) +import builtins +import importlib +import re +from typing import List, Type + + +def get_class_path(cls: type) -> str: + """ + The full import path of the type + """ + if hasattr(cls, "__class_path__"): + cls = cls.__class_path__ + return re.search("'(.*)'", str(cls))[1] + + +def get_class(class_path: str) -> Type[object]: + return GetClass(class_path).cls + + +class GetClass: + def __init__(self, class_path): + self.class_path = class_path + + @property + def _class_path_array(self) -> List[str]: + """ + A list of strings describing the module and class of the + real object represented here + """ + return self.class_path.split(".") + + @property + def _class_name(self) -> str: + """ + The name of the real class + """ + return self._class_path_array[-1] + + @property + def _module_path(self) -> str: + """ + The path of the module containing the real class + """ + return ".".join(self._class_path_array[:-1]) + + @property + def _module(self): + """ + The module containing the real class + """ + try: + return importlib.import_module(self._module_path) + except ValueError: + return builtins + + @property + def cls(self) -> Type[object]: + """ + The class of the real object + """ + return getattr(self._module, self._class_name) diff --git a/autoconf/directory_config.py b/autoconf/directory_config.py index a419178..8250025 100644 --- a/autoconf/directory_config.py +++ b/autoconf/directory_config.py @@ -1,231 +1,231 @@ -import configparser -import os -from abc import abstractmethod, ABC -from pathlib import Path - -import yaml - -from autoconf import exc - - -class AbstractConfig(ABC): - @abstractmethod - def _getitem(self, item): - pass - - def __getitem__(self, item): - if isinstance(item, int): - return self.items()[item] - return self._getitem(item) - - def items(self): - return [(key, self[key]) for key in self.keys()] - - def __len__(self): - return len(self.items()) - - @abstractmethod - def keys(self): - pass - - def family(self, cls): - for cls in family(cls): - key = cls.__name__ - try: - return self[key] - except (KeyError, configparser.NoOptionError): - pass - raise KeyError(f"No configuration found for {cls.__name__}") - - def dict(self): - d = {} - for key in self.keys(): - value = self[key] - if isinstance(value, AbstractConfig): - value = value.dict() - d[key] = value - return d - - -class DictConfig(AbstractConfig): - def keys(self): - return self.d.keys() - - def __init__(self, d): - self.d = d - - def __getitem__(self, item): - value = self.d[item] - if isinstance(value, dict): - return DictConfig(value) - return value - - def _getitem(self, item): - return self[item] - - def items(self): - for key in self.d: - yield key, self[key] - - -class YAMLConfig(AbstractConfig): - def __init__(self, path): - with open(path) as f: - self._dict = yaml.safe_load(f) - - def _getitem(self, item): - value = self._dict[item] - if isinstance(value, dict): - return DictConfig(value) - return value - - def keys(self): - return self._dict.keys() - - -class SectionConfig(AbstractConfig): - def __init__(self, path, parser, section): - self.path = path - self.section = section - self.parser = parser - - def keys(self): - with open(self.path) as f: - string = f.read() - - lines = string.split("\n") - is_section = False - for line in lines: - if line == f"[{self.section}]": - is_section = True - continue - if line.startswith("["): - is_section = False - continue - if is_section and "=" in line: - yield line.split("=")[0] - - def _getitem(self, item): - try: - result = self.parser.get(self.section, item) - if result.lower() == "true": - return True - if result.lower() == "false": - return False - if result.lower() in ("none", "null"): - return None - if result.isdigit(): - return int(result) - try: - return float(result) - except ValueError: - return result - except (configparser.NoSectionError, configparser.NoOptionError): - raise KeyError(f"No configuration found for {item} at path {self.path}") - - -class NamedConfig(AbstractConfig): - def __init__(self, config_path): - """ - Parses generic config - - Parameters - ---------- - config_path - The path to the config file - """ - self.path = config_path - self.parser = configparser.ConfigParser() - self.parser.read(self.path) - - def keys(self): - return self.parser.sections() - - def _getitem(self, item): - return SectionConfig( - self.path, - self.parser, - item, - ) - - -class RecursiveConfig(AbstractConfig): - def keys(self): - try: - return [ - path.split(".")[0] - for path in os.listdir(self.path) - if all( - [ - path != "priors", - len(path.split(".")[0]) != 0, - os.path.isdir(f"{self.path}/{path}") - or path.endswith(".ini") - or path.endswith(".yaml") - or path.endswith(".yml"), - ] - ) - ] - except FileNotFoundError as e: - raise KeyError(f"No configuration found at {self.path}") from e - - def __init__(self, path): - self.path = Path(path) - - def __eq__(self, other): - return str(self) == str(other) - - def __str__(self): - return str(self.path) - - def __repr__(self): - return f"<{self.__class__.__name__} {self.path}>" - - def _getitem(self, item): - item_path = self.path / f"{item}" - file_path = f"{item_path}.ini" - if os.path.isfile(file_path): - return NamedConfig(file_path) - yml_path = item_path.with_suffix(".yml") - if yml_path.exists(): - return YAMLConfig(yml_path) - yaml_path = item_path.with_suffix(".yaml") - if yaml_path.exists(): - return YAMLConfig(yaml_path) - if os.path.isdir(item_path): - return RecursiveConfig(item_path) - raise KeyError(f"No configuration found for {item} at path {self.path}") - - -class PriorConfigWrapper: - def __init__(self, prior_configs): - self.prior_configs = prior_configs - - def for_class_and_suffix_path(self, cls, path): - for config in self.prior_configs: - try: - return config.for_class_and_suffix_path(cls, path) - except KeyError: - pass - directories = " ".join(str(config.directory) for config in self.prior_configs) - - print() - - raise exc.ConfigException( - f"No prior config found for class: \n\n" - f"{cls.__name__} \n\n" - f"For parameter name and path: \n\n " - f"{'.'.join(path)} \n\n " - f"In any of the following directories:\n\n" - f"{directories}\n\n" - f"Either add configuration for the parameter or a type annotation for a class with valid configuration.\n\n" - f"The following readthedocs page explains prior configuration files in PyAutoFit and will help you fix " - f"the error https://pyautofit.readthedocs.io/en/latest/general/adding_a_model_component.html" - ) - - -def family(current_class): - yield current_class - for next_class in current_class.__bases__: - for val in family(next_class): - yield val +import configparser +import os +from abc import abstractmethod, ABC +from pathlib import Path + +import yaml + +from autoconf import exc + + +class AbstractConfig(ABC): + @abstractmethod + def _getitem(self, item): + pass + + def __getitem__(self, item): + if isinstance(item, int): + return self.items()[item] + return self._getitem(item) + + def items(self): + return [(key, self[key]) for key in self.keys()] + + def __len__(self): + return len(self.items()) + + @abstractmethod + def keys(self): + pass + + def family(self, cls): + for cls in family(cls): + key = cls.__name__ + try: + return self[key] + except (KeyError, configparser.NoOptionError): + pass + raise KeyError(f"No configuration found for {cls.__name__}") + + def dict(self): + d = {} + for key in self.keys(): + value = self[key] + if isinstance(value, AbstractConfig): + value = value.dict() + d[key] = value + return d + + +class DictConfig(AbstractConfig): + def keys(self): + return self.d.keys() + + def __init__(self, d): + self.d = d + + def __getitem__(self, item): + value = self.d[item] + if isinstance(value, dict): + return DictConfig(value) + return value + + def _getitem(self, item): + return self[item] + + def items(self): + for key in self.d: + yield key, self[key] + + +class YAMLConfig(AbstractConfig): + def __init__(self, path): + with open(path) as f: + self._dict = yaml.safe_load(f) + + def _getitem(self, item): + value = self._dict[item] + if isinstance(value, dict): + return DictConfig(value) + return value + + def keys(self): + return self._dict.keys() + + +class SectionConfig(AbstractConfig): + def __init__(self, path, parser, section): + self.path = path + self.section = section + self.parser = parser + + def keys(self): + with open(self.path) as f: + string = f.read() + + lines = string.split("\n") + is_section = False + for line in lines: + if line == f"[{self.section}]": + is_section = True + continue + if line.startswith("["): + is_section = False + continue + if is_section and "=" in line: + yield line.split("=")[0] + + def _getitem(self, item): + try: + result = self.parser.get(self.section, item) + if result.lower() == "true": + return True + if result.lower() == "false": + return False + if result.lower() in ("none", "null"): + return None + if result.isdigit(): + return int(result) + try: + return float(result) + except ValueError: + return result + except (configparser.NoSectionError, configparser.NoOptionError): + raise KeyError(f"No configuration found for {item} at path {self.path}") + + +class NamedConfig(AbstractConfig): + def __init__(self, config_path): + """ + Parses generic config + + Parameters + ---------- + config_path + The path to the config file + """ + self.path = config_path + self.parser = configparser.ConfigParser() + self.parser.read(self.path) + + def keys(self): + return self.parser.sections() + + def _getitem(self, item): + return SectionConfig( + self.path, + self.parser, + item, + ) + + +class RecursiveConfig(AbstractConfig): + def keys(self): + try: + return [ + path.split(".")[0] + for path in os.listdir(self.path) + if all( + [ + path != "priors", + len(path.split(".")[0]) != 0, + os.path.isdir(f"{self.path}/{path}") + or path.endswith(".ini") + or path.endswith(".yaml") + or path.endswith(".yml"), + ] + ) + ] + except FileNotFoundError as e: + raise KeyError(f"No configuration found at {self.path}") from e + + def __init__(self, path): + self.path = Path(path) + + def __eq__(self, other): + return str(self) == str(other) + + def __str__(self): + return str(self.path) + + def __repr__(self): + return f"<{self.__class__.__name__} {self.path}>" + + def _getitem(self, item): + item_path = self.path / f"{item}" + file_path = f"{item_path}.ini" + if os.path.isfile(file_path): + return NamedConfig(file_path) + yml_path = item_path.with_suffix(".yml") + if yml_path.exists(): + return YAMLConfig(yml_path) + yaml_path = item_path.with_suffix(".yaml") + if yaml_path.exists(): + return YAMLConfig(yaml_path) + if os.path.isdir(item_path): + return RecursiveConfig(item_path) + raise KeyError(f"No configuration found for {item} at path {self.path}") + + +class PriorConfigWrapper: + def __init__(self, prior_configs): + self.prior_configs = prior_configs + + def for_class_and_suffix_path(self, cls, path): + for config in self.prior_configs: + try: + return config.for_class_and_suffix_path(cls, path) + except KeyError: + pass + directories = " ".join(str(config.directory) for config in self.prior_configs) + + print() + + raise exc.ConfigException( + f"No prior config found for class: \n\n" + f"{cls.__name__} \n\n" + f"For parameter name and path: \n\n " + f"{'.'.join(path)} \n\n " + f"In any of the following directories:\n\n" + f"{directories}\n\n" + f"Either add configuration for the parameter or a type annotation for a class with valid configuration.\n\n" + f"The following readthedocs page explains prior configuration files in PyAutoFit and will help you fix " + f"the error https://pyautofit.readthedocs.io/en/latest/general/adding_a_model_component.html" + ) + + +def family(current_class): + yield current_class + for next_class in current_class.__bases__: + for val in family(next_class): + yield val diff --git a/autoconf/fitsable.py b/autoconf/fitsable.py index 9901630..fae5784 100644 --- a/autoconf/fitsable.py +++ b/autoconf/fitsable.py @@ -109,6 +109,12 @@ def hdu_list_for_output_from( if ext_name_list is not None: header["EXTNAME"] = ext_name_list[i].upper() + # Convert from JAX + try: + values = np.array(values.array) + except AttributeError: + values = np.array(values) + values = flip_for_ds9_from(values) if i == 0: diff --git a/autoconf/output.py b/autoconf/output.py index 775ec4d..fc44fc6 100644 --- a/autoconf/output.py +++ b/autoconf/output.py @@ -1,64 +1,64 @@ -from functools import wraps -from typing import Callable -import logging - -from autoconf.conf import instance - -logger = logging.getLogger(__name__) - - -def should_output(name: str) -> bool: - """ - Determine whether a file with a given name (excluding extension) should be output. - - This is configured in config/output.yaml. If the file is not present in the config, the default value is used. - - Parameters - ---------- - name - The name of the file to be output, excluding extension. - - Returns - ------- - Whether the file should be output. - """ - output_config = instance["output"] - try: - return output_config[name] - except KeyError: - return output_config["default"] - - -def conditional_output(func: Callable): - """ - Decorator for functions that output files. If the file should not be output, the function is not called. - - Parameters - ---------- - func - A method where the first argument is the name of the file to be output. - - Returns - ------- - The decorated function. - """ - - @wraps(func) - def wrapper(self, name: str, *args, **kwargs): - """ - Conditionally call the decorated function if the file should be output according - to the config. - - Parameters - ---------- - self - name - The name of the file to be output, excluding extension. - args - kwargs - """ - if should_output(name): - return func(self, name, *args, **kwargs) - logger.info(f"Skipping output of {name}") - - return wrapper +from functools import wraps +from typing import Callable +import logging + +from autoconf.conf import instance + +logger = logging.getLogger(__name__) + + +def should_output(name: str) -> bool: + """ + Determine whether a file with a given name (excluding extension) should be output. + + This is configured in config/output.yaml. If the file is not present in the config, the default value is used. + + Parameters + ---------- + name + The name of the file to be output, excluding extension. + + Returns + ------- + Whether the file should be output. + """ + output_config = instance["output"] + try: + return output_config[name] + except KeyError: + return output_config["default"] + + +def conditional_output(func: Callable): + """ + Decorator for functions that output files. If the file should not be output, the function is not called. + + Parameters + ---------- + func + A method where the first argument is the name of the file to be output. + + Returns + ------- + The decorated function. + """ + + @wraps(func) + def wrapper(self, name: str, *args, **kwargs): + """ + Conditionally call the decorated function if the file should be output according + to the config. + + Parameters + ---------- + self + name + The name of the file to be output, excluding extension. + args + kwargs + """ + if should_output(name): + return func(self, name, *args, **kwargs) + logger.info(f"Skipping output of {name}") + + return wrapper diff --git a/autoconf/tools/decorators.py b/autoconf/tools/decorators.py index a1b5fb8..dc493a6 100644 --- a/autoconf/tools/decorators.py +++ b/autoconf/tools/decorators.py @@ -19,3 +19,68 @@ def __get__(self, obj, cls): cached_property = CachedProperty + + + + + +# The is sourced from: torch.distributions.util.py +# +# Copyright (c) 2016- Facebook, Inc (Adam Paszke) +# Copyright (c) 2014- Facebook, Inc (Soumith Chintala) +# Copyright (c) 2011-2014 Idiap Research Institute (Ronan Collobert) +# Copyright (c) 2012-2014 Deepmind Technologies (Koray Kavukcuoglu) +# Copyright (c) 2011-2012 NEC Laboratories America (Koray Kavukcuoglu) +# Copyright (c) 2011-2013 NYU (Clement Farabet) +# Copyright (c) 2006-2010 NEC Laboratories America (Ronan Collobert, Leon Bottou, Iain Melvin, Jason Weston) +# Copyright (c) 2006 Idiap Research Institute (Samy Bengio) +# Copyright (c) 2001-2004 Idiap Research Institute (Ronan Collobert, Samy Bengio, Johnny Mariethoz) +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from jax.core import Tracer +from functools import update_wrapper + +def not_jax_tracer(x): + """ + Checks if `x` is not an array generated inside `jit`, `pmap`, `vmap`, or `lax_control_flow`. + """ + return not isinstance(x, Tracer) + + +def identity(x, *args, **kwargs): + return x + +class lazy_property(object): + r""" + Used as a decorator for lazy loading of class attributes. This uses a + non-data descriptor that calls the wrapped method to compute the property on + first call; thereafter replacing the wrapped method into an instance + attribute. + """ + + def __init__(self, wrapped): + self.wrapped = wrapped + update_wrapper(self, wrapped) + + # This is to prevent warnings from sphinx + def __call__(self, *args, **kwargs): + return self.wrapped(*args, **kwargs) + + def __get__(self, instance, obj_type=None): + if instance is None: + return self + value = self.wrapped(instance) + if not_jax_tracer(value): + setattr(instance, self.wrapped.__name__, value) + return value \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 2219694..ee75b39 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -typing-inspect>=0.4.0 -pathlib -PyYAML>=6.0.1 -numpy>=1.24.0,<=2.0.1 +typing-inspect>=0.4.0 +pathlib +PyYAML>=6.0.1 +numpy>=1.24.0,<=2.0.1 diff --git a/scripts/convert_config.py b/scripts/convert_config.py index 4c8f6f6..f7abba7 100755 --- a/scripts/convert_config.py +++ b/scripts/convert_config.py @@ -1,37 +1,37 @@ -#!/usr/bin/env python -""" -Converts the configuration files and directories in a given directory into YAML configs. - -Usage: -./convert_config.py path/to/directory -""" - -import os -import shutil -import sys -from pathlib import Path - -import yaml - -from autoconf.directory_config import RecursiveConfig, YAMLConfig - -target_path = Path(sys.argv[1]) - -config = RecursiveConfig(str(target_path)) - -for key in config.keys(): - value = config[key] - if isinstance(value, YAMLConfig): - continue - - d = value.dict() - path = target_path / key - with open(path.with_suffix(".yaml"), "w") as f: - yaml.dump(d, f) - - try: - os.remove(path.with_suffix(".ini")) - except FileNotFoundError: - pass - - shutil.rmtree(path, ignore_errors=True) +#!/usr/bin/env python +""" +Converts the configuration files and directories in a given directory into YAML configs. + +Usage: +./convert_config.py path/to/directory +""" + +import os +import shutil +import sys +from pathlib import Path + +import yaml + +from autoconf.directory_config import RecursiveConfig, YAMLConfig + +target_path = Path(sys.argv[1]) + +config = RecursiveConfig(str(target_path)) + +for key in config.keys(): + value = config[key] + if isinstance(value, YAMLConfig): + continue + + d = value.dict() + path = target_path / key + with open(path.with_suffix(".yaml"), "w") as f: + yaml.dump(d, f) + + try: + os.remove(path.with_suffix(".ini")) + except FileNotFoundError: + pass + + shutil.rmtree(path, ignore_errors=True) diff --git a/scripts/convert_prior_configs.py b/scripts/convert_prior_configs.py index f105729..5cb4fbd 100755 --- a/scripts/convert_prior_configs.py +++ b/scripts/convert_prior_configs.py @@ -1,55 +1,55 @@ -#!/usr/bin/env python -""" -Converts JSON prior configs to YAML equivalent. - -Usage: -./convert_prior_configs.py /path/to/prior/directory -""" -import json -import os -import sys -from pathlib import Path - -import oyaml as yaml - -ORDER = [ - "type", - "mean", - "sigma", - "lower_limit", - "upper_limit", - "width_modifier", - "gaussian_limits", -] - -for path in Path(sys.argv[1]).rglob("*.json"): - with open(path) as f: - d = json.load(f) - - with open(path.with_suffix(".yaml"), "w") as f: - yaml.dump(d, f) - - os.remove(path) - - -def sort_dict(obj): - if isinstance(obj, dict): - return { - key: sort_dict(value) - for key, value in sorted( - obj.items(), - key=lambda item: ORDER.index(item[0]) if item[0] in ORDER else 999, - ) - } - if isinstance(obj, list): - return list(map(sort_dict, obj)) - return obj - - -for path in Path(sys.argv[1]).rglob("*.yaml"): - with open(path) as f: - d = yaml.safe_load(f) - - print(sort_dict(d)) - with open(path, "w") as f: - yaml.dump(sort_dict(d), f) +#!/usr/bin/env python +""" +Converts JSON prior configs to YAML equivalent. + +Usage: +./convert_prior_configs.py /path/to/prior/directory +""" +import json +import os +import sys +from pathlib import Path + +import oyaml as yaml + +ORDER = [ + "type", + "mean", + "sigma", + "lower_limit", + "upper_limit", + "width_modifier", + "gaussian_limits", +] + +for path in Path(sys.argv[1]).rglob("*.json"): + with open(path) as f: + d = json.load(f) + + with open(path.with_suffix(".yaml"), "w") as f: + yaml.dump(d, f) + + os.remove(path) + + +def sort_dict(obj): + if isinstance(obj, dict): + return { + key: sort_dict(value) + for key, value in sorted( + obj.items(), + key=lambda item: ORDER.index(item[0]) if item[0] in ORDER else 999, + ) + } + if isinstance(obj, list): + return list(map(sort_dict, obj)) + return obj + + +for path in Path(sys.argv[1]).rglob("*.yaml"): + with open(path) as f: + d = yaml.safe_load(f) + + print(sort_dict(d)) + with open(path, "w") as f: + yaml.dump(sort_dict(d), f) diff --git a/test_autoconf/files/config/embedded.yaml b/test_autoconf/files/config/embedded.yaml index 697fad1..9b93dd9 100644 --- a/test_autoconf/files/config/embedded.yaml +++ b/test_autoconf/files/config/embedded.yaml @@ -1,4 +1,4 @@ -first: - first_a: - first_a_a: one - first_a_c: three +first: + first_a: + first_a_a: one + first_a_c: three diff --git a/test_autoconf/files/config/logging.yaml b/test_autoconf/files/config/logging.yaml index 0e803c6..6bd8722 100644 --- a/test_autoconf/files/config/logging.yaml +++ b/test_autoconf/files/config/logging.yaml @@ -1,12 +1,12 @@ -name: config -version: 1 -disable_existing_loggers: false -handlers: - console: - class: logging.StreamHandler - level: WARN - stream: ext://sys.stdout - -root: - level: INFO - handlers: [ console ] +name: config +version: 1 +disable_existing_loggers: false +handlers: + console: + class: logging.StreamHandler + level: WARN + stream: ext://sys.stdout + +root: + level: INFO + handlers: [ console ] diff --git a/test_autoconf/files/config/one/two.ini b/test_autoconf/files/config/one/two.ini index 2277aba..727638f 100644 --- a/test_autoconf/files/config/one/two.ini +++ b/test_autoconf/files/config/one/two.ini @@ -1,3 +1,3 @@ -[three] -four=five +[three] +four=five six=seven \ No newline at end of file diff --git a/test_autoconf/files/config/output.yaml b/test_autoconf/files/config/output.yaml index 1362a9c..1525237 100644 --- a/test_autoconf/files/config/output.yaml +++ b/test_autoconf/files/config/output.yaml @@ -1,3 +1,3 @@ -should_output: true -should_not_output: false +should_output: true +should_not_output: false default: true \ No newline at end of file diff --git a/test_autoconf/files/config/priors/subdirectory/subconfig.yaml b/test_autoconf/files/config/priors/subdirectory/subconfig.yaml index 0dbe2c4..de92798 100644 --- a/test_autoconf/files/config/priors/subdirectory/subconfig.yaml +++ b/test_autoconf/files/config/priors/subdirectory/subconfig.yaml @@ -1,5 +1,5 @@ -SubClass: - variable: - type: Uniform - lower_limit: 0.0 +SubClass: + variable: + type: Uniform + lower_limit: 0.0 upper_limit: 3.0 \ No newline at end of file diff --git a/test_autoconf/files/config/priors/test_yaml_config.yaml b/test_autoconf/files/config/priors/test_yaml_config.yaml index 798c786..5ffbad5 100644 --- a/test_autoconf/files/config/priors/test_yaml_config.yaml +++ b/test_autoconf/files/config/priors/test_yaml_config.yaml @@ -1,5 +1,5 @@ -YAMLClass: - variable: - type: Uniform - lower_limit: 0.0 +YAMLClass: + variable: + type: Uniform + lower_limit: 0.0 upper_limit: 3.0 \ No newline at end of file diff --git a/test_autoconf/files/default/embedded.yaml b/test_autoconf/files/default/embedded.yaml index 6c56ed7..6e78077 100644 --- a/test_autoconf/files/default/embedded.yaml +++ b/test_autoconf/files/default/embedded.yaml @@ -1,4 +1,4 @@ -first: - first_a: - first_a_a: one +first: + first_a: + first_a_a: one first_a_b: two \ No newline at end of file diff --git a/test_autoconf/files/default/logging.yaml b/test_autoconf/files/default/logging.yaml index 8d93b7f..2b5c6ba 100644 --- a/test_autoconf/files/default/logging.yaml +++ b/test_autoconf/files/default/logging.yaml @@ -1,12 +1,12 @@ -name: default -version: 1 -disable_existing_loggers: false -handlers: - console: - class: logging.StreamHandler - level: WARN - stream: ext://sys.stdout - -root: - level: INFO - handlers: [ console ] +name: default +version: 1 +disable_existing_loggers: false +handlers: + console: + class: logging.StreamHandler + level: WARN + stream: ext://sys.stdout + +root: + level: INFO + handlers: [ console ] diff --git a/test_autoconf/files/default/one.yaml b/test_autoconf/files/default/one.yaml index 426842b..28c3c61 100644 --- a/test_autoconf/files/default/one.yaml +++ b/test_autoconf/files/default/one.yaml @@ -1,4 +1,4 @@ -two: - three: - four: five +two: + three: + four: five eight: nine \ No newline at end of file diff --git a/test_autoconf/json_prior/source_code/subdirectory/subconfig.py b/test_autoconf/json_prior/source_code/subdirectory/subconfig.py index fcaf5ca..15380e1 100644 --- a/test_autoconf/json_prior/source_code/subdirectory/subconfig.py +++ b/test_autoconf/json_prior/source_code/subdirectory/subconfig.py @@ -1,3 +1,3 @@ -class SubClass: - def __init__(self, variable: float): - self.variable = variable +class SubClass: + def __init__(self, variable: float): + self.variable = variable diff --git a/test_autoconf/json_prior/test_yaml_config.py b/test_autoconf/json_prior/test_yaml_config.py index cbbc20e..fb8994a 100644 --- a/test_autoconf/json_prior/test_yaml_config.py +++ b/test_autoconf/json_prior/test_yaml_config.py @@ -1,27 +1,27 @@ -from .source_code.subdirectory.subconfig import SubClass - - -class YAMLClass: - def __init__(self, variable: float): - self.variable = variable - - -def test_load_yaml_config(config): - assert config.prior_config.for_class_and_suffix_path(YAMLClass, ["variable"]) == { - "lower_limit": 0.0, - "type": "Uniform", - "upper_limit": 3.0, - } - - -def test_embedded_path(config): - path_value_map = config.prior_config.prior_configs[0].path_value_map - assert "subdirectory.subconfig.SubClass.variable.type" in path_value_map - - -def test_subdirectory(config): - assert config.prior_config.for_class_and_suffix_path(SubClass, ["variable"]) == { - "lower_limit": 0.0, - "type": "Uniform", - "upper_limit": 3.0, - } +from .source_code.subdirectory.subconfig import SubClass + + +class YAMLClass: + def __init__(self, variable: float): + self.variable = variable + + +def test_load_yaml_config(config): + assert config.prior_config.for_class_and_suffix_path(YAMLClass, ["variable"]) == { + "lower_limit": 0.0, + "type": "Uniform", + "upper_limit": 3.0, + } + + +def test_embedded_path(config): + path_value_map = config.prior_config.prior_configs[0].path_value_map + assert "subdirectory.subconfig.SubClass.variable.type" in path_value_map + + +def test_subdirectory(config): + assert config.prior_config.for_class_and_suffix_path(SubClass, ["variable"]) == { + "lower_limit": 0.0, + "type": "Uniform", + "upper_limit": 3.0, + } diff --git a/test_autoconf/test_decorator.py b/test_autoconf/test_decorator.py index e8ebfa9..44bac15 100644 --- a/test_autoconf/test_decorator.py +++ b/test_autoconf/test_decorator.py @@ -1,19 +1,19 @@ -import pytest - -from autoconf import conf -from autoconf.conf import with_config - - -@pytest.fixture(autouse=True) -def push_configs(files_directory): - conf.instance.push(files_directory / "config") - conf.instance.push(files_directory / "default") - - -@with_config("general", "output", "identifier_version", value=9) -def test_with_config(): - assert conf.instance["general"]["output"]["identifier_version"] == 9 - - -def test_config(): - assert conf.instance["general"]["output"]["identifier_version"] == 4 +import pytest + +from autoconf import conf +from autoconf.conf import with_config + + +@pytest.fixture(autouse=True) +def push_configs(files_directory): + conf.instance.push(files_directory / "config") + conf.instance.push(files_directory / "default") + + +@with_config("general", "output", "identifier_version", value=9) +def test_with_config(): + assert conf.instance["general"]["output"]["identifier_version"] == 9 + + +def test_config(): + assert conf.instance["general"]["output"]["identifier_version"] == 4 diff --git a/test_autoconf/test_default.py b/test_autoconf/test_default.py index 6dd6c37..821c6b9 100644 --- a/test_autoconf/test_default.py +++ b/test_autoconf/test_default.py @@ -1,88 +1,88 @@ -from autoconf.mock.mock_real import Redshift - - -def test_override_file(config): - hpc = config["general"]["hpc"] - - assert hpc["hpc_mode"] is False - assert hpc["default_field"] == "hello" - - -def test_logging_config(config, files_directory): - assert config.logging_config["name"] == "config" - - config.push(files_directory / "default") - assert config.logging_config["name"] == "default" - - -def test_push(config, files_directory): - assert len(config.configs) == 2 - assert config["general"]["hpc"]["hpc_mode"] is False - - config.push(files_directory / "default") - - assert len(config.configs) == 2 - assert config["general"]["hpc"]["hpc_mode"] is True - - config.push(files_directory / "config") - - assert len(config.configs) == 2 - assert config["general"]["hpc"]["hpc_mode"] is False - - -def test_keep_first(config, files_directory): - config.push(files_directory / "default", keep_first=True) - - assert config["general"]["hpc"]["hpc_mode"] is False - - -def test_override_in_directory(config): - superscript = config["text"]["label"]["superscript"] - - assert superscript["Galaxy"] == "g" - assert superscript["default_field"] == "label default" - - -def test_novel_directory(config): - assert config["default"]["other"]["section"]["key"] == "value" - - -def test_novel_file(config): - assert config["default_file"]["section"]["key"] == "file value" - - -def test_json(config): - assert ( - config.prior_config.for_class_and_suffix_path(Redshift, ["redshift"])[ - "upper_limit" - ] - == 3.0 - ) - assert ( - config.prior_config.for_class_and_suffix_path(Redshift, ["rodshift"])[ - "upper_limit" - ] - == 4.0 - ) - - -def test_embedded_yaml_default(config): - embedded_dict = config["embedded"]["first"]["first_a"] - - assert embedded_dict["first_a_a"] == "one" - assert embedded_dict["first_a_b"] == "two" - assert embedded_dict["first_a_c"] == "three" - - -def test_as_dict(config): - embedded_dict = config["embedded"]["first"]["first_a"] - - assert {**embedded_dict} - - -def test_mix_files(config): - embedded_dict = config["one"]["two"]["three"] - - assert embedded_dict["four"] == "five" - assert embedded_dict["six"] == "seven" - assert embedded_dict["eight"] == "nine" +from autoconf.mock.mock_real import Redshift + + +def test_override_file(config): + hpc = config["general"]["hpc"] + + assert hpc["hpc_mode"] is False + assert hpc["default_field"] == "hello" + + +def test_logging_config(config, files_directory): + assert config.logging_config["name"] == "config" + + config.push(files_directory / "default") + assert config.logging_config["name"] == "default" + + +def test_push(config, files_directory): + assert len(config.configs) == 2 + assert config["general"]["hpc"]["hpc_mode"] is False + + config.push(files_directory / "default") + + assert len(config.configs) == 2 + assert config["general"]["hpc"]["hpc_mode"] is True + + config.push(files_directory / "config") + + assert len(config.configs) == 2 + assert config["general"]["hpc"]["hpc_mode"] is False + + +def test_keep_first(config, files_directory): + config.push(files_directory / "default", keep_first=True) + + assert config["general"]["hpc"]["hpc_mode"] is False + + +def test_override_in_directory(config): + superscript = config["text"]["label"]["superscript"] + + assert superscript["Galaxy"] == "g" + assert superscript["default_field"] == "label default" + + +def test_novel_directory(config): + assert config["default"]["other"]["section"]["key"] == "value" + + +def test_novel_file(config): + assert config["default_file"]["section"]["key"] == "file value" + + +def test_json(config): + assert ( + config.prior_config.for_class_and_suffix_path(Redshift, ["redshift"])[ + "upper_limit" + ] + == 3.0 + ) + assert ( + config.prior_config.for_class_and_suffix_path(Redshift, ["rodshift"])[ + "upper_limit" + ] + == 4.0 + ) + + +def test_embedded_yaml_default(config): + embedded_dict = config["embedded"]["first"]["first_a"] + + assert embedded_dict["first_a_a"] == "one" + assert embedded_dict["first_a_b"] == "two" + assert embedded_dict["first_a_c"] == "three" + + +def test_as_dict(config): + embedded_dict = config["embedded"]["first"]["first_a"] + + assert {**embedded_dict} + + +def test_mix_files(config): + embedded_dict = config["one"]["two"]["three"] + + assert embedded_dict["four"] == "five" + assert embedded_dict["six"] == "seven" + assert embedded_dict["eight"] == "nine" diff --git a/test_autoconf/test_output_config.py b/test_autoconf/test_output_config.py index 59a7537..87adab1 100644 --- a/test_autoconf/test_output_config.py +++ b/test_autoconf/test_output_config.py @@ -1,46 +1,46 @@ -import pytest - -from autoconf import instance -from autoconf.conf import with_config -from autoconf.output import conditional_output - - -class OutputClass: - def __init__(self): - self.output_names = [] - - @conditional_output - def output_function(self, name): - self.output_names.append(name) - - -@pytest.fixture(name="output_class") -def make_output_class(): - return OutputClass() - - -@pytest.fixture(autouse=True) -def add_config(files_directory): - instance.push(files_directory / "config") - - -def test_output(output_class): - output_class.output_function("should_output") - assert output_class.output_names == ["should_output"] - - -def test_no_output(output_class): - output_class.output_function("should_not_output") - assert output_class.output_names == [] - - -@with_config("output", "default", value=True) -def test_default_true(output_class): - output_class.output_function("other") - assert output_class.output_names == ["other"] - - -@with_config("output", "default", value=False) -def test_default_false(output_class): - output_class.output_function("other") - assert output_class.output_names == [] +import pytest + +from autoconf import instance +from autoconf.conf import with_config +from autoconf.output import conditional_output + + +class OutputClass: + def __init__(self): + self.output_names = [] + + @conditional_output + def output_function(self, name): + self.output_names.append(name) + + +@pytest.fixture(name="output_class") +def make_output_class(): + return OutputClass() + + +@pytest.fixture(autouse=True) +def add_config(files_directory): + instance.push(files_directory / "config") + + +def test_output(output_class): + output_class.output_function("should_output") + assert output_class.output_names == ["should_output"] + + +def test_no_output(output_class): + output_class.output_function("should_not_output") + assert output_class.output_names == [] + + +@with_config("output", "default", value=True) +def test_default_true(output_class): + output_class.output_function("other") + assert output_class.output_names == ["other"] + + +@with_config("output", "default", value=False) +def test_default_false(output_class): + output_class.output_function("other") + assert output_class.output_names == []