Source code for spyne.model.primitive

#
# spyne - Copyright (C) Spyne contributors.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
#


"""
The ``spyne.model.primitive`` package contains types with values that fit
in a single field.

See :mod:`spyne.protocol._model` for {to,from}_string implementations.
"""


from __future__ import absolute_import

import sys
import re
import math
import uuid
import decimal
import datetime
import platform
import spyne

from spyne.const import xml_ns
from spyne.model import SimpleModel
from spyne.util import memoize
from spyne.model._base import apply_pssm, msgpack, xml, json

string_encoding = 'utf8'

FLOAT_PATTERN = r'-?[0-9]+\.?[0-9]*(e-?[0-9]+)?'
DATE_PATTERN = r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})'
TIME_PATTERN = r'(?P<hr>\d{2}):(?P<min>\d{2}):(?P<sec>\d{2})(?P<sec_frac>\.\d+)?'
OFFSET_PATTERN = r'(?P<tz_hr>[+-]\d{2}):(?P<tz_min>\d{2})'
DATETIME_PATTERN = DATE_PATTERN + '[T ]' + TIME_PATTERN
UUID_PATTERN = "%(x)s{8}-%(x)s{4}-%(x)s{4}-%(x)s{4}-%(x)s{12}" % \
                                                            {'x': '[a-fA-F0-9]'}

#
# FIXME: Supports e.g.
#     MULTIPOINT (10 40, 40 30, 20 20, 30 10)
#
# but not:
#     MULTIPOINT ((10 40), (40 30), (20 20), (30 10))
#

_rinse_and_repeat = r'\s*\(%s\s*(,\s*%s)*\)\s*'
def _get_one_point_pattern(dim):
    return ' +'.join([FLOAT_PATTERN] * dim)

def _get_point_pattern(dim):
    return r'POINT\s*\(%s\)' % _get_one_point_pattern(dim)

def _get_one_multipoint_pattern(dim):
    one_point = _get_one_point_pattern(dim)
    return _rinse_and_repeat % (one_point, one_point)

def _get_multipoint_pattern(dim):
    return r'MULTIPOINT\s*%s' % _get_one_multipoint_pattern(dim)


def _get_one_line_pattern(dim):
    one_point = _get_one_point_pattern(dim)
    return _rinse_and_repeat % (one_point, one_point)

def _get_linestring_pattern(dim):
    return r'LINESTRING\s*%s' % _get_one_line_pattern(dim)

def _get_one_multilinestring_pattern(dim):
    one_line = _get_one_line_pattern(dim)
    return _rinse_and_repeat % (one_line, one_line)

def _get_multilinestring_pattern(dim):
    return r'MULTILINESTRING\s*%s' % _get_one_multilinestring_pattern(dim)


def _get_one_polygon_pattern(dim):
    one_line = _get_one_line_pattern(dim)
    return _rinse_and_repeat % (one_line, one_line)

def _get_polygon_pattern(dim):
    return r'POLYGON\s*%s' % _get_one_polygon_pattern(dim)

def _get_one_multipolygon_pattern(dim):
    one_line = _get_one_polygon_pattern(dim)
    return _rinse_and_repeat % (one_line, one_line)

def _get_multipolygon_pattern(dim):
    return r'MULTIPOLYGON\s*%s' % _get_one_multipolygon_pattern(dim)


_date_re = re.compile(DATE_PATTERN)
_time_re = re.compile(TIME_PATTERN)
_duration_re = re.compile(
        r'(?P<sign>-?)'
        r'P'
        r'(?:(?P<years>\d+)Y)?'
        r'(?:(?P<months>\d+)M)?'
        r'(?:(?P<days>\d+)D)?'
        r'(?:T(?:(?P<hours>\d+)H)?'
        r'(?:(?P<minutes>\d+)M)?'
        r'(?:(?P<seconds>\d+(.\d+)?)S)?)?'
    )


_ns_xs = xml_ns.xsd
_ns_xsi = xml_ns.xsi


class AnyXml(SimpleModel):
[docs] """An xml node that can contain any number of sub nodes. It's represented by an ElementTree object.""" __type_name__ = 'anyType' class Attributes(SimpleModel.Attributes): namespace = None """Xml-Schema specific namespace attribute""" process_contents = None """Xml-Schema specific processContents attribute""" # EXPERIMENTAL class AnyHtml(SimpleModel):
__type_name__ = 'string' class AnyDict(SimpleModel):
[docs] """A dict instance that can contain other dicts, iterables or primitive types. Its serialization is protocol-dependent. """ __type_name__ = 'anyType' class Attributes(SimpleModel.Attributes): store_as = None """Method for serializing to persistent storage. One of 'xml', 'json' or 'msgpack'. It makes sense to specify this only when this object is child of a `ComplexModel` sublass.""" @classmethod def customize(cls, **kwargs):
[docs] """Duplicates cls and overwrites the values in ``cls.Attributes`` with ``**kwargs`` and returns the new class.""" store_as = apply_pssm(kwargs.get('store_as', None), {'json': json, 'xml': xml, 'msgpack': msgpack}) if store_as is not None: kwargs['store_as'] = store_as return super(AnyDict, cls).customize(**kwargs) class Unicode(SimpleModel):
[docs] """The type to represent human-readable data. Its native format is `unicode` or `str` with given encoding. """ __type_name__ = 'string' class Attributes(SimpleModel.Attributes):
[docs] """Customizable attributes of the :class:`spyne.model.primitive.Unicode` type.""" min_len = 0 """Minimum length of string. Can be set to any positive integer""" max_len = decimal.Decimal('inf') """Maximum length of string. Can be set to ``decimal.Decimal('inf')`` to accept strings of arbitrary length. You may also need to adjust :const:`spyne.server.wsgi.MAX_CONTENT_LENGTH`.""" pattern = None """A regular expression that matches the whole string. See here for more info: http://www.regular-expressions.info/xml.html""" encoding = None """The encoding of `str` objects this class may have to deal with.""" unicode_errors = 'strict' """The argument to the ``unicode`` builtin; one of 'strict', 'replace' or 'ignore'.""" format = None """A regular python string formatting string. See here: http://docs.python.org/library/stdtypes.html#string-formatting""" def __new__(cls, *args, **kwargs):
assert len(args) <= 1 if len(args) == 1: kwargs['max_len'] = args[0] retval = SimpleModel.__new__(cls, ** kwargs) return retval @staticmethod def is_default(cls): return ( SimpleModel.is_default(cls) and cls.Attributes.min_len == Unicode.Attributes.min_len and cls.Attributes.max_len == Unicode.Attributes.max_len and cls.Attributes.pattern == Unicode.Attributes.pattern ) @staticmethod def validate_string(cls, value): return ( SimpleModel.validate_string(cls, value) and (value is None or ( cls.Attributes.min_len <= len(value) <= cls.Attributes.max_len and _re_match_with_span(cls.Attributes, value) ))) def _re_match_with_span(attr, value):
if attr.pattern is None: return True m = attr._pattern_re.match(value) return (m is not None) and (m.span() == (0, len(value))) class String(Unicode): pass if sys.version > '3': String = Unicode class AnyUri(Unicode):
[docs] """A special kind of String type designed to hold an uri.""" __type_name__ = 'anyURI' class Attributes(String.Attributes): text = None """The text shown in link. This is an object-wide constant.""" class Value(object):
[docs] """A special object that is just a better way of carrying the information carried with a link. :param href: The uri string. :param text: The text data that goes with the link. This is a ``str`` or a ``unicode`` instance. :param content: The structured data that goes with the link. This is an `lxml.etree.Element` instance. """ def __init__(self, href, text=None, content=None): self.href = href self.text = text self.content = content class ImageUri(AnyUri):
[docs] """A special kind of String that holds the uri of an image.""" class Decimal(SimpleModel):
[docs] """The primitive that corresponds to the native python Decimal. This is also the base class for denoting numbers. Note that it is your responsibility to make sure that the scale and precision constraints set in this type is consistent with the values in the context of the decimal package. See the :func:`decimal.getcontext` documentation for more information. """ __type_name__ = 'decimal' class Attributes(SimpleModel.Attributes):
[docs] """Customizable attributes of the :class:`spyne.model.primitive.Decimal` type.""" gt = decimal.Decimal('-inf') # minExclusive """The value should be greater than this number.""" ge = decimal.Decimal('-inf') # minInclusive """The value should be greater than or equal to this number.""" lt = decimal.Decimal('inf') # maxExclusive """The value should be lower than this number.""" le = decimal.Decimal('inf') # maxInclusive """The value should be lower than or equal to this number.""" max_str_len = 1024 """The maximum length of string to be attempted to convert to number.""" format = None """A regular python string formatting string. See here: http://docs.python.org/library/stdtypes.html#string-formatting""" str_format = None """A regular python string formatting string used by invoking its ``format()`` function. See here: http://docs.python.org/2/library/string.html#format-string-syntax""" pattern = None """A regular expression that matches the whole field. See here for more info: http://www.regular-expressions.info/xml.html""" total_digits = decimal.Decimal('inf') """Maximum number of digits.""" fraction_digits = decimal.Decimal('inf') """Maximum number of digits after the decimal separator.""" min_bound = None """Hardware limit that determines the lowest value this type can store.""" max_bound = None """Hardware limit that determines the highest value this type can store.""" def __new__(cls, *args, **kwargs):
assert len(args) <= 2 if len(args) >= 1 and args[0] is not None: kwargs['total_digits'] = args[0] kwargs['fraction_digits'] = 0 if len(args) == 2 and args[1] is not None: kwargs['fraction_digits'] = args[1] assert args[0] > 0, "'total_digits' must be positive." assert args[1] <= args[0], "'total_digits' must be greater than" \ " or equal to 'fraction_digits'." \ " %r ! <= %r" % (args[1], args[0]) # + 1 for decimal separator # + 1 for negative sign msl = kwargs.get('max_str_len', None) if msl is None: kwargs['max_str_len'] = (cls.Attributes.total_digits + cls.Attributes.fraction_digits + 2) else: kwargs['max_str_len'] = msl retval = SimpleModel.__new__(cls, ** kwargs) return retval @staticmethod def is_default(cls): return ( SimpleModel.is_default(cls) and cls.Attributes.gt == Decimal.Attributes.gt and cls.Attributes.ge == Decimal.Attributes.ge and cls.Attributes.lt == Decimal.Attributes.lt and cls.Attributes.le == Decimal.Attributes.le and cls.Attributes.total_digits == Decimal.Attributes.total_digits and cls.Attributes.fraction_digits == Decimal.Attributes.fraction_digits ) @staticmethod def validate_string(cls, value): return SimpleModel.validate_string(cls, value) and ( value is None or (len(value) <= cls.Attributes.max_str_len) ) @staticmethod def validate_native(cls, value): return SimpleModel.validate_native(cls, value) and ( value is None or ( value > cls.Attributes.gt and value >= cls.Attributes.ge and value < cls.Attributes.lt and value <= cls.Attributes.le )) class Double(Decimal):
[docs] """This is serialized as the python ``float``. So this type comes with its gotchas. Unless you really know what you're doing, you should use a :class:`Decimal` with a pre-defined number of integer and decimal digits. """ __type_name__ = 'double' if platform.python_version_tuple()[:2] == ('2','6'): class Attributes(Decimal.Attributes): """Customizable attributes of the :class:`spyne.model.primitive.Double` type. This class is only here for Python 2.6: See this bug report for more info: http://bugs.python.org/issue2531 """ gt = float('-inf') # minExclusive """The value should be greater than this number.""" ge = float('-inf') # minInclusive """The value should be greater than or equal to this number.""" lt = float('inf') # maxExclusive """The value should be lower than this number.""" le = float('inf') # maxInclusive """The value should be lower than or equal to this number.""" @staticmethod def is_default(cls): return ( SimpleModel.is_default(cls) and cls.Attributes.gt == Double.Attributes.gt and cls.Attributes.ge == Double.Attributes.ge and cls.Attributes.lt == Double.Attributes.lt and cls.Attributes.le == Double.Attributes.le ) class Float(Double):
[docs] """Synonym for Double (as far as python side of things are concerned). It's here for compatibility reasons.""" __type_name__ = 'float' class Integer(Decimal):
[docs] """The arbitrary-size signed integer.""" __type_name__ = 'integer' @staticmethod def validate_native(cls, value): return ( Decimal.validate_native(cls, value) and (value is None or int(value) == value) ) class UnsignedInteger(Integer):
[docs] """The arbitrary-size unsigned integer, also known as nonNegativeInteger.""" __type_name__ = 'nonNegativeInteger' @staticmethod def validate_native(cls, value): return ( Integer.validate_native(cls, value) and (value is None or value >= 0) ) NonNegativeInteger = UnsignedInteger
"""The arbitrary-size unsigned integer, alias for UnsignedInteger.""" class PositiveInteger(NonNegativeInteger):
[docs] """The arbitrary-size positive integer (natural number).""" __type_name__ = 'positiveInteger' @staticmethod def validate_native(cls, value): return (Integer.validate_native(cls, value) and (value is None or value > 0)) @memoize
def TBoundedInteger(num_bits, type_name): _min_b = -(0x8<<(num_bits-4)) # 0x8 is 4 bits. _max_b = (0x8<<(num_bits-4)) - 1 # -1? c'est la vie class _BoundedInteger(Integer): __type_name__ = type_name class Attributes(Integer.Attributes): max_str_len = math.ceil(math.log(2**num_bits, 10)) min_bound = _min_b max_bound = _max_b @staticmethod def validate_native(cls, value): return ( Integer.validate_native(cls, value) and (value is None or (_min_b <= value <= _max_b)) ) return _BoundedInteger @memoize def TBoundedUnsignedInteger(num_bits, type_name): _min_b = 0 _max_b = 2 ** num_bits - 1 # -1? c'est la vie ;) class _BoundedUnsignedInteger(UnsignedInteger): __type_name__ = type_name class Attributes(UnsignedInteger.Attributes): max_str_len = math.ceil(math.log(2**num_bits, 10)) min_bound = _min_b max_bound = _max_b @staticmethod def validate_native(cls, value): return ( UnsignedInteger.validate_native(cls, value) and (value is None or (_min_b <= value < _max_b)) ) return _BoundedUnsignedInteger Integer64 = TBoundedInteger(64, 'long') """The 64-bit signed integer, also known as ``long``.""" Long = Integer64 """The 64-bit signed integer, alias for :class:`Integer64`.""" Integer32 = TBoundedInteger(32, 'int') """The 64-bit signed integer, also known as ``int``.""" Int = Integer32 """The 32-bit signed integer, alias for :class:`Integer32`.""" Integer16 = TBoundedInteger(16, 'short') """The 16-bit signed integer, also known as ``short``.""" Short = Integer16 """The 16-bit signed integer, alias for :class:`Integer16`.""" Integer8 = TBoundedInteger(8, 'byte') """The 8-bit signed integer, also known as ``byte``.""" Byte = Integer8 """The 8-bit signed integer, alias for :class:`Integer8`.""" UnsignedInteger64 = TBoundedUnsignedInteger(64, 'unsignedLong') """The 64-bit unsigned integer, also known as ``unsignedLong``.""" UnsignedLong = UnsignedInteger64 """The 64-bit unsigned integer, alias for :class:`UnsignedInteger64`.""" UnsignedInteger32 = TBoundedUnsignedInteger(32, 'unsignedInt') """The 64-bit unsigned integer, also known as ``unsignedInt``.""" UnsignedInt = UnsignedInteger32 """The 32-bit unsigned integer, alias for :class:`UnsignedInteger32`.""" UnsignedInteger16 = TBoundedUnsignedInteger(16, 'unsignedShort') """The 16-bit unsigned integer, also known as ``unsignedShort``.""" UnsignedShort = UnsignedInteger16 """The 16-bit unsigned integer, alias for :class:`UnsignedInteger16`.""" UnsignedInteger8 = TBoundedUnsignedInteger(8, 'unsignedByte') """The 8-bit unsigned integer, also known as ``unsignedByte``.""" UnsignedByte = UnsignedInteger8 """The 8-bit unsigned integer, alias for :class:`UnsignedInteger8`.""" class Time(SimpleModel):
[docs] """Just that, Time. No time zone support. Native type is :class:`datetime.time`. """ __type_name__ = 'time' class Attributes(SimpleModel.Attributes):
[docs] """Customizable attributes of the :class:`spyne.model.primitive.Time` type.""" gt = datetime.time(0, 0, 0, 0) # minExclusive """The time should be greater than this time.""" ge = datetime.time(0, 0, 0, 0) # minInclusive """The time should be greater than or equal to this time.""" lt = datetime.time(23, 59, 59, 999999) # maxExclusive """The time should be lower than this time.""" le = datetime.time(23, 59, 59, 999999) # maxInclusive """The time should be lower than or equal to this time.""" pattern = None """A regular expression that matches the whole time. See here for more info: http://www.regular-expressions.info/xml.html""" @staticmethod
def is_default(cls): return ( SimpleModel.is_default(cls) and cls.Attributes.gt == Time.Attributes.gt and cls.Attributes.ge == Time.Attributes.ge and cls.Attributes.lt == Time.Attributes.lt and cls.Attributes.le == Time.Attributes.le and cls.Attributes.pattern == Time.Attributes.pattern ) @staticmethod def validate_native(cls, value): return SimpleModel.validate_native(cls, value) and ( value is None or ( value > cls.Attributes.gt and value >= cls.Attributes.ge and value < cls.Attributes.lt and value <= cls.Attributes.le )) class DateTime(SimpleModel):
[docs] """A compact way to represent dates and times together. Supports time zones. Working with timezones is a bit quirky -- Spyne works very hard to have all datetimes with time zones internally and only strips them when explicitly requested with ``timezone=False``\. See :attr:`DateTime.Attributes.as_timezone` for more information. Native type is :class:`datetime.datetime`. """ __type_name__ = 'dateTime' _local_re = re.compile(DATETIME_PATTERN) _utc_re = re.compile(DATETIME_PATTERN + 'Z') _offset_re = re.compile(DATETIME_PATTERN + OFFSET_PATTERN) class Attributes(SimpleModel.Attributes):
[docs] """Customizable attributes of the :class:`spyne.model.primitive.DateTime` type.""" gt = datetime.datetime(datetime.MINYEAR, 1, 1, 0, 0, 0, 0, spyne.LOCAL_TZ) # minExclusive """The datetime should be greater than this datetime. It must always have a timezone.""" ge = datetime.datetime(datetime.MINYEAR, 1, 1, 0, 0, 0, 0, spyne.LOCAL_TZ) # minInclusive """The datetime should be greater than or equal to this datetime. It must always have a timezone.""" lt = datetime.datetime(datetime.MAXYEAR, 12, 31, 23, 59, 59, 999999, spyne.LOCAL_TZ) # maxExclusive """The datetime should be lower than this datetime. It must always have a timezone.""" le = datetime.datetime(datetime.MAXYEAR, 12, 31, 23, 59, 59, 999999, spyne.LOCAL_TZ) # maxInclusive """The datetime should be lower than or equal to this datetime. It must always have a timezone.""" pattern = None """A regular expression that matches the whole datetime. See here for more info: http://www.regular-expressions.info/xml.html""" format = None """DateTime format fed to the ``strftime`` function. See: http://docs.python.org/library/datetime.html?highlight=strftime#strftime-strptime-behavior Ignored by protocols like SOAP which have their own ideas about how DateTime objects should be serialized.""" string_format = None """A regular python string formatting string. %s will contain the date string. See here for more info: http://docs.python.org/library/stdtypes.html#string-formatting""" as_timezone = None """When not None, converts: - Outgoing values to the given time zone (by calling ``.astimezone()``). - Incoming values without tzinfo to the given time zone by calling ``.replace(tzinfo=<as_timezone>)`` and values with tzinfo to the given timezone by calling ``.astimezone()``. Either None or a return value of pytz.timezone() When this is None and a datetime with tzinfo=None comes in, it's converted to spyne.LOCAL_TZ which defaults to ``pytz.utc``. You can use `tzlocal <https://pypi.python.org/pypi/tzlocal>`_ to set it to local time right after ``import spyne``. """ timezone = True """If False, time zone info is stripped before serialization. Also makes sqlalchemy schema generator emit 'timestamp without timezone'.""" serialize_as = None """One of (None, 'sec', 'sec_float', 'msec', 'msec_float', 'usec')""" @staticmethod
def is_default(cls): return ( SimpleModel.is_default(cls) and cls.Attributes.gt == DateTime.Attributes.gt and cls.Attributes.ge == DateTime.Attributes.ge and cls.Attributes.lt == DateTime.Attributes.lt and cls.Attributes.le == DateTime.Attributes.le and cls.Attributes.pattern == DateTime.Attributes.pattern ) @staticmethod def validate_native(cls, value): if isinstance(value, datetime.datetime) and value.tzinfo is None: value = value.replace(tzinfo=spyne.LOCAL_TZ) return SimpleModel.validate_native(cls, value) and ( value is None or ( value > cls.Attributes.gt and value >= cls.Attributes.ge and value < cls.Attributes.lt and value <= cls.Attributes.le )) class Date(DateTime):
[docs] """Just that, Date. No time zone support. Native type is :class:`datetime.date`. """ __type_name__ = 'date' _offset_re = re.compile(DATE_PATTERN + '(' + OFFSET_PATTERN + '|Z)') class Attributes(DateTime.Attributes):
[docs] """Customizable attributes of the :class:`spyne.model.primitive.Date` type.""" gt = datetime.date(1, 1, 1) # minExclusive """The date should be greater than this date.""" ge = datetime.date(1, 1, 1) # minInclusive """The date should be greater than or equal to this date.""" lt = datetime.date(datetime.MAXYEAR, 12, 31) # maxExclusive """The date should be lower than this date.""" le = datetime.date(datetime.MAXYEAR, 12, 31) # maxInclusive """The date should be lower than or equal to this date.""" format = '%Y-%m-%d' """DateTime format fed to the ``strftime`` function. See: http://docs.python.org/library/datetime.html?highlight=strftime#strftime-strptime-behavior Ignored by protocols like SOAP which have their own ideas about how Date objects should be serialized.""" pattern = None """A regular expression that matches the whole date. See here for more info: http://www.regular-expressions.info/xml.html""" @staticmethod
def is_default(cls): return ( SimpleModel.is_default(cls) and cls.Attributes.gt == Date.Attributes.gt and cls.Attributes.ge == Date.Attributes.ge and cls.Attributes.lt == Date.Attributes.lt and cls.Attributes.le == Date.Attributes.le and cls.Attributes.pattern == Date.Attributes.pattern ) # this object tries to follow ISO 8601 standard. class Duration(SimpleModel):
[docs] """Native type is :class:`datetime.timedelta`.""" __type_name__ = 'duration' class Boolean(SimpleModel):
[docs] """Life is simple here. Just true or false.""" __type_name__ = 'boolean' def _uuid_validate_string(cls, value):
return ( SimpleModel.validate_string(cls, value) and (value is None or ( cls.Attributes.min_len <= len(value) <= cls.Attributes.max_len and _re_match_with_span(cls.Attributes, value) ))) def _Tuuid_validate(key): from uuid import UUID def _uvalid(cls, v): try: UUID(**{key:v}) except ValueError: return False return True return _uvalid _uuid_validate = { None: _uuid_validate_string, 'hex': _Tuuid_validate('hex'), 'urn': _Tuuid_validate('urn'), 'bytes': _Tuuid_validate('bytes'), 'bytes_le': _Tuuid_validate('bytes_le'), 'fields': _Tuuid_validate('fields'), 'int': _Tuuid_validate('int'), } class Uuid(Unicode(pattern=UUID_PATTERN)):
[docs] """Unicode subclass for Universially-Unique Identifiers.""" __namespace__ = 'http://spyne.io/schema' __type_name__ = 'uuid' class Attributes(Unicode(pattern=UUID_PATTERN).Attributes): serialize_as = None @staticmethod def validate_string(cls, value): return _uuid_validate[cls.Attributes.serialize_as](cls, value) class NormalizedString(Unicode):
__type_name__ = 'normalizedString' __extends__ = Unicode class Attributes(Unicode.Attributes): white_space = "replace" class Token(NormalizedString): __type_name__ = 'token' class Attributes(Unicode.Attributes): white_space = "collapse" class Name(Token): __type_name__ = 'Name' class Attributes(Unicode.Attributes): # Original: '[\i-[:]][\c-[:]]*' # See: http://www.regular-expressions.info/xmlcharclass.html pattern = '[[_:A-Za-z]-[:]][[-._:A-Za-z0-9]-[:]]*' class NCName(Name): __type_name__ = 'NCName' class ID(NCName): __type_name__ = 'ID' class Language(Token): __type_name__ = 'language' class Attributes(Unicode.Attributes): pattern = '[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*' class Point(Unicode):
[docs] """A point type whose native format is a WKT string. You can use :func:`shapely.wkt.loads` to get a proper point type. It's a subclass of the :class:`Unicode` type, so regular Unicode constraints apply. The only additional parameter is the number of dimensions. :param dim: Number of dimensons. """ __type_name__ = None class Attributes(Unicode.Attributes): dim = None @staticmethod def Value(x, y, prec=15): return ('POINT(%%3.%(prec)sf %%3.%(prec)sf)' % {'prec': prec}) % (x,y) def __new__(cls, dim=None, **kwargs): assert dim in (None,2,3) if dim is not None: kwargs['dim'] = dim kwargs['pattern'] = _get_point_pattern(dim) kwargs['type_name'] = 'point%dd' % dim retval = SimpleModel.__new__(cls, **kwargs) retval.__namespace__ = 'http://spyne.io/schema' retval.__extends__ = Unicode retval.__orig__ = Unicode return retval class Line(Unicode):
[docs] """A line type whose native format is a WKT string. You can use :func:`shapely.wkt.loads` to get a proper line type. It's a subclass of the :class:`Unicode` type, so regular Unicode constraints apply. The only additional parameter is the number of dimensions. :param dim: Number of dimensons. """ __type_name__ = None class Attributes(Unicode.Attributes): dim = None def __new__(cls, dim=None, **kwargs): assert dim in (None,2,3) if dim is not None: kwargs['dim'] = dim kwargs['pattern'] = _get_linestring_pattern(dim) kwargs['type_name'] = 'line%dd' % dim retval = SimpleModel.__new__(cls, **kwargs) retval.__namespace__ = 'http://spyne.io/schema' retval.__extends__ = Unicode retval.__orig__ = Unicode return retval LineString = Line
class Polygon(Unicode):
[docs] """A polygon type whose native format is a WKT string. You can use :func:`shapely.wkt.loads` to get a proper polygon type. It's a subclass of the :class:`Unicode` type, so regular Unicode constraints apply. The only additional parameter is the number of dimensions. :param dim: Number of dimensons. """ __type_name__ = None class Attributes(Unicode.Attributes): dim = None def __new__(cls, dim=None, **kwargs): assert dim in (None,2,3) if dim is not None: kwargs['dim'] = dim kwargs['pattern'] = _get_polygon_pattern(dim) kwargs['type_name'] = 'polygon%dd' % dim retval = SimpleModel.__new__(cls, **kwargs) retval.__namespace__ = 'http://spyne.io/schema' retval.__extends__ = Unicode retval.__orig__ = Unicode return retval class MultiPoint(Unicode):
[docs] """A MultiPoint type whose native format is a WKT string. You can use :func:`shapely.wkt.loads` to get a proper MultiPoint type. It's a subclass of the :class:`Unicode` type, so regular Unicode constraints apply. The only additional parameter is the number of dimensions. :param dim: Number of dimensons. """ __type_name__ = None class Attributes(Unicode.Attributes): dim = None def __new__(cls, dim=None, **kwargs): assert dim in (None,2,3) if dim is not None: kwargs['dim'] = dim kwargs['pattern'] = _get_multipoint_pattern(dim) kwargs['type_name'] = 'multiPoint%dd' % dim retval = SimpleModel.__new__(cls, **kwargs) retval.__namespace__ = 'http://spyne.io/schema' retval.__extends__ = Unicode retval.__orig__ = Unicode return retval class MultiLine(Unicode):
[docs] """A MultiLine type whose native format is a WKT string. You can use :func:`shapely.wkt.loads` to get a proper MultiLine type. It's a subclass of the :class:`Unicode` type, so regular Unicode constraints apply. The only additional parameter is the number of dimensions. :param dim: Number of dimensons. """ __type_name__ = None class Attributes(Unicode.Attributes): dim = None def __new__(cls, dim=None, **kwargs): assert dim in (None,2,3) if dim is not None: kwargs['dim'] = dim kwargs['pattern'] = _get_multilinestring_pattern(dim) kwargs['type_name'] = 'multiLine%dd' % dim retval = SimpleModel.__new__(cls, **kwargs) retval.__namespace__ = 'http://spyne.io/schema' retval.__extends__ = Unicode retval.__orig__ = Unicode return retval MultiLineString = MultiLine
class MultiPolygon(Unicode):
[docs] """A MultiPolygon type whose native format is a WKT string. You can use :func:`shapely.wkt.loads` to get a proper MultiPolygon type. It's a subclass of the :class:`Unicode` type, so regular Unicode constraints apply. The only additional parameter is the number of dimensions. :param dim: Number of dimensons. """ __type_name__ = None class Attributes(Unicode.Attributes): dim = None def __new__(cls, dim=None, **kwargs): assert dim in (None,2,3) if dim is not None: kwargs['dim'] = dim kwargs['pattern'] = _get_multipolygon_pattern(dim) kwargs['type_name'] = 'multipolygon%dd' % dim retval = SimpleModel.__new__(cls, **kwargs) retval.__namespace__ = 'http://spyne.io/schema' retval.__extends__ = Unicode retval.__orig__ = Unicode return retval # This class is DEPRECATED. Use the spyne.model.Mandatory like this: # >>> from spyne.model import Mandatory as M, Unicode # >>> MandatoryEmail = M(Unicode(pattern='[^@]+@[^@]+')) class Mandatory:
Unicode = Unicode(type_name="MandatoryString", min_occurs=1, nillable=False, min_len=1) String = String(type_name="MandatoryString", min_occurs=1, nillable=False, min_len=1) AnyXml = AnyXml(type_name="MandatoryXml", min_occurs=1, nillable=False) AnyDict = AnyDict(type_name="MandatoryDict", min_occurs=1, nillable=False) AnyUri = AnyUri(type_name="MandatoryUri", min_occurs=1, nillable=False, min_len=1) ImageUri = ImageUri(type_name="MandatoryImageUri", min_occurs=1, nillable=False, min_len=1) Boolean = Boolean(type_name="MandatoryBoolean", min_occurs=1, nillable=False) Date = Date(type_name="MandatoryDate", min_occurs=1, nillable=False) Time = Time(type_name="MandatoryTime", min_occurs=1, nillable=False) DateTime = DateTime(type_name="MandatoryDateTime", min_occurs=1, nillable=False) Duration = Duration(type_name="MandatoryDuration", min_occurs=1, nillable=False) Decimal = Decimal(type_name="MandatoryDecimal", min_occurs=1, nillable=False) Double = Double(type_name="MandatoryDouble", min_occurs=1, nillable=False) Float = Float(type_name="MandatoryFloat", min_occurs=1, nillable=False) Integer = Integer(type_name="MandatoryInteger", min_occurs=1, nillable=False) Integer64 = Integer64(type_name="MandatoryLong", min_occurs=1, nillable=False) Integer32 = Integer32(type_name="MandatoryInt", min_occurs=1, nillable=False) Integer16 = Integer16(type_name="MandatoryShort", min_occurs=1, nillable=False) Integer8 = Integer8(type_name="MandatoryByte", min_occurs=1, nillable=False) Long = Integer64 Int = Integer32 Short = Integer16 Byte = Integer8 UnsignedInteger = UnsignedInteger(type_name="MandatoryUnsignedInteger", min_occurs=1, nillable=False) UnsignedInteger64 = UnsignedInteger64(type_name="MandatoryUnsignedLong", min_occurs=1, nillable=False) UnsignedInteger32 = UnsignedInteger32(type_name="MandatoryUnsignedInt", min_occurs=1, nillable=False) UnsignedInteger16 = UnsignedInteger16(type_name="MandatoryUnsignedShort", min_occurs=1, nillable=False) UnsignedInteger8 = UnsignedInteger8(type_name="MandatoryUnsignedByte", min_occurs=1, nillable=False) UnsignedLong = UnsignedInteger64 UnsignedInt = UnsignedInteger32 UnsignedShort = UnsignedInteger16 UnsignedByte = UnsignedInteger8 Uuid = Uuid(type_name="MandatoryUuid", min_len=1, min_occurs=1, nillable=False) Point = Point(type_name="Point", min_len=1, min_occurs=1, nillable=False) Line = Line(type_name="LineString", min_len=1, min_occurs=1, nillable=False) LineString = Line Polygon = Polygon(type_name="Polygon", min_len=1, min_occurs=1, nillable=False) MultiPoint = MultiPoint(type_name="MandatoryMultiPoint", min_len=1, min_occurs=1, nillable=False) MultiLine = MultiLine(type_name="MandatoryMultiLineString", min_len=1, min_occurs=1, nillable=False) MultiLineString = MultiLine MultiPolygon = MultiPolygon(type_name="MandatoryMultiPolygon", min_len=1, min_occurs=1, nillable=False) NATIVE_MAP = { float: Double, bool: Boolean, datetime.datetime: DateTime, datetime.time: Time, datetime.date: Date, datetime.timedelta: Duration, decimal.Decimal: Decimal, uuid.UUID: Uuid, } from spyne.util import six if six.PY3: NATIVE_MAP.update({ str: Unicode, int: Integer, }) else: NATIVE_MAP.update({ str: String, unicode: Unicode, long: Integer, }) if isinstance (0x80000000, long): # 32-bit architecture NATIVE_MAP[int] = Integer32 else: # not 32-bit (so most probably 64-bit) architecture NATIVE_MAP[int] = Integer64 assert Mandatory.Long == Mandatory.Integer64