wcs/wcs/qommon/evalutils.py

172 lines
5.6 KiB
Python

# w.c.s. - web application for online forms
# Copyright (C) 2005-2016 Entr'ouvert
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
"""
Collection of utility functions to be used in the context of calls to
eval(). They are made available in the "utils" namespace of
get_global_eval_dict.
"""
import datetime
import re
import time
from django.utils.encoding import force_bytes
from wcs.qommon import force_str
from .misc import get_as_datetime
today = datetime.date.today
now = datetime.datetime.now
def make_date(date_var):
'''Extract a date from a datetime, a date, a struct_time or a string'''
if isinstance(date_var, datetime.datetime):
return date_var.date()
if isinstance(date_var, datetime.date):
return date_var.replace() # use replace to un-lazy
if isinstance(date_var, time.struct_time) or (
isinstance(date_var, tuple) and len(date_var) == 9):
return datetime.date(*date_var[:3])
try:
return get_as_datetime(str(date_var)).date()
except ValueError:
raise ValueError('invalid date value: %s' % date_var)
def make_datetime(datetime_var):
'''Extract a date from a datetime, a date, a struct_time or a string'''
if isinstance(datetime_var, datetime.datetime):
return datetime_var.replace() # use replace to un-lazy
if isinstance(datetime_var, datetime.date):
return datetime.datetime(year=datetime_var.year, month=datetime_var.month,
day=datetime_var.day)
if isinstance(datetime_var, time.struct_time) or (
isinstance(datetime_var, tuple) and len(datetime_var) == 9):
return datetime.datetime(*datetime_var[:6])
try:
return get_as_datetime(str(datetime_var))
except ValueError:
raise ValueError('invalid datetime value: %s' % datetime_var)
def date(var, month=None, day=None):
if var and month and day:
return datetime.date(int(var), int(month), int(day))
return make_date(var)
def days(count):
return datetime.timedelta(days=int(count))
def time_delta(t1, t2):
return make_date(t1) - make_date(t2)
def date_delta(t1, t2):
'''Return the timedelta between two date like values'''
t1, t2 = make_date(t1), make_date(t2)
return t1 - t2
def datetime_delta(t1, t2):
'''Return the timedelta between two datetime like values'''
t1, t2 = make_datetime(t1), make_datetime(t2)
return t1 - t2
def age_in_years_and_months(born, today=None):
'''Compute age since today as the number of years and months elapsed'''
born = make_date(born)
if today is None:
today = datetime.date.today()
today = make_date(today)
before = (today.month, today.day) < (born.month, born.day)
years = today.year - born.year
months = today.month - born.month
if before:
years -= 1
months += 12
if today.day < born.day:
months -= 1
return years, months
def age_in_years(born, today=None):
'''Compute age since today as the number of years elapsed'''
return age_in_years_and_months(born, today=today)[0]
def age_in_days(born, today=None):
'''Compute age since today as the number of days elapsed'''
born = make_date(born)
if today is None:
today = datetime.date.today()
today = make_date(today)
return date_delta(today, born).days
def age_in_seconds(born, today=None):
'''Compute age since today as the number of seconds elapsed'''
born = make_datetime(born)
if today is None:
today = datetime.datetime.now()
today = make_datetime(today)
return datetime_delta(today, born).total_seconds()
def add_days(date, count):
'''Add the given number of days to date'''
return make_date(date) + datetime.timedelta(days=count)
def attachment(content, filename='', content_type='application/octet-stream'):
'''Serialize content as an attachment'''
import base64
return {
'filename': filename,
'content_type': content_type,
'b64_content': force_str(base64.b64encode(force_bytes(content))),
}
def dict_from_prefix(prefix, in_dict):
'''Return a dict based on a dict filtered by a key prefix.
The prefix is removed from the key.
Intent: meant to help build a PicklableUpload from a set
of key/values stored in the workflow data.
Note: to use this function in a context of a Python
expression, you should pass the _wf_data_ using
the function locals()
Example: utils.dict_from_prefix('akey_', locals())
Where: the workflow data contains the key/values:
akey_filename = <filename>
akey_content_type = <mime_type>
akey_b64_content = <content base64 encoded>
And: it produces a dict like the key/values are:
filename = wf_data['akey_filename']
content_type = wf_data['akey_content_type']
b64_content = wf_data['akey_b64_content']
'''
return {k[len(prefix):]: v for k, v in in_dict.items() if k.startswith('%s' % prefix)}