@@ 1,6 1,13 @@
import json
+import calendar as cal
+from datetime import datetime as dt
-from dateutil.parser import isoparse, parse as defaultparse
+from dateutil.parser import (
+ isoparse,
+ parse as defaultparse
+)
+from dateutil.relativedelta import relativedelta
+from psyl import lisp
def parsedatetime(strdt):
@@ 105,3 112,41 @@ class datetime(inputio):
return isoparse(val)
except ValueError:
return defaultparse(val)
+
+
+def last_day_of_month(dt):
+ return cal.monthrange(dt.year, dt.month)[1]
+
+
+_MOMENT_ENV = lisp.Env({
+ 'date': lambda strdate: parsedatetime(strdate),
+ 'today': lambda: dt.now(),
+ 'monthstart': lambda dt: dt.replace(day=1),
+ 'monthend': lambda dt: dt.replace(day=last_day_of_month(dt)),
+ 'yearstart': lambda dt: dt.replace(day=1, month=1),
+ 'yearend': lambda dt: dt.replace(day=31, month=12),
+ 'delta': lambda dt, **kw: dt + relativedelta(**kw),
+})
+
+
+class moment(inputio):
+
+ def binary_encode(self, args):
+ val = self.val(args)
+ if val is None:
+ return
+ try:
+ # validate the expression
+ lisp.evaluate(val, env=_MOMENT_ENV)
+ except:
+ import traceback as tb; tb.print_exc()
+ raise
+
+ return val.encode('utf-8')
+
+ def binary_decode(self, args):
+ val = args.get(self.name)
+ if val is None:
+ return
+ val = val.decode('utf-8')
+ return lisp.evaluate(val, env=_MOMENT_ENV)
@@ 27,7 27,8 @@ setup(name='rework',
'inireader',
'apscheduler',
'zstd',
- 'dateutil'
+ 'dateutils',
+ 'psyl'
],
package_data={'rework': [
'schema.sql'
@@ 65,6 65,10 @@ def register_tasks():
def noinput(task):
pass
+ @api.task(inputs=(input.moment('when'),))
+ def happy_days(task):
+ pass
+
def test_freeze_ops(engine, cleanup):
@@ 82,6 86,9 @@ def test_freeze_ops(engine, cleanup):
assert res == [
('cheesy', 'cheese', None),
('foo', 'default', None),
+ ('happy_days', 'default', [
+ {'choices': None, 'name': 'when', 'required': False, 'type': 'moment'}
+ ]),
('noinput', 'default', []),
('yummy', 'default', [
{'choices': None, 'name': 'myfile.txt', 'required': True, 'type': 'file'},
@@ 104,6 111,7 @@ def test_freeze_ops(engine, cleanup):
).fetchall()
assert res == [
('foo', 'default'),
+ ('happy_days', 'default'),
('noinput', 'default'),
('yummy', 'default'),
('hammy', 'ham')
@@ 177,6 185,26 @@ def test_with_inputs(engine, cleanup):
}
+def test_moment_input(engine, cleanup):
+ register_tasks()
+ api.freeze_operations(engine)
+ t = api.schedule(
+ engine,
+ 'happy_days',
+ inputdata={'when': '(delta (today) #:days 1)'}
+ )
+ when = t.input['when']
+ assert when > dt.now()
+
+ t = api.schedule(
+ engine,
+ 'happy_days',
+ inputdata={'when': '(date "2021-1-1 09:00")'}
+ )
+ when = t.input['when']
+ assert when == dt(2021, 1, 1, 9, 0)
+
+
def test_prepare_with_inputs(engine, cleanup):
reset_ops(engine)
register_tasks()