Skip to content

Instantly share code, notes, and snippets.

@scastillo
Created August 17, 2018 07:11
Show Gist options
  • Select an option

  • Save scastillo/0139c63805181076bb4d31aebe2079b4 to your computer and use it in GitHub Desktop.

Select an option

Save scastillo/0139c63805181076bb4d31aebe2079b4 to your computer and use it in GitHub Desktop.
import logging
import datetime
from google.appengine.ext import db
from core import configuration
from core import errors
from core.helpers import properties
class PropertyParser(object):
@classmethod
def parse_nested_param(cls, attr, value):
attr1, attr2 = attr.split('.')
#logging.debug('attr1: %s - attr2: %s - value' % (attr1, attr2))
valid_attrs = cls.properties()
if attr1 in valid_attrs:
logging.info('attr1 in valid attrs: %s' % attr1)
ref_class = valid_attrs[attr1].reference_class
#logging.debug('ref_class: %s' % ref_class)
if ref_class is not None:
filter = {attr2: value}
items = ref_class.find(keys_only=True, limit=30, **filter) # GAE limitation for IN filter
if len(items) == 1:
items = items[0]
attr = attr1
value = items
logging.info('RESULT: attr: %s - value: %s' % (attr, value))
else:
logging.error("Nested Query: Reference class could not be resolved: %s" % attr)
return attr, value
@classmethod
def parse_properties(cls, params):
"""
"""
e = errors.Error()
valid_attrs = cls.properties().keys()
parsed_params = {}
for attr, value in params.items():
#logging.debug("attr = %s" % attr)
# Check for nested queries
if '.' in attr:
logging.info('We have a nested value here %s' % attr)
attr, value = cls.parse_nested_param(attr, value)
if isinstance(value, list):
attr = 'in_' + attr
# strip min, max, dif, in from attribute so we can parse those ones too.
_attr = attr
if attr.startswith('min_') or attr.startswith('max_') or attr.startswith('dif_'):
_attr = attr[4:]
elif attr.startswith('in_'):
_attr = attr[3:]
elif attr.startswith('like_'):
_attr = attr[5:]
if _attr not in valid_attrs:
#logging.info("%s is not in valid_attrs: %s" % (_attr, valid_attrs))
continue
# Strip params (this is mostly for codes that don't accept spaces)
if attr in cls.get_strip_properties() and is_string_or_unicode(value):
value = value.strip()
prop = getattr(cls, _attr)
try:
#logging.debug("before parse_params: %s=%s" % (attr, value))
parsed_params[attr] = parse_param(prop, value)
#logging.debug("after parse_params: %s=%s" % (attr, parsed_params[attr]))
except Exception, err:
logging.error("Error parsing param %s: %s" % (prop, err))
e.InvalidFormatError("%s" % (prop.name))
if e.has_errors():
logging.error("PARSER_ERROR: %s" % e)
raise e
# parent is not a property, so just pass it as it comes
if 'parent' in params:
parsed_params['parent'] = params['parent']
return parsed_params
def parse_param(property, value):
functions = {
db.IntegerProperty: parse_int,
db.FloatProperty: parse_float,
db.DateTimeProperty: parse_datetime,
db.DateProperty: parse_date,
db.StringProperty: parse_non_multiline_string,
db.TextProperty: parse_string,
db.EmailProperty: parse_email,
db.ReferenceProperty: parse_reference,
db.ListProperty: parse_list,
db.StringListProperty: parse_string_list,
properties.PasswordProperty: parse_password,
properties.PasswordPropertyRot13: parse_password,
db.GeoPtProperty: parse_geopt,
db.BooleanProperty: parse_boolean,
properties.IdentityDocumentProperty: parse_identity_document,
}
# Allow _None for all properties
if is_string_or_unicode(value) and value == '_None':
ret = None
# This is needed for IN queries
elif isinstance(value, list) and type(property) != db.StringListProperty:
ret = parse_list(property, value)
else:
property_model = type(property)
ret = functions[property_model](property, value)
return ret
def parse_int(property, value):
if not isinstance(value, int):
return int(value)
else:
return value
def parse_float(property, value):
if type(value) in [int, str, unicode]:
return float(value)
else:
return value
def parse_datetime(property, value):
if is_string_or_unicode(value):
return datetime.datetime.strptime(value, configuration("datetime-format"))
else:
return value
def parse_date(property, value):
if is_string_or_unicode(value):
return datetime.datetime.strptime(value, configuration("date-format")).date()
else:
return value
def parse_non_multiline_string(property, value):
value = parse_string(property, value)
if value is not None:
value = value.replace('\n', ' ')
return value
def parse_string(property, value):
if isinstance(value, str):
value = value.decode('utf-8')
elif not isinstance(value, unicode) and value is not None: # Accept None at StringProperty
value = str(value)
return value
def parse_email(property, value):
parsed_email = parse_non_multiline_string(property, value)
if parsed_email == "":
parsed_email = None
if parsed_email is not None:
parsed_email = parsed_email.lower()
return parsed_email
def parse_reference(property, value):
"""
If value is an str it could be an ID let's search for it
"""
reference_class = property.reference_class
if is_string_or_unicode(value) and hasattr(reference_class, 'find_by_id'):
entity = reference_class.find_by_id(value)
if entity is not None:
value = entity
else:
value = -1
return value
def parse_password(property, value):
password = parse_string(property, value)
res = property.paymentez_encode(password.encode('utf-8', 'ignore'))
return res
def parse_list(property, items):
logging.debug("############PROPERTY %s, items %s" % (type(property), type(items)))
if not isinstance(items, list):
logging.debug("############PROPERTY entra %s" % items )
if property.item_type in [int]: # Supported item types casting in lists
items = property.item_type(items)
return items
logging.debug("############PROPERTY out %s" % items)
return [parse_param(property, item) for item in items]
def parse_string_list(property, items):
TYPES_TO_CAST = [int]
if not isinstance(items, list):
if type(items) in TYPES_TO_CAST:
items = parse_string(items)
items = [items]
return items
def parse_geopt(property, value):
logging.debug("parse_geopt")
x = value[0]
y = value[1]
logging.debug("$$$$$$ x=%s, y=%s" % (x, y))
logging.debug("type(property): %s" % type(property))
return "%s,%s" % (x, y)
def parse_boolean(property, value):
options = {'true': True, 'false': False, '0': False, '1': True}
if is_string_or_unicode(value):
return options[value.lower()]
else:
return value
def is_string_or_unicode(value):
return isinstance(value, str) or isinstance(value, unicode)
def parse_identity_document(property, value):
document = parse_string(property, value)
return property.paymentez_encode(document)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment