Package: loguru-config
Loguru-configLoguru-config is a simple configurator for theLogurulogging library. It extends
the functionality of Loguru by allowing the user to configure the logger from a configuration file. This package
provides a much-needed feature to Loguru, which is the ability to configure the logger from a configuration file (for
example, using loguru alone, one can't automatically configure the logger to write tosys.stdoutorsys.stderrfrom within a configuration file).The configuration can have syntax similar to the one used by the nativelogginglibrary in Python (i.e. supportcfg://,ext://, etc.), but extends it to support even more features. It can also be easily extended to support even
more features quite easily (seeExtending the configuratorfor more details).The configurator supports parsing of JSON, JSON5, YAML, and TOML files (out of the box) and can be extended to support
other formats (again, seeExtending the configuratorbelow).Installationpipinstallloguru-configFeaturesSupports parsing of JSON, YAML, and TOML files (out of the box) with a simpleConfigurator.loadcall.Supports loading a member of a module from a string (e.g.ext://sys.stdout).Support referencing another member of the configuration file (e.g.cfg://loggers.default.handlers.0).Support calling a user-defined function from within the configuration file (e.g.{ '()': 'datetime.datetime.now' }).Support referencing an environment variable (e.g.env://HOME).Support referencing (and parsing) referencing another file (e.g.file://./path/to/file.json).Support parsing literal python (strings, integers, lists, etc.) from within string values in a configuration (e.g.literal://[1, 2, 3]).Support string formatting (e.g.fmt://{cfg://loggers.default.handlers.0} - {{ESCAPED}}).Also, almost all of these parsings are recursively parsed (except user-defined functions).Both the special-case parsing and configuration loading can be easily extended to support more features (seeExtending the configuratorbelow).ExamplesThe following YAML configuration filehandlers:-sink:ext://sys.stderrformat:'[{time}]{message}'-sink:file.logenqueue:trueserialize:truelevels:-name:NEW'no':13icon:Â¤color:""extra:common_to_all:defaultactivation:-["my_module.secret",false]-["another_library.module",true]will be parsed tofromloguruimportloggerimportsyslogger.configure(handlers=[dict(sink=sys.stderr,format="[{time}]{message}"),dict(sink="file.log",enqueue=True,serialize=True),],levels=[dict(name="NEW",no=13,icon="Â¤",color="")],extra={"common_to_all":"default"},activation=[("my_module.secret",False),("another_library.module",True)],)Special-case parsingThere are multiple special cases that are applicable. Some are recursive (i.e. after parsing, their contents will be
reparsed), and some aren't. The recursive cases will be marked as such in their header.String fieldsext://(recursive) - Load the member according to the reference after the prefix. This can be used, for example to
refer to the application's out-streams (ext://sys.stdoutorext://sys.stderr), or to any loaded/loadable member
in your own code (e.g. set the level of verbosity according to a predefined
memberext://my_package.utils.log_level).cfg://(recursive) - load a member from elsewhere in the configuration. This is similar toext://, only within
the configuration. For example,cfg://handlers.0.levelwill refer to the log-level in the first handler. The
referencing supports both item-getting in dictionaries (dict.key), tuples and lists (list.index), and
attribute-getting in other classes (uses the class'__dict__attribute).env://(recursive) - load the field's value from an environmental variable. Since environmental-variables are only
strings,env://fields can be combined (i.e. contain)literal://tags (more on these below). As an example use
case, one can set anextrafield to be the Windows username:...extra:username:env://USERNAME...literal://- python-evaluate the contents of string following the prefix as literal python. For security reasons,
the evaluation supports only simple built-in types (i.e.int,float,str,bool,Noneand lists,
dictionaries, sets and tuples of these) without conditionals, assignments, lambda-expressions, etc. These are
especially useful from loading string-only configurations (like.inifiles), or mixed withenv://for loading
non-string values. Example:"literal://True"will evaluate toTruefmt://(recursive) - formats a string in an f-string-like way. This is useful to chain multiple variables. For
example:fmt://{env://APPDATA/}/{cfg://extra.name}/logsevaluates to sub-folder of the application-data directory
with the name given as the keynamein theextrapart.
Some notes on this tag:To escape curly braces, use double-curly braces ({{evaluates to"{").For now, specifying the individual formats of the formatted placeholders is not supported (e.g. one can not
specify"{number:.3f}")because:is used in the tag prefixes. This might be resolved in the future.file://(recursive) - for cases when you wish parts of the configuration to be shared among different
configurations, one can do it using this tag. This tag loads the contents of the file (the same way the original file
is loaded), and parses them to be inplace of the given tag. As an example, consider the case where multiple
configurations have differentextrasection but similar handlers, the configuration might look like:handlers:'file://handlers.yaml'extra:......Dictionary fieldsThe user-defined field, or()(NON-RECURSIVE) - when declaring a user-defined field, one should have the contents
of the field parse as a dictionary with the following keys:(): parses as anext://field above, but must refer to a callable.*(optional): this key's value, if such key is given, must be a list/tuple of positional arguments to pass to
the function.<key>(optional): keyword-arguments to give the function.For example, one might wish to configure alogginghandler as a sink:handlers:-sink:"()":logging.handlers.DatagramHandler"host":'127.0.0.1'"port":3871level:.........Extending the configuratorAside from inheriting theLoguruConfigclass, there are two ways to extend the existing configurator class:Add a custom loading function- by modifying theLoguruConfig.supported_loadersfield. This field contains a
list
of callables that take a string (file name) as an argument and return a parsable object (i.e. a dictionary that can
be passed as keyword-arguments to theLoguruConfigclass' constructor). Note that the order of this list matters
because the loaders will be attempted according to their order in the list.Add a custom string-field parser- similarly, one can extend the class' parsing capabilities by
extendingLoguruConfig.supported_protocol_parsers. This field contains a list of tuples, where each tuple contains
two elements:Condition: can be either a callable taking a string and returning a boolean, or a regular expression. If the
latter is given, then if the expression contains any groups, the first group will be passed to the parsing
function.Parsing function: a function that takes a string field and parses it.As an example to the latter, consider the case where a specialevalfield can be given. In this case, one should
extend the configurator as follows:importrefromloguru_configimportLoguruConfigeval_protocol=re.compile(r'^eval://(.+)$')LoguruConfig.supported_protocol_parsers=list(LoguruConfig.supported_protocol_parsers)+[(eval_protocol,eval)]LoguruConfig.load(...)In contrast, one might not want affect all configurators - just one of them. In this case:importrefromloguru_configimportLoguruConfigeval_protocol=re.compile(r'^eval://(.+)$')config=LoguruConfig.load(...,configure=False)config.supported_protocol_parsers=list(LoguruConfig.supported_protocol_parsers)+[(eval_protocol,eval)]config.parse().configure()