covid-formity/formity/utils.py

86 lines
2.2 KiB
Python

import re
import enum
import decimal
import unicodedata
from sqlalchemy import inspect
from sqlalchemy.orm import exc, class_mapper
from sqlalchemy.orm.attributes import get_history
from werkzeug.exceptions import abort
def get_object_or_404(model, *criterion):
try:
rv = model.query.filter(*criterion).one()
except (exc.NoResultFound, exc.MultipleResultsFound):
abort(404)
else:
return rv
def strip_accents(text):
"""
Strip accents from input String.
:param text: The input string.
:type text: String.
:returns: The processed String.
:rtype: String.
"""
try:
text = unicode(text, 'utf-8')
except (TypeError, NameError): # unicode is a default on python 3
pass
text = unicodedata.normalize('NFD', text)
text = text.encode('ascii', 'ignore')
text = text.decode("utf-8")
return str(text)
def text_to_id(text):
"""
Convert input text to id.
:param text: The input string.
:type text: String.
:returns: The processed String.
:rtype: String.
"""
text = strip_accents(text.lower())
text = re.sub('[ ]+', '_', text)
text = re.sub('[^0-9a-zA-Z_-]', '', text)
return text
diff_sanitization_rules = [
(enum.Enum, lambda v: v.name),
(decimal.Decimal, float),
]
def get_diff(target, blacklist=['created', 'updated']):
state_before = {}
state_after = {}
inspr = inspect(target)
attrs = class_mapper(target.__class__).column_attrs
for attr in attrs:
if attr.key in blacklist:
continue
hist = getattr(inspr.attrs, attr.key).history
if hist.has_changes():
state_before[attr.key] = get_history(target, attr.key)[2].pop()
state_after[attr.key] = getattr(target, attr.key)
for data in [state_before, state_after]:
for t, c in diff_sanitization_rules:
if isinstance(data[attr.key], t):
data[attr.key] = c(data[attr.key])
if state_after[attr.key] == state_before[attr.key] or (state_after[attr.key] in ['', None] and state_before[attr.key] in ['', None]):
state_after.pop(attr.key)
state_before.pop(attr.key)
return state_before, state_after