예제 #1
0
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
예제 #2
0
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