Skip to content

Commit

Permalink
:add: model.parser module.
Browse files Browse the repository at this point in the history
  • Loading branch information
b3j0f committed Oct 29, 2015
1 parent c380ca4 commit bd473e9
Show file tree
Hide file tree
Showing 6 changed files with 276 additions and 135 deletions.
3 changes: 1 addition & 2 deletions b3j0f/conf/configurable/test/decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@


class DecoratorTest(TestCase):
"""Configuration Manager unittest class.
"""
"""Configuration Manager unittest class."""

def test_conf_paths(self):

Expand Down
8 changes: 5 additions & 3 deletions b3j0f/conf/driver/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
from b3j0f.utils.version import basestring
from b3j0f.utils.path import lookup, getpath

from parser import ParserError

from ..model.configuration import Configuration
from ..model.category import Category
from ..model.parameter import Parameter
Expand Down Expand Up @@ -187,9 +189,9 @@ def get_conf(
# set value to param
if value not in (None, ''):
if override or cparam.value in (None, ''):
try:
cparam.value = value
except Parameter.Error as ex:
try: # set serialized value
cparam.svalue = value
except ParserError as ex:
pass

configurable = cparam.value
Expand Down
208 changes: 79 additions & 129 deletions b3j0f/conf/model/parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,11 @@


from b3j0f.utils.version import basestring
from b3j0f.utils.path import lookup

from json import loads as jsonloads

from re import compile as re_compile

from parser import ParserError


class Parameter(object):
"""Parameter identified among a category by its name.
Expand Down Expand Up @@ -68,8 +67,8 @@ class Error(Exception):
"""Handle Parameter errors."""

def __init__(
self, name, vtype=object, parser=None, value=None, conf=None,
critical=False, local=True, asitem=None
self, name, vtype=object, parser=None, svalue=None, value=None,
conf=None, critical=False, local=True, asitem=None
):
"""
:param name: depends on type:
Expand All @@ -79,6 +78,7 @@ def __init__(
:param type vtype: parameter value type.
:param callable parser: param test deserializer which takes in param
a str.
:param str svalue: serialized value.
:param value: param value. None if not given.
:param dict conf: parameter configuration used to init the parameter
value if not None. In this case, the parameter value must be
Expand All @@ -97,6 +97,7 @@ def __init__(
self._name = None
self._value = None
self._error = None
self._svalue = None

# init public attributes
self.name = name
Expand All @@ -106,6 +107,7 @@ def __init__(
self.critical = critical
self.local = local
self.asitem = asitem
self.svalue = svalue
self.value = value

def __eq__(self, other):
Expand Down Expand Up @@ -162,60 +164,97 @@ def conf_name(self):

return '{0}{1}'.format(self.name, Parameter.CONF_SUFFIX)

@property
def svalue(self):
"""Get serialized value.
:rtype: str
"""

return self._svalue

@svalue.setter
def svalue(self, value):
"""Change of serialized value.
Nonify this value as well.
:param str value: serialized value to use.
"""

self._value = None
self._svalue = value

@property
def value(self):
"""Get parameter value.
If this cached value is None and this serialized value is not None,
calculate the new value from the serialized one.
:return: parameter value.
:raises: TypeError if serialized value is not an instance of self vtype
. ParserError if parsing step raised an error.
"""
return self._value

@value.setter
def value(self, value):
"""Change of parameter value.
# if cached value is None and serialiazed value exists
if self._value is None and self.svalue is not None:

If an error occured, the error is available from the property error.
self._error = None # nonify error.

:param value: new value to use. If value is a str and not parable by
this parameter, the value becomes the parsing exception.
:raises: Parameter.Error for any error occuring while changing of value
.
"""
if self.parser is None:

self._error = None # nonify error.
self.value = self._svalue

finalvalue = None # final value to compare with self type
else:
# parse value if str and if parser exists
try:
self._value = self.parser(self._svalue, conf=self)

if isinstance(value, basestring) and self.parser is not None:
# parse value if str and if parser exists
except Exception as ex:
self._error = ex
raise ParserError(
'Impossible to parse value {0} in {1}.'.format(
self._svalue, self
)
).with_traceback(ex.__traceback__)

try:
finalvalue = self.parser(value)
except Exception as ex:
self._error = ex
raise Parameter.Error(
'Impossible to parse value {0} with {1}.'.format(
value, self
)
).with_traceback(ex.__traceback__)
else:
# try to apply conf
if self._value is None or self.conf is None:
self.value = self._value

else:
finalvalue = value
else: # apply conf
try:
self.value = self._value(**self.conf)
except Exception as ex:
self._error = ex
raise ex

return self._value

@value.setter
def value(self, value):
"""Change of parameter value.
# check type
if finalvalue is None or isinstance(finalvalue, self.vtype):
If an error occured, it is stored in this error attribute.
:param value: new value to use. If input value is not an instance of
self.vtype, self error
:raises: TypeError if input value is not an instance of self vtype.
"""

# apply conf if necessary
if finalvalue is not None and self.conf is not None:
finalvalue = finalvalue(**self.conf)
if value is None or (
self.vtype is not None and isinstance(value, self.vtype)
):

# update value property
self._value = finalvalue
self._value = value

else: # raise wrong type error
error = Parameter.Error(
else:
# raise wrong type error
error = TypeError(
'Wrong value type of {0}. {1} expected.'.format(
finalvalue, self.vtype
value, self.vtype
)
)
self._error = error
Expand Down Expand Up @@ -249,92 +288,3 @@ def clean(self):
"""Clean this param in removing values."""

self._value = None

@staticmethod
def bool(value):
"""Boolean value parser.
:param str value: value to parse.
:return: True if value in [True, true, 1]. False Otherwise.
:rtype: bool
"""

return value == 'True' or value == 'true' or value == '1'

@staticmethod
def path(value):
"""Python class path value parser.
:param str value: python class path to parse.
:return: lookup(value).
"""

return lookup(value)

@staticmethod
def json(value):
"""Get a data from a json data format.
:param str value: json format to parse.
:return: data.
:rtype: str, list, dict, int, float or bool
"""

return jsonloads(value)

@staticmethod
def _typedjson(value, cls):
"""Private static method which uses the json method and check if result
inherits from the cls. Otherwise, raise an error.
:param str value: value to parse in a json format.
:param type cls: expected result class.
:return: parsed value.
:rtype: cls
"""

result = Parameter.json(value)

if not isinstance(result, cls):
raise Parameter.Error(
'Wrong type: {0}. {1} expected.'.format(value, cls)
)

return result

@staticmethod
def dict(value):
"""Get a dict from a dict json format.
:param str value: dictionary json format to parse.
:return: parsed dictionary.
:rtype: dict
:raises: Parameter.Error if value is not a dict json format.
"""

return Parameter._typedjson(value, dict)

@staticmethod
def array(value):
"""Get an array from:
- an array json format.
- a list of item name separated by commas.
:param str value: list of items to parse. The format must be of
- array json type.
- named item separated by commas.
:return: parsed array.
:rtype: list
:raises: Parameter.Error if value is not a list json format.
"""

if value[0] == '[':
result = Parameter._typedjson(value, list)

else:
result = list(value.split(','))

return result

0 comments on commit bd473e9

Please sign in to comment.