def parse_body_dict(self, model, allow_recursion, body_data): attributes = {} linked_attributes = {} mapper = inspect(model) for key, value in body_data.items(): if isinstance(getattr(model, key, None), property): # Value is set using a function, so we cannot tell what type it will be attributes[key] = value continue try: column = mapper.columns[key] except KeyError: if not allow_recursion: # Assume programmer has done their job of filtering out invalid # columns, and that they are going to use this field for some # custom purpose continue try: relationship = mapper.relationships[key] if relationship.uselist: linked_attributes[key] = [ self.parse_body_dict(relationship.mapper.entity, False, entity)[0] for entity in value ] else: linked_attributes[key] = self.parse_body_dict( relationship.mapper.entity, False, value)[0] continue except KeyError: # Assume programmer has done their job of filtering out invalid # columns, and that they are going to use this field for some # custom purpose continue if isinstance(column.type, sqlalchemy.sql.sqltypes.DateTime): if value is None: attributes[key] = None elif key in getattr( self, 'datetime_in_ms', [] ): # List of datetime columns to keep as ms since Unix epoch attributes[key] = datetime.fromtimestamp(value) elif key in getattr(self, 'naive_datetimes', []): # List of naive datetime columns attributes[key] = datetime.strptime( value, '%Y-%m-%dT%H:%M:%S') else: attributes[key] = datetime.strptime( value, '%Y-%m-%dT%H:%M:%SZ') elif isinstance(column.type, sqlalchemy.sql.sqltypes.Date): attributes[key] = datetime.strptime( value, '%Y-%m-%d').date() if value is not None else None elif isinstance(column.type, sqlalchemy.sql.sqltypes.Time): if value is not None: hour, minute, second = value.split(':') attributes[key] = time(int(hour), int(minute), int(second)) else: attributes[key] = None elif support_geo and isinstance( column.type, Geometry) and column.type.geometry_type in [ 'POINT', 'POINTZ' ]: axes = getattr(self, 'geometry_axes', {}).get( key, ['x', 'y', 'z'] if column.type.geometry_type == 'POINTZ' else ['x', 'y']) point = Point(*list( value.get(axes[index], 0) for index in range(0, len(axes)))) # geoalchemy2.shape.from_shape uses buffer() which causes INSERT to fail attributes[key] = WKBElement(point.wkb, srid=4326) elif support_geo and isinstance( column.type, Geometry) and column.type.geometry_type in [ 'LINESTRING', 'LINESTRINGZ' ]: axes = getattr(self, 'geometry_axes', {}).get( key, ['x', 'y', 'z'] if column.type.geometry_type == 'LINESTRINGZ' else ['x', 'y']) line = LineString([ point.get(axes[index], 0) for index in range(0, len(axes)) ] for point in value) # geoalchemy2.shape.from_shape uses buffer() which causes INSERT to fail attributes[key] = WKBElement(line.wkb, srid=4326) elif support_geo and isinstance( column.type, Geometry) and column.type.geometry_type in [ 'POLYGON', 'POLYGONZ' ]: axes = getattr(self, 'geometry_axes', {}).get( key, ['x', 'y', 'z'] if column.type.geometry_type == 'POLYGONZ' else ['x', 'y']) polygon = Polygon([ point.get(axes[index], 0) for index in range(0, len(axes)) ] for point in value) # geoalchemy2.shape.from_shape uses buffer() which causes INSERT to fail attributes[key] = WKBElement(polygon.wkb, srid=4326) else: attributes[key] = value return (attributes, linked_attributes)
def deserialize(self, model, path_data, body_data, allow_recursion=False): mapper = inspect(model) attributes = {} naive_datetimes = getattr(self, 'naive_datetimes', []) for key, value in path_data.items(): key = getattr(self, 'attr_map', {}).get(key, key) if getattr(model, key, None) is None or not isinstance( inspect(model).attrs[key], ColumnProperty): self.logger.error( "Programming error: {0}.attr_map['{1}'] does not exist or is not a column" .format(model, key)) raise falcon.errors.HTTPInternalServerError( 'Internal Server Error', 'An internal server error occurred') attributes[key] = value deserialized = [attributes, {}] for key, value in body_data.items(): if isinstance(getattr(model, key, None), property): # Value is set using a function, so we cannot tell what type it will be attributes[key] = value continue try: column = mapper.columns[key] except KeyError: if not allow_recursion: # Assume programmer has done their job of filtering out invalid # columns, and that they are going to use this field for some # custom purpose continue try: relationship = mapper.relationships[key] if relationship.uselist: for entity in value: deserialized[1][key] = [ self.deserialize(relationship.mapper.entity, {}, entity, False)[0] for entity in value ] else: deserialized[1][key] = self.deserialize( relationship.mapper.entity, {}, value, False)[0] continue except KeyError: # Assume programmer has done their job of filtering out invalid # columns, and that they are going to use this field for some # custom purpose continue if isinstance(column.type, sqlalchemy.sql.sqltypes.DateTime): if value is None: attributes[key] = None elif key in naive_datetimes: attributes[key] = datetime.strptime( value, '%Y-%m-%dT%H:%M:%S') else: attributes[key] = datetime.strptime( value, '%Y-%m-%dT%H:%M:%SZ') elif isinstance(column.type, sqlalchemy.sql.sqltypes.Date): attributes[key] = datetime.strptime( value, '%Y-%m-%d').date() if value is not None else None elif isinstance(column.type, sqlalchemy.sql.sqltypes.Time): if value is not None: hour, minute, second = value.split(':') attributes[key] = time(int(hour), int(minute), int(second)) else: attributes[key] = None elif support_geo and isinstance( column.type, Geometry) and column.type.geometry_type in [ 'POINT', 'POINTZ' ]: axes = getattr(self, 'geometry_axes', {}).get( key, ['x', 'y', 'z'] if column.type.geometry_type == 'POINTZ' else ['x', 'y']) point = Point(*list( value.get(axes[index], 0) for index in range(0, len(axes)))) # geoalchemy2.shape.from_shape uses buffer() which causes INSERT to fail attributes[key] = WKBElement(point.wkb, srid=4326) elif support_geo and isinstance( column.type, Geometry) and column.type.geometry_type in [ 'LINESTRING', 'LINESTRINGZ' ]: axes = getattr(self, 'geometry_axes', {}).get( key, ['x', 'y', 'z'] if column.type.geometry_type == 'LINESTRINGZ' else ['x', 'y']) line = LineString([ point.get(axes[index], 0) for index in range(0, len(axes)) ] for point in value) # geoalchemy2.shape.from_shape uses buffer() which causes INSERT to fail attributes[key] = WKBElement(line.wkb, srid=4326) elif support_geo and isinstance( column.type, Geometry) and column.type.geometry_type in [ 'POLYGON', 'POLYGONZ' ]: axes = getattr(self, 'geometry_axes', {}).get( key, ['x', 'y', 'z'] if column.type.geometry_type == 'POLYGONZ' else ['x', 'y']) polygon = Polygon([ point.get(axes[index], 0) for index in range(0, len(axes)) ] for point in value) # geoalchemy2.shape.from_shape uses buffer() which causes INSERT to fail attributes[key] = WKBElement(polygon.wkb, srid=4326) else: attributes[key] = value return deserialized