diff options
author | Jason Madden <jamadden@gmail.com> | 2018-09-22 16:51:47 -0500 |
---|---|---|
committer | Jason Madden <jamadden@gmail.com> | 2018-09-22 16:55:47 -0500 |
commit | e554ce3c6ebca03f9f809e197f8d44d35f7fb39f (patch) | |
tree | 8ae0ee149e907c9053206df9396cc1a0ec926dbb | |
parent | d78c57c3c9ab8608fda1c1213c64d1666db770e2 (diff) | |
download | zope-schema-e554ce3c6ebca03f9f809e197f8d44d35f7fb39f.tar.gz |
Make NativeString[Line] into distinct types.issue74
This facilitates documentation and interactive exploration.
Fixes #74.
-rw-r--r-- | CHANGES.rst | 7 | ||||
-rw-r--r-- | docs/api.rst | 8 | ||||
-rw-r--r-- | src/zope/schema/_field.py | 57 | ||||
-rw-r--r-- | src/zope/schema/interfaces.py | 24 | ||||
-rw-r--r-- | src/zope/schema/tests/test__field.py | 57 | ||||
-rw-r--r-- | version.txt | 2 |
6 files changed, 131 insertions, 24 deletions
diff --git a/CHANGES.rst b/CHANGES.rst index a861314..01773e1 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -2,10 +2,13 @@ Changes ========= -4.8.1 (unreleased) +4.9.0 (unreleased) ================== -- Nothing changed yet. +- Make ``NativeString`` and ``NativeStringLine`` distinct types that + implement the newly-distinct interfaces ``INativeString`` and + ``INativeStringLine``. Previously these were just aliases for either + ``Text`` (on Python 3) or ``Bytes`` (on Python 2). 4.8.0 (2018-09-19) diff --git a/docs/api.rst b/docs/api.rst index 9344e44..bea7c69 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -37,6 +37,8 @@ Strings .. autointerface:: zope.schema.interfaces.ITextLine .. autointerface:: zope.schema.interfaces.IASCII .. autointerface:: zope.schema.interfaces.IASCIILine +.. autointerface:: zope.schema.interfaces.INativeString +.. autointerface:: zope.schema.interfaces.INativeStringLine .. autointerface:: zope.schema.interfaces.IPassword .. autointerface:: zope.schema.interfaces.IURI @@ -199,8 +201,6 @@ Field Implementations .. autoclass:: zope.schema.MutableMapping .. autoclass:: zope.schema.MutableSequence .. autoclass:: zope.schema.MinMaxLen -.. autoclass:: zope.schema.NativeString -.. autoclass:: zope.schema.NativeStringLine .. autoclass:: zope.schema.Object :no-show-inheritance: .. autoclass:: zope.schema.Orderable @@ -232,6 +232,10 @@ Strings :no-show-inheritance: .. autoclass:: zope.schema.TextLine :no-show-inheritance: +.. autoclass:: zope.schema.NativeString + :no-show-inheritance: +.. autoclass:: zope.schema.NativeStringLine + :no-show-inheritance: Numbers ------- diff --git a/src/zope/schema/_field.py b/src/zope/schema/_field.py index 1414b47..0444656 100644 --- a/src/zope/schema/_field.py +++ b/src/zope/schema/_field.py @@ -65,6 +65,8 @@ 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 INativeString +from zope.schema.interfaces import INativeStringLine from zope.schema.interfaces import IObject from zope.schema.interfaces import INumber from zope.schema.interfaces import IPassword @@ -170,11 +172,27 @@ class Bytes(MinMaxLen, Field): self.validate(value) return value -# for things which are of the str type on both Python 2 and 3 -if PY3: # pragma: no cover - NativeString = Text -else: # pragma: no cover - NativeString = Bytes + +@implementer(INativeString, IFromUnicode, IFromBytes) +class NativeString(Text if PY3 else Bytes): + """ + A native string is always the type `str`. + + In addition to :class:`~zope.schema.interfaces.INativeString`, + this implements :class:`~zope.schema.interfaces.IFromUnicode` and + :class:`~zope.schema.interfaces.IFromBytes`. + + .. versionchanged:: 4.9.0 + This is now a distinct type instead of an alias for either `Text` or `Bytes`, + depending on the platform. + """ + _type = str + + if PY3: + def fromBytes(self, value): + value = value.decode('utf-8') + self.validate(value) + return value @implementer(IASCII) @@ -191,17 +209,34 @@ class ASCII(NativeString): @implementer(IBytesLine) class BytesLine(Bytes): - """A Text field with no newlines.""" + """A `Bytes` field with no newlines.""" def constraint(self, value): # TODO: we should probably use a more general definition of newlines return b'\n' not in value -# for things which are of the str type on both Python 2 and 3 -if PY3: # pragma: no cover - NativeStringLine = TextLine -else: # pragma: no cover - NativeStringLine = BytesLine + +@implementer(INativeStringLine, IFromUnicode, IFromBytes) +class NativeStringLine(TextLine if PY3 else BytesLine): + """ + A native string is always the type `str`; this field excludes + newlines. + + In addition to :class:`~zope.schema.interfaces.INativeStringLine`, + this implements :class:`~zope.schema.interfaces.IFromUnicode` and + :class:`~zope.schema.interfaces.IFromBytes`. + + .. versionchanged:: 4.9.0 + This is now a distinct type instead of an alias for either `TextLine` + or `BytesLine`, depending on the platform. + """ + _type = str + + if PY3: + def fromBytes(self, value): + value = value.decode('utf-8') + self.validate(value) + return value @implementer(IASCIILine) diff --git a/src/zope/schema/interfaces.py b/src/zope/schema/interfaces.py index c0ac93b..c6c7aea 100644 --- a/src/zope/schema/interfaces.py +++ b/src/zope/schema/interfaces.py @@ -416,10 +416,14 @@ class IText(IMinMaxLen, IIterable, IField): # for things which are of the str type on both Python 2 and 3 -if PY3: # pragma: no cover - INativeString = IText -else: # pragma: no cover - INativeString = IBytes +class INativeString(IText if PY3 else IBytes): + """ + A field that always contains the native `str` type. + + .. versionchanged:: 4.9.0 + This is now a distinct type instead of an alias for either `IText` + or `IBytes`, depending on the platform. + """ class IASCII(INativeString): @@ -446,10 +450,14 @@ class ITextLine(IText): """Field containing a unicode string without newlines.""" -if PY3: # pragma: no cover - INativeStringLine = ITextLine -else: # pragma: no cover - INativeStringLine = IBytesLine +class INativeStringLine(ITextLine if PY3 else IBytesLine): + """ + A field that always contains the native `str` type, without any newlines. + + .. versionchanged:: 4.9.0 + This is now a distinct type instead of an alias for either `ITextLine` + or `IBytesLine`, depending on the platform. + """ class IPassword(ITextLine): diff --git a/src/zope/schema/tests/test__field.py b/src/zope/schema/tests/test__field.py index 0eb02ff..4f99d69 100644 --- a/src/zope/schema/tests/test__field.py +++ b/src/zope/schema/tests/test__field.py @@ -1702,6 +1702,63 @@ class DictTests(MutableMappingTests): with self.assertRaises(WrongType): super(DictTests, self).test_mutable_mapping() +class NativeStringTests(EqualityTestsMixin, + WrongTypeTestsMixin, + unittest.TestCase): + + def _getTargetClass(self): + from zope.schema._field import NativeString + return NativeString + + def _getTargetInterface(self): + from zope.schema.interfaces import INativeString + return INativeString + + def _getTargetInterfaces(self): + from zope.schema.interfaces import IFromUnicode + from zope.schema.interfaces import IFromBytes + return [self._getTargetInterface(), IFromUnicode, IFromBytes] + + def test_fromBytes(self): + field = self._makeOne() + self.assertEqual(field.fromBytes(b''), '') + self.assertEqual(field.fromBytes(b'DEADBEEF'), 'DEADBEEF') + + def test_fromUnicode(self): + field = self._makeOne() + self.assertIsInstance(field.fromUnicode(u''), str) + self.assertEqual(field.fromUnicode(u''), '') + self.assertEqual(field.fromUnicode(u'DEADBEEF'), 'DEADBEEF') + + +class NativeStringLineTests(EqualityTestsMixin, + WrongTypeTestsMixin, + unittest.TestCase): + + def _getTargetClass(self): + from zope.schema._field import NativeStringLine + return NativeStringLine + + def _getTargetInterface(self): + from zope.schema.interfaces import INativeStringLine + return INativeStringLine + + def _getTargetInterfaces(self): + from zope.schema.interfaces import IFromUnicode + from zope.schema.interfaces import IFromBytes + return [self._getTargetInterface(), IFromUnicode, IFromBytes] + + def test_fromBytes(self): + field = self._makeOne() + self.assertEqual(field.fromBytes(b''), '') + self.assertEqual(field.fromBytes(b'DEADBEEF'), 'DEADBEEF') + + def test_fromUnicode(self): + field = self._makeOne() + self.assertIsInstance(field.fromUnicode(u''), str) + self.assertEqual(field.fromUnicode(u''), '') + self.assertEqual(field.fromUnicode(u'DEADBEEF'), 'DEADBEEF') + def _makeSampleVocabulary(): from zope.interface import implementer diff --git a/version.txt b/version.txt index 40aa077..4cc29d9 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -4.8.1.dev0 +4.9.0.dev0 |