Add start value to PYSON Date and DateTime

This enable the customization of the starting point for delta operations.

issue8561
review264041002
This commit is contained in:
Cédric Krier
2019-09-20 11:36:05 +02:00
parent def268915a
commit 507a8e26fe
4 changed files with 108 additions and 32 deletions
+1
View File
@@ -1,3 +1,4 @@
* Add start value to PYSON Date and DateTime
* Add MultiSelection field
* Support dot notation on PYSON Eval
* Add __slots__
+25 -21
View File
@@ -176,17 +176,16 @@ statement for look-up dictionary or integer objects. Returns true when
a list (or dictionary) object named by ``obj`` contains the value of
the variable (or key) named by ``key``. Otherwise returns false.
.. class:: Date([year[, month[, day[, delta_years[, delta_month[, delta_days]]]]]])
.. class:: Date([year[, month[, day[, delta_years[, delta_month[, delta_days[, start]]]]]]])
A :class:`Date` object represents the PYSON ``Date()``
statement for date related conversions and basic calculations.
Returns a date object which represents
the values of arguments named by the *variables* explained below.
Missing values of arguments named by ``year`` or ``month`` or
``day`` take their defaults from the actual date. When values of
arguments named by ``delta_*`` are given, they are added to the
values of the appropriate arguments in a date and time preserving
manner.
A :class:`Date` object represents the PYSON ``Date()`` statement for date
related conversions and basic calculations.
Returns a date object which represents the values of arguments named by the
*variables* explained below.
Missing values of arguments named by ``year`` or ``month`` or ``day`` take
their defaults from ``start`` or the actual date. When values of arguments
named by ``delta_*`` are given, they are added to the values of the appropriate
arguments in a date and time preserving manner.
Arguments:
@@ -208,18 +207,20 @@ Arguments:
``delta_days``
Contains a PYSON statement of type int or long.
.. class:: DateTime([year[, month[, day[, hour[, minute[, second[, microsecond[, delta_years[, delta_months[, delta_days[, delta_hours[, delta_minutes[, delta_seconds[, delta_microseconds]]]]]]]]]]]]]])
``start``
Contains a PYSON statement of type date.
A :class:`DateTime` object represents the PYSON ``Date()``
statement for date and time related conversions and calculations.
Returns a date time object which represents the values of
variables named by the *arguments* explained below.
Missing values of arguments named by ``year``, ``month``, ``day``,
``hour``, ``minute``, ``second``, ``microseconds`` take their
defaults from the actual date and time.
When values of arguments named by ``delta_*`` are given, these are
added to the appropriate attributes in a date and time preserving
manner.
.. class:: DateTime([year[, month[, day[, hour[, minute[, second[, microsecond[, delta_years[, delta_months[, delta_days[, delta_hours[, delta_minutes[, delta_seconds[, delta_microseconds[, start]]]]]]]]]]]]]]])
A :class:`DateTime` object represents the PYSON ``Date()`` statement for date
and time related conversions and calculations.
Returns a date time object which represents the values of variables named by
the *arguments* explained below.
Missing values of arguments named by ``year``, ``month``, ``day``, ``hour``,
``minute``, ``second``, ``microseconds`` take their defaults from ``start`` or
the actual date and time.
When values of arguments named by ``delta_*`` are given, these are added to
the appropriate attributes in a date and time preserving manner.
Arguments:
@@ -265,6 +266,9 @@ Arguments:
``delta_microseconds``
Contains a PYSON statement of type int or long.
``start``
Contains a PYSON statement of type datetime.
.. class:: Len(value)
A :class:`Len` object represents the PYSON ``Len()`` statement for length of a
+23 -8
View File
@@ -501,7 +501,7 @@ class In(PYSON):
class Date(PYSON):
def __init__(self, year=None, month=None, day=None,
delta_years=0, delta_months=0, delta_days=0, **kwargs):
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)
@@ -522,11 +522,13 @@ class Date(PYSON):
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._delta_years, self._delta_months, self._delta_days,
self._start)
def pyson(self):
return {
@@ -537,6 +539,7 @@ class Date(PYSON):
'dy': self._delta_years,
'dM': self._delta_months,
'dd': self._delta_days,
'start': self._start,
}
def types(self):
@@ -544,7 +547,12 @@ class Date(PYSON):
@staticmethod
def eval(dct, context):
return datetime.date.today() + relativedelta(
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'],
@@ -560,7 +568,7 @@ class DateTime(Date):
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, **kwargs):
delta_microseconds=0, start=None, **kwargs):
hour = kwargs.get('h', hour)
minute = kwargs.get('m', minute)
second = kwargs.get('s', second)
@@ -571,7 +579,7 @@ class DateTime(Date):
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, **kwargs)
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):
@@ -594,9 +602,10 @@ class DateTime(Date):
date_params = super(DateTime, self).__repr_params__
return (date_params[:3]
+ (self._hour, self._minute, self._second, self._microsecond)
+ date_params[3:]
+ date_params[3:-1]
+ (self._delta_hours, self._delta_minutes, self._delta_seconds,
self._delta_microseconds))
self._delta_microseconds)
+ date_params[-1:])
def pyson(self):
res = super(DateTime, self).pyson()
@@ -616,7 +625,13 @@ class DateTime(Date):
@staticmethod
def eval(dct, context):
return datetime.datetime.now() + relativedelta(
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.now()
return now + relativedelta(
year=dct['y'],
month=dct['M'],
day=dct['d'],
+59 -3
View File
@@ -408,7 +408,8 @@ class PYSONTestCase(unittest.TestCase):
'd': 12,
'dy': -1,
'dM': 12,
'dd': -7
'dd': -7,
'start': None,
})
if not sys.flags.optimize:
@@ -453,7 +454,33 @@ class PYSONTestCase(unittest.TestCase):
datetime.date(2010, 2, 22))
self.assertEqual(repr(pyson.Date(2010, 1, 12, -1, 12, -7)),
'Date(2010, 1, 12, -1, 12, -7)')
'Date(2010, 1, 12, -1, 12, -7, None)')
def test_Date_start(self):
"Test Date with start"
eval = pyson.PYSONEncoder().encode(pyson.Date(
start=pyson.Eval('date')))
date = datetime.date(2000, 1, 1)
self.assertEqual(pyson.PYSONDecoder(
{'date': date}).decode(eval), date)
def test_Date_start_datetime(self):
"Test Date with start as datetime"
eval = pyson.PYSONEncoder().encode(pyson.Date(
start=pyson.Eval('datetime')))
datetime_ = datetime.datetime(2000, 1, 1, 12, 00)
self.assertEqual(pyson.PYSONDecoder(
{'datetime': datetime_}).decode(eval), datetime_.date())
def test_Date_start_invalid(self):
"Test Date with invalid start"
eval = pyson.PYSONEncoder().encode(pyson.Date(
start=pyson.Eval('foo')))
self.assertEqual(pyson.PYSONDecoder(
{'foo': 'bar'}).decode(eval), datetime.date.today())
def test_DateTime(self):
'Test pyson.DateTime'
@@ -474,6 +501,7 @@ class PYSONTestCase(unittest.TestCase):
'dm': 15,
'ds': 30,
'dms': 1,
'start': None,
})
if not sys.flags.optimize:
@@ -570,7 +598,35 @@ class PYSONTestCase(unittest.TestCase):
self.assertEqual(repr(pyson.DateTime(2010, 1, 12, 10, 30, 20, 0,
-1, 12, -7, 2, 15, 30, 1)),
'DateTime(2010, 1, 12, 10, 30, 20, 0, -1, 12, -7, 2, 15, 30, 1)')
('DateTime(2010, 1, 12, 10, 30, 20, 0, '
'-1, 12, -7, 2, 15, 30, 1, None)'))
def test_DateTime_start(self):
"Test DateTime with start"
eval = pyson.PYSONEncoder().encode(pyson.DateTime(
start=pyson.Eval('datetime')))
datetime_ = datetime.datetime(2000, 1, 1, 12, 0)
self.assertEqual(pyson.PYSONDecoder(
{'datetime': datetime_}).decode(eval), datetime_)
def test_DateTime_start_datetime(self):
"Test DateTime with start as date"
eval = pyson.PYSONEncoder().encode(pyson.DateTime(
start=pyson.Eval('date')))
date = datetime.date(2000, 1, 1)
self.assertEqual(pyson.PYSONDecoder(
{'date': date}).decode(eval),
datetime.datetime(2000, 1, 1, 0, 0))
def test_DateTime_start_invalid(self):
"Test DateTime with invalid start"
eval = pyson.PYSONEncoder().encode(pyson.DateTime(
start=pyson.Eval('foo')))
self.assertIsInstance(pyson.PYSONDecoder(
{'foo': 'bar'}).decode(eval), datetime.datetime)
def test_Len(self):
'Test pyson.Len'