Skip to content

Commit

Permalink
Drop support for Python < 3.7
Browse files Browse the repository at this point in the history
  • Loading branch information
cjwatson committed Dec 21, 2022
1 parent 044ef14 commit 908f0cd
Show file tree
Hide file tree
Showing 13 changed files with 54 additions and 188 deletions.
7 changes: 5 additions & 2 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@
Changes
=========

6.2.2 (unreleased)
7.0.0 (unreleased)
==================


- Add support for Python 3.11.

- Drop support for Python 2.7, 3.5, 3.6.

- Drop ``zope.schema._compat`` module.

6.2.1 (2022-09-14)
==================

Expand Down
2 changes: 1 addition & 1 deletion docs/fields.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Bytes
-----

:class:`zope.schema.Bytes` fields contain binary data, represented
as a sequence of bytes (``str`` in Python2, ``bytes`` in Python3).
as a sequence of ``bytes``.

Conversion from Unicode:

Expand Down
3 changes: 1 addition & 2 deletions docs/narr.rst
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,7 @@ occurs a ``ValidationError`` will be raised; for example:

.. doctest::

>>> from zope.schema._compat import non_native_string
>>> url_bound.validate(non_native_string('http://zope.org/foo'))
>>> url_bound.validate(b'http://zope.org/foo')
Traceback (most recent call last):
...
WrongType: ...
Expand Down
6 changes: 1 addition & 5 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,7 @@ def read(*rnames):
"License :: OSI Approved :: Zope Public License",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
Expand All @@ -78,7 +74,7 @@ def read(*rnames):
"Framework :: Zope :: 3",
"Topic :: Software Development :: Libraries :: Python Modules",
],
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*',
python_requires='>=3.7',
include_package_data=True,
zip_safe=False,
tests_require=TESTS_REQUIRE,
Expand Down
18 changes: 5 additions & 13 deletions src/zope/schema/_bootstrapfields.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,6 @@
from zope.schema._bootstrapinterfaces import TooSmall
from zope.schema._bootstrapinterfaces import ValidationError
from zope.schema._bootstrapinterfaces import WrongType
from zope.schema._compat import PY2
from zope.schema._compat import integer_types
from zope.schema._compat import text_type


class _NotGiven(object):
Expand Down Expand Up @@ -524,7 +521,7 @@ def _validate(self, value):
@implementer(IFromUnicode)
class Text(MinMaxLen, Field):
"""A field containing text used for human discourse."""
_type = text_type
_type = str
unicode_normalization = 'NFC'

def __init__(self, *args, **kw):
Expand Down Expand Up @@ -552,7 +549,7 @@ def fromUnicode(self, value):
zope.schema._bootstrapinterfaces.ConstraintNotSatisfied:
(u'foo spam', '')
"""
if isinstance(value, text_type):
if isinstance(value, str):
if self.unicode_normalization:
value = unicodedata.normalize(
self.unicode_normalization, value)
Expand Down Expand Up @@ -759,13 +756,8 @@ def fromUnicode(self, value):
finally:
last_exc = None

# On Python 2, native strings are byte strings, which is
# what the converters expect, so we don't need to do any decoding.
if PY2: # pragma: PY2
fromBytes = fromUnicode
else: # pragma: PY3
def fromBytes(self, value):
return self.fromUnicode(value.decode('utf-8'))
def fromBytes(self, value):
return self.fromUnicode(value.decode('utf-8'))


class Complex(Number):
Expand Down Expand Up @@ -930,7 +922,7 @@ class Int(Integral):
"""A field representing a native integer type. and implementing
:class:`zope.schema.interfaces.IInt`.
"""
_type = integer_types
_type = int
_unicode_converters = (int,)


Expand Down
39 changes: 0 additions & 39 deletions src/zope/schema/_compat.py

This file was deleted.

55 changes: 20 additions & 35 deletions src/zope/schema/_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,8 @@
"""
__docformat__ = 'restructuredtext'

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

import re
from collections import abc
from datetime import date
from datetime import datetime
from datetime import time
Expand Down Expand Up @@ -53,11 +48,6 @@
from zope.schema._bootstrapfields import Text
from zope.schema._bootstrapfields import TextLine
from zope.schema._bootstrapfields import _NotGiven
from zope.schema._compat import PY3
from zope.schema._compat import binary_type
from zope.schema._compat import make_binary
from zope.schema._compat import string_types
from zope.schema._compat import text_type
from zope.schema.fieldproperty import FieldProperty
from zope.schema.interfaces import IASCII
from zope.schema.interfaces import IURI
Expand Down Expand Up @@ -174,27 +164,26 @@ def __call__(self, cls):
@implementer(ISourceText)
class SourceText(Text):
__doc__ = ISourceText.__doc__
_type = text_type
_type = str


@implementer(IBytes, IFromUnicode, IFromBytes)
class Bytes(MinMaxLen, Field):
__doc__ = IBytes.__doc__

_type = binary_type
_type = bytes

def fromUnicode(self, value):
""" See IFromUnicode.
"""
return self.fromBytes(make_binary(value))
return self.fromBytes(value.encode('ascii'))

def fromBytes(self, value):
self.validate(value)
return value


@implementer_if_needed(INativeString, IFromUnicode, IFromBytes)
class NativeString(Text if PY3 else Bytes):
class NativeString(Text):
"""
A native string is always the type `str`.
Expand All @@ -208,11 +197,10 @@ class NativeString(Text if PY3 else Bytes):
"""
_type = str

if PY3: # pragma: no branch
def fromBytes(self, value):
value = value.decode('utf-8')
self.validate(value)
return value
def fromBytes(self, value):
value = value.decode('utf-8')
self.validate(value)
return value


@implementer(IASCII)
Expand All @@ -237,7 +225,7 @@ def constraint(self, value):


@implementer_if_needed(INativeStringLine, IFromUnicode, IFromBytes)
class NativeStringLine(TextLine if PY3 else BytesLine):
class NativeStringLine(TextLine):
"""
A native string is always the type `str`; this field excludes
newlines.
Expand All @@ -252,11 +240,10 @@ class NativeStringLine(TextLine if PY3 else BytesLine):
"""
_type = str

if PY3: # pragma: no branch
def fromBytes(self, value):
value = value.decode('utf-8')
self.validate(value)
return value
def fromBytes(self, value):
value = value.decode('utf-8')
self.validate(value)
return value


@implementer(IASCIILine)
Expand Down Expand Up @@ -397,7 +384,7 @@ class Choice(Field):
def __init__(self, values=None, vocabulary=None, source=None, **kw):
"""Initialize object."""
if vocabulary is not None:
if (not isinstance(vocabulary, string_types)
if (not isinstance(vocabulary, str)
and not IBaseVocabulary.providedBy(vocabulary)):
raise ValueError('vocabulary must be a string or implement '
'IBaseVocabulary')
Expand All @@ -420,7 +407,7 @@ def __init__(self, values=None, vocabulary=None, source=None, **kw):
self.vocabularyName = None
if values is not None:
self.vocabulary = SimpleVocabulary.fromValues(values)
elif isinstance(vocabulary, string_types):
elif isinstance(vocabulary, str):
self.vocabularyName = vocabulary
else:
if (not ISource.providedBy(vocabulary)
Expand Down Expand Up @@ -500,17 +487,15 @@ class _StrippedNativeStringLine(NativeStringLine):

def fromUnicode(self, value):
v = value.strip()
# On Python 2, self._type is bytes, so we need to encode
# unicode down to ASCII bytes. On Python 3, self._type is
# unicode, but we don't want to allow non-ASCII values, to match
# Python 2 (our regexs would reject that anyway.)
# self._type is unicode, but we don't want to allow non-ASCII
# values, to match the old behaviour on Python 2 (our regexes would
# reject that anyway).
try:
v = v.encode('ascii') # bytes
except UnicodeEncodeError:
raise self._invalid_exc_type(value).with_field_and_value(
self, value)
if not isinstance(v, self._type): # pragma: no branch
v = v.decode('ascii')
v = v.decode('ascii')
self.validate(v)
return v

Expand Down
2 changes: 1 addition & 1 deletion src/zope/schema/_messageid.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@
try:
from zope.i18nmessageid import MessageFactory
except ImportError: # pragma: no cover
from zope.schema._compat import text_type as _
MessageFactory = str
else: # pragma: no cover
_ = MessageFactory("zope")
11 changes: 4 additions & 7 deletions src/zope/schema/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@
from zope.schema._bootstrapinterfaces import ValidationError
from zope.schema._bootstrapinterfaces import WrongContainedType
from zope.schema._bootstrapinterfaces import WrongType
from zope.schema._compat import PY3
from zope.schema._messageid import _


Expand Down Expand Up @@ -420,7 +419,7 @@ class IText(IMinMaxLen, IIterable, IField):


# for things which are of the str type on both Python 2 and 3
class INativeString(IText if PY3 else IBytes):
class INativeString(IText):
"""
A field that always contains the native `str` type.
Expand Down Expand Up @@ -454,7 +453,7 @@ class ITextLine(IText):
"""Field containing a unicode string without newlines."""


class INativeStringLine(ITextLine if PY3 else IBytesLine):
class INativeStringLine(ITextLine):
"""
A field that always contains the native `str` type, without any newlines.
Expand Down Expand Up @@ -613,8 +612,7 @@ class IIntegral(IRational):

class IInt(IIntegral):
"""
Field containing exactly the native class :class:`int` (or, on
Python 2, ``long``).
Field containing exactly the native class :class:`int`.
.. seealso:: :class:`zope.schema.Int`
"""
Expand Down Expand Up @@ -918,8 +916,7 @@ class ITokenizedTerm(ITerm):
"token",
"""Token which can be used to represent the value on a stream.
The value of this attribute must be a non-empty 7-bit native string
(i.e., the ``str`` type on both Python 2 and 3).
The value of this attribute must be a non-empty 7-bit ``str``.
Control characters, including newline, are not allowed.
""")

Expand Down
51 changes: 0 additions & 51 deletions src/zope/schema/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,52 +1 @@
#
# This file is necessary to make this directory a package.

import re

from zope.testing import renormalizing

from zope.schema._compat import PY3


def _make_transforms(patterns):
return [(re.compile(pattern), repl) for pattern, repl in patterns]


if PY3: # pragma: PY3
py3_checker = renormalizing.RENormalizing(_make_transforms([
(r"u'([^']*)'",
r"'\1'"),
(r"^b'([^']*)'",
r"'\1'"),
(r"([^'])b'([^']*)'",
r"\1'\2'"),
(r"<class 'bytes'>",
r"<type 'str'>"),
(r"<class 'str'>",
r"<type 'unicode'>"),
(r"zope.schema._bootstrapinterfaces.InvalidValue",
r"InvalidValue"),
(r"zope.schema.interfaces.InvalidId: '([^']*)'",
r"InvalidId: \1"),
(r"zope.schema.interfaces.InvalidId:",
r"InvalidId:"),
(r"zope.schema.interfaces.InvalidURI: '([^']*)'",
r"InvalidURI: \1"),
(r"zope.schema.interfaces.InvalidURI:",
r"InvalidURI:"),
(r"zope.schema.interfaces.InvalidDottedName: '([^']*)'",
r"InvalidDottedName: \1"),
(r"zope.schema.interfaces.InvalidDottedName:",
r"InvalidDottedName:"),
(r"zope.schema._bootstrapinterfaces.ConstraintNotSatisfied: '([^']*)'",
r"ConstraintNotSatisfied: \1"),
(r"zope.schema._bootstrapinterfaces.ConstraintNotSatisfied:",
r"ConstraintNotSatisfied:"),
(r"zope.schema._bootstrapinterfaces.WrongType:",
r"WrongType:"),
]))
else: # pragma: PY2
py3_checker = renormalizing.RENormalizing(_make_transforms([
(r"([^'])b'([^']*)'",
r"\1'\2'"),
]))

0 comments on commit 908f0cd

Please sign in to comment.