Ejemplo n.º 1
0
def query(data, **options):
    """
    Filter data with given JMESPath expression.

    See also: https://github.com/jmespath/jmespath.py and http://jmespath.org.

    :param data: Target object (a dict or a dict-like object) to query
    :param options:
        Keyword option may include 'ac_query' which is a string represents
        JMESPath expression.

    :return: Maybe queried result data, primitive (int, str, ...) or dict
    """
    expression = options.get("ac_query", None)
    if expression is None or not expression:
        return data

    try:
        pexp = jmespath.compile(expression)
        return pexp.search(data)
    except ValueError as exc:  # jmespath.exceptions.*Error inherit from it.
        LOGGER.warning("Failed to compile or search: exp=%s, exc=%r",
                       expression, exc)
    except (NameError, AttributeError):
        LOGGER.warning("Filter module (jmespath) is not available. "
                       "Do nothing.")

    return data
Ejemplo n.º 2
0
def _maybe_validated(cnf, schema, format_checker=None, **options):
    """
    :param cnf: Configuration object
    :param schema: JSON schema object
    :param format_checker: A format property checker object of which class is
        inherited from jsonschema.FormatChecker, it's default if None given.
    :param options: Keyword options such as:

        - ac_namedtuple: Convert result to nested namedtuple object if True

    :return: Given `cnf` as it is if validation succeeds else None
    """
    valid = True
    if schema:
        (valid, msg) = validate(cnf, schema, format_checker=format_checker,
                                safe=True)
        if msg:
            LOGGER.warning(msg)

    if valid:
        if options.get("ac_namedtuple", False):
            return anyconfig.mdicts.convert_to(cnf, ac_namedtuple=True)
        else:
            return cnf

    return None
Ejemplo n.º 3
0
def _maybe_validated(cnf, schema, format_checker=None, **options):
    """
    :param cnf: Configuration object
    :param schema: JSON schema object
    :param format_checker: A format property checker object of which class is
        inherited from jsonschema.FormatChecker, it's default if None given.
    :param options: Keyword options such as:

        - ac_namedtuple: Convert result to nested namedtuple object if True

    :return: Given `cnf` as it is if validation succeeds else None
    """
    valid = True
    if schema:
        (valid, msg) = validate(cnf,
                                schema,
                                format_checker=format_checker,
                                safe=True)
        if msg:
            LOGGER.warning(msg)

    if valid:
        if options.get("ac_namedtuple", False):
            return anyconfig.mdicts.convert_to(cnf, ac_namedtuple=True)
        else:
            return cnf

    return None
Ejemplo n.º 4
0
def find_loader(path_or_stream, parser_or_type=None, is_path_=False):
    """
    Find out parser object appropriate to load configuration from a file of
    given path or file or file-like object.

    :param path_or_stream: Configuration file path or file or file-like object
    :param parser_or_type:
        Forced configuration parser type or parser object itself
    :param is_path_: Specify True if given `path_or_stream` is a file path

    :return:
        An instance of a class inherits :class:`~anyconfig.backend.base.Parser`
        or None
    """
    if anyconfig.backends.is_parser(parser_or_type):
        return parser_or_type

    try:
        psr = anyconfig.backends.find_parser(path_or_stream,
                                             forced_type=parser_or_type,
                                             is_path_=is_path_)
        LOGGER.debug("Using config parser: %r [%s]", psr, psr.type())
        return psr()  # TBD: Passing initialization arguments.
    except (ValueError, UnknownParserTypeError, UnknownFileTypeError):
        raise
Ejemplo n.º 5
0
def query(data, **options):
    """
    Filter data with given JMESPath expression.

    See also: https://github.com/jmespath/jmespath.py and http://jmespath.org.

    :parae data: Target object (a dict or a dict-like object) to query
    :param options:
        Keyword option may include 'ac_query' which is a string represents
        JMESPath expression.

    :return: Maybe queried result data, primitive (int, str, ...) or dict
    """
    expression = options.get("ac_query", None)
    if expression is None or not expression:
        return data

    try:
        pexp = jmespath.compile(expression)
        return pexp.search(data)
    except ValueError as exc:  # jmespath.exceptions.*Error inherit from it.
        LOGGER.warning("Failed to compile or search: exp=%s, exc=%r",
                       expression, exc)
    except (NameError, AttributeError):
        LOGGER.warning("Filter module (jmespath) is not available. "
                       "Do nothing.")

    return data
Ejemplo n.º 6
0
def mk_dump_dir_if_not_exist(f):
    """
    Make dir to dump f if that dir does not exist.

    :param f: path of file to dump
    """
    dumpdir = os.path.dirname(f)

    if not os.path.exists(dumpdir):
        logging.debug("Creating output dir as it's not found: " + dumpdir)
        os.makedirs(dumpdir)
Ejemplo n.º 7
0
def mk_dump_dir_if_not_exist(f):
    """
    Make dir to dump f if that dir does not exist.

    :param f: path of file to dump
    """
    dumpdir = os.path.dirname(f)

    if not os.path.exists(dumpdir):
        logging.debug("Creating output dir as it's not found: " + dumpdir)
        os.makedirs(dumpdir)
Ejemplo n.º 8
0
def loads(content,
          ac_parser=None,
          ac_dict=None,
          ac_template=False,
          ac_context=None,
          **options):
    """
    :param content: Configuration file's content (a string)
    :param ac_parser: Forced parser type or ID or parser object
    :param ac_dict:
        callable (function or class) to make mapping object will be returned as
        a result or None. If not given or ac_dict is None, default mapping
        object used to store resutls is dict or
        :class:`collections.OrderedDict` if ac_ordered is True and selected
        backend can keep the order of items in mapping objects.
    :param ac_template: Assume configuration file may be a template file and
        try to compile it AAR if True
    :param ac_context: Context dict to instantiate template
    :param options:
        Optional keyword arguments. See also the description of 'options' in
        :func:`single_load` function.

    :return: Mapping object or any query result might be primitive objects
    :raises: ValueError, UnknownProcessorTypeError
    """
    if ac_parser is None:
        LOGGER.warning("ac_parser was not given but it's must to find correct "
                       "parser to load configurations from string.")
        return None

    psr = find(None, forced_type=ac_parser)
    schema = None
    ac_schema = options.get("ac_schema", None)
    if ac_schema is not None:
        options["ac_schema"] = None
        schema = loads(ac_schema,
                       ac_parser=psr,
                       ac_dict=ac_dict,
                       ac_template=ac_template,
                       ac_context=ac_context,
                       **options)

    if ac_template:
        compiled = anyconfig.template.try_render(content=content,
                                                 ctx=ac_context,
                                                 **options)
        if compiled is not None:
            content = compiled

    cnf = psr.loads(content, ac_dict=ac_dict, **options)
    cnf = _try_validate(cnf, schema, **options)
    return _try_query(cnf, options.get("ac_query", False), **options)
Ejemplo n.º 9
0
def find_loader(path_or_stream, parser_or_type=None, is_path_=False):
    """
    Find out config parser object appropriate to load from a file of given path
    or file/file-like object.

    :param path_or_stream: Configuration file path or file / file-like object
    :param parser_or_type: Forced configuration parser type or parser object
    :param is_path_: True if given `path_or_stream` is a file path

    :return: Config parser instance or None
    """
    if anyconfig.backends.is_parser(parser_or_type):
        return parser_or_type

    (psr, err) = anyconfig.backends.find_parser(path_or_stream, parser_or_type,
                                                is_path_=is_path_)
    if err:
        LOGGER.error(err)

    if psr is None:
        if parser_or_type is None:
            LOGGER.warning("No parser (type) was given!")
        else:
            LOGGER.warning("Parser %s was not found!", str(parser_or_type))
        return None

    LOGGER.debug("Using config parser: %r [%s]", psr, psr.type())
    return psr()  # TBD: Passing initialization arguments.
Ejemplo n.º 10
0
def find_loader(path_or_stream, parser_or_type=None, is_path_=False):
    """
    Find out config parser object appropriate to load from a file of given path
    or file/file-like object.

    :param path_or_stream: Configuration file path or file / file-like object
    :param parser_or_type: Forced configuration parser type or parser object
    :param is_path_: True if given `path_or_stream` is a file path

    :return: Config parser instance or None
    """
    if anyconfig.backends.is_parser(parser_or_type):
        return parser_or_type

    (psr, err) = anyconfig.backends.find_parser(path_or_stream,
                                                parser_or_type,
                                                is_path_=is_path_)
    if err:
        LOGGER.error(err)

    if psr is None:
        if parser_or_type is None:
            LOGGER.warning("No parser (type) was given!")
        else:
            LOGGER.warning("Parser %s was not found!", str(parser_or_type))
        return None

    LOGGER.debug("Using config parser: %r [%s]", psr, psr.type())
    return psr()  # TBD: Passing initialization arguments.
Ejemplo n.º 11
0
def dump(data, path_or_stream, ac_parser=None, **options):
    """
    Save `data` as `path_or_stream`.

    :param data: A mapping object may have configurations data to dump
    :param path_or_stream: Output file path or file / file-like object
    :param ac_parser: Forced parser type or parser object
    :param options:
        Backend specific optional arguments, e.g. {"indent": 2} for JSON
        loader/dumper backend
    """
    dumper = _find_dumper(path_or_stream, ac_parser)
    LOGGER.info("Dumping: %s",
                anyconfig.utils.get_path_from_stream(path_or_stream))
    dumper.dump(data, path_or_stream, **options)
Ejemplo n.º 12
0
def dump(data, config_path, forced_type=None, **kwargs):
    """
    Save `data` as `config_path`.

    :param data: Config data object to dump ::
        anyconfig.mergeabledict.MergeableDict by default
    :param config_path: Output filename
    :param forced_type: Forced configuration parser type
    :param kwargs: Backend specific optional arguments, e.g. {"indent": 2} for
        JSON loader/dumper backend
    """
    dumper = _find_dumper(config_path, forced_type)

    LOGGER.info("Dumping: %s", config_path)
    dumper.dump(data, config_path, **kwargs)
Ejemplo n.º 13
0
def _find_dumper(path_or_stream, ac_parser=None):
    """
    Find configuration parser to dump data.

    :param path_or_stream: Output file path or file / file-like object
    :param ac_parser: Forced parser type or parser object

    :return: Parser-inherited class object
    """
    psr = find_loader(path_or_stream, ac_parser)

    if psr is None or not getattr(psr, "dump", False):
        LOGGER.warning("Dump method not implemented. Fallback to json.Parser")
        psr = anyconfig.backend.json.Parser()

    return psr
Ejemplo n.º 14
0
def _validate(config, schema, format_checker=None):
    """
    Wrapper function for anyconfig.schema.vaildate.

    :param config: Configuration object :: container
    :param schema: JSON schema object :: container
    :param format_checker: A format property checker object of which class is
        inherited from jsonschema.FormatChecker, it's default if None given.

    :return: True if validation suceeds or jsonschema module is not available.
    """
    (ret, msg) = validate(config, schema, format_checker, True)
    if msg:
        LOGGER.warn(msg)

    return ret
Ejemplo n.º 15
0
def _find_dumper(config_path, forced_type=None):
    """
    Find configuration parser to dump data.

    :param config_path: Output filename
    :param forced_type: Forced configuration parser type

    :return: Parser-inherited class object
    """
    cparser = find_loader(config_path, forced_type)

    if cparser is None or not getattr(cparser, "dump", False):
        LOGGER.warn("Dump method not implemented. Fallback to json.Parser")
        cparser = anyconfig.backend.json.Parser()

    return cparser
Ejemplo n.º 16
0
def _find_dumper(path_or_stream, ac_parser=None):
    """
    Find configuration parser to dump data.

    :param path_or_stream: Output file path or file / file-like object
    :param ac_parser: Forced parser type or parser object

    :return: Parser-inherited class object
    """
    psr = find_loader(path_or_stream, ac_parser)

    if psr is None or not getattr(psr, "dump", False):
        LOGGER.warning("Dump method not implemented. Fallback to json.Parser")
        psr = anyconfig.backend.json.Parser()

    return psr
Ejemplo n.º 17
0
def dump(data, path_or_stream, ac_parser=None, **options):
    """
    Save `data` as `path_or_stream`.

    :param data: Config data object (dict[-like] or namedtuple) to dump
    :param path_or_stream: Output file path or file / file-like object
    :param ac_parser: Forced parser type or parser object
    :param options:
        Backend specific optional arguments, e.g. {"indent": 2} for JSON
        loader/dumper backend
    """
    dumper = _find_dumper(path_or_stream, ac_parser)
    LOGGER.info("Dumping: %s",
                anyconfig.utils.get_path_from_stream(path_or_stream))
    if anyconfig.mdicts.is_namedtuple(data):
        data = to_container(data, **options)  # namedtuple -> dict-like
    dumper.dump(data, path_or_stream, **options)
Ejemplo n.º 18
0
def dump(data, path_or_stream, ac_parser=None, **options):
    """
    Save `data` as `path_or_stream`.

    :param data: Config data object (dict[-like] or namedtuple) to dump
    :param path_or_stream: Output file path or file / file-like object
    :param ac_parser: Forced parser type or parser object
    :param options:
        Backend specific optional arguments, e.g. {"indent": 2} for JSON
        loader/dumper backend
    """
    dumper = _find_dumper(path_or_stream, ac_parser)
    LOGGER.info("Dumping: %s",
                anyconfig.utils.get_path_from_stream(path_or_stream))
    if anyconfig.mdicts.is_namedtuple(data):
        data = to_container(data, **options)  # namedtuple -> dict-like
    dumper.dump(data, path_or_stream, **options)
Ejemplo n.º 19
0
def loads(config_content, forced_type=None, ac_template=False, ac_context=None, ac_schema=None, **kwargs):
    """
    :param config_content: Configuration file's content
    :param forced_type: Forced configuration parser type
    :param ignore_missing: Ignore missing config files
    :param ac_template: Assume configuration file may be a template file and
        try to compile it AAR if True
    :param ac_context: Context dict to instantiate template
    :param ac_schema: JSON schema content to validate given config file
    :param kwargs: Backend specific optional arguments, e.g. {"indent": 2} for
        JSON loader/dumper backend

    :return: Dict-like object (instance of
        anyconfig.mergeabledict.MergeableDict by default) supports merge
        operations.
    """
    if forced_type is None:
        LOGGER.warn("No config type was given. Try to parse...")
        return anyconfig.parser.parse(config_content)

    cparser = find_loader(None, forced_type)
    if cparser is None:
        return anyconfig.parser.parse(config_content)

    if ac_schema is not None:
        kwargs["ac_schema"] = None  # Avoid infinit loop
        format_checker = kwargs.get("format_checker", None)
        schema = loads(ac_schema, forced_type, ac_template, ac_context, **kwargs)

    if ac_template:
        try:
            LOGGER.debug("Compiling")
            config_content = anyconfig.template.render_s(config_content, ac_context)
        except Exception as exc:
            LOGGER.debug("Exc=%s", str(exc))
            LOGGER.warn("Failed to compile and fallback to no template " "mode: '%s'", config_content[:50] + "...")

    config = cparser.loads(config_content, **kwargs)

    if ac_schema is not None:
        if not _validate(config, schema, format_checker):
            LOGGER.warn("Validation failed: schema=%s", schema)
            return None

    return config
Ejemplo n.º 20
0
def _try_validate(cnf, schema, **options):
    """
    :param cnf: Mapping object represents configuration data
    :param schema: JSON schema object
    :param options: Keyword options passed to :func:`jsonschema.validate`

    :return: Given 'cnf' as it is if validation succeeds else None
    """
    valid = True
    if schema:
        (valid, msg) = validate(cnf, schema, **options)
        if msg:
            LOGGER.warning(msg)

    if valid:
        return cnf

    return None
Ejemplo n.º 21
0
def _try_validate(cnf, schema, **options):
    """
    :param cnf: Mapping object represents configuration data
    :param schema: JSON schema object
    :param options: Keyword options passed to :func:`~jsonschema.validate`

    :return: Given `cnf` as it is if validation succeeds else None
    """
    valid = True
    if schema:
        (valid, msg) = validate(cnf, schema, **options)
        if msg:
            LOGGER.warning(msg)

    if valid:
        return cnf

    return None
Ejemplo n.º 22
0
def find_loader(path_or_stream, forced_type=None, is_path_=None):
    """
    Find out config parser object appropriate to load from a file of given path
    or file/file-like object.

    :param path_or_stream: Configuration file path or file / file-like object
    :param forced_type: Forced configuration parser type
    :param is_path_: True if given `path_or_stream` is a file path

    :return: Config parser instance or None
    """
    (psr, err) = anyconfig.backends.find_parser(path_or_stream, forced_type, is_path_=is_path_)
    if psr is None:
        LOGGER.error(err)
        return None

    LOGGER.debug("Using config parser of type: %s", psr.type())
    return psr()  # TBD: Passing initialization arguments.
Ejemplo n.º 23
0
def loads(content, ac_parser=None, ac_dict=None, ac_template=False,
          ac_context=None, **options):
    """
    :param content: Configuration file's content (a string)
    :param ac_parser: Forced parser type or ID or parser object
    :param ac_dict:
        callable (function or class) to make mapping object will be returned as
        a result or None. If not given or ac_dict is None, default mapping
        object used to store resutls is dict or
        :class:`collections.OrderedDict` if ac_ordered is True and selected
        backend can keep the order of items in mapping objects.
    :param ac_template: Assume configuration file may be a template file and
        try to compile it AAR if True
    :param ac_context: Context dict to instantiate template
    :param options:
        Optional keyword arguments. See also the description of 'options' in
        :func:`single_load` function.

    :return: Mapping object or any query result might be primitive objects
    :raises: ValueError, UnknownProcessorTypeError
    """
    if ac_parser is None:
        LOGGER.warning("ac_parser was not given but it's must to find correct "
                       "parser to load configurations from string.")
        return None

    psr = find(None, forced_type=ac_parser)
    schema = None
    ac_schema = options.get("ac_schema", None)
    if ac_schema is not None:
        options["ac_schema"] = None
        schema = loads(ac_schema, ac_parser=psr, ac_dict=ac_dict,
                       ac_template=ac_template, ac_context=ac_context,
                       **options)

    if ac_template:
        compiled = anyconfig.template.try_render(content=content,
                                                 ctx=ac_context, **options)
        if compiled is not None:
            content = compiled

    cnf = psr.loads(content, ac_dict=ac_dict, **options)
    cnf = _try_validate(cnf, schema, **options)
    return anyconfig.query.query(cnf, **options)
Ejemplo n.º 24
0
def _single_load(input_,
                 ac_parser=None,
                 ac_template=False,
                 ac_context=None,
                 **options):
    """
    :param input_:
        File path or file or file-like object or pathlib.Path object represents
        the file or a namedtuple 'anyconfig.globals.IOInfo' object represents
        some input to load some data from
    :param ac_parser: Forced parser type or parser object itself
    :param ac_template:
        Assume configuration file may be a template file and try to compile it
        AAR if True
    :param ac_context: A dict presents context to instantiate template
    :param options:
        Optional keyword arguments :func:`single_load` supports except for
        ac_schema and ac_query

    :return: Mapping object
    :raises: ValueError, UnknownProcessorTypeError, UnknownFileTypeError
    """
    ioi = anyconfig.ioinfo.make(input_)
    psr = find(ioi, forced_type=ac_parser)
    filepath = ioi.path

    # .. note::
    #    This will be kept for backward compatibility until 'ignore_missing'
    #    option is deprecated and removed completely.
    if "ignore_missing" in options:
        warnings.warn(
            "keyword option 'ignore_missing' is deprecated, use "
            "'ac_ignore_missing' instead", DeprecationWarning)
        options["ac_ignore_missing"] = options["ignore_missing"]

    LOGGER.info("Loading: %s", filepath)
    if ac_template and filepath is not None:
        content = anyconfig.template.try_render(filepath=filepath,
                                                ctx=ac_context,
                                                **options)
        if content is not None:
            return psr.loads(content, **options)

    return psr.load(ioi, **options)
Ejemplo n.º 25
0
def _maybe_schema(**options):
    """
    :param options: Optional keyword arguments such as

        - ac_template: Assume configuration file may be a template file and try
          to compile it AAR if True
        - ac_context: Mapping object presents context to instantiate template
        - ac_schema: JSON schema file path to validate configuration files
    """
    ac_schema = options.get("ac_schema", None)
    if ac_schema is not None:
        # Try to detect the appropriate as it may be different from the
        # original config file's format, perhaps.
        options["ac_parser"] = None
        options["ac_schema"] = None  # Avoid infinite loop.
        LOGGER.info("Loading schema: %s", ac_schema)
        return load(ac_schema, **options)

    return None
Ejemplo n.º 26
0
def dump(data, path_or_stream, forced_type=None, **kwargs):
    """
    Save `data` as `path_or_stream`.

    :param data: Config data object to dump ::
        anyconfig.mergeabledict.MergeableDict by default
    :param path_or_stream: Output file path or file / file-like object
    :param forced_type: Forced configuration parser type
    :param kwargs: Backend specific optional arguments, e.g. {"indent": 2} for
        JSON loader/dumper backend
    """
    dumper = _find_dumper(path_or_stream, forced_type)

    if _is_path(path_or_stream):
        LOGGER.info("Dumping: %s", path_or_stream)
    else:
        LOGGER.info("Dumping: %s", get_path_from_stream(path_or_stream))

    dumper.dump(data, path_or_stream, **kwargs)
Ejemplo n.º 27
0
def _load_schema(**options):
    """
    :param options: Optional keyword arguments such as

        - ac_template: Assume configuration file may be a template file and try
          to compile it AAR if True
        - ac_context: A dict presents context to instantiate template
        - ac_schema: JSON schema file path to validate given config file
    """
    ac_schema = options.get("ac_schema", None)
    if ac_schema is not None:
        # Try to detect the appropriate as it may be different from the
        # original config file's format, perhaps.
        options["ac_parser"] = None
        options["ac_schema"] = None  # Avoid infinite loop.
        LOGGER.info("Loading schema: %s", ac_schema)
        return load(ac_schema, **options)

    return None
Ejemplo n.º 28
0
def dump(data, out, ac_parser=None, **options):
    """
    Save `data` to `out`.

    :param data: A mapping object may have configurations data to dump
    :param out:
        An output file path or a file or a file-like object or a `pathlib.Path`
        object represents the file or a namedtuple `~anyconfig.globals.IOInfo`
        object represents output to dump some data to.
    :param ac_parser: Forced parser type or parser object
    :param options:
        Backend specific optional arguments, e.g. {"indent": 2} for JSON
        loader/dumper backend

    :raises: ValueError, UnknownParserTypeError, UnknownFileTypeError
    """
    ioi = anyconfig.backends.inspect_io_obj(out, forced_type=ac_parser)
    LOGGER.info("Dumping: %s", ioi.path)
    ioi.processor.dump(data, ioi, **options)
Ejemplo n.º 29
0
def dump(data, out, ac_parser=None, **options):
    """
    Save 'data' to 'out'.

    :param data: A mapping object may have configurations data to dump
    :param out:
        An output file path, a file, a file-like object, :class:`pathlib.Path`
        object represents the file or a namedtuple 'anyconfig.globals.IOInfo'
        object represents output to dump some data to.
    :param ac_parser: Forced parser type or parser object
    :param options:
        Backend specific optional arguments, e.g. {"indent": 2} for JSON
        loader/dumper backend

    :raises: ValueError, UnknownProcessorTypeError, UnknownFileTypeError
    """
    ioi = anyconfig.ioinfo.make(out)
    psr = find(ioi, forced_type=ac_parser)
    LOGGER.info("Dumping: %s", ioi.path)
    psr.dump(data, ioi, **options)
Ejemplo n.º 30
0
def dump(data, out, ac_parser=None, **options):
    """
    Save 'data' to 'out'.

    :param data: A mapping object may have configurations data to dump
    :param out:
        An output file path, a file, a file-like object, :class:`pathlib.Path`
        object represents the file or a namedtuple 'anyconfig.globals.IOInfo'
        object represents output to dump some data to.
    :param ac_parser: Forced parser type or parser object
    :param options:
        Backend specific optional arguments, e.g. {"indent": 2} for JSON
        loader/dumper backend

    :raises: ValueError, UnknownProcessorTypeError, UnknownFileTypeError
    """
    ioi = anyconfig.ioinfo.make(out)
    psr = find(ioi, forced_type=ac_parser)
    LOGGER.info("Dumping: %s", ioi.path)
    psr.dump(data, ioi, **options)
Ejemplo n.º 31
0
def _load_impl(config_fp, sep=_SEP, **kwargs):
    """
    :param config_fp: File or file-like object provides ini-style conf
    :return: Dict or dict-like object represents config values
    """
    config = dict()

    # Optional arguements for configparser.SafeConfigParser{,readfp}
    kwargs_0 = Base.mk_opt_args(("defaults", "dict_type", "allow_no_value"),
                                kwargs)
    kwargs_1 = Base.mk_opt_args(("filename", ), kwargs)

    try:
        try:
            parser = configparser.SafeConfigParser(**kwargs_0)
        except TypeError:
            # It seems ConfigPaser.*ConfigParser in python 2.6 does not support
            # 'allow_no_value' option parameter, and TypeError will be thrown.
            kwargs_0 = Base.mk_opt_args(("defaults", "dict_type"), kwargs)
            parser = configparser.SafeConfigParser(**kwargs_0)

        parser.readfp(config_fp, **kwargs_1)

        if parser.defaults():
            config["DEFAULT"] = dict()

            for k, v in iteritems(parser.defaults()):
                config["DEFAULT"][k] = _parse(v, sep)

        for s in parser.sections():
            config[s] = dict()

            for k, v in parser.items(s):
                config[s][k] = _parse(v, sep)

    except Exception:
        logging.warn(sys.exc_info()[-1])
        raise

    return config
Ejemplo n.º 32
0
def single_load(path_or_stream,
                ac_parser=None,
                ac_template=False,
                ac_context=None,
                **options):
    """
    Load single config file.

    :param path_or_stream: Configuration file path or file / file-like object
    :param ac_parser: Forced parser type or parser object
    :param ac_template: Assume configuration file may be a template file and
        try to compile it AAR if True
    :param ac_context: A dict presents context to instantiate template
    :param options: Optional keyword arguments such as:

        - Common options:

          - ac_namedtuple: Convert result to nested namedtuple object if True
          - ac_schema: JSON schema file path to validate given config file

        - Common backend options:

          - ignore_missing: Ignore and just return empty result if given file
            (``path_or_stream``) does not exist.

        - Backend specific options such as {"indent": 2} for JSON backend

    :return: dict or dict-like object supports merge operations
    """
    is_path_ = is_path(path_or_stream)
    if is_path_:
        path_or_stream = anyconfig.utils.ensure_expandusr(path_or_stream)
        filepath = path_or_stream
    else:
        filepath = anyconfig.utils.get_path_from_stream(path_or_stream)

    psr = find_loader(path_or_stream, ac_parser, is_path_)
    if psr is None:
        return None

    schema = _load_schema(ac_template=ac_template,
                          ac_context=ac_context,
                          **options)
    options["ac_schema"] = None  # It's not needed now.

    LOGGER.info("Loading: %s", filepath)
    if ac_template and filepath is not None:
        try:
            LOGGER.debug("Compiling: %s", filepath)
            content = anyconfig.template.render(filepath, ac_context)
            cnf = psr.loads(content, **options)
            return _maybe_validated(cnf, schema, **options)

        except Exception as exc:
            LOGGER.warning(
                "Failed to compile %s, fallback to no template "
                "mode, exc=%r", path_or_stream, exc)

    cnf = psr.load(path_or_stream, **options)
    return _maybe_validated(cnf, schema, **options)
Ejemplo n.º 33
0
def _load_impl(config_fp, sep=_SEP, **kwargs):
    """
    :param config_fp: File or file-like object provides ini-style conf
    :return: Dict or dict-like object represents config values
    """
    config = dict()

    # Optional arguements for configparser.SafeConfigParser{,readfp}
    kwargs_0 = Base.mk_opt_args(("defaults", "dict_type", "allow_no_value"),
                                kwargs)
    kwargs_1 = Base.mk_opt_args(("filename", ), kwargs)

    try:
        try:
            parser = configparser.SafeConfigParser(**kwargs_0)
        except TypeError:
            # It seems ConfigPaser.*ConfigParser in python 2.6 does not support
            # 'allow_no_value' option parameter, and TypeError will be thrown.
            kwargs_0 = Base.mk_opt_args(("defaults", "dict_type"), kwargs)
            parser = configparser.SafeConfigParser(**kwargs_0)

        parser.readfp(config_fp, **kwargs_1)

        if parser.defaults():
            config["DEFAULT"] = dict()

            for k, v in iteritems(parser.defaults()):
                config["DEFAULT"][k] = _parse(v, sep)

        for s in parser.sections():
            config[s] = dict()

            for k, v in parser.items(s):
                config[s][k] = _parse(v, sep)

    except Exception:
        logging.warn(sys.exc_info()[-1])
        raise

    return config
Ejemplo n.º 34
0
def _single_load(input_, ac_parser=None, ac_template=False,
                 ac_context=None, **options):
    """
    :param input_:
        File path or file or file-like object or pathlib.Path object represents
        the file or a namedtuple 'anyconfig.globals.IOInfo' object represents
        some input to load some data from
    :param ac_parser: Forced parser type or parser object itself
    :param ac_template:
        Assume configuration file may be a template file and try to compile it
        AAR if True
    :param ac_context: A dict presents context to instantiate template
    :param options:
        Optional keyword arguments :func:`single_load` supports except for
        ac_schema and ac_query

    :return: Mapping object
    :raises: ValueError, UnknownProcessorTypeError, UnknownFileTypeError
    """
    ioi = anyconfig.ioinfo.make(input_)
    psr = find(ioi, forced_type=ac_parser)
    filepath = ioi.path

    # .. note::
    #    This will be kept for backward compatibility until 'ignore_missing'
    #    option is deprecated and removed completely.
    if "ignore_missing" in options:
        warnings.warn("keyword option 'ignore_missing' is deprecated, use "
                      "'ac_ignore_missing' instead", DeprecationWarning)
        options["ac_ignore_missing"] = options["ignore_missing"]

    LOGGER.info("Loading: %s", filepath)
    if ac_template and filepath is not None:
        content = anyconfig.template.try_render(filepath=filepath,
                                                ctx=ac_context, **options)
        if content is not None:
            return psr.loads(content, **options)

    return psr.load(ioi, **options)
Ejemplo n.º 35
0
def loads(content,
          ac_parser=None,
          ac_template=False,
          ac_context=None,
          **options):
    """
    :param content: Configuration file's content
    :param ac_parser: Forced parser type or parser object
    :param ac_template: Assume configuration file may be a template file and
        try to compile it AAR if True
    :param ac_context: Context dict to instantiate template
    :param options:
        Optional keyword arguments. See also the description of `options` in
        `single_load` function.

    :return: dict or dict-like object supports merge operations
    """
    msg = "Try parsing with a built-in parser because %s"
    if ac_parser is None:
        LOGGER.warning(msg, "ac_parser was not given.")
        return None

    psr = find_loader(None, ac_parser)
    if psr is None:
        LOGGER.warning(msg, "parser '%s' was not found" % ac_parser)
        return None

    schema = None
    ac_schema = options.get("ac_schema", None)
    if ac_schema is not None:
        options["ac_schema"] = None
        schema = loads(ac_schema,
                       ac_parser=psr,
                       ac_template=ac_template,
                       ac_context=ac_context,
                       **options)

    if ac_template:
        try:
            LOGGER.debug("Compiling")
            content = anyconfig.template.render_s(content, ac_context)
        except Exception as exc:
            LOGGER.warning(
                "Failed to compile and fallback to no template "
                "mode: '%s', exc=%r", content[:50] + '...', exc)

    cnf = psr.loads(content, **options)
    return _maybe_validated(cnf, schema, **options)
Ejemplo n.º 36
0
def single_load(path_or_stream, ac_parser=None, ac_template=False,
                ac_context=None, **options):
    """
    Load single config file.

    :param path_or_stream: Configuration file path or file / file-like object
    :param ac_parser: Forced parser type or parser object
    :param ac_template: Assume configuration file may be a template file and
        try to compile it AAR if True
    :param ac_context: A dict presents context to instantiate template
    :param options: Optional keyword arguments such as:

        - Common options:

          - ac_namedtuple: Convert result to nested namedtuple object if True
          - ac_schema: JSON schema file path to validate given config file

        - Common backend options:

          - ignore_missing: Ignore and just return empty result if given file
            (``path_or_stream``) does not exist.

        - Backend specific options such as {"indent": 2} for JSON backend

    :return: dict or dict-like object supports merge operations
    """
    is_path_ = is_path(path_or_stream)
    if is_path_:
        path_or_stream = anyconfig.utils.ensure_expandusr(path_or_stream)
        filepath = path_or_stream
    else:
        filepath = anyconfig.utils.get_path_from_stream(path_or_stream)

    psr = find_loader(path_or_stream, ac_parser, is_path_)
    if psr is None:
        return None

    schema = _load_schema(ac_template=ac_template, ac_context=ac_context,
                          **options)
    options["ac_schema"] = None  # It's not needed now.

    LOGGER.info("Loading: %s", filepath)
    if ac_template and filepath is not None:
        try:
            LOGGER.debug("Compiling: %s", filepath)
            content = anyconfig.template.render(filepath, ac_context)
            cnf = psr.loads(content, **options)
            return _maybe_validated(cnf, schema, **options)

        except Exception as exc:
            LOGGER.warning("Failed to compile %s, fallback to no template "
                           "mode, exc=%r", path_or_stream, exc)

    cnf = psr.load(path_or_stream, **options)
    return _maybe_validated(cnf, schema, **options)
Ejemplo n.º 37
0
def loads(content, ac_parser=None, ac_template=False, ac_context=None,
          **options):
    """
    :param content: Configuration file's content
    :param ac_parser: Forced parser type or parser object
    :param ac_template: Assume configuration file may be a template file and
        try to compile it AAR if True
    :param ac_context: Context dict to instantiate template
    :param options:
        Optional keyword arguments. See also the description of `options` in
        `single_load` function.

    :return: dict or dict-like object supports merge operations
    """
    msg = "Try parsing with a built-in parser because %s"
    if ac_parser is None:
        LOGGER.warning(msg, "ac_parser was not given.")
        return None

    psr = find_loader(None, ac_parser)
    if psr is None:
        LOGGER.warning(msg, "parser '%s' was not found" % ac_parser)
        return None

    schema = None
    ac_schema = options.get("ac_schema", None)
    if ac_schema is not None:
        options["ac_schema"] = None
        schema = loads(ac_schema, ac_parser=psr, ac_template=ac_template,
                       ac_context=ac_context, **options)

    if ac_template:
        try:
            LOGGER.debug("Compiling")
            content = anyconfig.template.render_s(content, ac_context)
        except Exception as exc:
            LOGGER.warning("Failed to compile and fallback to no template "
                           "mode: '%s', exc=%r", content[:50] + '...', exc)

    cnf = psr.loads(content, **options)
    return _maybe_validated(cnf, schema, **options)
Ejemplo n.º 38
0
def find_loader(config_path, forced_type=None):
    """
    :param config_path: Configuration file path
    :param forced_type: Forced configuration parser type

    :return: Parser-inherited class object
    """
    if forced_type is not None:
        cparser = anyconfig.backends.find_by_type(forced_type)
        if not cparser:
            LOGGER.error("No parser found for given type: %s", forced_type)
            return None
    else:
        cparser = anyconfig.backends.find_by_file(config_path)
        if not cparser:
            LOGGER.error("No parser found for given file: %s", config_path)
            return None

    LOGGER.debug("Using config parser of type: %s", cparser.type())
    return cparser
Ejemplo n.º 39
0
import anyconfig.compat as AC


SUPPORTED = True
try:
    # First, try lxml which is compatible with elementtree and looks faster a
    # lot. See also: http://getpython3.com/diveintopython3/xml.html
    from lxml2 import etree
except ImportError:
    try:
        import xml.etree.ElementTree as etree
    except ImportError:
        try:
            import elementtree.ElementTree as etree
        except ImportError:
            logging.warn("ElementTree module is not available. Disabled "
                         "XML support.")
            SUPPORTED = False


if SUPPORTED:
    def etree_getroot_fromstring(s):
        """
        :param s: A XML string
        :return: etree object gotten by parsing ``s``
        """
        return etree.ElementTree(etree.fromstring(s)).getroot()

    def etree_getroot_fromsrc(src):
        """
        :param src: A file name/path or a file[-like] object or a URL
        :return: etree object gotten by parsing ``s``
Ejemplo n.º 40
0
import anyconfig.backend.base as Base
import anyconfig.compat as AC

SUPPORTED = True
try:
    # First, try lxml which is compatible with elementtree and looks faster a
    # lot. See also: http://getpython3.com/diveintopython3/xml.html
    from lxml2 import etree
except ImportError:
    try:
        import xml.etree.ElementTree as etree
    except ImportError:
        try:
            import elementtree.ElementTree as etree
        except ImportError:
            logging.warn("ElementTree module is not available. Disabled "
                         "XML support.")
            SUPPORTED = False

if SUPPORTED:

    def etree_getroot_fromstring(s):
        """
        :param s: A XML string
        :return: etree object gotten by parsing ``s``
        """
        return etree.ElementTree(etree.fromstring(s)).getroot()

    def etree_getroot_fromsrc(src):
        """
        :param src: A file name/path or a file[-like] object or a URL
        :return: etree object gotten by parsing ``s``
Ejemplo n.º 41
0
def set_loglevel(level):
    """
    :param level: Log level, e.g. logging.INFO and logging.WARN.
    """
    LOGGER.setLevel(level)
Ejemplo n.º 42
0
#
# Copyright (C) 2011 - 2013 Satoru SATOH <ssato @ redhat.com>
# License: MIT
#
from anyconfig.globals import LOGGER as logging

import anyconfig.backend.base as Base

SUPPORTED = False
try:
    import yaml
    SUPPORTED = True
except ImportError:
    logging.warn("YAML module is not available. Disabled its support.")

if SUPPORTED:

    def filter_keys(keys, filter_key):
        return [k for k in keys if k != filter_key]

    def yaml_load(fp, **kwargs):
        keys = filter_keys(kwargs.keys(), "safe")
        if kwargs.get("safe", False):
            return yaml.safe_load(fp, **Base.mk_opt_args(keys, kwargs))
        else:
            return yaml.load(fp, **kwargs)

    def yaml_dump(data, fp, **kwargs):
        keys = filter_keys(kwargs.keys(), "safe")
        if kwargs.get("safe", False):
            return yaml.safe_dump(data, fp, **Base.mk_opt_args(keys, kwargs))
Ejemplo n.º 43
0
 def _dummy_fun(*args, **kwargs):
     logging.warn(
         "Return {} as YAML module is not available: "
         "args=%s, kwargs=%s", ','.join(args), str(kwargs))
     return {}
Ejemplo n.º 44
0
 def _dummy_fun(*args, **kwargs):
     logging.warn("Return None as XML module is not available: "
                  "args=%s, kwargs=%s", ','.join(args), str(kwargs))
     return None
Ejemplo n.º 45
0
def single_load(
    config_path, forced_type=None, ignore_missing=False, ac_template=False, ac_context=None, ac_schema=None, **kwargs
):
    """
    Load single config file.

    :param config_path: Configuration file path
    :param forced_type: Forced configuration parser type
    :param ignore_missing: Ignore and just return empty result if given file
        (``config_path``) does not exist
    :param ac_template: Assume configuration file may be a template file and
        try to compile it AAR if True
    :param ac_context: A dict presents context to instantiate template
    :param ac_schema: JSON schema file path to validate given config file
    :param kwargs: Backend specific optional arguments, e.g. {"indent": 2} for
        JSON loader/dumper backend

    :return: Dict-like object (instance of
        anyconfig.mergeabledict.MergeableDict by default) supports merge
        operations.
    """
    config_path = anyconfig.utils.ensure_expandusr(config_path)

    cparser = find_loader(config_path, forced_type)
    if cparser is None:
        return None

    if ac_schema is not None:
        kwargs["ac_schema"] = None  # Avoid infinit loop
        format_checker = kwargs.get("format_checker", None)
        LOGGER.info("Loading schema: %s", ac_schema)
        schema = load(
            ac_schema,
            forced_type=forced_type,
            ignore_missing=ignore_missing,
            ac_template=ac_template,
            ac_context=ac_context,
            **kwargs
        )

    LOGGER.info("Loading: %s", config_path)
    if ac_template:
        try:
            LOGGER.debug("Compiling: %s", config_path)
            config_content = anyconfig.template.render(config_path, ac_context)
            config = cparser.loads(config_content, ignore_missing=ignore_missing, **kwargs)
            if ac_schema is not None:
                if not _validate(config, schema, format_checker):
                    return None

            return config

        except Exception as exc:
            LOGGER.debug("Exc=%s", str(exc))
            LOGGER.warn("Failed to compile %s, fallback to no template " "mode", config_path)

    config = cparser.load(config_path, ignore_missing=ignore_missing, **kwargs)

    if ac_schema is not None:
        if not _validate(config, schema, format_checker):
            return None

    return config
Ejemplo n.º 46
0
def set_loglevel(level):
    """
    :param level: Log level, e.g. logging.INFO and logging.WARN.
    """
    LOGGER.setLevel(level)
Ejemplo n.º 47
0
def single_load(path_or_stream,
                ac_parser=None,
                ac_template=False,
                ac_context=None,
                **options):
    """
    Load single configuration file.

    .. note::

       :func:`load` is a preferable alternative and this API should be used
       only if there is a need to emphasize given file path is single one.

    :param path_or_stream: Configuration file path or file or file-like object
    :param ac_parser: Forced parser type or parser object itself
    :param ac_template:
        Assume configuration file may be a template file and try to compile it
        AAR if True
    :param ac_context: A dict presents context to instantiate template
    :param options: Optional keyword arguments such as:

        - Options common with :func:`multi_load` and :func:`load`:

          - ac_dict: callable (function or class) to make mapping object will
            be returned as a result or None. If not given or ac_dict is None,
            default mapping object used to store resutls is dict or
            :class:`~collections.OrderedDict` if ac_ordered is True and
            selected backend can keep the order of items in mapping objects.

          - ac_ordered: True if you want to keep resuls ordered. Please note
            that order of items may be lost depends on backend used.

          - ac_schema: JSON schema file path to validate given config file
          - ac_query: JMESPath expression to query data

        - Common backend options:

          - ignore_missing: Ignore and just return empty result if given file
            (``path_or_stream``) does not exist.

        - Backend specific options such as {"indent": 2} for JSON backend

    :return: Mapping object
    """
    is_path_ = is_path(path_or_stream)
    if is_path_:
        filepath = path_or_stream = anyconfig.utils.normpath(path_or_stream)
    else:
        filepath = anyconfig.utils.get_path_from_stream(path_or_stream)

    psr = find_loader(path_or_stream, ac_parser, is_path_)
    schema = _maybe_schema(ac_template=ac_template,
                           ac_context=ac_context,
                           **options)

    LOGGER.info("Loading: %s", filepath)
    if ac_template and filepath is not None:
        content = anyconfig.template.try_render(filepath=filepath,
                                                ctx=ac_context)
        if content is not None:
            cnf = psr.loads(content, **options)
            return _maybe_validated(cnf, schema, **options)

    cnf = psr.load(path_or_stream, **options)
    return _maybe_validated(cnf, schema, **options)