Skip to content

Commit

Permalink
Merge pull request #47 from zopefoundation/issue11
Browse files Browse the repository at this point in the history
Add [Mutable]Sequence and [Mutable]Mapping and make List, Dict and Tuple extend them
  • Loading branch information
jamadden committed Aug 24, 2018
2 parents f169f30 + 7995afe commit 19c9511
Show file tree
Hide file tree
Showing 6 changed files with 314 additions and 49 deletions.
8 changes: 8 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@
validating invariants. See `issue 16
<https://github.com/zopefoundation/zope.schema/issues/16>`_.

- Add new fields ``Mapping`` and ``MutableMapping``, corresponding to
the collections ABCs of the same name; ``Dict`` now extends and
specializes ``MutableMapping`` to only accept instances of ``dict``.

- Add new fields ``Sequence`` and ``MutableSequence``, corresponding
to the collections ABCs of the same name; ``Tuple`` now extends
``Sequence`` and ``List`` now extends ``MutableSequence``.

4.5.0 (2017-07-10)
==================

Expand Down
7 changes: 6 additions & 1 deletion docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ Collections
.. autoclass:: zope.schema.interfaces.IContainer
.. autoclass:: zope.schema.interfaces.ICollection
.. autoclass:: zope.schema.interfaces.ISequence
.. autoclass:: zope.schema.interfaces.IMutableSequence
.. autoclass:: zope.schema.interfaces.IUnorderedCollection
.. autoclass:: zope.schema.interfaces.IAbstractSet
.. autoclass:: zope.schema.interfaces.IAbstractBag
Expand Down Expand Up @@ -160,7 +161,6 @@ Fields
.. autoclass:: zope.schema.Decimal
:no-show-inheritance:
.. autoclass:: zope.schema.Dict
:no-show-inheritance:
.. autoclass:: zope.schema.DottedName
:no-show-inheritance:

Expand All @@ -177,6 +177,10 @@ Fields
.. autoclass:: zope.schema.Iterable
:no-show-inheritance:
.. autoclass:: zope.schema.List
.. autoclass:: zope.schema.Mapping
:no-show-inheritance:
.. autoclass:: zope.schema.MutableMapping
.. autoclass:: zope.schema.MutableSequence
.. autoclass:: zope.schema.MinMaxLen
.. autoclass:: zope.schema.NativeString
.. autoclass:: zope.schema.NativeStringLine
Expand All @@ -186,6 +190,7 @@ Fields
.. autoclass:: zope.schema.Password
:no-show-inheritance:
.. autoclass:: zope.schema.Set
.. autoclass:: zope.schema.Sequence
.. autoclass:: zope.schema.SourceText
:no-show-inheritance:
.. autoclass:: zope.schema.Text
Expand Down
64 changes: 53 additions & 11 deletions src/zope/schema/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,17 @@
from zope.schema._field import InterfaceField
from zope.schema._field import Iterable
from zope.schema._field import List
from zope.schema._field import Mapping
from zope.schema._field import MutableMapping
from zope.schema._field import MutableSequence
from zope.schema._field import MinMaxLen
from zope.schema._field import NativeString
from zope.schema._field import NativeStringLine
from zope.schema._field import Object
from zope.schema._field import Orderable
from zope.schema._field import Password
from zope.schema._field import Set
from zope.schema._field import Sequence
from zope.schema._field import SourceText
from zope.schema._field import Text
from zope.schema._field import TextLine
Expand All @@ -64,14 +68,52 @@
from zope.schema.interfaces import ValidationError
from zope.schema._bootstrapinterfaces import NO_VALUE


# pep 8 friendlyness
ASCII, ASCIILine, Bool, Bytes, BytesLine, Choice, Container, Date, Datetime
Decimal, Dict, DottedName, Field, Float, FrozenSet, Id, Int, InterfaceField
Iterable, List, MinMaxLen, NativeString, NativeStringLine, Object, Orderable
Password, Set, SourceText, Text, TextLine, Time, Timedelta, Tuple, URI
getFields, getFieldsInOrder, getFieldNames, getFieldNamesInOrder,
getValidationErrors, getSchemaValidationErrors
accessors
ValidationError
NO_VALUE
__all__ = [
'ASCII',
'ASCIILine',
'Bool',
'Bytes',
'BytesLine',
'Choice',
'Container',
'Date',
'Datetime',
'Decimal',
'Dict',
'DottedName',
'Field',
'Float',
'FrozenSet',
'Id',
'Int',
'InterfaceField',
'Iterable',
'List',
'Mapping',
'MutableMapping',
'MutableSequence',
'MinMaxLen',
'NativeString',
'NativeStringLine',
'Object',
'Orderable',
'Password',
'Set',
'Sequence',
'SourceText',
'Text',
'TextLine',
'Time',
'Timedelta',
'Tuple',
'URI',
'getFields',
'getFieldsInOrder',
'getFieldNames',
'getFieldNamesInOrder',
'getValidationErrors',
'getSchemaValidationErrors',
'accessors',
'ValidationError',
'NO_VALUE'
]
68 changes: 59 additions & 9 deletions src/zope/schema/_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
"""
__docformat__ = 'restructuredtext'

try:
from collections import abc
except ImportError: # pragma: no cover
# Python 2
import collections as abc

from datetime import datetime
from datetime import date
from datetime import timedelta
Expand Down Expand Up @@ -54,9 +60,13 @@
from zope.schema.interfaces import IInterfaceField
from zope.schema.interfaces import IList
from zope.schema.interfaces import IMinMaxLen
from zope.schema.interfaces import IMapping
from zope.schema.interfaces import IMutableMapping
from zope.schema.interfaces import IMutableSequence
from zope.schema.interfaces import IObject
from zope.schema.interfaces import IPassword
from zope.schema.interfaces import ISet
from zope.schema.interfaces import ISequence
from zope.schema.interfaces import ISource
from zope.schema.interfaces import ISourceText
from zope.schema.interfaces import IText
Expand Down Expand Up @@ -562,14 +572,34 @@ def _validate(self, value):
_validate_uniqueness(self, value)


@implementer(ISequence)
class Sequence(AbstractCollection):
"""
A field representing an ordered sequence.
.. versionadded:: 4.6.0
"""
_type = abc.Sequence


@implementer(ITuple)
class Tuple(AbstractCollection):
class Tuple(Sequence):
"""A field representing a Tuple."""
_type = tuple


@implementer(IMutableSequence)
class MutableSequence(Sequence):
"""
A field representing a mutable sequence.
.. versionadded:: 4.6.0
"""
_type = abc.MutableSequence


@implementer(IList)
class List(AbstractCollection):
class List(MutableSequence):
"""A field representing a List."""
_type = list

Expand Down Expand Up @@ -725,15 +755,19 @@ def __init__(self, object, name, context):
self.context = context


@implementer(IDict)
class Dict(MinMaxLen, Iterable):
"""A field representing a Dict."""
_type = dict
@implementer(IMapping)
class Mapping(MinMaxLen, Iterable):
"""
A field representing a mapping.
.. versionadded:: 4.6.0
"""
_type = abc.Mapping
key_type = None
value_type = None

def __init__(self, key_type=None, value_type=None, **kw):
super(Dict, self).__init__(**kw)
super(Mapping, self).__init__(**kw)
# whine if key_type or value_type is not a field
if key_type is not None and not IField.providedBy(key_type):
raise ValueError("'key_type' must be field instance.")
Expand All @@ -743,7 +777,7 @@ def __init__(self, key_type=None, value_type=None, **kw):
self.value_type = value_type

def _validate(self, value):
super(Dict, self)._validate(value)
super(Mapping, self)._validate(value)
errors = []
if self.value_type:
errors = _validate_sequence(self.value_type, value.values(),
Expand All @@ -759,11 +793,27 @@ def _validate(self, value):

def bind(self, object):
"""See zope.schema._bootstrapinterfaces.IField."""
clone = super(Dict, self).bind(object)
clone = super(Mapping, self).bind(object)
# binding value_type is necessary for choices with named vocabularies,
# and possibly also for other fields.
if clone.key_type is not None:
clone.key_type = clone.key_type.bind(object)
if clone.value_type is not None:
clone.value_type = clone.value_type.bind(object)
return clone


@implementer(IMutableMapping)
class MutableMapping(Mapping):
"""
A field representing a mutable mapping.
.. versionadded:: 4.6.0
"""
_type = abc.MutableMapping


@implementer(IDict)
class Dict(MutableMapping):
"""A field representing a Dict."""
_type = dict
31 changes: 25 additions & 6 deletions src/zope/schema/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,14 @@ class ISequence(ICollection):
"""Abstract interface specifying that the value is ordered"""


class IMutableSequence(ISequence):
"""
Abstract interface specifying that the value is ordered and
mutable.
.. versionadded:: 4.6.0
"""

class IUnorderedCollection(ICollection):
"""Abstract interface specifying that the value cannot be ordered"""

Expand All @@ -529,7 +537,7 @@ class ITuple(ISequence):
Python tuple."""


class IList(ISequence):
class IList(IMutableSequence):
"""Field containing a value that implements the API of a conventional
Python list."""

Expand Down Expand Up @@ -583,14 +591,14 @@ class IBeforeObjectAssignedEvent(Interface):
context = Attribute("The context object where the object will be "
"assigned to.")

class IMapping(IMinMaxLen, IIterable, IContainer):
"""
Field containing an instance of :class:`collections.Mapping`.
class IDict(IMinMaxLen, IIterable, IContainer):
"""Field containing a conventional dict.
The key_type and value_type fields allow specification
The *key_type* and *value_type* fields allow specification
of restrictions for keys and values contained in the dict.
"""
"""
key_type = Attribute(
"key_type",
_("Field keys must conform to the given type, expressed via a Field.")
Expand All @@ -603,6 +611,17 @@ class IDict(IMinMaxLen, IIterable, IContainer):
)


class IMutableMapping(IMapping):
"""
Field containing an instance of :class:`collections.MutableMapping`.
"""


class IDict(IMutableMapping):
"""Field containing a conventional dict.
"""


class ITerm(Interface):
"""Object representing a single value in a vocabulary."""

Expand Down

0 comments on commit 19c9511

Please sign in to comment.