Created
August 17, 2018 07:11
-
-
Save scastillo/0139c63805181076bb4d31aebe2079b4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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