Source code for kim.pipelines.numeric
# kim/pipelines/numeric.py
# Copyright (C) 2014-2015 the Kim authors and contributors
# <see AUTHORS file>
#
# This module is part of Kim and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
from decimal import Decimal, InvalidOperation
from .base import pipe, is_valid_choice
from .marshaling import MarshalPipeline
from .serialization import SerializePipeline
@pipe()
[docs]def is_valid_integer(session):
"""Pipe used to determine if a value can be coerced to an int
:param session: Kim pipeline session instance
"""
try:
session.data = int(session.data)
except TypeError:
raise session.field.invalid(error_type='type_error')
except ValueError:
raise session.field.invalid(error_type='type_error')
return session.data
@pipe()
[docs]def bounds_check(session):
"""Pipe used to determine if a value is within the min and max bounds on
the field
:param session: Kim pipeline session instance
"""
max_ = session.field.opts.max
min_ = session.field.opts.min
if max_ is not None and session.data > max_:
raise session.field.invalid(error_type='out_of_bounds')
if min_ is not None and session.data < min_:
raise session.field.invalid(error_type='out_of_bounds')
return session.data
[docs]class IntegerMarshalPipeline(MarshalPipeline):
"""IntegerMarshalPipeline
.. seealso::
:func:`kim.pipelines.numeric.is_valid_integer`
:func:`kim.pipelines.base.is_valid_choice`
:func:`kim.pipelines.numeric.bounds_check`
:class:`kim.pipelines.marshaling.MarshalPipeline`
"""
validation_pipes = \
[is_valid_integer, is_valid_choice, bounds_check] + MarshalPipeline.validation_pipes
[docs]class IntegerSerializePipeline(SerializePipeline):
"""IntegerSerializePipeline
.. seealso::
:class:`kim.pipelines.serialization.SerializePipeline`
"""
pass
@pipe()
[docs]def is_valid_decimal(session):
"""Pipe used to determine if a value can be coerced to a Decimal
:param session: Kim pipeline session instance
"""
try:
return Decimal(session.data)
except InvalidOperation:
raise session.field.invalid(error_type='type_error')
@pipe()
[docs]def coerce_to_decimal(session):
"""Coerce str representation of a decimal into a valid Decimal object.
"""
decimals = session.field.opts.precision
precision = Decimal('0.' + '0' * (decimals - 1) + '1')
session.data = Decimal(session.data).quantize(precision)
return session.data
[docs]class DecimalMarshalPipeline(MarshalPipeline):
"""DecimalMarshalPipeline
.. seealso::
:func:`kim.pipelines.numeric.is_valid_decimal`
:func:`kim.pipelines.numeric.coerce_to_decimal`
:class:`kim.pipelines.marshaling.MarshalPipeline`
"""
validation_pipes = [is_valid_decimal, bounds_check] + MarshalPipeline.validation_pipes
process_pipes = [coerce_to_decimal] + MarshalPipeline.process_pipes
# TODO(mike) This should probably move to base
@pipe()
[docs]def to_string(session):
"""coerce decimal value into str so it's valid for json
"""
if session.data is not None:
session.data = str(session.data)
return session.data
[docs]class DecimalSerializePipeline(SerializePipeline):
"""DecimalSerializePipeline
.. seealso::
:func:`kim.pipelines.numeric.coerce_to_decimal`
:func:`kim.pipelines.numeric.to_string`
:class:`kim.pipelines.serialization.SerializePipeline`
"""
process_pipes = [coerce_to_decimal, to_string] + SerializePipeline.process_pipes
@pipe()
def is_valid_float(session):
"""Pipe used to determine if a value can be coerced to a Float
:param session: Kim pipeline session instance
"""
try:
return float(session.data)
except (InvalidOperation, ValueError):
raise session.field.invalid(error_type='type_error')
@pipe()
def coerce_to_float(session):
"""Coerce str representation of a decimal into a valid Float object.
"""
decimals = session.field.opts.precision
session.data = round(float(session.data), decimals)
return session.data
class FloatMarshalPipeline(MarshalPipeline):
"""FloatMarshalPipeline
.. seealso::
:func:`kim.pipelines.numeric.is_valid_decimal`
:func:`kim.pipelines.numeric.coerce_to_decimal`
:class:`kim.pipelines.marshaling.MarshalPipeline`
"""
validation_pipes = [is_valid_float, bounds_check] + MarshalPipeline.validation_pipes
process_pipes = [coerce_to_float] + MarshalPipeline.process_pipes
class FloatSerializePipeline(SerializePipeline):
"""FloatSerializePipeline
.. seealso::
:func:`kim.pipelines.numeric.coerce_to_float`
:func:`kim.pipelines.numeric.to_string`
:class:`kim.pipelines.serialization.SerializePipeline`
"""
process_pipes = [coerce_to_float, to_string] + SerializePipeline.process_pipes