def string_to_datatype(string_value): """Converts a string representation of a value into its original datatype.""" string_value = string_value.strip(' "') # try to return as boolean or none retval = string_value if string_value.lower() in ['true', 'false', 'none']: retval = eval(string_value) return retval # try to return as a decimal try: value = Decimal(string_value) if str(value) == string_value: retval = value except ValueError: pass except InvalidOperation: pass # try to return as an integer try: value = int(string_value) if str(value) == string_value: retval = value except ValueError: pass # try to return as date try: value = parser.parse(string_value) if value.strftime('%Y-%m-%d') == string_value: retval = value.date() except ValueError: pass except TypeError: pass # try to return as datetime try: value = parser.parse(string_value) if value.strftime('%Y-%m-%d %H:%M') == string_value: retval = value except ValueError: pass except TypeError: pass # otherwise return string value return retval
def coerce_value(cls, column, value, size_check=True): if value is None: if not column.nullable: raise ValueError( f'Null value not allowed for property {column.key} of type ' f'{cls!r}') return None try: python_type = column.type.python_type except NotImplementedError: # SA types that don't implement python_type treated early and explicity if column.type is HSTORE or type(column.type) is HSTORE: if value is None or isinstance(value, dict): # coerce all non-string values of hstore dict return {key: str(val) for key, val in value.items()} raise ValueError( f'Invalid type {type(value)!r} for property {column.key} of ' f'class {cls!r}') if column.type is UUID or type(column.type) is UUID: if column.type.as_uuid: if type(value) is int: return uuid.UUID(int=value) return uuid.UUID(value) return str(value) raise NotImplementedError(f'py_liant does not support {column.type!r} ' 'yet') if python_type is str: if value is not str: value = str(value) if isinstance(column.type, String) and hasattr(column.type, "length") \ and value is not None and column.type.length is not None \ and column.type.length < len(value) and size_check: raise ValueError( f'Text value too large for property {column.key} of class ' f'{cls!r}, limit {column.type.length}') if python_type is int: try: value = int(value) except ValueError: raise ValueError( 'Could not convert value to target type for property ' f'{column.key} of class {cls!r}') if python_type is Decimal and value is not None \ and type(value) is not Decimal: try: value = Decimal(value) except ArithmeticError: raise ValueError( 'Could not convert value to target type for property ' f'{column.key} of class {cls!r}') if python_type is float and value is not None and type(value) is not float: try: value = float(value) except ValueError: raise ValueError( 'Could not convert value to target type for property ' f'{column.key} of class {cls!r}') if python_type is bool and value is not None and type(value) is not bool: try: if type(value) is str: value = asbool(value) elif type(value) is int: if value not in [0, 1]: raise ValueError value = bool(value) else: raise ValueError( 'Could not convert value to target type for property ' f'{column.key} of class {cls!r}') except ValueError: raise ValueError( f'Expected boolean value for property {column.key} of class ' f'{cls!r}, received {type(value)!r} instead') if python_type in (datetime, date, time): try: use_timezone = False if isinstance(column.type, (DateTime, Time)): use_timezone = column.type.timezone def tzinfos(name, offset): if offset is not None: return tz.tzoffset(name, offset) return tz.gettz(name) or None value = parser.parse(value, tzinfos=tzinfos, ignoretz=not use_timezone) if python_type is date: value = value.date() if python_type is time: value = value.timetz() if use_timezone else value.time() except ValueError: raise ValueError( 'Could not convert value to target type for property ' f'{column.key} of class {cls!r}') if python_type is bytes: return base64.b64decode(value) if python_type is list: if column.type is ARRAY or isinstance(column.type, ARRAY): # use SQL casting for arrays return cast(value, column.type) raise NotImplementedError(f'py_liant does not support {column.type!r} ' 'yet') if issubclass(python_type, Enum) and value is not None: value = str(value) try: value = next(item for item in python_type if item.name == value or item.value == value) except StopIteration: raise ValueError( 'Could not convert value to target type for property ' f'{column.key} of class {cls!r}') return value