Skip to content

Commit

Permalink
Refactor resolvers (#4)
Browse files Browse the repository at this point in the history
* Refactor resolvers
* Update example
  • Loading branch information
kmagusiak authored Oct 6, 2022
1 parent 604756c commit a659a36
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 32 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ For example, `${oc.env:USER,me}` would resolve to the environment variable
USER with a default value "me".
Similarly, `${oc.select:path}` will resolve to another configuration value.

Additional resolvers are added to read file contents.
These are the same as type casts: read_text, read_strip, read_bytes.

The select is used to build multiple templates for configurations by providing
base configurations.
An argument `--select key=template` is a shortcut for
Expand Down
10 changes: 8 additions & 2 deletions alphaconf/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import contextlib
import contextvars
import logging
import re
import sys
from contextvars import ContextVar
from typing import Any, Callable, Dict, Union, cast
Expand All @@ -9,7 +10,7 @@

from .application import Application, _log
from .arg_parser import ArgumentError, ExitApplication
from .arg_type import convert_to_type
from .type_resolvers import convert_to_type

__doc__ = """AlphaConf
Expand All @@ -24,10 +25,15 @@
"""

"""A list of functions which given a key indicate whether it's a secret"""
SECRET_MASKS = [
# mask if contains a kind of secret and it's not in a file
re.compile(r'.*(key|password|secret)s?(?!_file)(_|$)').match,
]

#######################################
# APPLICATION CONTEXT


"""The application context"""
application: ContextVar[Application] = ContextVar('application')
"""The current configuration"""
Expand Down
9 changes: 2 additions & 7 deletions alphaconf/application.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import logging
import os
import re
import sys
import uuid
from typing import Any, Dict, Iterable, List, Optional, Tuple, Union, cast
Expand All @@ -16,12 +15,6 @@

_log = logging.getLogger(__name__)

"""A list of functions which given a key indicate whether it's a secret"""
SECRET_MASKS = [
# mask if contains a kind of secret and it's not in a file
re.compile(r'.*(password|secret|key)(?!_file)(_|$)').match,
]


class Application:
"""An application description
Expand Down Expand Up @@ -298,6 +291,8 @@ def yaml_configuration(self, mask_base: bool = True, mask_secrets: bool = True)

@staticmethod
def __mask_secrets(configuration):
from . import SECRET_MASKS

for key in list(configuration):
if isinstance(key, str) and any(mask(key) for mask in SECRET_MASKS):
configuration[key] = '*****'
Expand Down
22 changes: 0 additions & 22 deletions alphaconf/arg_type.py

This file was deleted.

42 changes: 42 additions & 0 deletions alphaconf/type_resolvers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import datetime
from pathlib import Path

from omegaconf import OmegaConf

__doc__ = """Resolves types when reading values from the configuration.
You can add values to TYPE_CONVERTER which is used in `alphaconf.get()`.
This way, you can load values from an external source.
By the way, you could register new resolvers in OmegaConf.
"""


def read_text(value):
return Path(value).expanduser().read_text()


TYPE_CONVERTER = {
datetime.datetime: datetime.datetime.fromisoformat,
datetime.date: lambda s: datetime.datetime.strptime(s, '%Y-%m-%d').date(),
datetime.time: datetime.time.fromisoformat,
Path: lambda s: Path(s).expanduser(),
'read_text': read_text,
'read_strip': lambda s: read_text(s).strip(),
'read_bytes': lambda s: Path(s).expanduser().read_bytes(),
}

# register resolved from strings
for _name, _function in TYPE_CONVERTER.items():
if isinstance(_name, str):
OmegaConf.register_new_resolver(_name, _function) # type: ignore


def convert_to_type(value, type):
"""Converts a value to the given type.
:param value: Any value
:param type: A class or a callable used to convert the value
:return: Result of the callable
"""
type = TYPE_CONVERTER.get(type, type)
return type(value)
12 changes: 11 additions & 1 deletion example-simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,14 @@
url: http://default
user: ${oc.env:USER}
home: "~"
show: false
exception: false
""",
{"server": "Arguments for the demo"},
{
"server": "Arguments for the demo",
"show": "The name of the selection to show",
"exception": "If set, raise an exception",
},
)


Expand All @@ -27,6 +33,10 @@ def main():
# shortcut version to get a configuration value
print('server.user:', alphaconf.get('server.user'))
print('server.home', alphaconf.get('server.home', Path))
# show configuration
value = alphaconf.get('show')
if value and (value := alphaconf.get(value)):
print(value)
# log an exception if we have it in the configuration
if alphaconf.get('exception'):
try:
Expand Down

0 comments on commit a659a36

Please sign in to comment.