Initial import from Docker volume
This commit is contained in:
842
pyson.py
Executable file
842
pyson.py
Executable file
@@ -0,0 +1,842 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
import datetime
|
||||
import json
|
||||
from decimal import Decimal
|
||||
from functools import reduce
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
|
||||
class PYSON(object):
|
||||
_operator = None
|
||||
_binary_operator = None
|
||||
|
||||
def pyson(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def types(self):
|
||||
raise NotImplementedError
|
||||
|
||||
@staticmethod
|
||||
def eval(dct, context):
|
||||
raise NotImplementedError
|
||||
|
||||
def __invert__(self):
|
||||
if self.types() != {bool}:
|
||||
return Not(Bool(self))
|
||||
else:
|
||||
return Not(self)
|
||||
|
||||
def __and__(self, other):
|
||||
if (isinstance(other, PYSON)
|
||||
and other.types() != {bool}):
|
||||
other = Bool(other)
|
||||
if (isinstance(self, And)
|
||||
and not isinstance(self, Or)):
|
||||
return And(*self._statements, other)
|
||||
if self.types() != {bool}:
|
||||
return And(Bool(self), other)
|
||||
else:
|
||||
return And(self, other)
|
||||
|
||||
__rand__ = __and__
|
||||
|
||||
def __or__(self, other):
|
||||
if (isinstance(other, PYSON)
|
||||
and other.types() != {bool}):
|
||||
other = Bool(other)
|
||||
if isinstance(self, Or):
|
||||
return Or(*self._statements, other)
|
||||
if self.types() != {bool}:
|
||||
return Or(Bool(self), other)
|
||||
else:
|
||||
return Or(self, other)
|
||||
|
||||
__ror__ = __or__
|
||||
|
||||
def __eq__(self, other):
|
||||
return Equal(self, other)
|
||||
|
||||
def __ne__(self, other):
|
||||
return Not(Equal(self, other))
|
||||
|
||||
def __gt__(self, other):
|
||||
return Greater(self, other)
|
||||
|
||||
def __ge__(self, other):
|
||||
return Greater(self, other, True)
|
||||
|
||||
def __lt__(self, other):
|
||||
return Less(self, other)
|
||||
|
||||
def __le__(self, other):
|
||||
return Less(self, other, True)
|
||||
|
||||
def get(self, k, d=''):
|
||||
return Get(self, k, d)
|
||||
|
||||
def in_(self, obj):
|
||||
return In(self, obj)
|
||||
|
||||
def contains(self, k):
|
||||
return In(k, self)
|
||||
|
||||
def __repr__(self):
|
||||
params = self.__repr_params__
|
||||
if self._operator and isinstance(params[0], PYSON):
|
||||
return '%s.%s(%s)' % (
|
||||
repr(params[0]), self._operator,
|
||||
', '.join(map(repr, params[1:])))
|
||||
elif self._binary_operator and isinstance(params[0], PYSON):
|
||||
return '(%s %s %s)' % (
|
||||
repr(params[0]), self._binary_operator, repr(params[1]))
|
||||
else:
|
||||
klass = self.__class__.__name__
|
||||
return '%s(%s)' % (klass, ', '.join(map(repr, params)))
|
||||
|
||||
@property
|
||||
def __repr_params__(self):
|
||||
return NotImplementedError
|
||||
|
||||
|
||||
class PYSONEncoder(json.JSONEncoder):
|
||||
|
||||
def default(self, obj):
|
||||
if isinstance(obj, PYSON):
|
||||
return obj.pyson()
|
||||
elif isinstance(obj, datetime.date):
|
||||
if isinstance(obj, datetime.datetime):
|
||||
return DateTime(obj.year, obj.month, obj.day,
|
||||
obj.hour, obj.minute, obj.second, obj.microsecond
|
||||
).pyson()
|
||||
else:
|
||||
return Date(obj.year, obj.month, obj.day).pyson()
|
||||
elif isinstance(obj, datetime.timedelta):
|
||||
return TimeDelta(obj.days, obj.seconds, obj.microseconds)
|
||||
elif isinstance(obj, Decimal):
|
||||
return float(obj)
|
||||
return super(PYSONEncoder, self).default(obj)
|
||||
|
||||
|
||||
class PYSONDecoder(json.JSONDecoder):
|
||||
|
||||
def __init__(self, context=None, noeval=False):
|
||||
self.__context = context or {}
|
||||
self.noeval = noeval
|
||||
super(PYSONDecoder, self).__init__(object_hook=self._object_hook)
|
||||
|
||||
def _object_hook(self, dct):
|
||||
if '__class__' in dct:
|
||||
klass = CONTEXT.get(dct['__class__'])
|
||||
if klass:
|
||||
if not self.noeval:
|
||||
return klass.eval(dct, self.__context)
|
||||
else:
|
||||
dct = dct.copy()
|
||||
del dct['__class__']
|
||||
return klass(**dct)
|
||||
return dct
|
||||
|
||||
|
||||
class Eval(PYSON):
|
||||
|
||||
def __init__(self, v, d=''):
|
||||
super(Eval, self).__init__()
|
||||
self._value = v
|
||||
self._default = d
|
||||
|
||||
@property
|
||||
def __repr_params__(self):
|
||||
params = (self._value,)
|
||||
if self._default != '':
|
||||
params += (self._default,)
|
||||
return params
|
||||
|
||||
def pyson(self):
|
||||
return {
|
||||
'__class__': 'Eval',
|
||||
'v': self._value,
|
||||
'd': self._default,
|
||||
}
|
||||
|
||||
def types(self):
|
||||
if isinstance(self._default, PYSON):
|
||||
return self._default.types()
|
||||
else:
|
||||
return {type(self._default)}
|
||||
|
||||
@staticmethod
|
||||
def eval(dct, context):
|
||||
if '.' in dct['v'] and dct['v'] not in context:
|
||||
base, name = dct['v'].split('.', 1)
|
||||
return Eval.eval({
|
||||
'v': name,
|
||||
'd': dct['d'],
|
||||
}, context.get(base) or {})
|
||||
return context.get(dct['v'], dct['d'])
|
||||
|
||||
@property
|
||||
def basename(self):
|
||||
name = self._value
|
||||
if name.startswith('_parent_'):
|
||||
name = name[len('_parent_'):]
|
||||
if '.' in name:
|
||||
name = name.split('.', 1)[0]
|
||||
return name
|
||||
|
||||
|
||||
class Not(PYSON):
|
||||
|
||||
def __init__(self, v):
|
||||
super(Not, self).__init__()
|
||||
if isinstance(v, PYSON):
|
||||
if v.types() != {bool}:
|
||||
v = Bool(v)
|
||||
elif not isinstance(v, bool):
|
||||
v = bool(v)
|
||||
self._value = v
|
||||
|
||||
def __repr__(self):
|
||||
if (isinstance(self._value, Equal)
|
||||
and isinstance(self._value._statement1, PYSON)):
|
||||
return '(%s != %s)' % (
|
||||
repr(self._value._statement1),
|
||||
repr(self._value._statement2))
|
||||
elif isinstance(self._value, PYSON):
|
||||
return '~%s' % repr(self._value)
|
||||
else:
|
||||
return super().__repr__()
|
||||
|
||||
@property
|
||||
def __repr_params__(self):
|
||||
return (self._value,)
|
||||
|
||||
def pyson(self):
|
||||
return {
|
||||
'__class__': 'Not',
|
||||
'v': self._value,
|
||||
}
|
||||
|
||||
def types(self):
|
||||
return {bool}
|
||||
|
||||
@staticmethod
|
||||
def eval(dct, context):
|
||||
return not Bool(dct['v']).eval(dct, context)
|
||||
|
||||
|
||||
class Bool(PYSON):
|
||||
|
||||
def __init__(self, v):
|
||||
super(Bool, self).__init__()
|
||||
self._value = v
|
||||
|
||||
@property
|
||||
def __repr_params__(self):
|
||||
return (self._value,)
|
||||
|
||||
def pyson(self):
|
||||
return {
|
||||
'__class__': 'Bool',
|
||||
'v': self._value,
|
||||
}
|
||||
|
||||
def types(self):
|
||||
return {bool}
|
||||
|
||||
@staticmethod
|
||||
def eval(dct, context):
|
||||
return bool(dct['v'])
|
||||
|
||||
|
||||
class And(PYSON):
|
||||
_pyson_class = 'And'
|
||||
_binary_operator = '&'
|
||||
|
||||
def __init__(self, *statements, **kwargs):
|
||||
super(And, self).__init__()
|
||||
statements = list(statements) + kwargs.get('s', [])
|
||||
for i, statement in enumerate(list(statements)):
|
||||
if isinstance(statement, PYSON):
|
||||
if statement.types() != {bool}:
|
||||
statements[i] = Bool(statement)
|
||||
elif not isinstance(statement, bool):
|
||||
statements[i] = bool(statement)
|
||||
assert len(statements) >= 2, 'must have at least 2 statements'
|
||||
self._statements = statements
|
||||
|
||||
@property
|
||||
def __repr_params__(self):
|
||||
return tuple(self._statements)
|
||||
|
||||
def pyson(self):
|
||||
return {
|
||||
'__class__': 'And',
|
||||
's': self._statements,
|
||||
}
|
||||
|
||||
def types(self):
|
||||
return {bool}
|
||||
|
||||
@staticmethod
|
||||
def eval(dct, context):
|
||||
return bool(reduce(lambda x, y: x and y, dct['s']))
|
||||
|
||||
|
||||
class Or(And):
|
||||
_binary_operator = '|'
|
||||
|
||||
def pyson(self):
|
||||
res = super(Or, self).pyson()
|
||||
res['__class__'] = 'Or'
|
||||
return res
|
||||
|
||||
@staticmethod
|
||||
def eval(dct, context):
|
||||
return bool(reduce(lambda x, y: x or y, dct['s']))
|
||||
|
||||
|
||||
class Equal(PYSON):
|
||||
_binary_operator = '=='
|
||||
|
||||
def __init__(self, s1, s2):
|
||||
statement1, statement2 = s1, s2
|
||||
super(Equal, self).__init__()
|
||||
if isinstance(statement1, PYSON):
|
||||
types1 = statement1.types()
|
||||
else:
|
||||
types1 = {type(s1)}
|
||||
if isinstance(statement2, PYSON):
|
||||
types2 = statement2.types()
|
||||
else:
|
||||
types2 = {type(s2)}
|
||||
assert types1 == types2, 'statements must have the same type'
|
||||
self._statement1 = statement1
|
||||
self._statement2 = statement2
|
||||
|
||||
@property
|
||||
def __repr_params__(self):
|
||||
return (self._statement1, self._statement2)
|
||||
|
||||
def pyson(self):
|
||||
return {
|
||||
'__class__': 'Equal',
|
||||
's1': self._statement1,
|
||||
's2': self._statement2,
|
||||
}
|
||||
|
||||
def types(self):
|
||||
return {bool}
|
||||
|
||||
@staticmethod
|
||||
def eval(dct, context):
|
||||
return dct['s1'] == dct['s2']
|
||||
|
||||
|
||||
class Greater(PYSON):
|
||||
|
||||
def __init__(self, s1, s2, e=False):
|
||||
statement1, statement2, equal = s1, s2, e
|
||||
super(Greater, self).__init__()
|
||||
for i in (statement1, statement2):
|
||||
if isinstance(i, PYSON):
|
||||
assert i.types().issubset({
|
||||
int, float, type(None),
|
||||
datetime.datetime, datetime.date,
|
||||
datetime.timedelta}), \
|
||||
'statement must be an integer, float, date or datetime'
|
||||
else:
|
||||
assert isinstance(i, (
|
||||
int, float, type(None),
|
||||
datetime.datetime, datetime.date,
|
||||
datetime.timedelta)), \
|
||||
'statement must be an integer, float, date or datetime'
|
||||
if isinstance(equal, PYSON):
|
||||
if equal.types() != {bool}:
|
||||
equal = Bool(equal)
|
||||
elif not isinstance(equal, bool):
|
||||
equal = bool(equal)
|
||||
self._statement1 = statement1
|
||||
self._statement2 = statement2
|
||||
self._equal = equal
|
||||
|
||||
@property
|
||||
def _binary_operator(self):
|
||||
return '>=' if self._equal else '>'
|
||||
|
||||
@property
|
||||
def __repr_params__(self):
|
||||
return (self._statement1, self._statement2, self._equal)
|
||||
|
||||
def pyson(self):
|
||||
return {
|
||||
'__class__': 'Greater',
|
||||
's1': self._statement1,
|
||||
's2': self._statement2,
|
||||
'e': self._equal,
|
||||
}
|
||||
|
||||
def types(self):
|
||||
return {bool}
|
||||
|
||||
@staticmethod
|
||||
def _convert(dct):
|
||||
for i in ('s1', 's2'):
|
||||
if dct[i] is None:
|
||||
dct[i] = 0.0
|
||||
if not isinstance(dct[i], (int, float)):
|
||||
dct = dct.copy()
|
||||
stmt = dct[i]
|
||||
if isinstance(stmt, datetime.datetime):
|
||||
stmt = stmt.timestamp()
|
||||
elif isinstance(stmt, datetime.date):
|
||||
time = datetime.time(0, 0)
|
||||
stmt = datetime.datetime.combine(stmt, time).timestamp()
|
||||
elif isinstance(stmt, datetime.timedelta):
|
||||
stmt = stmt.total_seconds()
|
||||
dct[i] = float(stmt)
|
||||
return dct
|
||||
|
||||
@staticmethod
|
||||
def eval(dct, context):
|
||||
if dct['s1'] is None or dct['s2'] is None:
|
||||
return False
|
||||
dct = Greater._convert(dct)
|
||||
if dct['e']:
|
||||
return dct['s1'] >= dct['s2']
|
||||
else:
|
||||
return dct['s1'] > dct['s2']
|
||||
|
||||
|
||||
class Less(Greater):
|
||||
|
||||
@property
|
||||
def _binary_operator(self):
|
||||
return '<=' if self._equal else '<'
|
||||
|
||||
def pyson(self):
|
||||
res = super(Less, self).pyson()
|
||||
res['__class__'] = 'Less'
|
||||
return res
|
||||
|
||||
@staticmethod
|
||||
def eval(dct, context):
|
||||
if dct['s1'] is None or dct['s2'] is None:
|
||||
return False
|
||||
dct = Less._convert(dct)
|
||||
if dct['e']:
|
||||
return dct['s1'] <= dct['s2']
|
||||
else:
|
||||
return dct['s1'] < dct['s2']
|
||||
|
||||
|
||||
class If(PYSON):
|
||||
|
||||
def __init__(self, c, t, e=None):
|
||||
condition, then_statement, else_statement = c, t, e
|
||||
super(If, self).__init__()
|
||||
if isinstance(condition, PYSON):
|
||||
if condition.types() != {bool}:
|
||||
condition = Bool(condition)
|
||||
elif not isinstance(condition, bool):
|
||||
condition = bool(condition)
|
||||
self._condition = condition
|
||||
self._then_statement = then_statement
|
||||
self._else_statement = else_statement
|
||||
|
||||
@property
|
||||
def __repr_params__(self):
|
||||
return (self._condition, self._then_statement, self._else_statement)
|
||||
|
||||
def pyson(self):
|
||||
return {
|
||||
'__class__': 'If',
|
||||
'c': self._condition,
|
||||
't': self._then_statement,
|
||||
'e': self._else_statement,
|
||||
}
|
||||
|
||||
def types(self):
|
||||
if isinstance(self._then_statement, PYSON):
|
||||
types = self._then_statement.types()
|
||||
else:
|
||||
types = {type(self._then_statement)}
|
||||
if isinstance(self._else_statement, PYSON):
|
||||
types |= self._else_statement.types()
|
||||
else:
|
||||
types |= {type(self._else_statement)}
|
||||
return types
|
||||
|
||||
@staticmethod
|
||||
def eval(dct, context):
|
||||
if dct['c']:
|
||||
return dct['t']
|
||||
else:
|
||||
return dct['e']
|
||||
|
||||
|
||||
class Get(PYSON):
|
||||
_operator = 'get'
|
||||
|
||||
def __init__(self, v, k, d=''):
|
||||
obj, key, default = v, k, d
|
||||
super(Get, self).__init__()
|
||||
if isinstance(obj, PYSON):
|
||||
assert obj.types() == {dict}, 'obj must be a dict'
|
||||
else:
|
||||
assert isinstance(obj, dict), 'obj must be a dict'
|
||||
self._obj = obj
|
||||
if isinstance(key, PYSON):
|
||||
assert key.types() == {str}, 'key must be a string'
|
||||
else:
|
||||
assert isinstance(key, str), 'key must be a string'
|
||||
self._key = key
|
||||
self._default = default
|
||||
|
||||
@property
|
||||
def __repr_params__(self):
|
||||
params = (self._obj, self._key)
|
||||
if self._default != '':
|
||||
params += (self._default,)
|
||||
return params
|
||||
|
||||
def pyson(self):
|
||||
return {
|
||||
'__class__': 'Get',
|
||||
'v': self._obj,
|
||||
'k': self._key,
|
||||
'd': self._default,
|
||||
}
|
||||
|
||||
def types(self):
|
||||
if isinstance(self._default, PYSON):
|
||||
return self._default.types()
|
||||
else:
|
||||
return {type(self._default)}
|
||||
|
||||
@staticmethod
|
||||
def eval(dct, context):
|
||||
return dct['v'].get(dct['k'], dct['d'])
|
||||
|
||||
|
||||
class In(PYSON):
|
||||
_operator = 'in_'
|
||||
|
||||
def __init__(self, k, v):
|
||||
key, obj = k, v
|
||||
super(In, self).__init__()
|
||||
if isinstance(key, PYSON):
|
||||
assert key.types().issubset({str, int}), \
|
||||
'key must be a string or an integer or a long'
|
||||
else:
|
||||
assert isinstance(key, (str, int)), \
|
||||
'key must be a string or an integer or a long'
|
||||
if isinstance(obj, PYSON):
|
||||
assert obj.types().issubset({dict, list}), \
|
||||
'obj must be a dict or a list'
|
||||
if obj.types() == {dict}:
|
||||
if isinstance(key, PYSON):
|
||||
assert key.types() == {str}, 'key must be a string'
|
||||
else:
|
||||
assert isinstance(key, str), 'key must be a string'
|
||||
else:
|
||||
assert isinstance(obj, (dict, list))
|
||||
if isinstance(obj, dict):
|
||||
if isinstance(key, PYSON):
|
||||
assert key.types() == {str}, 'key must be a string'
|
||||
else:
|
||||
assert isinstance(key, str), 'key must be a string'
|
||||
self._key = key
|
||||
self._obj = obj
|
||||
|
||||
def __repr__(self):
|
||||
params = self.__repr_params__
|
||||
if isinstance(params[1], PYSON):
|
||||
return '%s.contains(%s)' % (
|
||||
repr(params[1]), ', '.join(map(repr, params[:1] + params[2:])))
|
||||
else:
|
||||
return super().__repr__()
|
||||
|
||||
@property
|
||||
def __repr_params__(self):
|
||||
return (self._key, self._obj)
|
||||
|
||||
def pyson(self):
|
||||
return {
|
||||
'__class__': 'In',
|
||||
'k': self._key,
|
||||
'v': self._obj,
|
||||
}
|
||||
|
||||
def types(self):
|
||||
return {bool}
|
||||
|
||||
@staticmethod
|
||||
def eval(dct, context):
|
||||
if dct['v']:
|
||||
return dct['k'] in dct['v']
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class Date(PYSON):
|
||||
|
||||
def __init__(self, year=None, month=None, day=None,
|
||||
delta_years=0, delta_months=0, delta_days=0, start=None, **kwargs):
|
||||
year = kwargs.get('y', year)
|
||||
month = kwargs.get('M', month)
|
||||
day = kwargs.get('d', day)
|
||||
delta_years = kwargs.get('dy', delta_years)
|
||||
delta_months = kwargs.get('dM', delta_months)
|
||||
delta_days = kwargs.get('dd', delta_days)
|
||||
super(Date, self).__init__()
|
||||
for i in (year, month, day, delta_years, delta_months, delta_days):
|
||||
if isinstance(i, PYSON):
|
||||
assert i.types().issubset({int, type(None)}), \
|
||||
'%s must be an integer or None' % (i,)
|
||||
else:
|
||||
assert isinstance(i, (int, type(None))), \
|
||||
'%s must be an integer or None' % (i,)
|
||||
self._year = year
|
||||
self._month = month
|
||||
self._day = day
|
||||
self._delta_years = delta_years
|
||||
self._delta_months = delta_months
|
||||
self._delta_days = delta_days
|
||||
self._start = start
|
||||
|
||||
@property
|
||||
def __repr_params__(self):
|
||||
return (self._year, self._month, self._day,
|
||||
self._delta_years, self._delta_months, self._delta_days,
|
||||
self._start)
|
||||
|
||||
def pyson(self):
|
||||
return {
|
||||
'__class__': 'Date',
|
||||
'y': self._year,
|
||||
'M': self._month,
|
||||
'd': self._day,
|
||||
'dy': self._delta_years,
|
||||
'dM': self._delta_months,
|
||||
'dd': self._delta_days,
|
||||
'start': self._start,
|
||||
}
|
||||
|
||||
def types(self):
|
||||
return {datetime.date}
|
||||
|
||||
@staticmethod
|
||||
def eval(dct, context):
|
||||
today = dct.get('start')
|
||||
if isinstance(today, datetime.datetime):
|
||||
today = today.date()
|
||||
if not isinstance(today, datetime.date):
|
||||
today = datetime.date.today()
|
||||
return today + relativedelta(
|
||||
year=dct['y'],
|
||||
month=dct['M'],
|
||||
day=dct['d'],
|
||||
years=dct['dy'],
|
||||
months=dct['dM'],
|
||||
days=dct['dd'],
|
||||
)
|
||||
|
||||
|
||||
class DateTime(Date):
|
||||
|
||||
def __init__(self, year=None, month=None, day=None,
|
||||
hour=None, minute=None, second=None, microsecond=None,
|
||||
delta_years=0, delta_months=0, delta_days=0,
|
||||
delta_hours=0, delta_minutes=0, delta_seconds=0,
|
||||
delta_microseconds=0, start=None, **kwargs):
|
||||
hour = kwargs.get('h', hour)
|
||||
minute = kwargs.get('m', minute)
|
||||
second = kwargs.get('s', second)
|
||||
microsecond = kwargs.get('ms', microsecond)
|
||||
delta_hours = kwargs.get('dh', delta_hours)
|
||||
delta_minutes = kwargs.get('dm', delta_minutes)
|
||||
delta_seconds = kwargs.get('ds', delta_seconds)
|
||||
delta_microseconds = kwargs.get('dms', delta_microseconds)
|
||||
super(DateTime, self).__init__(year=year, month=month, day=day,
|
||||
delta_years=delta_years, delta_months=delta_months,
|
||||
delta_days=delta_days, start=start, **kwargs)
|
||||
for i in (hour, minute, second, microsecond,
|
||||
delta_hours, delta_minutes, delta_seconds, delta_microseconds):
|
||||
if isinstance(i, PYSON):
|
||||
assert i.types() == {int, type(None)}, \
|
||||
'%s must be an integer or None' % (i,)
|
||||
else:
|
||||
assert isinstance(i, (int, type(None))), \
|
||||
'%s must be an integer or None' % (i,)
|
||||
self._hour = hour
|
||||
self._minute = minute
|
||||
self._second = second
|
||||
self._microsecond = microsecond
|
||||
self._delta_hours = delta_hours
|
||||
self._delta_minutes = delta_minutes
|
||||
self._delta_seconds = delta_seconds
|
||||
self._delta_microseconds = delta_microseconds
|
||||
|
||||
@property
|
||||
def __repr_params__(self):
|
||||
date_params = super(DateTime, self).__repr_params__
|
||||
return (date_params[:3]
|
||||
+ (self._hour, self._minute, self._second, self._microsecond)
|
||||
+ date_params[3:-1]
|
||||
+ (self._delta_hours, self._delta_minutes, self._delta_seconds,
|
||||
self._delta_microseconds)
|
||||
+ date_params[-1:])
|
||||
|
||||
def pyson(self):
|
||||
res = super(DateTime, self).pyson()
|
||||
res['__class__'] = 'DateTime'
|
||||
res['h'] = self._hour
|
||||
res['m'] = self._minute
|
||||
res['s'] = self._second
|
||||
res['ms'] = self._microsecond
|
||||
res['dh'] = self._delta_hours
|
||||
res['dm'] = self._delta_minutes
|
||||
res['ds'] = self._delta_seconds
|
||||
res['dms'] = self._delta_microseconds
|
||||
return res
|
||||
|
||||
def types(self):
|
||||
return {datetime.datetime}
|
||||
|
||||
@staticmethod
|
||||
def eval(dct, context):
|
||||
now = dct.get('start')
|
||||
if (isinstance(now, datetime.date)
|
||||
and not isinstance(now, datetime.datetime)):
|
||||
now = datetime.datetime.combine(now, datetime.time())
|
||||
if not isinstance(now, datetime.datetime):
|
||||
now = datetime.datetime.utcnow()
|
||||
return now + relativedelta(
|
||||
year=dct['y'],
|
||||
month=dct['M'],
|
||||
day=dct['d'],
|
||||
hour=dct['h'],
|
||||
minute=dct['m'],
|
||||
second=dct['s'],
|
||||
microsecond=dct['ms'],
|
||||
years=dct['dy'],
|
||||
months=dct['dM'],
|
||||
days=dct['dd'],
|
||||
hours=dct['dh'],
|
||||
minutes=dct['dm'],
|
||||
seconds=dct['ds'],
|
||||
microseconds=dct['dms'],
|
||||
)
|
||||
|
||||
|
||||
class TimeDelta(PYSON):
|
||||
|
||||
def __init__(self, days=0, seconds=0, microseconds=0):
|
||||
for i in [days, seconds, microseconds]:
|
||||
if isinstance(i, PYSON):
|
||||
assert i.types().issubset({int, float}), \
|
||||
'%s must be an integer' % (i,)
|
||||
else:
|
||||
assert isinstance(i, (int, float)), \
|
||||
'%s must be an integer' % (i,)
|
||||
self._days = days
|
||||
self._seconds = seconds
|
||||
self._microseconds = microseconds
|
||||
|
||||
@property
|
||||
def __repr_params__(self):
|
||||
return self._days, self._seconds, self._microseconds
|
||||
|
||||
def pyson(self):
|
||||
return {
|
||||
'__class__': 'TimeDelta',
|
||||
'd': self._days,
|
||||
's': self._seconds,
|
||||
'm': self._microseconds,
|
||||
}
|
||||
|
||||
def types(self):
|
||||
return {datetime.timedelta}
|
||||
|
||||
@staticmethod
|
||||
def eval(dct, context):
|
||||
return datetime.timedelta(
|
||||
days=dct['d'],
|
||||
seconds=dct['s'],
|
||||
microseconds=dct['m'],
|
||||
)
|
||||
|
||||
|
||||
class Len(PYSON):
|
||||
|
||||
def __init__(self, v):
|
||||
super(Len, self).__init__()
|
||||
if isinstance(v, PYSON):
|
||||
assert v.types().issubset({dict, list, str}), \
|
||||
'value must be a dict or a list or a string'
|
||||
else:
|
||||
assert isinstance(v, (dict, list, str)), \
|
||||
'value must be a dict or list or a string'
|
||||
self._value = v
|
||||
|
||||
@property
|
||||
def __repr_params__(self):
|
||||
return (self._value,)
|
||||
|
||||
def pyson(self):
|
||||
return {
|
||||
'__class__': 'Len',
|
||||
'v': self._value,
|
||||
}
|
||||
|
||||
def types(self):
|
||||
return {int}
|
||||
|
||||
@staticmethod
|
||||
def eval(dct, context):
|
||||
return len(dct['v'])
|
||||
|
||||
|
||||
class Id(PYSON):
|
||||
"""The database id for filesystem id"""
|
||||
|
||||
def __init__(self, module, fs_id):
|
||||
super(Id, self).__init__()
|
||||
self._module = module
|
||||
self._fs_id = fs_id
|
||||
|
||||
@property
|
||||
def __repr_params__(self):
|
||||
return (self._module, self._fs_id)
|
||||
|
||||
def pyson(self):
|
||||
from trytond.pool import Pool
|
||||
ModelData = Pool().get('ir.model.data')
|
||||
return ModelData.get_id(self._module, self._fs_id)
|
||||
|
||||
def types(self):
|
||||
return {int}
|
||||
|
||||
|
||||
CONTEXT = {
|
||||
'Eval': Eval,
|
||||
'Not': Not,
|
||||
'Bool': Bool,
|
||||
'And': And,
|
||||
'Or': Or,
|
||||
'Equal': Equal,
|
||||
'Greater': Greater,
|
||||
'Less': Less,
|
||||
'If': If,
|
||||
'Get': Get,
|
||||
'In': In,
|
||||
'Date': Date,
|
||||
'DateTime': DateTime,
|
||||
'TimeDelta': TimeDelta,
|
||||
'Len': Len,
|
||||
'Id': Id,
|
||||
'true': True,
|
||||
'false': False,
|
||||
}
|
||||
Reference in New Issue
Block a user