Skip to content

Commit

Permalink
:add: besteffort in the py resolver
Browse files Browse the repository at this point in the history
  • Loading branch information
b3j0f committed Feb 25, 2016
1 parent 6e51155 commit d10201d
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 30 deletions.
9 changes: 6 additions & 3 deletions b3j0f/conf/configurable/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@
from ..model.conf import Configuration
from ..model.cat import Category
from ..model.param import Parameter
from ..driver.file.json import JSONConfDriver
from ..driver.file.ini import INIConfDriver
from ..driver.file.json import JSONFileConfDriver
from ..driver.file.ini import INIFileConfDriver
from ..driver.file.xml import XMLFileConfDriver

__CONFIGURABLES__ = '__configurables__'

Expand Down Expand Up @@ -71,7 +72,9 @@ class Configurable(PrivateInterceptor):
DEFAULT_STORE = True #: default store value.
DEFAULT_FOREIGNS = True #: default value for setting not specified params.
# default drivers which are json and ini.
DEFAULT_DRIVERS = (JSONConfDriver(), INIConfDriver())
DEFAULT_DRIVERS = (
JSONFileConfDriver(), INIFileConfDriver(), XMLFileConfDriver()
)
DEFAULT_AUTOCONF = True #: default value for auto configuration.
DEFAULT_SAFE = True #: default value for safe attribute.

Expand Down
6 changes: 5 additions & 1 deletion b3j0f/conf/driver/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@

"""Conf driver package with the ConfDriver definition."""

__all__ = ['ConfDriver']
from __future__ import absolute_import

__all__ = ['ConfDriver', 'JSONConfDriver', 'XMLConfDriver']

from .base import ConfDriver
from .json import JSONConfDriver
from .xml import XMLConfDriver
6 changes: 3 additions & 3 deletions b3j0f/conf/driver/file/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@
# SOFTWARE.
# --------------------------------------------------------------------

__all__ = ['FileConfDriver', 'INIConfDriver', 'JSONConfDriver']
__all__ = ['FileConfDriver', 'INIFileConfDriver', 'JSONFileConfDriver']


from .base import FileConfDriver
from .ini import INIConfDriver
from .json import JSONConfDriver
from .ini import INIFileConfDriver
from .json import JSONFileConfDriver
6 changes: 3 additions & 3 deletions b3j0f/conf/driver/file/ini.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@

from __future__ import absolute_import

__all__ = ['INIConfDriver']
__all__ = ['INIFileConfDriver']

from configparser import RawConfigParser
from six.moves.configparser import RawConfigParser

from .base import FileConfDriver


class INIConfDriver(FileConfDriver):
class INIFileConfDriver(FileConfDriver):
"""Manage ini resource configuration."""

def resource(self):
Expand Down
59 changes: 43 additions & 16 deletions b3j0f/conf/parser/resolver/lang/py.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,36 @@
from b3j0f.utils.runtime import safe_eval
from b3j0f.utils.path import lookup

from re import compile as re_compile
from re import compile as re_compile, sub

from copy import deepcopy

from ..registry import register

MISSING_NAME = r'\'(?P<name>.+)\''

MISSING_NAME = r'\'(?P<name>\w+)\''
MISSING_NAME_REGEX = re_compile(MISSING_NAME)

MISSING_VARIABLE = r'(?P<name>(\w+\.)*{0}(\.\w+)*)'


def genrepl(scope):
"""Replacement function with specific scope."""

def repl(match):
"""Internal replacement function."""

name = match.group('name')

value = lookup(name, scope=scope)

result = name.replace('.', '_')
scope[result] = value

return result

return repl


@register('py')
def resolvepy(expr, safe=True, tostr=False, scope=None, besteffort=True):
Expand All @@ -51,32 +72,38 @@ def resolvepy(expr, safe=True, tostr=False, scope=None, besteffort=True):
:param dict scope: execution scope (contains references to expression
objects).
:param bool besteffort: try to resolve unknown variable name with execution
runtime.
"""
runtime."""

result = None

_eval = safe_eval if safe else eval

_scope = deepcopy(scope)
_scope = {} if scope is None else deepcopy(scope)

while besteffort:
_expr = expr

while True:

try:
result = _eval(_expr, _scope)

except (AttributeError, NameError) as nex:

result = _eval(expr, _scope)
if not besteffort:
raise

except NameError as nex:
arg = nex.args[0]
missing = MISSING_NAME_REGEX.findall(arg)[-1]

arg = nex.args
match = MISSING_NAME_REGEX.search(arg)
missing = match.group('name')
try:
missing_value = lookup(missing)
_expr = sub(
MISSING_VARIABLE.format(missing),
genrepl(scope=_scope),
_expr
)

except ImportError:
break

else:
_scope[missing] = missing_value
raise nex

else:
break
Expand Down
23 changes: 19 additions & 4 deletions b3j0f/conf/parser/resolver/lang/test/py.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,42 @@ class Test(UTCase):

def test_safe(self):

self.assertRaises(Exception, resolvepy, expr='open', safe=True)
self.assertRaises(
NameError, resolvepy, expr='open', safe=True, besteffort=False
)

def test_unsafe(self):

result = resolvepy(expr='open', safe=False)
result = resolvepy(expr='open', safe=False, besteffort=False)

self.assertIs(open, result)

def test_tostr(self):

result = resolvepy(expr='open', safe=False, tostr=True)
result = resolvepy(
expr='open', safe=False, tostr=True, besteffort=False
)

self.assertEqual(result, str(open))

def test_scope(self):

self.assertRaises(Exception, resolvepy, expr='test')
self.assertRaises(NameError, resolvepy, expr='test', besteffort=False)

result = resolvepy(expr='test', scope={'test': 1})

self.assertEqual(result, 1)

def test_besteffort(self):

test = 'b3j0f.conf.configurable.log.Logger'

self.assertRaises(
NameError, resolvepy, expr=test, besteffort=False
)

resolvepy(expr=test, besteffort=True)


if __name__ == '__main__':
main()

0 comments on commit d10201d

Please sign in to comment.