Merge ~cjwatson/lazr.restful:pyupgrade-py3 into lazr.restful:main

Proposed by Colin Watson
Status: Merged
Merged at revision: 6f588c2bd39e71694dd66d6f76a7c11a0826b2ce
Proposed branch: ~cjwatson/lazr.restful:pyupgrade-py3
Merge into: lazr.restful:main
Diff against target: 3006 lines (+305/-532)
53 files modified
.pre-commit-config.yaml (+1/-1)
pyproject.toml (+1/-1)
src/lazr/restful/__init__.py (+0/-2)
src/lazr/restful/_bytestorage.py (+0/-3)
src/lazr/restful/_operation.py (+6/-12)
src/lazr/restful/_resource.py (+29/-39)
src/lazr/restful/debug.py (+0/-3)
src/lazr/restful/declarations.py (+10/-19)
src/lazr/restful/directives/__init__.py (+0/-3)
src/lazr/restful/docs/conf.py (+7/-9)
src/lazr/restful/error.py (+0/-3)
src/lazr/restful/example/base/filemanager.py (+0/-3)
src/lazr/restful/example/base/interfaces.py (+28/-33)
src/lazr/restful/example/base/root.py (+10/-13)
src/lazr/restful/example/base/security.py (+0/-3)
src/lazr/restful/example/base/subscribers.py (+0/-3)
src/lazr/restful/example/base/tests/test_integration.py (+1/-9)
src/lazr/restful/example/base/traversal.py (+1/-6)
src/lazr/restful/example/base_extended/comments.py (+1/-3)
src/lazr/restful/example/base_extended/tests/test_integration.py (+1/-8)
src/lazr/restful/example/multiversion/resources.py (+5/-9)
src/lazr/restful/example/multiversion/root.py (+0/-3)
src/lazr/restful/example/multiversion/tests/test_integration.py (+1/-8)
src/lazr/restful/example/wsgi/resources.py (+3/-7)
src/lazr/restful/example/wsgi/root.py (+0/-3)
src/lazr/restful/example/wsgi/run.py (+0/-2)
src/lazr/restful/example/wsgi/tests/test_integration.py (+1/-8)
src/lazr/restful/fields.py (+2/-5)
src/lazr/restful/frameworks/django.py (+2/-3)
src/lazr/restful/interface.py (+0/-3)
src/lazr/restful/interfaces/__init__.py (+0/-2)
src/lazr/restful/interfaces/_fields.py (+0/-3)
src/lazr/restful/interfaces/_rest.py (+39/-42)
src/lazr/restful/jsoncache.py (+0/-4)
src/lazr/restful/marshallers.py (+27/-45)
src/lazr/restful/metazcml.py (+1/-4)
src/lazr/restful/publisher.py (+4/-11)
src/lazr/restful/security.py (+0/-3)
src/lazr/restful/simple.py (+4/-10)
src/lazr/restful/tales.py (+5/-11)
src/lazr/restful/testing/event.py (+0/-4)
src/lazr/restful/testing/helpers.py (+0/-2)
src/lazr/restful/testing/tales.py (+0/-4)
src/lazr/restful/testing/webservice.py (+14/-18)
src/lazr/restful/tests/test_declarations.py (+40/-42)
src/lazr/restful/tests/test_docs.py (+1/-9)
src/lazr/restful/tests/test_error.py (+3/-7)
src/lazr/restful/tests/test_etag.py (+6/-10)
src/lazr/restful/tests/test_navigation.py (+6/-10)
src/lazr/restful/tests/test_utils.py (+1/-5)
src/lazr/restful/tests/test_webservice.py (+37/-46)
src/lazr/restful/utils.py (+7/-10)
src/lazr/restful/wsgi.py (+0/-3)
Reviewer Review Type Date Requested Status
Jürgen Gmach Approve
Review via email: mp+413604@code.launchpad.net

Commit message

Apply pyupgrade --py3-plus

To post a comment you must log in.
Revision history for this message
Jürgen Gmach (jugmac00) wrote :

LGTM with a minor issue, see comment

review: Approve
Revision history for this message
Colin Watson (cjwatson) :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 6f75344..6b363b1 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -23,7 +23,7 @@ repos:
23 rev: v2.29.023 rev: v2.29.0
24 hooks:24 hooks:
25 - id: pyupgrade25 - id: pyupgrade
26 args: [--keep-percent-format]26 args: [--keep-percent-format, --py3-plus]
27- repo: https://github.com/psf/black27- repo: https://github.com/psf/black
28 rev: 21.10b028 rev: 21.10b0
29 hooks:29 hooks:
diff --git a/pyproject.toml b/pyproject.toml
index 486bbe6..1f331da 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,3 +1,3 @@
1[tool.black]1[tool.black]
2line-length = 792line-length = 79
3target-version = ['py27']3target-version = ['py35']
diff --git a/src/lazr/restful/__init__.py b/src/lazr/restful/__init__.py
index 25235cd..c8e3f40 100644
--- a/src/lazr/restful/__init__.py
+++ b/src/lazr/restful/__init__.py
@@ -17,8 +17,6 @@
1717
18# pylint: disable-msg=W040118# pylint: disable-msg=W0401
1919
20from __future__ import absolute_import, print_function
21
22try:20try:
23 import importlib.metadata as importlib_metadata21 import importlib.metadata as importlib_metadata
24except ImportError:22except ImportError:
diff --git a/src/lazr/restful/_bytestorage.py b/src/lazr/restful/_bytestorage.py
index 7d6c6a0..b25369c 100644
--- a/src/lazr/restful/_bytestorage.py
+++ b/src/lazr/restful/_bytestorage.py
@@ -16,9 +16,6 @@
1616
17"""Classes for a resource that implements a binary file repository."""17"""Classes for a resource that implements a binary file repository."""
1818
19from __future__ import absolute_import, print_function
20
21__metaclass__ = type
22__all__ = [19__all__ = [
23 "ByteStorageResource",20 "ByteStorageResource",
24]21]
diff --git a/src/lazr/restful/_operation.py b/src/lazr/restful/_operation.py
index af48e48..7cab8ea 100644
--- a/src/lazr/restful/_operation.py
+++ b/src/lazr/restful/_operation.py
@@ -2,10 +2,7 @@
22
3"""Base classes for one-off HTTP operations."""3"""Base classes for one-off HTTP operations."""
44
5from __future__ import absolute_import, print_function
6
7import simplejson5import simplejson
8import six
96
10from zope.component import getMultiAdapter, getUtility, queryMultiAdapter7from zope.component import getMultiAdapter, getUtility, queryMultiAdapter
11from zope.event import notify8from zope.event import notify
@@ -40,7 +37,6 @@ from lazr.restful._resource import (
40)37)
4138
4239
43__metaclass__ = type
44__all__ = [40__all__ = [
45 "IObjectLink",41 "IObjectLink",
46 "ObjectLink",42 "ObjectLink",
@@ -163,9 +159,7 @@ class ResourceOperation(BatchingResourceMixin):
163 # has its response batched.159 # has its response batched.
164 return True160 return True
165161
166 if zope_isinstance(162 if zope_isinstance(result, (bytes, str, dict, set, list, tuple)):
167 result, (bytes, six.text_type, dict, set, list, tuple)
168 ):
169 # Ordinary Python data structures generally are not163 # Ordinary Python data structures generally are not
170 # batched.164 # batched.
171 return False165 return False
@@ -216,14 +210,14 @@ class ResourceOperation(BatchingResourceMixin):
216 self.request.form.get(name)210 self.request.form.get(name)
217 )211 )
218 except ValueError as e:212 except ValueError as e:
219 errors.append(u"%s: %s" % (name, e))213 errors.append("%s: %s" % (name, e))
220 continue214 continue
221 try:215 try:
222 field.validate(value)216 field.validate(value)
223 except RequiredMissing:217 except RequiredMissing:
224 errors.append(u"%s: Required input is missing." % name)218 errors.append("%s: Required input is missing." % name)
225 except ValidationError as e:219 except ValidationError as e:
226 errors.append(u"%s: %s" % (name, e))220 errors.append("%s: %s" % (name, e))
227 else:221 else:
228 validated_values[name] = value222 validated_values[name] = value
229 return (validated_values, errors)223 return (validated_values, errors)
@@ -252,7 +246,7 @@ class IObjectLink(IField):
252 """Field containing a link to an object."""246 """Field containing a link to an object."""
253247
254 schema = Attribute(248 schema = Attribute(
255 "schema", u"The Interface of the Object on the other end of the link."249 "schema", "The Interface of the Object on the other end of the link."
256 )250 )
257251
258252
@@ -265,4 +259,4 @@ class ObjectLink(Field):
265 raise WrongType259 raise WrongType
266260
267 self.schema = schema261 self.schema = schema
268 super(ObjectLink, self).__init__(**kw)262 super().__init__(**kw)
diff --git a/src/lazr/restful/_resource.py b/src/lazr/restful/_resource.py
index f01326d..45f717e 100644
--- a/src/lazr/restful/_resource.py
+++ b/src/lazr/restful/_resource.py
@@ -2,10 +2,6 @@
22
3"""Base classes for HTTP resources."""3"""Base classes for HTTP resources."""
44
5from __future__ import absolute_import, division, print_function
6
7__metaclass__ = type
8
9__all__ = [5__all__ = [
10 "BatchingResourceMixin",6 "BatchingResourceMixin",
11 "Collection",7 "Collection",
@@ -55,7 +51,6 @@ try:
55except ImportError:51except ImportError:
56 from cgi import escape52 from cgi import escape
5753
58import six
59from zope.component import (54from zope.component import (
60 adapter,55 adapter,
61 getAdapters,56 getAdapters,
@@ -162,7 +157,7 @@ init_status_codes()
162157
163def decode_value(value):158def decode_value(value):
164 """Return a unicode value curresponding to `value`."""159 """Return a unicode value curresponding to `value`."""
165 if isinstance(value, six.text_type):160 if isinstance(value, str):
166 return value161 return value
167 elif isinstance(value, bytes):162 elif isinstance(value, bytes):
168 return value.decode("utf-8")163 return value.decode("utf-8")
@@ -172,7 +167,7 @@ def decode_value(value):
172167
173def _default_html_renderer(value):168def _default_html_renderer(value):
174 """The default technique for rendering a value as an HTML snippet."""169 """The default technique for rendering a value as an HTML snippet."""
175 return escape(six.text_type(value), quote=False)170 return escape(str(value), quote=False)
176171
177172
178@adapter(Interface, IField, IWebServiceClientRequest)173@adapter(Interface, IField, IWebServiceClientRequest)
@@ -212,7 +207,7 @@ class ResourceJSONEncoder(simplejson.encoder.JSONEncoderForHTML):
212207
213 def __init__(self, *args, **kwargs):208 def __init__(self, *args, **kwargs):
214 self.media_type = kwargs.pop("media_type", HTTPResource.JSON_TYPE)209 self.media_type = kwargs.pop("media_type", HTTPResource.JSON_TYPE)
215 super(ResourceJSONEncoder, self).__init__(*args, **kwargs)210 super().__init__(*args, **kwargs)
216211
217 def default(self, obj):212 def default(self, obj):
218 """Convert the given object to a simple data structure."""213 """Convert the given object to a simple data structure."""
@@ -711,7 +706,7 @@ class CustomOperationResourceMixin:
711 # with multiple inheritance. That requires defining __init__706 # with multiple inheritance. That requires defining __init__
712 # to call the next constructor in the chain, which means using707 # to call the next constructor in the chain, which means using
713 # super() even though this class itself has no superclass.708 # super() even though this class itself has no superclass.
714 super(CustomOperationResourceMixin, self).__init__(context, request)709 super().__init__(context, request)
715710
716 def handleCustomGET(self, operation_name):711 def handleCustomGET(self, operation_name):
717 """Execute a custom search-type operation triggered through GET.712 """Execute a custom search-type operation triggered through GET.
@@ -722,7 +717,7 @@ class CustomOperationResourceMixin:
722 :return: The result of the operation: either a string or an717 :return: The result of the operation: either a string or an
723 object that needs to be serialized to JSON.718 object that needs to be serialized to JSON.
724 """719 """
725 if not isinstance(operation_name, six.string_types):720 if not isinstance(operation_name, str):
726 self.request.response.setStatus(400)721 self.request.response.setStatus(400)
727 return "Expected a single operation: %r" % (operation_name,)722 return "Expected a single operation: %r" % (operation_name,)
728723
@@ -750,7 +745,7 @@ class CustomOperationResourceMixin:
750 :return: The result of the operation: either a string or an745 :return: The result of the operation: either a string or an
751 object that needs to be serialized to JSON.746 object that needs to be serialized to JSON.
752 """747 """
753 if not isinstance(operation_name, six.string_types):748 if not isinstance(operation_name, str):
754 self.request.response.setStatus(400)749 self.request.response.setStatus(400)
755 return "Expected a single operation: %r" % (operation_name,)750 return "Expected a single operation: %r" % (operation_name,)
756751
@@ -810,7 +805,7 @@ class FieldUnmarshallerMixin:
810 # with multiple inheritance. That requires defining __init__805 # with multiple inheritance. That requires defining __init__
811 # to call the next constructor in the chain, which means using806 # to call the next constructor in the chain, which means using
812 # super() even though this class itself has no superclass.807 # super() even though this class itself has no superclass.
813 super(FieldUnmarshallerMixin, self).__init__(context, request)808 super().__init__(context, request)
814 self._unmarshalled_field_cache = {}809 self._unmarshalled_field_cache = {}
815810
816 def _unmarshallField(self, field_name, field, detail=NORMAL_DETAIL):811 def _unmarshallField(self, field_name, field, detail=NORMAL_DETAIL):
@@ -909,7 +904,7 @@ class ReadOnlyResource(HTTPResource):
909 # This class is designed to be used with mixins. That means904 # This class is designed to be used with mixins. That means
910 # defining __init__ to call the next constructor in the chain,905 # defining __init__ to call the next constructor in the chain,
911 # even though there's no other code in __init__.906 # even though there's no other code in __init__.
912 super(ReadOnlyResource, self).__init__(context, request)907 super().__init__(context, request)
913908
914 def __call__(self):909 def __call__(self):
915 """Handle a GET or (if implemented) POST request."""910 """Handle a GET or (if implemented) POST request."""
@@ -936,7 +931,7 @@ class ReadWriteResource(HTTPResource):
936 # This class is designed to be used with mixins. That means931 # This class is designed to be used with mixins. That means
937 # defining __init__ to call the next constructor in the chain,932 # defining __init__ to call the next constructor in the chain,
938 # even though there's no other code in __init__.933 # even though there's no other code in __init__.
939 super(ReadWriteResource, self).__init__(context, request)934 super().__init__(context, request)
940935
941 def __call__(self):936 def __call__(self):
942 """Handle a GET, PUT, or PATCH request."""937 """Handle a GET, PUT, or PATCH request."""
@@ -980,10 +975,7 @@ class ReadWriteResource(HTTPResource):
980 # hopefully handle it better. Note the careful975 # hopefully handle it better. Note the careful
981 # reraising that ensures the original traceback is976 # reraising that ensures the original traceback is
982 # preserved.977 # preserved.
983 if six.PY3:978 raise exception_info[1] from None
984 six.raise_from(exception_info[1], None)
985 else:
986 six.reraise(*exception_info)
987 finally:979 finally:
988 del exception_info980 del exception_info
989981
@@ -1035,7 +1027,7 @@ class EntryManipulatingResource(ReadWriteResource):
1035 # This class is designed to be used with mixins. That means1027 # This class is designed to be used with mixins. That means
1036 # defining __init__ to call the next constructor in the chain,1028 # defining __init__ to call the next constructor in the chain,
1037 # even though there's no other code in __init__.1029 # even though there's no other code in __init__.
1038 super(EntryManipulatingResource, self).__init__(context, request)1030 super().__init__(context, request)
10391031
1040 def processAsJSONDocument(self, media_type, representation):1032 def processAsJSONDocument(self, media_type, representation):
1041 """Process an incoming representation as a JSON document."""1033 """Process an incoming representation as a JSON document."""
@@ -1066,7 +1058,7 @@ class EntryManipulatingResource(ReadWriteResource):
1066 # Some fields aren't part of the schema, so they're handled1058 # Some fields aren't part of the schema, so they're handled
1067 # separately.1059 # separately.
1068 modified_read_only_attribute = (1060 modified_read_only_attribute = (
1069 u"%s: You tried to modify a " "read-only attribute."1061 "%s: You tried to modify a " "read-only attribute."
1070 )1062 )
1071 if "self_link" in changeset:1063 if "self_link" in changeset:
1072 if changeset["self_link"] != absoluteURL(1064 if changeset["self_link"] != absoluteURL(
@@ -1143,7 +1135,7 @@ class EntryManipulatingResource(ReadWriteResource):
1143 try:1135 try:
1144 value = marshaller.marshall_from_json_data(original_value)1136 value = marshaller.marshall_from_json_data(original_value)
1145 except (ValueError, ValidationError) as e:1137 except (ValueError, ValidationError) as e:
1146 errors.append(u"%s: %s" % (repr_name, e))1138 errors.append("%s: %s" % (repr_name, e))
1147 continue1139 continue
11481140
1149 if ICollectionField.providedBy(field):1141 if ICollectionField.providedBy(field):
@@ -1152,7 +1144,7 @@ class EntryManipulatingResource(ReadWriteResource):
1152 # current one.1144 # current one.
1153 if value != current_value:1145 if value != current_value:
1154 errors.append(1146 errors.append(
1155 u"%s: You tried to modify a collection "1147 "%s: You tried to modify a collection "
1156 "attribute." % repr_name1148 "attribute." % repr_name
1157 )1149 )
1158 continue1150 continue
@@ -1170,7 +1162,7 @@ class EntryManipulatingResource(ReadWriteResource):
1170 errors.append(modified_read_only_attribute % repr_name)1162 errors.append(modified_read_only_attribute % repr_name)
1171 else:1163 else:
1172 errors.append(1164 errors.append(
1173 u"%s: To modify this field you need to send a PUT "1165 "%s: To modify this field you need to send a PUT "
1174 "request to its URI (%s)."1166 "request to its URI (%s)."
1175 % (repr_name, current_value)1167 % (repr_name, current_value)
1176 )1168 )
@@ -1186,7 +1178,7 @@ class EntryManipulatingResource(ReadWriteResource):
1186 # class the way IReference fields can.1178 # class the way IReference fields can.
1187 if value is not None and not field.schema.providedBy(value):1179 if value is not None and not field.schema.providedBy(value):
1188 errors.append(1180 errors.append(
1189 u"%s: Your value points to the "1181 "%s: Your value points to the "
1190 "wrong kind of object" % repr_name1182 "wrong kind of object" % repr_name
1191 )1183 )
1192 continue1184 continue
@@ -1215,22 +1207,20 @@ class EntryManipulatingResource(ReadWriteResource):
1215 # the exception; otherwise use a generic message1207 # the exception; otherwise use a generic message
1216 # instead of whatever object the raise site1208 # instead of whatever object the raise site
1217 # thought would be a good idea.1209 # thought would be a good idea.
1218 if len(e.args) > 0 and isinstance(1210 if len(e.args) > 0 and isinstance(e.args[0], str):
1219 e.args[0], six.string_types
1220 ):
1221 error = e.args[0]1211 error = e.args[0]
1222 else:1212 else:
1223 error = "Constraint not satisfied."1213 error = "Constraint not satisfied."
1224 errors.append(u"%s: %s" % (repr_name, error))1214 errors.append("%s: %s" % (repr_name, error))
1225 continue1215 continue
1226 except RequiredMissing:1216 except RequiredMissing:
1227 error = "Missing required value."1217 error = "Missing required value."
1228 errors.append(u"%s: %s" % (repr_name, error))1218 errors.append("%s: %s" % (repr_name, error))
1229 except (ValueError, ValidationError) as e:1219 except (ValueError, ValidationError) as e:
1230 error = str(e)1220 error = str(e)
1231 if error == "":1221 if error == "":
1232 error = "Validation error"1222 error = "Validation error"
1233 errors.append(u"%s: %s" % (repr_name, error))1223 errors.append("%s: %s" % (repr_name, error))
1234 continue1224 continue
1235 validated_changeset.append((field, value))1225 validated_changeset.append((field, value))
1236 # If there are any fields left in the changeset, they're1226 # If there are any fields left in the changeset, they're
@@ -1238,7 +1228,7 @@ class EntryManipulatingResource(ReadWriteResource):
1238 # schema. They're all errors.1228 # schema. They're all errors.
1239 for invalid_field in changeset.keys():1229 for invalid_field in changeset.keys():
1240 errors.append(1230 errors.append(
1241 u"%s: You tried to modify a nonexistent "1231 "%s: You tried to modify a nonexistent "
1242 "attribute." % invalid_field1232 "attribute." % invalid_field
1243 )1233 )
12441234
@@ -1331,7 +1321,7 @@ class EntryFieldResource(FieldUnmarshallerMixin, EntryManipulatingResource):
13311321
1332 def __init__(self, context, request):1322 def __init__(self, context, request):
1333 """Initialize with respect to a context and request."""1323 """Initialize with respect to a context and request."""
1334 super(EntryFieldResource, self).__init__(context, request)1324 super().__init__(context, request)
1335 self.entry = self.context.entry1325 self.entry = self.context.entry
13361326
1337 def do_GET(self):1327 def do_GET(self):
@@ -1367,7 +1357,7 @@ class EntryFieldResource(FieldUnmarshallerMixin, EntryManipulatingResource):
1367 # generating the representation might itself change across1357 # generating the representation might itself change across
1368 # versions.1358 # versions.
1369 revno = getUtility(IWebServiceConfiguration).code_revision1359 revno = getUtility(IWebServiceConfiguration).code_revision
1370 return [core.encode("utf-8") for core in [revno, six.text_type(value)]]1360 return [core.encode("utf-8") for core in [revno, str(value)]]
13711361
1372 def _representation(self, media_type):1362 def _representation(self, media_type):
1373 """Create a representation of the field value."""1363 """Create a representation of the field value."""
@@ -1454,13 +1444,13 @@ class EntryResource(
14541444
1455 def __init__(self, context, request):1445 def __init__(self, context, request):
1456 """Associate this resource with a specific object and request."""1446 """Associate this resource with a specific object and request."""
1457 super(EntryResource, self).__init__(context, request)1447 super().__init__(context, request)
1458 self.entry = getMultiAdapter((context, request), IEntry)1448 self.entry = getMultiAdapter((context, request), IEntry)
14591449
1460 def handleCustomPOST(self, operation_name):1450 def handleCustomPOST(self, operation_name):
1461 """See `CustomOperationResourceMixin`."""1451 """See `CustomOperationResourceMixin`."""
1462 original_url = absoluteURL(self.entry.context, self.request)1452 original_url = absoluteURL(self.entry.context, self.request)
1463 value = super(EntryResource, self).handleCustomPOST(operation_name)1453 value = super().handleCustomPOST(operation_name)
1464 # We don't know what the custom operation might have done.1454 # We don't know what the custom operation might have done.
1465 # Remove this object from the representation cache, just to be1455 # Remove this object from the representation cache, just to be
1466 # safe.1456 # safe.
@@ -1617,7 +1607,7 @@ class EntryResource(
1617 operation_name = self.request.form.pop("ws.op", None)1607 operation_name = self.request.form.pop("ws.op", None)
1618 if operation_name is not None:1608 if operation_name is not None:
1619 result = self.handleCustomGET(operation_name)1609 result = self.handleCustomGET(operation_name)
1620 if isinstance(result, (bytes, six.text_type)):1610 if isinstance(result, (bytes, str)):
1621 # The custom operation took care of everything and1611 # The custom operation took care of everything and
1622 # just needs this string served to the client.1612 # just needs this string served to the client.
1623 return result1613 return result
@@ -1860,7 +1850,7 @@ class CollectionResource(
18601850
1861 def __init__(self, context, request):1851 def __init__(self, context, request):
1862 """Associate this resource with a specific object and request."""1852 """Associate this resource with a specific object and request."""
1863 super(CollectionResource, self).__init__(context, request)1853 super().__init__(context, request)
1864 if ICollection.providedBy(context):1854 if ICollection.providedBy(context):
1865 self.collection = context1855 self.collection = context
1866 else:1856 else:
@@ -1872,7 +1862,7 @@ class CollectionResource(
1872 operation_name = self.request.form.pop("ws.op", None)1862 operation_name = self.request.form.pop("ws.op", None)
1873 if operation_name is not None:1863 if operation_name is not None:
1874 result = self.handleCustomGET(operation_name)1864 result = self.handleCustomGET(operation_name)
1875 if isinstance(result, (bytes, six.text_type)):1865 if isinstance(result, (bytes, str)):
1876 # The custom operation took care of everything and1866 # The custom operation took care of everything and
1877 # just needs this string served to the client.1867 # just needs this string served to the client.
1878 return result1868 return result
@@ -1905,7 +1895,7 @@ class CollectionResource(
1905 entries = self.collection.find()1895 entries = self.collection.find()
1906 if request is None:1896 if request is None:
1907 request = self.request1897 request = self.request
1908 result = super(CollectionResource, self).batch(entries, request)1898 result = super().batch(entries, request)
1909 result += ', "resource_type_link" : ' + simplejson.dumps(self.type_url)1899 result += ', "resource_type_link" : ' + simplejson.dumps(self.type_url)
1910 return result1900 return result
19111901
diff --git a/src/lazr/restful/debug.py b/src/lazr/restful/debug.py
index 0567455..ebcf526 100644
--- a/src/lazr/restful/debug.py
+++ b/src/lazr/restful/debug.py
@@ -2,9 +2,6 @@
22
3"""Module docstring goes here."""3"""Module docstring goes here."""
44
5from __future__ import absolute_import, print_function
6
7__metaclass__ = type
8__all__ = ["debug_proxy", "typename"]5__all__ = ["debug_proxy", "typename"]
96
107
diff --git a/src/lazr/restful/declarations.py b/src/lazr/restful/declarations.py
index 4c95bcd..f717592 100644
--- a/src/lazr/restful/declarations.py
+++ b/src/lazr/restful/declarations.py
@@ -2,9 +2,6 @@
22
3"""Declaration helpers to define a web service."""3"""Declaration helpers to define a web service."""
44
5from __future__ import absolute_import, print_function
6
7__metaclass__ = type
8__all__ = [5__all__ = [
9 "COLLECTION_TYPE",6 "COLLECTION_TYPE",
10 "ENTRY_TYPE",7 "ENTRY_TYPE",
@@ -1134,9 +1131,7 @@ class export_factory_operation(_export_operation):
11341131
1135 def annotate_method(self, method, annotations):1132 def annotate_method(self, method, annotations):
1136 """See `_method_annotator`."""1133 """See `_method_annotator`."""
1137 super(export_factory_operation, self).annotate_method(1134 super().annotate_method(method, annotations)
1138 method, annotations
1139 )
1140 annotations["creates"] = self.interface1135 annotations["creates"] = self.interface
1141 annotations["params"] = self.params1136 annotations["params"] = self.params
1142 annotations["return_type"] = ObjectLink(schema=self.interface)1137 annotations["return_type"] = ObjectLink(schema=self.interface)
@@ -1147,7 +1142,7 @@ class cache_for(_method_annotator):
11471142
1148 def __init__(self, duration):1143 def __init__(self, duration):
1149 """Specify the duration, in seconds, of the caching resource."""1144 """Specify the duration, in seconds, of the caching resource."""
1150 if not isinstance(duration, six.integer_types):1145 if not isinstance(duration, int):
1151 raise TypeError(1146 raise TypeError(
1152 "Caching duration should be an integer type, not %s"1147 "Caching duration should be an integer type, not %s"
1153 % duration.__class__.__name__1148 % duration.__class__.__name__
@@ -1174,7 +1169,7 @@ class scoped(_method_annotator):
11741169
1175 def __init__(self, *scopes):1170 def __init__(self, *scopes):
1176 for scope in scopes:1171 for scope in scopes:
1177 if not isinstance(scope, six.string_types):1172 if not isinstance(scope, str):
1178 raise TypeError(1173 raise TypeError(
1179 "Scope should be a string type, not %s"1174 "Scope should be a string type, not %s"
1180 % scope.__class__.__name__1175 % scope.__class__.__name__
@@ -1214,9 +1209,7 @@ class export_destructor_operation(_export_operation):
12141209
1215 Every version must have a self-consistent set of annotations.1210 Every version must have a self-consistent set of annotations.
1216 """1211 """
1217 super(export_destructor_operation, self).annotate_method(1212 super().annotate_method(method, annotation_stack)
1218 method, annotation_stack
1219 )
1220 # The mutator method must take no arguments, not counting1213 # The mutator method must take no arguments, not counting
1221 # arguments with values fixed by call_with().1214 # arguments with values fixed by call_with().
1222 for version, annotations in annotation_stack.stack:1215 for version, annotations in annotation_stack.stack:
@@ -1555,14 +1548,14 @@ class _ScopeChecker(Passthrough):
1555 if self.adaptation is not None:1548 if self.adaptation is not None:
1556 context = self.adaptation(context)1549 context = self.adaptation(context)
1557 _check_request(context, None)1550 _check_request(context, None)
1558 return super(_ScopeChecker, self).__get__(inst, cls=cls)1551 return super().__get__(inst, cls=cls)
15591552
1560 def __set__(self, inst, value):1553 def __set__(self, inst, value):
1561 context = getattr(inst, self.contextvar)1554 context = getattr(inst, self.contextvar)
1562 if self.adaptation is not None:1555 if self.adaptation is not None:
1563 context = self.adaptation(context)1556 context = self.adaptation(context)
1564 _check_request(context, None)1557 _check_request(context, None)
1565 return super(_ScopeChecker, self).__set__(inst, value)1558 return super().__set__(inst, value)
15661559
15671560
1568class _AccessorWrapper:1561class _AccessorWrapper:
@@ -1615,7 +1608,7 @@ class PropertyWithAccessor(_AccessorWrapper, _ScopeChecker):
1615 def __init__(1608 def __init__(
1616 self, name, context, accessor, accessor_annotations, adaptation1609 self, name, context, accessor, accessor_annotations, adaptation
1617 ):1610 ):
1618 super(PropertyWithAccessor, self).__init__(name, context, adaptation)1611 super().__init__(name, context, adaptation)
1619 self.accessor = accessor.__name__1612 self.accessor = accessor.__name__
1620 self.accessor_annotations = accessor_annotations1613 self.accessor_annotations = accessor_annotations
16211614
@@ -1626,7 +1619,7 @@ class PropertyWithMutator(_MutatorWrapper, _ScopeChecker):
1626 def __init__(1619 def __init__(
1627 self, name, context, mutator, mutator_annotations, adaptation1620 self, name, context, mutator, mutator_annotations, adaptation
1628 ):1621 ):
1629 super(PropertyWithMutator, self).__init__(name, context, adaptation)1622 super().__init__(name, context, adaptation)
1630 self.mutator = mutator.__name__1623 self.mutator = mutator.__name__
1631 self.mutator_annotations = mutator_annotations1624 self.mutator_annotations = mutator_annotations
16321625
@@ -1646,9 +1639,7 @@ class PropertyWithAccessorAndMutator(
1646 mutator_annotations,1639 mutator_annotations,
1647 adaptation,1640 adaptation,
1648 ):1641 ):
1649 super(PropertyWithAccessorAndMutator, self).__init__(1642 super().__init__(name, context, adaptation)
1650 name, context, adaptation
1651 )
1652 self.accessor = accessor.__name__1643 self.accessor = accessor.__name__
1653 self.accessor_annotations = accessor_annotations1644 self.accessor_annotations = accessor_annotations
1654 self.mutator = mutator.__name__1645 self.mutator = mutator.__name__
@@ -1792,7 +1783,7 @@ class BaseFactoryResourceOperationAdapter(BaseResourceOperationAdapter):
1792 response = self.request.response1783 response = self.request.response
1793 response.setStatus(201)1784 response.setStatus(201)
1794 response.setHeader("Location", absoluteURL(result, self.request))1785 response.setHeader("Location", absoluteURL(result, self.request))
1795 return u""1786 return ""
17961787
17971788
1798def generate_operation_adapter(method, version=None):1789def generate_operation_adapter(method, version=None):
diff --git a/src/lazr/restful/directives/__init__.py b/src/lazr/restful/directives/__init__.py
index 4db78d1..e311f8e 100644
--- a/src/lazr/restful/directives/__init__.py
+++ b/src/lazr/restful/directives/__init__.py
@@ -2,9 +2,6 @@
22
3"""Martian directives used in lazr.restful."""3"""Martian directives used in lazr.restful."""
44
5from __future__ import absolute_import, print_function
6
7__metaclass__ = type
8__all__ = [5__all__ = [
9 "request_class",6 "request_class",
10 "publication_class",7 "publication_class",
diff --git a/src/lazr/restful/docs/conf.py b/src/lazr/restful/docs/conf.py
index bd3dea3..f1c692d 100644
--- a/src/lazr/restful/docs/conf.py
+++ b/src/lazr/restful/docs/conf.py
@@ -1,5 +1,3 @@
1# -*- coding: utf-8 -*-
2#
3# lazr.restful documentation build configuration file, created by1# lazr.restful documentation build configuration file, created by
4# sphinx-quickstart on Sun Nov 3 15:00:52 2019.2# sphinx-quickstart on Sun Nov 3 15:00:52 2019.
5#3#
@@ -47,9 +45,9 @@ source_suffix = ".rst"
47master_doc = "index"45master_doc = "index"
4846
49# General information about the project.47# General information about the project.
50project = u"lazr.restful"48project = "lazr.restful"
51copyright = u"2004-2019, Canonical Ltd."49copyright = "2004-2019, Canonical Ltd."
52author = u"LAZR Developers <lazr-developers@lists.launchpad.net>"50author = "LAZR Developers <lazr-developers@lists.launchpad.net>"
5351
54# The version info for the project you're documenting, acts as replacement for52# The version info for the project you're documenting, acts as replacement for
55# |version| and |release|, also used in various other places throughout the53# |version| and |release|, also used in various other places throughout the
@@ -140,8 +138,8 @@ latex_documents = [
140 (138 (
141 master_doc,139 master_doc,
142 "lazrrestful.tex",140 "lazrrestful.tex",
143 u"lazr.restful Documentation",141 "lazr.restful Documentation",
144 u"LAZR Developers \\textless{}lazr-developers@lists.launchpad.net\\textgreater{}", # noqa: E501142 "LAZR Developers \\textless{}lazr-developers@lists.launchpad.net\\textgreater{}", # noqa: E501
145 "manual",143 "manual",
146 ),144 ),
147]145]
@@ -152,7 +150,7 @@ latex_documents = [
152# One entry per manual page. List of tuples150# One entry per manual page. List of tuples
153# (source start file, name, description, authors, manual section).151# (source start file, name, description, authors, manual section).
154man_pages = [152man_pages = [
155 (master_doc, "lazrrestful", u"lazr.restful Documentation", [author], 1)153 (master_doc, "lazrrestful", "lazr.restful Documentation", [author], 1)
156]154]
157155
158156
@@ -165,7 +163,7 @@ texinfo_documents = [
165 (163 (
166 master_doc,164 master_doc,
167 "lazrrestful",165 "lazrrestful",
168 u"lazr.restful Documentation",166 "lazr.restful Documentation",
169 author,167 author,
170 "lazrrestful",168 "lazrrestful",
171 "One line description of project.",169 "One line description of project.",
diff --git a/src/lazr/restful/error.py b/src/lazr/restful/error.py
index 86cef16..a2cf44b 100644
--- a/src/lazr/restful/error.py
+++ b/src/lazr/restful/error.py
@@ -2,9 +2,6 @@
22
3"""Error handling on the webservice."""3"""Error handling on the webservice."""
44
5from __future__ import absolute_import, division, print_function
6
7__metaclass__ = type
8__all__ = [5__all__ = [
9 "ClientErrorView",6 "ClientErrorView",
10 "expose",7 "expose",
diff --git a/src/lazr/restful/example/base/filemanager.py b/src/lazr/restful/example/base/filemanager.py
index fccb0fc..781bf88 100644
--- a/src/lazr/restful/example/base/filemanager.py
+++ b/src/lazr/restful/example/base/filemanager.py
@@ -2,9 +2,6 @@
22
3"""The file manager for the LAZR example web service."""3"""The file manager for the LAZR example web service."""
44
5from __future__ import absolute_import, print_function
6
7__metaclass__ = type
8__all__ = ["FileManager", "ManagedFileResource"]5__all__ = ["FileManager", "ManagedFileResource"]
96
10import datetime7import datetime
diff --git a/src/lazr/restful/example/base/interfaces.py b/src/lazr/restful/example/base/interfaces.py
index b6d7d85..c315cea 100644
--- a/src/lazr/restful/example/base/interfaces.py
+++ b/src/lazr/restful/example/base/interfaces.py
@@ -3,9 +3,6 @@
33
4"""Interface objects for the LAZR example web service."""4"""Interface objects for the LAZR example web service."""
55
6from __future__ import absolute_import, print_function
7
8__metaclass__ = type
9__all__ = [6__all__ = [
10 "AlreadyNew",7 "AlreadyNew",
11 "Cuisine",8 "Cuisine",
@@ -65,7 +62,7 @@ class WhitespaceStrippingTextLine(TextLine):
65 """Strip whitespace before setting."""62 """Strip whitespace before setting."""
66 if value is not None:63 if value is not None:
67 value = value.strip()64 value = value.strip()
68 super(WhitespaceStrippingTextLine, self).set(object, value)65 super().set(object, value)
6966
7067
71class Cuisine(EnumeratedType):68class Cuisine(EnumeratedType):
@@ -75,7 +72,7 @@ class Cuisine(EnumeratedType):
75 VEGETARIAN = Item("Vegetarian", "Vegetarian cooking")72 VEGETARIAN = Item("Vegetarian", "Vegetarian cooking")
76 AMERICAN = Item("American", "Traditional American cooking")73 AMERICAN = Item("American", "Traditional American cooking")
77 DESSERT = Item("Dessert", "Desserts")74 DESSERT = Item("Dessert", "Desserts")
78 FRANCAISE = Item(u"Fran\xe7aise", u"Cuisine fran\xe7aise")75 FRANCAISE = Item("Fran\xe7aise", "Cuisine fran\xe7aise")
7976
8077
81class IHasGet(Interface):78class IHasGet(Interface):
@@ -89,10 +86,10 @@ class IHasGet(Interface):
89class IDish(ILocation):86class IDish(ILocation):
90 """A dish, annotated for export to the web service."""87 """A dish, annotated for export to the web service."""
9188
92 name = exported(TextLine(title=u"Name", required=True))89 name = exported(TextLine(title="Name", required=True))
93 recipes = exported(90 recipes = exported(
94 CollectionField(91 CollectionField(
95 title=u"Recipes in this cookbook",92 title="Recipes in this cookbook",
96 value_type=Reference(schema=Interface),93 value_type=Reference(schema=Interface),
97 )94 )
98 )95 )
@@ -105,17 +102,17 @@ class IDish(ILocation):
105class IRecipe(ILocation):102class IRecipe(ILocation):
106 """A recipe, annotated for export to the web service."""103 """A recipe, annotated for export to the web service."""
107104
108 id = exported(Int(title=u"Unique ID", required=True))105 id = exported(Int(title="Unique ID", required=True))
109 dish = exported(Reference(title=u"Dish", schema=IDish))106 dish = exported(Reference(title="Dish", schema=IDish))
110 cookbook = exported(Reference(title=u"Cookbook", schema=Interface))107 cookbook = exported(Reference(title="Cookbook", schema=Interface))
111 instructions = exported(108 instructions = exported(
112 Text(title=u"How to prepare the recipe", required=True)109 Text(title="How to prepare the recipe", required=True)
113 )110 )
114 private = exported(111 private = exported(
115 Bool(title=u"Whether the public can see this recipe.", default=False)112 Bool(title="Whether the public can see this recipe.", default=False)
116 )113 )
117 prepared_image = exported(114 prepared_image = exported(
118 Bytes(0, 5000, title=u"An image of the prepared dish.", readonly=True)115 Bytes(0, 5000, title="An image of the prepared dish.", readonly=True)
119 )116 )
120117
121 @export_destructor_operation()118 @export_destructor_operation()
@@ -127,55 +124,53 @@ class IRecipe(ILocation):
127class ICookbook(IHasGet, ILocation):124class ICookbook(IHasGet, ILocation):
128 """A cookbook, annotated for export to the web service."""125 """A cookbook, annotated for export to the web service."""
129126
130 name = exported(TextLine(title=u"Name", required=True))127 name = exported(TextLine(title="Name", required=True))
131 copyright_date = exported(128 copyright_date = exported(
132 Date(129 Date(
133 title=u"Copyright Date",130 title="Copyright Date",
134 description=u"The copyright date for this work.",131 description="The copyright date for this work.",
135 ),132 ),
136 readonly=True,133 readonly=True,
137 )134 )
138 description = exported(135 description = exported(
139 WhitespaceStrippingTextLine(title=u"Description", required=False)136 WhitespaceStrippingTextLine(title="Description", required=False)
140 )137 )
141 revision_number = exported(138 revision_number = exported(
142 Int(139 Int(
143 title=u"A record of the number of times "140 title="A record of the number of times "
144 "this cookbook has been modified."141 "this cookbook has been modified."
145 )142 )
146 )143 )
147 confirmed = exported(144 confirmed = exported(
148 Bool(145 Bool(
149 title=u"Whether this information has been confirmed", default=False146 title="Whether this information has been confirmed", default=False
150 )147 )
151 )148 )
152 cuisine = exported(149 cuisine = exported(
153 Choice(150 Choice(
154 vocabulary=Cuisine, title=u"Cuisine", required=False, default=None151 vocabulary=Cuisine, title="Cuisine", required=False, default=None
155 )152 )
156 )153 )
157 last_printing = exported(154 last_printing = exported(
158 Date(155 Date(
159 title=u"Last printing",156 title="Last printing",
160 description=u"The date of this work's most recent printing.",157 description="The date of this work's most recent printing.",
161 )158 )
162 )159 )
163 # Don't try this at home! Float is a bad choice for a 'price'160 # Don't try this at home! Float is a bad choice for a 'price'
164 # field because it's imprecise. Decimal is a better choice. But161 # field because it's imprecise. Decimal is a better choice. But
165 # this is just an example and we need a Float field, so...162 # this is just an example and we need a Float field, so...
166 price = exported(Float(title=u"Retail price of the cookbook"))163 price = exported(Float(title="Retail price of the cookbook"))
167 recipes = exported(164 recipes = exported(
168 CollectionField(165 CollectionField(
169 title=u"Recipes in this cookbook",166 title="Recipes in this cookbook",
170 value_type=Reference(schema=IRecipe),167 value_type=Reference(schema=IRecipe),
171 )168 )
172 )169 )
173 cover = exported(170 cover = exported(Bytes(0, 5000, title="An image of the cookbook's cover."))
174 Bytes(0, 5000, title=u"An image of the cookbook's cover.")
175 )
176171
177 @operation_parameters(172 @operation_parameters(
178 search=TextLine(title=u"String to search for in recipe name.")173 search=TextLine(title="String to search for in recipe name.")
179 )174 )
180 @operation_returns_collection_of(IRecipe)175 @operation_returns_collection_of(IRecipe)
181 @export_read_operation()176 @export_read_operation()
@@ -183,7 +178,7 @@ class ICookbook(IHasGet, ILocation):
183 """Search for recipes in this cookbook."""178 """Search for recipes in this cookbook."""
184179
185 @operation_parameters(180 @operation_parameters(
186 dish=Reference(title=u"Dish to search for.", schema=IDish)181 dish=Reference(title="Dish to search for.", schema=IDish)
187 )182 )
188 @operation_returns_entry(IRecipe)183 @operation_returns_entry(IRecipe)
189 @export_read_operation()184 @export_read_operation()
@@ -197,7 +192,7 @@ class ICookbook(IHasGet, ILocation):
197 def removeRecipe(recipe):192 def removeRecipe(recipe):
198 """Remove one of this cookbook's recipes."""193 """Remove one of this cookbook's recipes."""
199194
200 @operation_parameters(cover=Bytes(title=u"New cover"))195 @operation_parameters(cover=Bytes(title="New cover"))
201 @export_write_operation()196 @export_write_operation()
202 def replace_cover(cover):197 def replace_cover(cover):
203 """Replace the cookbook's cover."""198 """Replace the cookbook's cover."""
@@ -231,9 +226,9 @@ class ICookbookSet(IHasGet):
231 """Return the list of cookbooks."""226 """Return the list of cookbooks."""
232227
233 @operation_parameters(228 @operation_parameters(
234 search=TextLine(title=u"String to search for in recipe name."),229 search=TextLine(title="String to search for in recipe name."),
235 vegetarian=Bool(230 vegetarian=Bool(
236 title=u"Whether or not to limit the search to "231 title="Whether or not to limit the search to "
237 "vegetarian cookbooks.",232 "vegetarian cookbooks.",
238 default=False,233 default=False,
239 ),234 ),
@@ -245,7 +240,7 @@ class ICookbookSet(IHasGet):
245240
246 @operation_parameters(241 @operation_parameters(
247 cuisine=Choice(242 cuisine=Choice(
248 vocabulary=Cuisine, title=u"Cuisine to search for in recipe name."243 vocabulary=Cuisine, title="Cuisine to search for in recipe name."
249 )244 )
250 )245 )
251 @operation_returns_collection_of(ICookbook)246 @operation_returns_collection_of(ICookbook)
diff --git a/src/lazr/restful/example/base/root.py b/src/lazr/restful/example/base/root.py
index 424c971..85771b7 100644
--- a/src/lazr/restful/example/base/root.py
+++ b/src/lazr/restful/example/base/root.py
@@ -2,9 +2,6 @@
22
3"""Data model objects for the LAZR example web service."""3"""Data model objects for the LAZR example web service."""
44
5from __future__ import absolute_import, print_function
6
7__metaclass__ = type
8__all__ = [5__all__ = [
9 "Cookbook",6 "Cookbook",
10 "CookbookServiceRootResource",7 "CookbookServiceRootResource",
@@ -382,22 +379,22 @@ def year(year):
382379
383380
384C1 = Cookbook(381C1 = Cookbook(
385 u"Mastering the Art of French Cooking", "", Cuisine.FRANCAISE, year(1961)382 "Mastering the Art of French Cooking", "", Cuisine.FRANCAISE, year(1961)
386)383)
387C2 = Cookbook(u"The Joy of Cooking", "", Cuisine.GENERAL, year(1995), price=20)384C2 = Cookbook("The Joy of Cooking", "", Cuisine.GENERAL, year(1995), price=20)
388C3 = Cookbook(385C3 = Cookbook(
389 u"James Beard's American Cookery", "", Cuisine.AMERICAN, year(1972)386 "James Beard's American Cookery", "", Cuisine.AMERICAN, year(1972)
390)387)
391C4 = Cookbook(u"Everyday Greens", "", Cuisine.VEGETARIAN, year(2003))388C4 = Cookbook("Everyday Greens", "", Cuisine.VEGETARIAN, year(2003))
392C5 = Cookbook(u"I'm Just Here For The Food", "", Cuisine.GENERAL, year(2002))389C5 = Cookbook("I'm Just Here For The Food", "", Cuisine.GENERAL, year(2002))
393C6 = Cookbook(u"Cooking Without Recipes", "", Cuisine.GENERAL, year(1959))390C6 = Cookbook("Cooking Without Recipes", "", Cuisine.GENERAL, year(1959))
394C7 = Cookbook(u"Construsions un repas", "", Cuisine.FRANCAISE, year(2007))391C7 = Cookbook("Construsions un repas", "", Cuisine.FRANCAISE, year(2007))
395COOKBOOKS = [C1, C2, C3, C4, C5, C6, C7]392COOKBOOKS = [C1, C2, C3, C4, C5, C6, C7]
396393
397D1 = Dish("Roast chicken")394D1 = Dish("Roast chicken")
398C1_D1 = Recipe(1, C1, D1, u"You can always judge...")395C1_D1 = Recipe(1, C1, D1, "You can always judge...")
399C2_D1 = Recipe(2, C2, D1, u"Draw, singe, stuff, and truss...")396C2_D1 = Recipe(2, C2, D1, "Draw, singe, stuff, and truss...")
400C3_D1 = Recipe(3, C3, D1, u"A perfectly roasted chicken is...")397C3_D1 = Recipe(3, C3, D1, "A perfectly roasted chicken is...")
401398
402D2 = Dish("Baked beans")399D2 = Dish("Baked beans")
403C2_D2 = Recipe(4, C2, D2, "Preheat oven to...")400C2_D2 = Recipe(4, C2, D2, "Preheat oven to...")
diff --git a/src/lazr/restful/example/base/security.py b/src/lazr/restful/example/base/security.py
index bbb5165..0f33cb0 100644
--- a/src/lazr/restful/example/base/security.py
+++ b/src/lazr/restful/example/base/security.py
@@ -2,9 +2,6 @@
22
3"""A simple security policy for the LAZR example web service."""3"""A simple security policy for the LAZR example web service."""
44
5from __future__ import absolute_import, print_function
6
7__metaclass__ = type
8__all__ = [5__all__ = [
9 "CookbookWebServiceSecurityPolicy",6 "CookbookWebServiceSecurityPolicy",
10]7]
diff --git a/src/lazr/restful/example/base/subscribers.py b/src/lazr/restful/example/base/subscribers.py
index 68ff062..fa6f973 100644
--- a/src/lazr/restful/example/base/subscribers.py
+++ b/src/lazr/restful/example/base/subscribers.py
@@ -2,9 +2,6 @@
22
3"""Event listeners for the example web service."""3"""Event listeners for the example web service."""
44
5from __future__ import absolute_import, print_function
6
7__metaclass__ = type
8__all__ = ["update_cookbook_revision_number"]5__all__ = ["update_cookbook_revision_number"]
96
10import grokcore.component7import grokcore.component
diff --git a/src/lazr/restful/example/base/tests/test_integration.py b/src/lazr/restful/example/base/tests/test_integration.py
index 99b987f..f0bbbb1 100644
--- a/src/lazr/restful/example/base/tests/test_integration.py
+++ b/src/lazr/restful/example/base/tests/test_integration.py
@@ -2,9 +2,6 @@
22
3"""Test harness for LAZR doctests."""3"""Test harness for LAZR doctests."""
44
5from __future__ import absolute_import, print_function
6
7__metaclass__ = type
8__all__ = []5__all__ = []
96
10import os7import os
@@ -58,16 +55,11 @@ def load_tests(loader, tests, pattern):
58 for name in os.listdir(os.path.dirname(__file__))55 for name in os.listdir(os.path.dirname(__file__))
59 if name.endswith(".txt")56 if name.endswith(".txt")
60 )57 )
61 globs = {
62 "absolute_import": absolute_import,
63 "print_function": print_function,
64 }
65 suite = doctest.DocFileSuite(58 suite = doctest.DocFileSuite(
66 *doctest_files,59 *doctest_files,
67 optionflags=DOCTEST_FLAGS,60 optionflags=DOCTEST_FLAGS,
68 globs=globs,
69 encoding="UTF-8",61 encoding="UTF-8",
70 checker=checker62 checker=checker,
71 )63 )
72 suite.layer = WSGILayer64 suite.layer = WSGILayer
73 tests.addTest(suite)65 tests.addTest(suite)
diff --git a/src/lazr/restful/example/base/traversal.py b/src/lazr/restful/example/base/traversal.py
index 4b06202..4ae07a9 100644
--- a/src/lazr/restful/example/base/traversal.py
+++ b/src/lazr/restful/example/base/traversal.py
@@ -2,9 +2,6 @@
22
3"""Traversal rules for the LAZR example web service."""3"""Traversal rules for the LAZR example web service."""
44
5from __future__ import absolute_import, print_function
6
7__metaclass__ = type
8__all__ = [5__all__ = [
9 "BelowRootAbsoluteURL",6 "BelowRootAbsoluteURL",
10 "CookbookSetTraverse",7 "CookbookSetTraverse",
@@ -99,6 +96,4 @@ class CookbookSetTraverse(TraverseWithGet):
99 url = absoluteURL(self.context.featured, request) + "{invalid}"96 url = absoluteURL(self.context.featured, request) + "{invalid}"
100 return RedirectResource(url, request)97 return RedirectResource(url, request)
101 else:98 else:
102 return super(CookbookSetTraverse, self).publishTraverse(99 return super().publishTraverse(request, name)
103 request, name
104 )
diff --git a/src/lazr/restful/example/base_extended/comments.py b/src/lazr/restful/example/base_extended/comments.py
index 8db2763..5973204 100644
--- a/src/lazr/restful/example/base_extended/comments.py
+++ b/src/lazr/restful/example/base_extended/comments.py
@@ -1,5 +1,3 @@
1from __future__ import absolute_import, print_function
2
3from zope.component import adapter1from zope.component import adapter
4from zope.interface import implementer, Interface2from zope.interface import implementer, Interface
5from zope.schema import List, Text3from zope.schema import List, Text
@@ -15,7 +13,7 @@ from lazr.restful.declarations import (
15@exported_as_webservice_entry(contributes_to=[IRecipe])13@exported_as_webservice_entry(contributes_to=[IRecipe])
16class IHasComments(Interface):14class IHasComments(Interface):
17 comments = exported(15 comments = exported(
18 List(title=u"Comments made by users", value_type=Text())16 List(title="Comments made by users", value_type=Text())
19 )17 )
2018
2119
diff --git a/src/lazr/restful/example/base_extended/tests/test_integration.py b/src/lazr/restful/example/base_extended/tests/test_integration.py
index e5b0021..866c905 100644
--- a/src/lazr/restful/example/base_extended/tests/test_integration.py
+++ b/src/lazr/restful/example/base_extended/tests/test_integration.py
@@ -2,9 +2,6 @@
22
3"""Test harness for LAZR doctests."""3"""Test harness for LAZR doctests."""
44
5from __future__ import absolute_import, print_function
6
7__metaclass__ = type
8__all__ = []5__all__ = []
96
10import os7import os
@@ -46,12 +43,8 @@ wsgi_intercept_layer(WSGILayer)
46def load_tests(loader, tests, pattern):43def load_tests(loader, tests, pattern):
47 """See `zope.testing.testrunner`."""44 """See `zope.testing.testrunner`."""
48 doctest_files = ["../README.txt"]45 doctest_files = ["../README.txt"]
49 globs = {
50 "absolute_import": absolute_import,
51 "print_function": print_function,
52 }
53 suite = doctest.DocFileSuite(46 suite = doctest.DocFileSuite(
54 *doctest_files, optionflags=DOCTEST_FLAGS, globs=globs, checker=checker47 *doctest_files, optionflags=DOCTEST_FLAGS, checker=checker
55 )48 )
56 suite.layer = WSGILayer49 suite.layer = WSGILayer
57 tests.addTest(suite)50 tests.addTest(suite)
diff --git a/src/lazr/restful/example/multiversion/resources.py b/src/lazr/restful/example/multiversion/resources.py
index 849d579..cf45690 100644
--- a/src/lazr/restful/example/multiversion/resources.py
+++ b/src/lazr/restful/example/multiversion/resources.py
@@ -1,7 +1,3 @@
1from __future__ import absolute_import, print_function
2
3__metaclass__ = type
4
5__all__ = ["IKeyValuePair", "IPairSet", "KeyValuePair", "PairSet"]1__all__ = ["IKeyValuePair", "IPairSet", "KeyValuePair", "PairSet"]
62
7from zope.interface import implementer3from zope.interface import implementer
@@ -36,14 +32,14 @@ from lazr.restful.example.wsgi.resources import (
36# define them separately.32# define them separately.
37@exported_as_webservice_entry()33@exported_as_webservice_entry()
38class IKeyValuePair(ILocation):34class IKeyValuePair(ILocation):
39 key = exported(Text(title=u"The key"))35 key = exported(Text(title="The key"))
40 value = exported(Text(title=u"The value"))36 value = exported(Text(title="The value"))
41 a_comment = exported(37 a_comment = exported(
42 Text(title=u"A comment on this key-value pair.", readonly=True),38 Text(title="A comment on this key-value pair.", readonly=True),
43 ("1.0", dict(exported=True, exported_as="comment")),39 ("1.0", dict(exported=True, exported_as="comment")),
44 )40 )
45 deleted = exported(41 deleted = exported(
46 Bool(title=u"Whether this key-value pair has been " "deleted"),42 Bool(title="Whether this key-value pair has been " "deleted"),
47 ("3.0", dict(exported=True)),43 ("3.0", dict(exported=True)),
48 exported=False,44 exported=False,
49 )45 )
@@ -117,7 +113,7 @@ class PairSet(BasicPairSet):
117@implementer(IKeyValuePair)113@implementer(IKeyValuePair)
118class KeyValuePair(BasicKeyValuePair):114class KeyValuePair(BasicKeyValuePair):
119 def __init__(self, pairset, key, value):115 def __init__(self, pairset, key, value):
120 super(KeyValuePair, self).__init__(pairset, key, value)116 super().__init__(pairset, key, value)
121 self.a_comment = ""117 self.a_comment = ""
122 self.deleted = False118 self.deleted = False
123119
diff --git a/src/lazr/restful/example/multiversion/root.py b/src/lazr/restful/example/multiversion/root.py
index 2391d4b..c611cda 100644
--- a/src/lazr/restful/example/multiversion/root.py
+++ b/src/lazr/restful/example/multiversion/root.py
@@ -1,8 +1,5 @@
1"""The RESTful service root."""1"""The RESTful service root."""
22
3from __future__ import absolute_import, print_function
4
5__metaclass__ = type
6__all__ = [3__all__ = [
7 "BelowRootAbsoluteURL",4 "BelowRootAbsoluteURL",
8 "RootAbsoluteURL",5 "RootAbsoluteURL",
diff --git a/src/lazr/restful/example/multiversion/tests/test_integration.py b/src/lazr/restful/example/multiversion/tests/test_integration.py
index 92772a4..ee04982 100644
--- a/src/lazr/restful/example/multiversion/tests/test_integration.py
+++ b/src/lazr/restful/example/multiversion/tests/test_integration.py
@@ -2,9 +2,6 @@
22
3"""Test harness for doctests for lazr.restful multiversion example service."""3"""Test harness for doctests for lazr.restful multiversion example service."""
44
5from __future__ import absolute_import, print_function
6
7__metaclass__ = type
8__all__ = []5__all__ = []
96
10import os7import os
@@ -59,12 +56,8 @@ def load_tests(loader, tests, pattern):
59 for name in os.listdir(os.path.dirname(__file__))56 for name in os.listdir(os.path.dirname(__file__))
60 if name.endswith(".txt")57 if name.endswith(".txt")
61 )58 )
62 globs = {
63 "absolute_import": absolute_import,
64 "print_function": print_function,
65 }
66 suite = doctest.DocFileSuite(59 suite = doctest.DocFileSuite(
67 *doctest_files, optionflags=DOCTEST_FLAGS, globs=globs, checker=checker60 *doctest_files, optionflags=DOCTEST_FLAGS, checker=checker
68 )61 )
69 suite.layer = WSGILayer62 suite.layer = WSGILayer
70 tests.addTest(suite)63 tests.addTest(suite)
diff --git a/src/lazr/restful/example/wsgi/resources.py b/src/lazr/restful/example/wsgi/resources.py
index ad42f66..1ae11fc 100644
--- a/src/lazr/restful/example/wsgi/resources.py
+++ b/src/lazr/restful/example/wsgi/resources.py
@@ -1,7 +1,3 @@
1from __future__ import absolute_import, print_function
2
3__metaclass__ = type
4
5__all__ = ["IKeyValuePair", "IPairSet", "KeyValuePair", "PairSet"]1__all__ = ["IKeyValuePair", "IPairSet", "KeyValuePair", "PairSet"]
62
7from zope.component import getUtility3from zope.component import getUtility
@@ -21,8 +17,8 @@ from lazr.restful.simple import TraverseWithGet
2117
22@exported_as_webservice_entry()18@exported_as_webservice_entry()
23class IKeyValuePair(ILocation):19class IKeyValuePair(ILocation):
24 key = exported(Text(title=u"The key"))20 key = exported(Text(title="The key"))
25 value = exported(Text(title=u"The value"))21 value = exported(Text(title="The value"))
2622
2723
28@exported_as_webservice_collection(IKeyValuePair)24@exported_as_webservice_collection(IKeyValuePair)
@@ -36,7 +32,7 @@ class IPairSet(ILocation):
3632
3733
38@implementer(IKeyValuePair, ILocation)34@implementer(IKeyValuePair, ILocation)
39class KeyValuePair(object):35class KeyValuePair:
40 """An object representing a key-value pair"""36 """An object representing a key-value pair"""
4137
42 def __init__(self, set, key, value):38 def __init__(self, set, key, value):
diff --git a/src/lazr/restful/example/wsgi/root.py b/src/lazr/restful/example/wsgi/root.py
index efd246d..a870d0b 100644
--- a/src/lazr/restful/example/wsgi/root.py
+++ b/src/lazr/restful/example/wsgi/root.py
@@ -1,8 +1,5 @@
1"""The RESTful service root."""1"""The RESTful service root."""
22
3from __future__ import absolute_import, print_function
4
5__metaclass__ = type
6__all__ = [3__all__ = [
7 "BelowRootAbsoluteURL",4 "BelowRootAbsoluteURL",
8 "RootAbsoluteURL",5 "RootAbsoluteURL",
diff --git a/src/lazr/restful/example/wsgi/run.py b/src/lazr/restful/example/wsgi/run.py
index b49b188..ff0dedc 100644
--- a/src/lazr/restful/example/wsgi/run.py
+++ b/src/lazr/restful/example/wsgi/run.py
@@ -1,7 +1,5 @@
1#!/usr/bin/python1#!/usr/bin/python
22
3from __future__ import absolute_import, print_function
4
5from lazr.restful.wsgi import WSGIApplication3from lazr.restful.wsgi import WSGIApplication
64
7if __name__ == "__main__":5if __name__ == "__main__":
diff --git a/src/lazr/restful/example/wsgi/tests/test_integration.py b/src/lazr/restful/example/wsgi/tests/test_integration.py
index f8f5583..cc02ba7 100644
--- a/src/lazr/restful/example/wsgi/tests/test_integration.py
+++ b/src/lazr/restful/example/wsgi/tests/test_integration.py
@@ -2,9 +2,6 @@
22
3"""Test harness for doctests for lazr.restful example WSGI service."""3"""Test harness for doctests for lazr.restful example WSGI service."""
44
5from __future__ import absolute_import, print_function
6
7__metaclass__ = type
8__all__ = []5__all__ = []
96
10import os7import os
@@ -57,12 +54,8 @@ def load_tests(loader, tests, pattern):
57 for name in os.listdir(os.path.dirname(__file__))54 for name in os.listdir(os.path.dirname(__file__))
58 if name.endswith(".txt")55 if name.endswith(".txt")
59 )56 )
60 globs = {
61 "absolute_import": absolute_import,
62 "print_function": print_function,
63 }
64 suite = doctest.DocFileSuite(57 suite = doctest.DocFileSuite(
65 *doctest_files, optionflags=DOCTEST_FLAGS, globs=globs, checker=checker58 *doctest_files, optionflags=DOCTEST_FLAGS, checker=checker
66 )59 )
67 suite.layer = WSGILayer60 suite.layer = WSGILayer
68 tests.addTest(suite)61 tests.addTest(suite)
diff --git a/src/lazr/restful/fields.py b/src/lazr/restful/fields.py
index a9e9756..4699769 100644
--- a/src/lazr/restful/fields.py
+++ b/src/lazr/restful/fields.py
@@ -2,9 +2,6 @@
22
3"""LAZR zope.schema.IField implementation."""3"""LAZR zope.schema.IField implementation."""
44
5from __future__ import absolute_import, print_function
6
7__metaclass__ = type
8__all__ = [5__all__ = [
9 "CollectionField",6 "CollectionField",
10 "Reference",7 "Reference",
@@ -39,7 +36,7 @@ class CollectionField(AbstractCollection):
39 are managed through a dedicated API.36 are managed through a dedicated API.
40 """37 """
41 kwargs.setdefault("readonly", True)38 kwargs.setdefault("readonly", True)
42 super(CollectionField, self).__init__(*args, **kwargs)39 super().__init__(*args, **kwargs)
4340
4441
45@implementer(IReference)42@implementer(IReference)
@@ -75,4 +72,4 @@ class ReferenceChoice(Choice):
75 """72 """
76 schema = kwargs.pop("schema", IObject)73 schema = kwargs.pop("schema", IObject)
77 self.schema = schema74 self.schema = schema
78 super(ReferenceChoice, self).__init__(*args, **kwargs)75 super().__init__(*args, **kwargs)
diff --git a/src/lazr/restful/frameworks/django.py b/src/lazr/restful/frameworks/django.py
index a1d09c2..a7ae447 100644
--- a/src/lazr/restful/frameworks/django.py
+++ b/src/lazr/restful/frameworks/django.py
@@ -2,7 +2,6 @@
22
3"""Helpers for publishing Django model objects in lazr.restful services."""3"""Helpers for publishing Django model objects in lazr.restful services."""
44
5__metaclass__ = type
6__all__ = [5__all__ = [
7 "DjangoLocation",6 "DjangoLocation",
8 "DjangoWebServiceConfiguration",7 "DjangoWebServiceConfiguration",
@@ -102,7 +101,7 @@ class DjangoAbsoluteURL(AbsoluteURL):
102101
103102
104@implementer(ILocation)103@implementer(ILocation)
105class DjangoLocation(object):104class DjangoLocation:
106 """Adapts Django model objects to ILocation.105 """Adapts Django model objects to ILocation.
107106
108 See `IDjangoLocation` for why Django model objects can't implement107 See `IDjangoLocation` for why Django model objects can't implement
@@ -125,7 +124,7 @@ grokcore.component.global_adapter(DjangoLocation, IDjangoLocation, ILocation)
125124
126125
127@implementer(IFiniteSequence)126@implementer(IFiniteSequence)
128class ManagerSequencer(object):127class ManagerSequencer:
129 """Makes a Django manager object usable with lazr.batchnavigator.128 """Makes a Django manager object usable with lazr.batchnavigator.
130129
131 IFiniteSequence requires that we implement __len__, and either130 IFiniteSequence requires that we implement __len__, and either
diff --git a/src/lazr/restful/interface.py b/src/lazr/restful/interface.py
index a69cf98..e63dcf1 100644
--- a/src/lazr/restful/interface.py
+++ b/src/lazr/restful/interface.py
@@ -2,9 +2,6 @@
22
3"""Helpers for working with Zope interface."""3"""Helpers for working with Zope interface."""
44
5from __future__ import absolute_import, print_function
6
7__metaclass__ = type
8__all__ = ["copy_attribute", "copy_field", "use_template"]5__all__ = ["copy_attribute", "copy_field", "use_template"]
96
10import sys7import sys
diff --git a/src/lazr/restful/interfaces/__init__.py b/src/lazr/restful/interfaces/__init__.py
index b0d1c27..8c7ea66 100644
--- a/src/lazr/restful/interfaces/__init__.py
+++ b/src/lazr/restful/interfaces/__init__.py
@@ -17,8 +17,6 @@
1717
18# pylint: disable-msg=W040118# pylint: disable-msg=W0401
1919
20from __future__ import absolute_import, print_function
21
22__version__ = 1.020__version__ = 1.0
2321
24# Re-export in such a way that __version__ can still be imported if22# Re-export in such a way that __version__ can still be imported if
diff --git a/src/lazr/restful/interfaces/_fields.py b/src/lazr/restful/interfaces/_fields.py
index d48a87d..36a15c1 100644
--- a/src/lazr/restful/interfaces/_fields.py
+++ b/src/lazr/restful/interfaces/_fields.py
@@ -16,9 +16,6 @@
1616
17"""Interfaces for LAZR zope.schema fields."""17"""Interfaces for LAZR zope.schema fields."""
1818
19from __future__ import absolute_import, print_function
20
21__metaclass__ = type
22__all__ = [19__all__ = [
23 "ICollectionField",20 "ICollectionField",
24 "IReference",21 "IReference",
diff --git a/src/lazr/restful/interfaces/_rest.py b/src/lazr/restful/interfaces/_rest.py
index 9632dc6..8b92c74 100644
--- a/src/lazr/restful/interfaces/_rest.py
+++ b/src/lazr/restful/interfaces/_rest.py
@@ -18,9 +18,6 @@
18# Pylint doesn't grok zope interfaces.18# Pylint doesn't grok zope interfaces.
19# pylint: disable-msg=E0211,E021319# pylint: disable-msg=E0211,E0213
2020
21from __future__ import absolute_import, print_function
22
23__metaclass__ = type
24__all__ = [21__all__ = [
25 "IByteStorage",22 "IByteStorage",
26 "IByteStorageResource",23 "IByteStorageResource",
@@ -479,8 +476,8 @@ class IWebServiceConfiguration(Interface):
479 caching_policy = List(476 caching_policy = List(
480 value_type=Int(),477 value_type=Int(),
481 default=[7 * 24 * HOUR, 1 * HOUR],478 default=[7 * 24 * HOUR, 1 * HOUR],
482 title=u"The web service caching policy.",479 title="The web service caching policy.",
483 description=u"""A list of two numbers, each to be used in the480 description="""A list of two numbers, each to be used in the
484 'max-age' field of the Cache-Control header. The first number is481 'max-age' field of the Cache-Control header. The first number is
485 used when serving the service root for any web service version482 used when serving the service root for any web service version
486 except the latest one. The second number is used when serving the483 except the latest one. The second number is used when serving the
@@ -489,32 +486,32 @@ class IWebServiceConfiguration(Interface):
489 )486 )
490487
491 enable_server_side_representation_cache = Bool(488 enable_server_side_representation_cache = Bool(
492 title=u"Enable the server-side representation cache.",489 title="Enable the server-side representation cache.",
493 default=True,490 default=True,
494 description=u"""If this is false, the server-side representation491 description="""If this is false, the server-side representation
495 cache will not be used, even if one is registered.""",492 cache will not be used, even if one is registered.""",
496 )493 )
497494
498 service_description = TextLine(495 service_description = TextLine(
499 title=u"Service description",496 title="Service description",
500 description=u"""A human-readable description of the web service.497 description="""A human-readable description of the web service.
501498
502 The description may contain HTML, but if it does, it must be a499 The description may contain HTML, but if it does, it must be a
503 valid XHTML fragment.500 valid XHTML fragment.
504 """,501 """,
505 default=u"",502 default="",
506 )503 )
507504
508 view_permission = TextLine(505 view_permission = TextLine(
509 title=u"View permission",506 title="View permission",
510 default=u"zope.View",507 default="zope.View",
511 description=u"The permission to use when checking object visibility.",508 description="The permission to use when checking object visibility.",
512 )509 )
513510
514 path_override = TextLine(511 path_override = TextLine(
515 title=u"Web service path override",512 title="Web service path override",
516 default=u"api",513 default="api",
517 description=u"The path component for Ajax clients to use when making "514 description="The path component for Ajax clients to use when making "
518 "HTTP requests to the web service from their current virtual host. "515 "HTTP requests to the web service from their current virtual host. "
519 "The use of this path component (/api/foo instead of /foo) will "516 "The use of this path component (/api/foo instead of /foo) will "
520 "ensure that the request is processed as a web service request "517 "ensure that the request is processed as a web service request "
@@ -522,29 +519,29 @@ class IWebServiceConfiguration(Interface):
522 )519 )
523520
524 use_https = Bool(521 use_https = Bool(
525 title=u"Web service is secured",522 title="Web service is secured",
526 default=True,523 default=True,
527 description=u"Whether or not requests to the web service are secured "524 description="Whether or not requests to the web service are secured "
528 "through SSL.",525 "through SSL.",
529 )526 )
530527
531 hostname = TextLine(528 hostname = TextLine(
532 title=u"The hostname to be used in generated URLs.",529 title="The hostname to be used in generated URLs.",
533 description=u"You only need to specify this if you're using the "530 description="You only need to specify this if you're using the "
534 "RootResourceAbsoluteURL class from lazr.restful.simple. This is "531 "RootResourceAbsoluteURL class from lazr.restful.simple. This is "
535 "the hostname of the lazr.restful application.",532 "the hostname of the lazr.restful application.",
536 )533 )
537534
538 port = Int(535 port = Int(
539 title=u"The TCP port on which the web service is running.",536 title="The TCP port on which the web service is running.",
540 description=u"Used in generated URLs.",537 description="Used in generated URLs.",
541 default=0,538 default=0,
542 )539 )
543540
544 service_root_uri_prefix = TextLine(541 service_root_uri_prefix = TextLine(
545 title=u"Any URL prefix necessary for the service root.",542 title="Any URL prefix necessary for the service root.",
546 default=u"",543 default="",
547 description=u"If your web service is not located at the root of "544 description="If your web service is not located at the root of "
548 "its domain (for instance, it's rooted at "545 "its domain (for instance, it's rooted at "
549 "http://foo.com/web-service/ instead of http://api.foo/com/, "546 "http://foo.com/web-service/ instead of http://api.foo/com/, "
550 "put the URL prefix here. (In the example case, the URL prefix "547 "put the URL prefix here. (In the example case, the URL prefix "
@@ -554,8 +551,8 @@ class IWebServiceConfiguration(Interface):
554 active_versions = List(551 active_versions = List(
555 value_type=TextLine(),552 value_type=TextLine(),
556 default=[],553 default=[],
557 title=u"The active versions of the web service.",554 title="The active versions of the web service.",
558 description=u"""A list of names of active versions of this555 description="""A list of names of active versions of this
559 web service. They might be version numbers, names such as556 web service. They might be version numbers, names such as
560 "beta", or the date a particular version was finalized.557 "beta", or the date a particular version was finalized.
561558
@@ -571,8 +568,8 @@ class IWebServiceConfiguration(Interface):
571 version_descriptions = Dict(568 version_descriptions = Dict(
572 key_type=TextLine(),569 key_type=TextLine(),
573 value_type=Text(),570 value_type=Text(),
574 title=u"Human-readable descriptions of the web service versions.",571 title="Human-readable descriptions of the web service versions.",
575 description=u"""A dictionary mapping version names to572 description="""A dictionary mapping version names to
576 human-readable descriptions. The descriptions should describe573 human-readable descriptions. The descriptions should describe
577 what distinguishes this version from other versions, and574 what distinguishes this version from other versions, and
578 mention if/when the version will be removed.575 mention if/when the version will be removed.
@@ -585,7 +582,7 @@ class IWebServiceConfiguration(Interface):
585582
586 require_explicit_versions = Bool(583 require_explicit_versions = Bool(
587 default=False,584 default=False,
588 description=u"""If true, each exported field and named585 description="""If true, each exported field and named
589 operation must explicitly declare the first version in which586 operation must explicitly declare the first version in which
590 it appears. If false, fields and operations are published in587 it appears. If false, fields and operations are published in
591 all versions.""",588 all versions.""",
@@ -593,7 +590,7 @@ class IWebServiceConfiguration(Interface):
593590
594 last_version_with_mutator_named_operations = TextLine(591 last_version_with_mutator_named_operations = TextLine(
595 default=None,592 default=None,
596 description=u"""In earlier versions of lazr.restful, mutator methods593 description="""In earlier versions of lazr.restful, mutator methods
597 were also published as named operations. This redundant594 were also published as named operations. This redundant
598 behavior is no longer enabled by default, but this setting595 behavior is no longer enabled by default, but this setting
599 allows for backwards compatibility.596 allows for backwards compatibility.
@@ -606,48 +603,48 @@ class IWebServiceConfiguration(Interface):
606603
607 first_version_with_total_size_link = TextLine(604 first_version_with_total_size_link = TextLine(
608 default=None,605 default=None,
609 description=u"""In earlier versions of lazr.restful collections606 description="""In earlier versions of lazr.restful collections
610 included a total_size field, now they include a total_size_link607 included a total_size field, now they include a total_size_link
611 instead. Setting this value determines in which version the new608 instead. Setting this value determines in which version the new
612 behavior takes effect.""",609 behavior takes effect.""",
613 )610 )
614611
615 code_revision = TextLine(612 code_revision = TextLine(
616 default=u"",613 default="",
617 description=u"""A string designating the current revision614 description="""A string designating the current revision
618 number of the code running the webservice. This may be a615 number of the code running the webservice. This may be a
619 revision number from version control, or a hand-chosen version616 revision number from version control, or a hand-chosen version
620 number.""",617 number.""",
621 )618 )
622619
623 show_tracebacks = Bool(620 show_tracebacks = Bool(
624 title=u"Show tracebacks to end-users",621 title="Show tracebacks to end-users",
625 default=True,622 default=True,
626 description=u"Whether or not to show tracebacks in an HTTP response "623 description="Whether or not to show tracebacks in an HTTP response "
627 "for a request that raised an exception.",624 "for a request that raised an exception.",
628 )625 )
629626
630 default_batch_size = Int(627 default_batch_size = Int(
631 title=u"The default batch size to use when serving a collection",628 title="The default batch size to use when serving a collection",
632 default=50,629 default=50,
633 description=u"When the client requests a collection and doesn't "630 description="When the client requests a collection and doesn't "
634 "specify how many entries they want, this many entries will be "631 "specify how many entries they want, this many entries will be "
635 "served them in the first page.",632 "served them in the first page.",
636 )633 )
637634
638 max_batch_size = Int(635 max_batch_size = Int(
639 title=u"The maximum batch size",636 title="The maximum batch size",
640 default=300,637 default=300,
641 description=u"When the client requests a batch of entries from "638 description="When the client requests a batch of entries from "
642 "a collection, they will not be allowed to request more entries "639 "a collection, they will not be allowed to request more entries "
643 "in the batch than this.",640 "in the batch than this.",
644 )641 )
645642
646 compensate_for_mod_compress_etag_modification = Bool(643 compensate_for_mod_compress_etag_modification = Bool(
647 title=u"Accept incoming ETags that appear to have been modified "644 title="Accept incoming ETags that appear to have been modified "
648 "in transit by Apache's mod_compress.",645 "in transit by Apache's mod_compress.",
649 default=False,646 default=False,
650 description=u"""When mod_compress compresses an outgoing647 description="""When mod_compress compresses an outgoing
651 representation, it (correctly) modifies the ETag. But when648 representation, it (correctly) modifies the ETag. But when
652 that ETag comes back in on a conditional GET or PUT request,649 that ETag comes back in on a conditional GET or PUT request,
653 mod_compress does _not_ transparently remove the modification,650 mod_compress does _not_ transparently remove the modification,
diff --git a/src/lazr/restful/jsoncache.py b/src/lazr/restful/jsoncache.py
index 5c217c2..02349c3 100644
--- a/src/lazr/restful/jsoncache.py
+++ b/src/lazr/restful/jsoncache.py
@@ -2,10 +2,6 @@
2#2#
3"""A class for storing resources where they can be seen by a template."""3"""A class for storing resources where they can be seen by a template."""
44
5from __future__ import absolute_import, print_function
6
7__metaclass__ = type
8
9__all__ = ["JSONRequestCache"]5__all__ = ["JSONRequestCache"]
106
11from lazr.restful.interfaces import IJSONRequestCache, LAZR_WEBSERVICE_NS7from lazr.restful.interfaces import IJSONRequestCache, LAZR_WEBSERVICE_NS
diff --git a/src/lazr/restful/marshallers.py b/src/lazr/restful/marshallers.py
index bec584a..3439106 100644
--- a/src/lazr/restful/marshallers.py
+++ b/src/lazr/restful/marshallers.py
@@ -2,9 +2,6 @@
22
3"""Marshallers for fields used in HTTP resources."""3"""Marshallers for fields used in HTTP resources."""
44
5from __future__ import absolute_import, print_function
6
7__metaclass__ = type
8__all__ = [5__all__ = [
9 "AbstractCollectionFieldMarshaller",6 "AbstractCollectionFieldMarshaller",
10 "BoolFieldMarshaller",7 "BoolFieldMarshaller",
@@ -31,7 +28,6 @@ import re
3128
32import pytz29import pytz
33import simplejson30import simplejson
34import six
35from six.moves.urllib.parse import unquote31from six.moves.urllib.parse import unquote
3632
37from zope.datetime import (33from zope.datetime import (
@@ -92,9 +88,9 @@ class URLDereferencingMixin:
92 request_host = full_request_host88 request_host = full_request_host
93 request_port = default_port89 request_port = default_port
9490
95 if not isinstance(url, six.string_types):91 if not isinstance(url, str):
96 raise ValueError(92 raise ValueError(
97 u"got '%s', expected string: %r" % (type(url).__name__, url)93 "got '%s', expected string: %r" % (type(url).__name__, url)
98 )94 )
99 if url.startswith("/"):95 if url.startswith("/"):
100 # It's a relative URI. Resolve it relative to the root of this96 # It's a relative URI. Resolve it relative to the root of this
@@ -145,9 +141,9 @@ class URLDereferencingMixin:
145 resource = self.dereference_url(url)141 resource = self.dereference_url(url)
146 except NotFound:142 except NotFound:
147 # The URL doesn't correspond to any real object.143 # The URL doesn't correspond to any real object.
148 raise ValueError(u'No such object "%s".' % url)144 raise ValueError('No such object "%s".' % url)
149 except InvalidURIError:145 except InvalidURIError:
150 raise ValueError(u'"%s" is not a valid URI.' % url)146 raise ValueError('"%s" is not a valid URI.' % url)
151 # We looked up the URL and got the thing at the other end of147 # We looked up the URL and got the thing at the other end of
152 # the URL: a resource. But internally, a resource isn't a148 # the URL: a resource. But internally, a resource isn't a
153 # valid value for any schema field. Instead we want the object149 # valid value for any schema field. Instead we want the object
@@ -193,8 +189,8 @@ class SimpleFieldMarshaller:
193 v = value189 v = value
194 if isinstance(v, bytes):190 if isinstance(v, bytes):
195 v = v.decode("utf8") # assume utf8191 v = v.decode("utf8") # assume utf8
196 elif not isinstance(v, six.text_type):192 elif not isinstance(v, str):
197 v = six.text_type(v)193 v = str(v)
198 value = simplejson.loads(v)194 value = simplejson.loads(v)
199 except (ValueError, TypeError):195 except (ValueError, TypeError):
200 # Pass the value as is. This saves client from having to encode196 # Pass the value as is. This saves client from having to encode
@@ -225,7 +221,7 @@ class SimpleFieldMarshaller:
225 else:221 else:
226 expected_name = self._type.__name__222 expected_name = self._type.__name__
227 raise ValueError(223 raise ValueError(
228 u"got '%s', expected %s: %r"224 "got '%s', expected %s: %r"
229 % (type(value).__name__, expected_name, value)225 % (type(value).__name__, expected_name, value)
230 )226 )
231 return value227 return value
@@ -275,9 +271,7 @@ class FloatFieldMarshaller(SimpleFieldMarshaller):
275271
276 Converts the value to a float.272 Converts the value to a float.
277 """273 """
278 return float(274 return float(super()._marshall_from_json_data(value))
279 super(FloatFieldMarshaller, self)._marshall_from_json_data(value)
280 )
281275
282276
283class BytesFieldMarshaller(SimpleFieldMarshaller):277class BytesFieldMarshaller(SimpleFieldMarshaller):
@@ -319,7 +313,7 @@ class BytesFieldMarshaller(SimpleFieldMarshaller):
319 if safe_hasattr(value, "seek"):313 if safe_hasattr(value, "seek"):
320 value.seek(0)314 value.seek(0)
321 value = value.read()315 value = value.read()
322 elif not isinstance(value, (bytes, six.text_type)):316 elif not isinstance(value, (bytes, str)):
323 value = str(value).encode("UTF-8")317 value = str(value).encode("UTF-8")
324 else:318 else:
325 # Leave string conversion to _marshall_from_json_data.319 # Leave string conversion to _marshall_from_json_data.
@@ -331,17 +325,15 @@ class BytesFieldMarshaller(SimpleFieldMarshaller):
331325
332 Convert all strings to byte strings.326 Convert all strings to byte strings.
333 """327 """
334 if isinstance(value, six.text_type):328 if isinstance(value, str):
335 value = value.encode("utf-8")329 value = value.encode("utf-8")
336 return super(BytesFieldMarshaller, self)._marshall_from_json_data(330 return super()._marshall_from_json_data(value)
337 value
338 )
339331
340332
341class TextFieldMarshaller(SimpleFieldMarshaller):333class TextFieldMarshaller(SimpleFieldMarshaller):
342 """FieldMarshaller for IText fields."""334 """FieldMarshaller for IText fields."""
343335
344 _type = six.text_type336 _type = str
345 _type_error_message = "not a unicode string: %r"337 _type_error_message = "not a unicode string: %r"
346338
347 def _marshall_from_request(self, value):339 def _marshall_from_request(self, value):
@@ -349,12 +341,12 @@ class TextFieldMarshaller(SimpleFieldMarshaller):
349341
350 Converts the value to unicode.342 Converts the value to unicode.
351 """343 """
352 value = six.text_type(value)344 value = str(value)
353 # multipart/form-data encoding of text fields is required (RFC 2046345 # multipart/form-data encoding of text fields is required (RFC 2046
354 # section 4.1.1) to use CRLF for line breaks. Normalize to346 # section 4.1.1) to use CRLF for line breaks. Normalize to
355 # Unix-style LF.347 # Unix-style LF.
356 value = re.sub(r"\r\n?", "\n", value)348 value = re.sub(r"\r\n?", "\n", value)
357 return super(TextFieldMarshaller, self)._marshall_from_request(value)349 return super()._marshall_from_request(value)
358350
359351
360class FixedVocabularyFieldMarshaller(SimpleFieldMarshaller):352class FixedVocabularyFieldMarshaller(SimpleFieldMarshaller):
@@ -369,7 +361,7 @@ class FixedVocabularyFieldMarshaller(SimpleFieldMarshaller):
369 part of a multiadapter lookup of the appropriate361 part of a multiadapter lookup of the appropriate
370 marshaller.362 marshaller.
371 """363 """
372 super(FixedVocabularyFieldMarshaller, self).__init__(field, request)364 super().__init__(field, request)
373365
374 def unmarshall_to_closeup(self, entry, value):366 def unmarshall_to_closeup(self, entry, value):
375 """Describe all values, not just the selected value."""367 """Describe all values, not just the selected value."""
@@ -386,9 +378,7 @@ class TokenizedVocabularyFieldMarshaller(FixedVocabularyFieldMarshaller):
386 """A marshaller that looks up value using a token in a vocabulary."""378 """A marshaller that looks up value using a token in a vocabulary."""
387379
388 def __init__(self, field, request, vocabulary):380 def __init__(self, field, request, vocabulary):
389 super(TokenizedVocabularyFieldMarshaller, self).__init__(381 super().__init__(field, request, vocabulary)
390 field, request, vocabulary
391 )
392382
393 def _marshall_from_json_data(self, value):383 def _marshall_from_json_data(self, value):
394 """See `SimpleFieldMarshaller`.384 """See `SimpleFieldMarshaller`.
@@ -396,11 +386,9 @@ class TokenizedVocabularyFieldMarshaller(FixedVocabularyFieldMarshaller):
396 Looks up the value as a token in the vocabulary.386 Looks up the value as a token in the vocabulary.
397 """387 """
398 try:388 try:
399 return self.field.vocabulary.getTermByToken(389 return self.field.vocabulary.getTermByToken(str(value)).value
400 six.text_type(value)
401 ).value
402 except LookupError:390 except LookupError:
403 raise ValueError(u"%r isn't a valid token" % value)391 raise ValueError("%r isn't a valid token" % value)
404392
405393
406class DateTimeFieldMarshaller(SimpleFieldMarshaller):394class DateTimeFieldMarshaller(SimpleFieldMarshaller):
@@ -454,7 +442,7 @@ class DateFieldMarshaller(DateTimeFieldMarshaller):
454442
455 def _marshall_from_json_data(self, value):443 def _marshall_from_json_data(self, value):
456 """Parse the value as a datetime.date object."""444 """Parse the value as a datetime.date object."""
457 super_class = super(DateFieldMarshaller, self)445 super_class = super()
458 date_time = super_class._marshall_from_json_data(value)446 date_time = super_class._marshall_from_json_data(value)
459 return date_time.date()447 return date_time.date()
460448
@@ -475,7 +463,7 @@ class AbstractCollectionFieldMarshaller(SimpleFieldMarshaller):
475463
476 This also looks for the appropriate marshaller for value_type.464 This also looks for the appropriate marshaller for value_type.
477 """465 """
478 super(AbstractCollectionFieldMarshaller, self).__init__(field, request)466 super().__init__(field, request)
479 self.value_marshaller = getMultiAdapter(467 self.value_marshaller = getMultiAdapter(
480 (field.value_type or Field(), request), IFieldMarshaller468 (field.value_type or Field(), request), IFieldMarshaller
481 )469 )
@@ -486,9 +474,7 @@ class AbstractCollectionFieldMarshaller(SimpleFieldMarshaller):
486 Marshall every elements of the list using the appropriate474 Marshall every elements of the list using the appropriate
487 marshaller.475 marshaller.
488 """476 """
489 value = super(477 value = super()._marshall_from_json_data(value)
490 AbstractCollectionFieldMarshaller, self
491 )._marshall_from_json_data(value)
492478
493 # In AbstractCollection subclasses, _type contains the type object,479 # In AbstractCollection subclasses, _type contains the type object,
494 # which can be used as a factory.480 # which can be used as a factory.
@@ -556,7 +542,7 @@ class DictFieldMarshaller(SimpleFieldMarshaller):
556 value_type. If key_type or value_type are not specified, the default542 value_type. If key_type or value_type are not specified, the default
557 field marshaller is used.543 field marshaller is used.
558 """544 """
559 super(DictFieldMarshaller, self).__init__(field, request)545 super().__init__(field, request)
560 self.key_marshaller = getMultiAdapter(546 self.key_marshaller = getMultiAdapter(
561 (field.key_type or Field(), request), IFieldMarshaller547 (field.key_type or Field(), request), IFieldMarshaller
562 )548 )
@@ -582,7 +568,7 @@ class DictFieldMarshaller(SimpleFieldMarshaller):
582 try:568 try:
583 value = dict(nv.split(",", 2) for nv in value)569 value = dict(nv.split(",", 2) for nv in value)
584 except ValueError:570 except ValueError:
585 raise ValueError(u"got '%s', list of name,value pairs" % value)571 raise ValueError("got '%s', list of name,value pairs" % value)
586 return {572 return {
587 self.key_marshaller.marshall_from_json_data(573 self.key_marshaller.marshall_from_json_data(
588 key574 key
@@ -602,9 +588,7 @@ class DictFieldMarshaller(SimpleFieldMarshaller):
602 if isinstance(value, list):588 if isinstance(value, list):
603 value = dict(value)589 value = dict(value)
604 # Call super to check for errors and raise a ValueError if necessary.590 # Call super to check for errors and raise a ValueError if necessary.
605 value = super(DictFieldMarshaller, self)._marshall_from_json_data(591 value = super()._marshall_from_json_data(value)
606 value
607 )
608 return {592 return {
609 self.key_marshaller.marshall_from_json_data(593 self.key_marshaller.marshall_from_json_data(
610 key594 key
@@ -671,9 +655,7 @@ class SimpleVocabularyLookupFieldMarshaller(FixedVocabularyFieldMarshaller):
671655
672 def __init__(self, field, request, vocabulary):656 def __init__(self, field, request, vocabulary):
673 """Initialize the marshaller with the vocabulary it'll use."""657 """Initialize the marshaller with the vocabulary it'll use."""
674 super(SimpleVocabularyLookupFieldMarshaller, self).__init__(658 super().__init__(field, request, vocabulary)
675 field, request, vocabulary
676 )
677 self.vocabulary = vocabulary659 self.vocabulary = vocabulary
678660
679 def _marshall_from_json_data(self, value):661 def _marshall_from_json_data(self, value):
@@ -684,7 +666,7 @@ class SimpleVocabularyLookupFieldMarshaller(FixedVocabularyFieldMarshaller):
684 return item666 return item
685 valid_titles.append(item.title)667 valid_titles.append(item.title)
686 raise ValueError(668 raise ValueError(
687 u'Invalid value "%s". Acceptable values are: %s'669 'Invalid value "%s". Acceptable values are: %s'
688 % (value, ", ".join(valid_titles))670 % (value, ", ".join(valid_titles))
689 )671 )
690672
@@ -704,7 +686,7 @@ class ObjectLookupFieldMarshaller(
704 """686 """
705687
706 def __init__(self, field, request, vocabulary=None):688 def __init__(self, field, request, vocabulary=None):
707 super(ObjectLookupFieldMarshaller, self).__init__(field, request)689 super().__init__(field, request)
708 self.vocabulary = vocabulary690 self.vocabulary = vocabulary
709691
710 @property692 @property
diff --git a/src/lazr/restful/metazcml.py b/src/lazr/restful/metazcml.py
index 1fe9422..09c0274 100644
--- a/src/lazr/restful/metazcml.py
+++ b/src/lazr/restful/metazcml.py
@@ -2,9 +2,6 @@
22
3"""ZCML registration directives for the LAZR webservice framework."""3"""ZCML registration directives for the LAZR webservice framework."""
44
5from __future__ import absolute_import, print_function
6
7__metaclass__ = type
8__all__ = []5__all__ = []
96
107
@@ -82,7 +79,7 @@ class IRegisterDirective(Interface):
82 """79 """
8380
84 module = GlobalObject(81 module = GlobalObject(
85 title=u"Module which will be inspected for webservice declarations"82 title="Module which will be inspected for webservice declarations"
86 )83 )
8784
8885
diff --git a/src/lazr/restful/publisher.py b/src/lazr/restful/publisher.py
index eb628a4..92b668a 100644
--- a/src/lazr/restful/publisher.py
+++ b/src/lazr/restful/publisher.py
@@ -6,9 +6,6 @@ This module defines classes that are usually needed for integration
6with the Zope publisher.6with the Zope publisher.
7"""7"""
88
9from __future__ import absolute_import, division, print_function
10
11__metaclass__ = type
12__all__ = [9__all__ = [
13 "browser_request_to_web_service_request",10 "browser_request_to_web_service_request",
14 "WebServicePublicationMixin",11 "WebServicePublicationMixin",
@@ -119,9 +116,7 @@ class WebServicePublicationMixin:
119 else:116 else:
120 # Falls through to our parent version.117 # Falls through to our parent version.
121 pass118 pass
122 return super(WebServicePublicationMixin, self).traverseName(119 return super().traverseName(request, ob, name)
123 request, ob, name
124 )
125120
126 def _traverseToByteStorage(self, request, entry, field, name):121 def _traverseToByteStorage(self, request, entry, field, name):
127 """Try to traverse to a byte storage resource in entry."""122 """Try to traverse to a byte storage resource in entry."""
@@ -223,9 +218,7 @@ class WebServicePublicationMixin:
223218
224 def callObject(self, request, object):219 def callObject(self, request, object):
225 """Help web browsers handle redirects correctly."""220 """Help web browsers handle redirects correctly."""
226 value = super(WebServicePublicationMixin, self).callObject(221 value = super().callObject(request, object)
227 request, object
228 )
229 self._processNotifications(request)222 self._processNotifications(request)
230 if request.response.getStatus() // 100 == 3:223 if request.response.getStatus() // 100 == 3:
231 if IWebBrowserInitiatedRequest.providedBy(request):224 if IWebBrowserInitiatedRequest.providedBy(request):
@@ -263,7 +256,7 @@ class WebServicePublicationMixin:
263256
264257
265@implementer(IWebServiceClientRequest)258@implementer(IWebServiceClientRequest)
266class WebServiceRequestTraversal(object):259class WebServiceRequestTraversal:
267 """Mixin providing web-service resource wrapping in traversal.260 """Mixin providing web-service resource wrapping in traversal.
268261
269 This should be mixed in the request using to the base publication used.262 This should be mixed in the request using to the base publication used.
@@ -288,7 +281,7 @@ class WebServiceRequestTraversal(object):
288 # was requested and has set the application appropriately, so281 # was requested and has set the application appropriately, so
289 # now we can get a good value for 'ob' and traverse it.282 # now we can get a good value for 'ob' and traverse it.
290 ob = self.publication.getApplication(self)283 ob = self.publication.getApplication(self)
291 result = super(WebServiceRequestTraversal, self).traverse(ob)284 result = super().traverse(ob)
292 return self.publication.getResource(self, result)285 return self.publication.getResource(self, result)
293286
294 def _removeVirtualHostTraversals(self):287 def _removeVirtualHostTraversals(self):
diff --git a/src/lazr/restful/security.py b/src/lazr/restful/security.py
index 05d5802..f7cc532 100644
--- a/src/lazr/restful/security.py
+++ b/src/lazr/restful/security.py
@@ -2,9 +2,6 @@
22
3"""Utilities for dealing with zope security."""3"""Utilities for dealing with zope security."""
44
5from __future__ import absolute_import, print_function
6
7__metaclass__ = type
8__all__ = [5__all__ = [
9 "protect_schema",6 "protect_schema",
10]7]
diff --git a/src/lazr/restful/simple.py b/src/lazr/restful/simple.py
index b846e96..2c58320 100644
--- a/src/lazr/restful/simple.py
+++ b/src/lazr/restful/simple.py
@@ -1,8 +1,5 @@
1"""Simple implementations of various Zope and lazr.restful interfaces."""1"""Simple implementations of various Zope and lazr.restful interfaces."""
22
3from __future__ import absolute_import, print_function
4
5__metaclass__ = type
6__all__ = [3__all__ = [
7 "BaseRepresentationCache",4 "BaseRepresentationCache",
8 "BaseWebServiceConfiguration",5 "BaseWebServiceConfiguration",
@@ -20,7 +17,6 @@ __all__ = [
2017
21import traceback18import traceback
2219
23import six
24from six.moves.urllib.parse import (20from six.moves.urllib.parse import (
25 quote,21 quote,
26 unquote,22 unquote,
@@ -63,7 +59,7 @@ from lazr.restful.utils import (
6359
6460
65@implementer(IPublication)61@implementer(IPublication)
66class PublicationMixin(object):62class PublicationMixin:
67 """A very simple implementation of `IPublication`.63 """A very simple implementation of `IPublication`.
6864
69 The object passed to the constructor is returned by getApplication().65 The object passed to the constructor is returned by getApplication().
@@ -160,7 +156,7 @@ class Publication(WebServicePublicationMixin, PublicationMixin):
160156
161157
162@implementer(ITraverseWithGet)158@implementer(ITraverseWithGet)
163class TraverseWithGet(object):159class TraverseWithGet:
164 """An implementation of `IPublishTraverse` that uses the get() method.160 """An implementation of `IPublishTraverse` that uses the get() method.
165161
166 This is a simple traversal technique that works with any object162 This is a simple traversal technique that works with any object
@@ -395,9 +391,7 @@ class MultiplePathPartAbsoluteURL:
395 parts = getattr(self.context, "__path_parts__", None)391 parts = getattr(self.context, "__path_parts__", None)
396 if parts is None:392 if parts is None:
397 raise TypeError(_insufficientContext)393 raise TypeError(_insufficientContext)
398 if isinstance(parts, six.string_types) or not hasattr(394 if isinstance(parts, str) or not hasattr(parts, "__iter__"):
399 parts, "__iter__"
400 ):
401 raise TypeError(395 raise TypeError(
402 "Expected an iterable of strings for __path_parts__."396 "Expected an iterable of strings for __path_parts__."
403 )397 )
@@ -409,7 +403,7 @@ class MultiplePathPartAbsoluteURL:
409403
410404
411@implementer(IRepresentationCache)405@implementer(IRepresentationCache)
412class BaseRepresentationCache(object):406class BaseRepresentationCache:
413 """A useful base class for representation caches.407 """A useful base class for representation caches.
414408
415 When an object is invalidated, all of its representations must be409 When an object is invalidated, all of its representations must be
diff --git a/src/lazr/restful/tales.py b/src/lazr/restful/tales.py
index 2968667..0be2185 100644
--- a/src/lazr/restful/tales.py
+++ b/src/lazr/restful/tales.py
@@ -26,10 +26,6 @@
2626
27"""Implementation of the ws: namespace in TALES."""27"""Implementation of the ws: namespace in TALES."""
2828
29from __future__ import absolute_import, print_function
30
31__metaclass__ = type
32
33import operator29import operator
34import re30import re
35import simplejson31import simplejson
@@ -370,7 +366,7 @@ class WadlEntryResourceAPI(WadlResourceAPI):
370366
371 def __init__(self, entry_resource):367 def __init__(self, entry_resource):
372 "Initialize with an entry resource."368 "Initialize with an entry resource."
373 super(WadlEntryResourceAPI, self).__init__(entry_resource)369 super().__init__(entry_resource)
374 self.entry = self.resource.entry370 self.entry = self.resource.entry
375 self.schema = self.entry.schema371 self.schema = self.entry.schema
376372
@@ -407,7 +403,7 @@ class WadlCollectionResourceAPI(WadlResourceAPI):
407 + quote(relationship_name)403 + quote(relationship_name)
408 )404 )
409 else:405 else:
410 return super(WadlCollectionResourceAPI, self).url406 return super().url
411407
412 @property408 @property
413 def type_link(self):409 def type_link(self):
@@ -563,9 +559,7 @@ class WadlEntryInterfaceAdapterAPI(WadlResourceAdapterAPI):
563 """559 """
564560
565 def __init__(self, entry_interface):561 def __init__(self, entry_interface):
566 super(WadlEntryInterfaceAdapterAPI, self).__init__(562 super().__init__(entry_interface, IEntry)
567 entry_interface, IEntry
568 )
569 self.utility = EntryAdapterUtility.forEntryInterface(563 self.utility = EntryAdapterUtility.forEntryInterface(
570 entry_interface, get_current_web_service_request()564 entry_interface, get_current_web_service_request()
571 )565 )
@@ -584,7 +578,7 @@ class WadlEntryAdapterAPI(WadlResourceAdapterAPI):
584 """578 """
585579
586 def __init__(self, adapter):580 def __init__(self, adapter):
587 super(WadlEntryAdapterAPI, self).__init__(adapter, IEntry)581 super().__init__(adapter, IEntry)
588 self.utility = EntryAdapterUtility(adapter)582 self.utility = EntryAdapterUtility(adapter)
589583
590 @property584 @property
@@ -662,7 +656,7 @@ class WadlCollectionAdapterAPI(WadlResourceAdapterAPI):
662 "Namespace for WADL functions that operate on collection adapters."656 "Namespace for WADL functions that operate on collection adapters."
663657
664 def __init__(self, adapter):658 def __init__(self, adapter):
665 super(WadlCollectionAdapterAPI, self).__init__(adapter, ICollection)659 super().__init__(adapter, ICollection)
666660
667 @property661 @property
668 def collection_type(self):662 def collection_type(self):
diff --git a/src/lazr/restful/testing/event.py b/src/lazr/restful/testing/event.py
index 7431413..e199790 100644
--- a/src/lazr/restful/testing/event.py
+++ b/src/lazr/restful/testing/event.py
@@ -2,10 +2,6 @@
22
3"""Helper class for checking the event notifications."""3"""Helper class for checking the event notifications."""
44
5from __future__ import absolute_import, print_function
6
7__metaclass__ = type
8
9import zope.component5import zope.component
106
117
diff --git a/src/lazr/restful/testing/helpers.py b/src/lazr/restful/testing/helpers.py
index 46c7d90..fc9c8b1 100644
--- a/src/lazr/restful/testing/helpers.py
+++ b/src/lazr/restful/testing/helpers.py
@@ -1,5 +1,3 @@
1from __future__ import absolute_import, print_function
2
3import sys1import sys
4from types import ModuleType2from types import ModuleType
53
diff --git a/src/lazr/restful/testing/tales.py b/src/lazr/restful/testing/tales.py
index ad64e0b..ce08dce 100644
--- a/src/lazr/restful/testing/tales.py
+++ b/src/lazr/restful/testing/tales.py
@@ -2,10 +2,6 @@
22
3"""Helper functions for testing TALES expressions."""3"""Helper functions for testing TALES expressions."""
44
5from __future__ import absolute_import, print_function
6
7__metaclass__ = type
8
9__all__ = [5__all__ = [
10 "test_tales",6 "test_tales",
11]7]
diff --git a/src/lazr/restful/testing/webservice.py b/src/lazr/restful/testing/webservice.py
index 9eccb04..a4405b1 100644
--- a/src/lazr/restful/testing/webservice.py
+++ b/src/lazr/restful/testing/webservice.py
@@ -2,9 +2,6 @@
22
3"""Testing helpers for webservice unit tests."""3"""Testing helpers for webservice unit tests."""
44
5from __future__ import absolute_import, print_function
6
7__metaclass__ = type
8__all__ = [5__all__ = [
9 "create_web_service_request",6 "create_web_service_request",
10 "StubAbsoluteURL",7 "StubAbsoluteURL",
@@ -141,7 +138,7 @@ class FakeResponse:
141 if result is None:138 if result is None:
142 result = ""139 result = ""
143140
144 if not isinstance(result, six.string_types):141 if not isinstance(result, str):
145 raise ValueError("only strings and None results are handled")142 raise ValueError("only strings and None results are handled")
146143
147 self.result = result144 self.result = result
@@ -200,7 +197,7 @@ def pformat_value(value):
200 JSON strings are always Unicode, never bytes, so this doesn't introduce197 JSON strings are always Unicode, never bytes, so this doesn't introduce
201 ambiguity.198 ambiguity.
202 """199 """
203 if isinstance(value, six.text_type):200 if isinstance(value, str):
204 value = value.encode("unicode_escape").decode("ASCII")201 value = value.encode("unicode_escape").decode("ASCII")
205 if "'" in value and '"' not in value:202 if "'" in value and '"' not in value:
206 return '"%s"' % value203 return '"%s"' % value
@@ -259,7 +256,7 @@ class WebServiceApplication(Application):
259 """A WSGI application for the tests."""256 """A WSGI application for the tests."""
260257
261 def __init__(self, global_config, publication, **options):258 def __init__(self, global_config, publication, **options):
262 if isinstance(publication, six.string_types):259 if isinstance(publication, str):
263 Application.__init__(self, global_config, publication, **options)260 Application.__init__(self, global_config, publication, **options)
264 else:261 else:
265 self.publication = publication(global_config, **options)262 self.publication = publication(global_config, **options)
@@ -329,7 +326,7 @@ class WebServiceCaller:
329 headers=None,326 headers=None,
330 api_version=None,327 api_version=None,
331 ):328 ):
332 if isinstance(path_or_url, (bytes, six.text_type)):329 if isinstance(path_or_url, (bytes, str)):
333 path_or_url = six.ensure_str(path_or_url)330 path_or_url = six.ensure_str(path_or_url)
334 else:331 else:
335 path_or_url = str(path_or_url)332 path_or_url = str(path_or_url)
@@ -468,7 +465,7 @@ class WebServiceCaller:
468 if isinstance(value, io.BufferedIOBase):465 if isinstance(value, io.BufferedIOBase):
469 buf.write(value.read())466 buf.write(value.read())
470 else:467 else:
471 if not isinstance(value, six.string_types):468 if not isinstance(value, str):
472 value = simplejson.dumps(value)469 value = simplejson.dumps(value)
473 lines = re.split(r"\r\n|\r|\n", value)470 lines = re.split(r"\r\n|\r|\n", value)
474 for line in lines[:-1]:471 for line in lines[:-1]:
@@ -536,7 +533,7 @@ class WebServiceCaller:
536533
537 This may mean turning the value into a JSON string.534 This may mean turning the value into a JSON string.
538 """535 """
539 if not isinstance(value, six.string_types):536 if not isinstance(value, str):
540 value = simplejson.dumps(value)537 value = simplejson.dumps(value)
541 return quote(value)538 return quote(value)
542539
@@ -560,17 +557,16 @@ class WebServiceAjaxCaller(WebServiceCaller):
560 def default_api_version(self):557 def default_api_version(self):
561 """Introduce the Ajax path override to the URI prefix."""558 """Introduce the Ajax path override to the URI prefix."""
562 config = getUtility(IWebServiceConfiguration)559 config = getUtility(IWebServiceConfiguration)
563 default_version = super(WebServiceAjaxCaller, self).default_api_version560 default_version = super().default_api_version
564 return config.path_override + "/" + default_version561 return config.path_override + "/" + default_version
565562
566563
567@six.python_2_unicode_compatible
568class WebServiceResponseWrapper(ProxyBase):564class WebServiceResponseWrapper(ProxyBase):
569 """A response from the web service with easy access to the JSON body."""565 """A response from the web service with easy access to the JSON body."""
570566
571 def __init__(self, response):567 def __init__(self, response):
572 self.body = response.read()568 self.body = response.read()
573 super(WebServiceResponseWrapper, self).__init__(response)569 super().__init__(response)
574570
575 def getHeader(self, key, default=None):571 def getHeader(self, key, default=None):
576 return self.getheader(key, default)572 return self.getheader(key, default)
@@ -659,7 +655,7 @@ class TestCaseWithWebServiceFixtures(CleanUp, unittest.TestCase):
659 """655 """
660656
661 def setUp(self):657 def setUp(self):
662 super(TestCaseWithWebServiceFixtures, self).setUp()658 super().setUp()
663 # Register a simple configuration object.659 # Register a simple configuration object.
664 webservice_configuration = WebServiceTestConfiguration()660 webservice_configuration = WebServiceTestConfiguration()
665 sm = getGlobalSiteManager()661 sm = getGlobalSiteManager()
@@ -717,7 +713,7 @@ class WebServiceTestCase(TestCaseWithWebServiceFixtures):
717713
718 def setUp(self):714 def setUp(self):
719 """Set the component registry with the given model."""715 """Set the component registry with the given model."""
720 super(WebServiceTestCase, self).setUp()716 super().setUp()
721717
722 # Register a service root resource718 # Register a service root resource
723 sm = getGlobalSiteManager()719 sm = getGlobalSiteManager()
@@ -769,12 +765,12 @@ class IGenericEntry(Interface):
769 # pylint: disable-msg=E0213765 # pylint: disable-msg=E0213
770 a_field = exported(766 a_field = exported(
771 TextLine(767 TextLine(
772 title=u'A "field"',768 title='A "field"',
773 description=u"The only field that can be <> 0 in the entry.",769 description="The only field that can be <> 0 in the entry.",
774 )770 )
775 )771 )
776772
777 @operation_parameters(message=TextLine(title=u"Message to say"))773 @operation_parameters(message=TextLine(title="Message to say"))
778 @export_read_operation()774 @export_read_operation()
779 def greet(message):775 def greet(message):
780 """Print an appropriate greeting based on the message.776 """Print an appropriate greeting based on the message.
@@ -831,4 +827,4 @@ def simple_renderer(value):
831 This is a good HTML field renderer to use in tests, because it827 This is a good HTML field renderer to use in tests, because it
832 tests Unicode values and embedded HTML.828 tests Unicode values and embedded HTML.
833 """829 """
834 return u"\N{SNOWMAN} <b>%s</b>" % value830 return "\N{SNOWMAN} <b>%s</b>" % value
diff --git a/src/lazr/restful/tests/test_declarations.py b/src/lazr/restful/tests/test_declarations.py
index f1c688c..305709b 100644
--- a/src/lazr/restful/tests/test_declarations.py
+++ b/src/lazr/restful/tests/test_declarations.py
@@ -2,8 +2,6 @@
22
3"""Unit tests for the conversion of interfaces into a web service."""3"""Unit tests for the conversion of interfaces into a web service."""
44
5from __future__ import absolute_import, print_function
6
7import sys5import sys
86
9import testtools7import testtools
@@ -85,7 +83,7 @@ class ContributingInterfacesTestCase(TestCaseWithWebServiceFixtures):
85 """Tests for interfaces that contribute fields/operations to others."""83 """Tests for interfaces that contribute fields/operations to others."""
8684
87 def setUp(self):85 def setUp(self):
88 super(ContributingInterfacesTestCase, self).setUp()86 super().setUp()
89 sm = getSiteManager()87 sm = getSiteManager()
90 sm.registerAdapter(ProductToHasBugsAdapter)88 sm.registerAdapter(ProductToHasBugsAdapter)
91 sm.registerAdapter(ProjectToHasBugsAdapter)89 sm.registerAdapter(ProjectToHasBugsAdapter)
@@ -152,7 +150,7 @@ class ContributingInterfacesTestCase(TestCaseWithWebServiceFixtures):
152 @exported_as_webservice_entry(contributes_to=[IProduct])150 @exported_as_webservice_entry(contributes_to=[IProduct])
153 class IHasTooManyAccessors(Interface):151 class IHasTooManyAccessors(Interface):
154 needs_an_accessor = exported(152 needs_an_accessor = exported(
155 TextLine(title=u"This needs an accessor", readonly=True)153 TextLine(title="This needs an accessor", readonly=True)
156 )154 )
157155
158 @accessor_for(needs_an_accessor)156 @accessor_for(needs_an_accessor)
@@ -353,7 +351,7 @@ class ContributingInterfacesTestCase(TestCaseWithWebServiceFixtures):
353351
354 @exported_as_webservice_entry(contributes_to=[INotExported])352 @exported_as_webservice_entry(contributes_to=[INotExported])
355 class IContributor(Interface):353 class IContributor(Interface):
356 title = exported(TextLine(title=u"The project title"))354 title = exported(TextLine(title="The project title"))
357355
358 self.assertRaises(356 self.assertRaises(
359 AttemptToContributeToNonExportedInterface,357 AttemptToContributeToNonExportedInterface,
@@ -436,7 +434,7 @@ class TestExportAsWebserviceEntry(testtools.TestCase):
436 """Tests for export_as_webservice_entry."""434 """Tests for export_as_webservice_entry."""
437435
438 def setUp(self):436 def setUp(self):
439 super(TestExportAsWebserviceEntry, self).setUp()437 super().setUp()
440 if sys.version_info[0] >= 3:438 if sys.version_info[0] >= 3:
441 self.skipTest(439 self.skipTest(
442 "export_as_webservice_entry is only supported on Python 2"440 "export_as_webservice_entry is only supported on Python 2"
@@ -454,7 +452,7 @@ class TestExportAsWebserviceEntry(testtools.TestCase):
454 def test_requires_interface(self):452 def test_requires_interface(self):
455 # export_as_webservice_entry can only be used on Interface.453 # export_as_webservice_entry can only be used on Interface.
456 def export_non_interface():454 def export_non_interface():
457 class NotAnInterface(object):455 class NotAnInterface:
458 export_as_webservice_entry()456 export_as_webservice_entry()
459457
460 exception = self.assertRaises(TypeError, export_non_interface)458 exception = self.assertRaises(TypeError, export_non_interface)
@@ -478,7 +476,7 @@ class TestExportAsWebserviceCollection(testtools.TestCase):
478 """Tests for export_as_webservice_collection."""476 """Tests for export_as_webservice_collection."""
479477
480 def setUp(self):478 def setUp(self):
481 super(TestExportAsWebserviceCollection, self).setUp()479 super().setUp()
482 if sys.version_info[0] >= 3:480 if sys.version_info[0] >= 3:
483 self.skipTest(481 self.skipTest(
484 "export_as_webservice_collection is only supported on "482 "export_as_webservice_collection is only supported on "
@@ -568,7 +566,7 @@ class TestExportAsWebserviceCollection(testtools.TestCase):
568 def test_requires_interface(self):566 def test_requires_interface(self):
569 # export_as_webservice_collection can only be used on Interface.567 # export_as_webservice_collection can only be used on Interface.
570 def export_non_interface():568 def export_non_interface():
571 class NotAnInterface(object):569 class NotAnInterface:
572 export_as_webservice_collection(Interface)570 export_as_webservice_collection(Interface)
573571
574 exception = self.assertRaises(TypeError, export_non_interface)572 exception = self.assertRaises(TypeError, export_non_interface)
@@ -626,21 +624,21 @@ class TestFindExportedInterfaces(testtools.TestCase):
626 )624 )
627625
628 def test_finds_exported_exceptions(self):626 def test_finds_exported_exceptions(self):
629 class Module(object):627 class Module:
630 NotExportedException_copy = NotExportedException628 NotExportedException_copy = NotExportedException
631 ExportedExceptionOne_copy = ExportedExceptionOne629 ExportedExceptionOne_copy = ExportedExceptionOne
632630
633 self.assertExportsNames(Module, ["ExportedExceptionOne"])631 self.assertExportsNames(Module, ["ExportedExceptionOne"])
634632
635 def test_finds_exported_interfaces(self):633 def test_finds_exported_interfaces(self):
636 class Module(object):634 class Module:
637 INotExported_copy = INotExported635 INotExported_copy = INotExported
638 IExported_copy = IExported636 IExported_copy = IExported
639637
640 self.assertExportsNames(Module, ["IExported"])638 self.assertExportsNames(Module, ["IExported"])
641639
642 def test_honours_all(self):640 def test_honours_all(self):
643 class Module(object):641 class Module:
644 __all__ = ["ExportedExceptionOne_copy"]642 __all__ = ["ExportedExceptionOne_copy"]
645 ExportedExceptionOne_copy = ExportedExceptionOne643 ExportedExceptionOne_copy = ExportedExceptionOne
646 ExportedExceptionTwo_copy = ExportedExceptionTwo644 ExportedExceptionTwo_copy = ExportedExceptionTwo
@@ -648,7 +646,7 @@ class TestFindExportedInterfaces(testtools.TestCase):
648 self.assertExportsNames(Module, ["ExportedExceptionOne"])646 self.assertExportsNames(Module, ["ExportedExceptionOne"])
649647
650 def test_skips_leading_underscore_without_all(self):648 def test_skips_leading_underscore_without_all(self):
651 class Module(object):649 class Module:
652 ExportedExceptionOne_copy = ExportedExceptionOne650 ExportedExceptionOne_copy = ExportedExceptionOne
653 _ExportedExceptionTwo_copy = ExportedExceptionTwo651 _ExportedExceptionTwo_copy = ExportedExceptionTwo
654652
@@ -657,7 +655,7 @@ class TestFindExportedInterfaces(testtools.TestCase):
657655
658@exported_as_webservice_entry()656@exported_as_webservice_entry()
659class IProduct(Interface):657class IProduct(Interface):
660 title = exported(TextLine(title=u"The product title"))658 title = exported(TextLine(title="The product title"))
661 # Need to define the three attributes below because we have a test which659 # Need to define the three attributes below because we have a test which
662 # wraps a Product object with a security proxy and later uses adapters660 # wraps a Product object with a security proxy and later uses adapters
663 # that access _dev_branch, _branches and _bug_count.661 # that access _dev_branch, _branches and _bug_count.
@@ -668,7 +666,7 @@ class IProduct(Interface):
668666
669667
670@implementer(IProduct)668@implementer(IProduct)
671class Product(object):669class Product:
672 title = "A product"670 title = "A product"
673 _bug_count = 0671 _bug_count = 0
674 _dev_branch = None672 _dev_branch = None
@@ -678,21 +676,21 @@ class Product(object):
678676
679@exported_as_webservice_entry()677@exported_as_webservice_entry()
680class IProject(Interface):678class IProject(Interface):
681 title = exported(TextLine(title=u"The project title"))679 title = exported(TextLine(title="The project title"))
682680
683681
684@implementer(IProject)682@implementer(IProject)
685class Project(object):683class Project:
686 title = "A project"684 title = "A project"
687 _bug_count = 0685 _bug_count = 0
688686
689687
690@exported_as_webservice_entry(contributes_to=[IProduct, IProject])688@exported_as_webservice_entry(contributes_to=[IProduct, IProject])
691class IHasBugs(Interface):689class IHasBugs(Interface):
692 bug_count = exported(Int(title=u"Number of bugs"))690 bug_count = exported(Int(title="Number of bugs"))
693 not_exported = TextLine(title=u"Not exported")691 not_exported = TextLine(title="Not exported")
694 bug_target_name = exported(692 bug_target_name = exported(
695 TextLine(title=u"The bug target name of this object.", readonly=True)693 TextLine(title="The bug target name of this object.", readonly=True)
696 )694 )
697695
698 @export_read_operation()696 @export_read_operation()
@@ -726,13 +724,13 @@ class IHasBugs(Interface):
726724
727@exported_as_webservice_entry(contributes_to=[IProduct])725@exported_as_webservice_entry(contributes_to=[IProduct])
728class IHasBugs2(Interface):726class IHasBugs2(Interface):
729 bug_count = exported(Int(title=u"Number of bugs"))727 bug_count = exported(Int(title="Number of bugs"))
730 not_exported = TextLine(title=u"Not exported")728 not_exported = TextLine(title="Not exported")
731729
732730
733@exported_as_webservice_entry(contributes_to=[IProduct])731@exported_as_webservice_entry(contributes_to=[IProduct])
734class IHasBugs3(Interface):732class IHasBugs3(Interface):
735 not_exported = TextLine(title=u"Not exported")733 not_exported = TextLine(title="Not exported")
736734
737 @export_read_operation()735 @export_read_operation()
738 def getBugsCount():736 def getBugsCount():
@@ -741,7 +739,7 @@ class IHasBugs3(Interface):
741739
742@adapter(IProduct)740@adapter(IProduct)
743@implementer(IHasBugs)741@implementer(IHasBugs)
744class ProductToHasBugsAdapter(object):742class ProductToHasBugsAdapter:
745 def __init__(self, context):743 def __init__(self, context):
746 self.context = context744 self.context = context
747 self.bug_count = context._bug_count745 self.bug_count = context._bug_count
@@ -766,18 +764,18 @@ class ProjectToHasBugsAdapter(ProductToHasBugsAdapter):
766764
767@exported_as_webservice_entry()765@exported_as_webservice_entry()
768class IBranch(Interface):766class IBranch(Interface):
769 name = TextLine(title=u"The branch name")767 name = TextLine(title="The branch name")
770768
771769
772@implementer(IBranch)770@implementer(IBranch)
773class Branch(object):771class Branch:
774 def __init__(self, name):772 def __init__(self, name):
775 self.name = name773 self.name = name
776774
777775
778@exported_as_webservice_entry(contributes_to=[IProduct])776@exported_as_webservice_entry(contributes_to=[IProduct])
779class IHasBranches(Interface):777class IHasBranches(Interface):
780 not_exported = TextLine(title=u"Not exported")778 not_exported = TextLine(title="Not exported")
781 development_branch = exported(779 development_branch = exported(
782 Reference(schema=IBranch, readonly=True),780 Reference(schema=IBranch, readonly=True),
783 ("2.0", dict(exported_as="development_branch_20")),781 ("2.0", dict(exported_as="development_branch_20")),
@@ -804,7 +802,7 @@ class IHasBranches(Interface):
804802
805@adapter(IProduct)803@adapter(IProduct)
806@implementer(IHasBranches)804@implementer(IHasBranches)
807class ProductToHasBranchesAdapter(object):805class ProductToHasBranchesAdapter:
808 def __init__(self, context):806 def __init__(self, context):
809 self.context = context807 self.context = context
810808
@@ -876,7 +874,7 @@ class TestEntryMultiversion(TestCaseWithWebServiceFixtures):
876 interfaces = generate_entry_interfaces(874 interfaces = generate_entry_interfaces(
877 INotInitiallyExported,875 INotInitiallyExported,
878 [],876 [],
879 *getUtility(IWebServiceConfiguration).active_versions877 *getUtility(IWebServiceConfiguration).active_versions,
880 )878 )
881 self.assertEqual(len(interfaces), 1)879 self.assertEqual(len(interfaces), 1)
882 self.assertEqual(interfaces[0].version, "2.0")880 self.assertEqual(interfaces[0].version, "2.0")
@@ -887,7 +885,7 @@ class TestEntryMultiversion(TestCaseWithWebServiceFixtures):
887 interfaces = generate_entry_interfaces(885 interfaces = generate_entry_interfaces(
888 INotPresentInLaterVersion,886 INotPresentInLaterVersion,
889 [],887 [],
890 *getUtility(IWebServiceConfiguration).active_versions888 *getUtility(IWebServiceConfiguration).active_versions,
891 )889 )
892 self.assertEqual(len(interfaces), 1)890 self.assertEqual(len(interfaces), 1)
893 self.assertEqual(interfaces[0].version, "1.0")891 self.assertEqual(interfaces[0].version, "1.0")
@@ -898,7 +896,7 @@ class TestEntryMultiversion(TestCaseWithWebServiceFixtures):
898 interfaces = generate_entry_interfaces(896 interfaces = generate_entry_interfaces(
899 IHasDifferentNamesInDifferentVersions,897 IHasDifferentNamesInDifferentVersions,
900 [],898 [],
901 *getUtility(IWebServiceConfiguration).active_versions899 *getUtility(IWebServiceConfiguration).active_versions,
902 )900 )
903 interface_10 = interfaces[0].object901 interface_10 = interfaces[0].object
904 tags_10 = interface_10.getTaggedValue(LAZR_WEBSERVICE_NAME)902 tags_10 = interface_10.getTaggedValue(LAZR_WEBSERVICE_NAME)
@@ -936,7 +934,7 @@ class TestEntryMultiversion(TestCaseWithWebServiceFixtures):
936 interfaces = generate_entry_interfaces(934 interfaces = generate_entry_interfaces(
937 IHasDifferentSingularNamesInDifferentVersions,935 IHasDifferentSingularNamesInDifferentVersions,
938 [],936 [],
939 *getUtility(IWebServiceConfiguration).active_versions937 *getUtility(IWebServiceConfiguration).active_versions,
940 )938 )
941 interface_10 = interfaces[0].object939 interface_10 = interfaces[0].object
942 tags_10 = interface_10.getTaggedValue(LAZR_WEBSERVICE_NAME)940 tags_10 = interface_10.getTaggedValue(LAZR_WEBSERVICE_NAME)
@@ -1024,7 +1022,7 @@ class IFieldExplicitOperationDefinition(Interface):
10241022
10251023
1026@implementer(IFieldExplicitOperationDefinition)1024@implementer(IFieldExplicitOperationDefinition)
1027class FieldExplicitOperationDefinition(object):1025class FieldExplicitOperationDefinition:
1028 pass1026 pass
10291027
10301028
@@ -1032,7 +1030,7 @@ class TestRequireExplicitVersions(TestCaseWithWebServiceFixtures):
1032 """Test behavior when require_explicit_versions is True."""1030 """Test behavior when require_explicit_versions is True."""
10331031
1034 def setUp(self):1032 def setUp(self):
1035 super(TestRequireExplicitVersions, self).setUp()1033 super().setUp()
1036 self.utility = getUtility(IWebServiceConfiguration)1034 self.utility = getUtility(IWebServiceConfiguration)
1037 self.utility.require_explicit_versions = True1035 self.utility.require_explicit_versions = True
10381036
@@ -1061,7 +1059,7 @@ class TestRequireExplicitVersions(TestCaseWithWebServiceFixtures):
1061 generate_entry_interfaces,1059 generate_entry_interfaces,
1062 IEntryExportedWithoutAsOf,1060 IEntryExportedWithoutAsOf,
1063 [],1061 [],
1064 *self.utility.active_versions1062 *self.utility.active_versions,
1065 )1063 )
1066 self.assertEqual(1064 self.assertEqual(
1067 str(exception),1065 str(exception),
@@ -1078,7 +1076,7 @@ class TestRequireExplicitVersions(TestCaseWithWebServiceFixtures):
1078 interfaces = generate_entry_interfaces(1076 interfaces = generate_entry_interfaces(
1079 IFieldExportedToEarliestVersionUsingAsOf,1077 IFieldExportedToEarliestVersionUsingAsOf,
1080 [],1078 [],
1081 *self.utility.active_versions1079 *self.utility.active_versions,
1082 )1080 )
1083 interface_10 = interfaces[0].object1081 interface_10 = interfaces[0].object
1084 interface_20 = interfaces[1].object1082 interface_20 = interfaces[1].object
@@ -1093,7 +1091,7 @@ class TestRequireExplicitVersions(TestCaseWithWebServiceFixtures):
1093 interfaces = generate_entry_interfaces(1091 interfaces = generate_entry_interfaces(
1094 IFieldExportedToLatestVersionUsingAsOf,1092 IFieldExportedToLatestVersionUsingAsOf,
1095 [],1093 [],
1096 *self.utility.active_versions1094 *self.utility.active_versions,
1097 )1095 )
1098 interface_10 = interfaces[0].object1096 interface_10 = interfaces[0].object
1099 interface_20 = interfaces[1].object1097 interface_20 = interfaces[1].object
@@ -1108,7 +1106,7 @@ class TestRequireExplicitVersions(TestCaseWithWebServiceFixtures):
1108 generate_entry_interfaces,1106 generate_entry_interfaces,
1109 IFieldExportedWithoutAsOf,1107 IFieldExportedWithoutAsOf,
1110 [],1108 [],
1111 *self.utility.active_versions1109 *self.utility.active_versions,
1112 )1110 )
1113 self.assertEqual(1111 self.assertEqual(
1114 str(exception),1112 str(exception),
@@ -1140,7 +1138,7 @@ class TestRequireExplicitVersions(TestCaseWithWebServiceFixtures):
1140 generate_entry_interfaces,1138 generate_entry_interfaces,
1141 IFieldAsOfNonexistentVersion,1139 IFieldAsOfNonexistentVersion,
1142 [],1140 [],
1143 *self.utility.active_versions1141 *self.utility.active_versions,
1144 )1142 )
1145 self.assertEqual(1143 self.assertEqual(
1146 str(exception),1144 str(exception),
@@ -1158,7 +1156,7 @@ class TestRequireExplicitVersions(TestCaseWithWebServiceFixtures):
1158 generate_entry_interfaces,1156 generate_entry_interfaces,
1159 IFieldDoubleDefinition,1157 IFieldDoubleDefinition,
1160 [],1158 [],
1161 *self.utility.active_versions1159 *self.utility.active_versions,
1162 )1160 )
1163 self.assertEqual(1161 self.assertEqual(
1164 str(exception),1162 str(exception),
@@ -1176,7 +1174,7 @@ class TestRequireExplicitVersions(TestCaseWithWebServiceFixtures):
1176 generate_entry_interfaces,1174 generate_entry_interfaces,
1177 IFieldDefiningAttributesBeforeAsOf,1175 IFieldDefiningAttributesBeforeAsOf,
1178 [],1176 [],
1179 *self.utility.active_versions1177 *self.utility.active_versions,
1180 )1178 )
1181 self.assertEqual(1179 self.assertEqual(
1182 str(exception),1180 str(exception),
@@ -1370,7 +1368,7 @@ class TestCoherenceChecking(TestCaseWithWebServiceFixtures):
1370 ValueError,1368 ValueError,
1371 register_test_module,1369 register_test_module,
1372 "testmod",1370 "testmod",
1373 *(list(classes) + [expect_failure_due_to_interface])1371 *(list(classes) + [expect_failure_due_to_interface]),
1374 )1372 )
1375 expected_message = (1373 expected_message = (
1376 "In version %(version)s, %(reason)s, but version %(version)s "1374 "In version %(version)s, %(reason)s, but version %(version)s "
diff --git a/src/lazr/restful/tests/test_docs.py b/src/lazr/restful/tests/test_docs.py
index a503ae6..26f9645 100644
--- a/src/lazr/restful/tests/test_docs.py
+++ b/src/lazr/restful/tests/test_docs.py
@@ -17,9 +17,6 @@
1717
18# pylint: disable=E0611,W014218# pylint: disable=E0611,W0142
1919
20from __future__ import absolute_import, print_function
21
22__metaclass__ = type
23__all__ = []20__all__ = []
2421
25import atexit22import atexit
@@ -66,19 +63,14 @@ def load_tests(loader, tests, pattern):
66 )63 )
67 )64 )
68 atexit.register(cleanup_resources)65 atexit.register(cleanup_resources)
69 globs = {
70 "absolute_import": absolute_import,
71 "print_function": print_function,
72 }
73 tests.addTest(66 tests.addTest(
74 doctest.DocFileSuite(67 doctest.DocFileSuite(
75 *doctest_files,68 *doctest_files,
76 module_relative=False,69 module_relative=False,
77 optionflags=DOCTEST_FLAGS,70 optionflags=DOCTEST_FLAGS,
78 tearDown=tearDown,71 tearDown=tearDown,
79 globs=globs,
80 encoding="UTF-8",72 encoding="UTF-8",
81 checker=checker73 checker=checker,
82 )74 )
83 )75 )
84 return tests76 return tests
diff --git a/src/lazr/restful/tests/test_error.py b/src/lazr/restful/tests/test_error.py
index d407ccb..69adf07 100644
--- a/src/lazr/restful/tests/test_error.py
+++ b/src/lazr/restful/tests/test_error.py
@@ -2,10 +2,6 @@
22
3"""Tests of lazr.restful navigation."""3"""Tests of lazr.restful navigation."""
44
5from __future__ import absolute_import, print_function
6
7__metaclass__ = type
8
9from pkg_resources import resource_filename5from pkg_resources import resource_filename
10import os6import os
11import traceback7import traceback
@@ -30,7 +26,7 @@ from lazr.restful.testing.webservice import FakeRequest
30class TestResource(ReadWriteResource):26class TestResource(ReadWriteResource):
31 def __init__(self, callable, request):27 def __init__(self, callable, request):
32 self.callable = callable28 self.callable = callable
33 super(TestResource, self).__init__(context=None, request=request)29 super().__init__(context=None, request=request)
3430
35 def do_GET(self):31 def do_GET(self):
36 return self.callable()32 return self.callable()
@@ -57,7 +53,7 @@ class ErrorsTestCase(unittest.TestCase):
57 pass53 pass
5854
59 self.exception_class = MyException55 self.exception_class = MyException
60 super(ErrorsTestCase, self).setUp()56 super().setUp()
6157
62 def test_decorated_exception_class_becomes_error_view(self):58 def test_decorated_exception_class_becomes_error_view(self):
63 # An exposed exception, when raised, will set the response59 # An exposed exception, when raised, will set the response
@@ -140,7 +136,7 @@ class ErrorsTestCase(unittest.TestCase):
140 # Register a view for the exception that does not subclass136 # Register a view for the exception that does not subclass
141 # WebServiceExceptionView and provides no information about137 # WebServiceExceptionView and provides no information about
142 # which HTTP status code should be used.138 # which HTTP status code should be used.
143 class ViewHasNoStatus(object):139 class ViewHasNoStatus:
144 def __init__(*args):140 def __init__(*args):
145 pass141 pass
146142
diff --git a/src/lazr/restful/tests/test_etag.py b/src/lazr/restful/tests/test_etag.py
index ed9a950..e9421a0 100644
--- a/src/lazr/restful/tests/test_etag.py
+++ b/src/lazr/restful/tests/test_etag.py
@@ -1,10 +1,6 @@
1# Copyright 2008 Canonical Ltd. All rights reserved.1# Copyright 2008 Canonical Ltd. All rights reserved.
2"""Tests for ETag generation."""2"""Tests for ETag generation."""
33
4from __future__ import absolute_import, print_function
5
6__metaclass__ = type
7
8from collections import OrderedDict4from collections import OrderedDict
9from datetime import (5from datetime import (
10 date,6 date,
@@ -178,11 +174,11 @@ class EntryFieldResourceTests(unittest.TestCase):
178 self.set_field_value("this is the field value")174 self.set_field_value("this is the field value")
179175
180 # Find the cores generated with a given revision...176 # Find the cores generated with a given revision...
181 self.config.code_revision = u"42"177 self.config.code_revision = "42"
182 first_cores = self.resource._getETagCores(self.resource.JSON_TYPE)178 first_cores = self.resource._getETagCores(self.resource.JSON_TYPE)
183179
184 # ...find the cores generated with a different revision.180 # ...find the cores generated with a different revision.
185 self.config.code_revision = u"99"181 self.config.code_revision = "99"
186 second_cores = self.resource._getETagCores(self.resource.JSON_TYPE)182 second_cores = self.resource._getETagCores(self.resource.JSON_TYPE)
187183
188 # The cores should be different.184 # The cores should be different.
@@ -223,11 +219,11 @@ class ServiceRootResourceTests(unittest.TestCase):
223 # web service change.219 # web service change.
224220
225 # Find the cores generated with a given revision...221 # Find the cores generated with a given revision...
226 self.config.code_revision = u"42"222 self.config.code_revision = "42"
227 first_cores = self.resource._getETagCores(self.resource.JSON_TYPE)223 first_cores = self.resource._getETagCores(self.resource.JSON_TYPE)
228224
229 # ...find the cores generated with a different revision.225 # ...find the cores generated with a different revision.
230 self.config.code_revision = u"99"226 self.config.code_revision = "99"
231 second_cores = self.resource._getETagCores(self.resource.JSON_TYPE)227 second_cores = self.resource._getETagCores(self.resource.JSON_TYPE)
232228
233 # The cores should be different.229 # The cores should be different.
@@ -240,12 +236,12 @@ class ServiceRootResourceTests(unittest.TestCase):
240 # information.)236 # information.)
241237
242 # Find the ETag generated with a given revision...238 # Find the ETag generated with a given revision...
243 self.config.code_revision = u"42"239 self.config.code_revision = "42"
244 first_etag = self.resource.getETag(self.resource.WADL_TYPE)240 first_etag = self.resource.getETag(self.resource.WADL_TYPE)
245241
246 # ...and find the ETag generated with a different revision.242 # ...and find the ETag generated with a different revision.
247 self.resource.etags_by_media_type = {}243 self.resource.etags_by_media_type = {}
248 self.config.code_revision = u"99"244 self.config.code_revision = "99"
249 second_etag = self.resource.getETag(self.resource.WADL_TYPE)245 second_etag = self.resource.getETag(self.resource.WADL_TYPE)
250246
251 # The ETags should be different.247 # The ETags should be different.
diff --git a/src/lazr/restful/tests/test_navigation.py b/src/lazr/restful/tests/test_navigation.py
index 568205e..ec5cc6d 100644
--- a/src/lazr/restful/tests/test_navigation.py
+++ b/src/lazr/restful/tests/test_navigation.py
@@ -2,10 +2,6 @@
22
3"""Tests of lazr.restful navigation."""3"""Tests of lazr.restful navigation."""
44
5from __future__ import absolute_import, print_function
6
7__metaclass__ = type
8
9import unittest5import unittest
106
11from zope.component import (7from zope.component import (
@@ -34,14 +30,14 @@ from lazr.restful.testing.webservice import FakeRequest
34class IChild(Interface):30class IChild(Interface):
35 """Interface for a simple entry."""31 """Interface for a simple entry."""
3632
37 one = Text(title=u"One")33 one = Text(title="One")
38 two = Text(title=u"Two")34 two = Text(title="Two")
3935
4036
41class IParent(Interface):37class IParent(Interface):
42 """Interface for a simple entry that contains another entry."""38 """Interface for a simple entry that contains another entry."""
4339
44 three = Text(title=u"Three")40 three = Text(title="Three")
45 child = Reference(schema=IChild)41 child = Reference(schema=IChild)
4642
4743
@@ -49,8 +45,8 @@ class IParent(Interface):
49class Child:45class Child:
50 """A simple implementation of IChild."""46 """A simple implementation of IChild."""
5147
52 one = u"one"48 one = "one"
53 two = u"two"49 two = "two"
5450
5551
56class ChildEntry:52class ChildEntry:
@@ -66,7 +62,7 @@ class ChildEntry:
66class Parent:62class Parent:
67 """A simple implementation of IParent."""63 """A simple implementation of IParent."""
6864
69 three = u"three"65 three = "three"
70 child = Child()66 child = Child()
7167
7268
diff --git a/src/lazr/restful/tests/test_utils.py b/src/lazr/restful/tests/test_utils.py
index d095e02..db180d0 100644
--- a/src/lazr/restful/tests/test_utils.py
+++ b/src/lazr/restful/tests/test_utils.py
@@ -2,10 +2,6 @@
22
3"""Test for lazr.restful.utils."""3"""Test for lazr.restful.utils."""
44
5from __future__ import absolute_import, print_function
6
7__metaclass__ = type
8
9import random5import random
10import testtools6import testtools
11import unittest7import unittest
@@ -101,7 +97,7 @@ class TestUtils(unittest.TestCase):
10197
102class TestVersionedDict(testtools.TestCase):98class TestVersionedDict(testtools.TestCase):
103 def setUp(self):99 def setUp(self):
104 super(TestVersionedDict, self).setUp()100 super().setUp()
105 self.dict = VersionedDict()101 self.dict = VersionedDict()
106102
107 def test_rename_version_works(self):103 def test_rename_version_works(self):
diff --git a/src/lazr/restful/tests/test_webservice.py b/src/lazr/restful/tests/test_webservice.py
index 4864150..e8c8010 100644
--- a/src/lazr/restful/tests/test_webservice.py
+++ b/src/lazr/restful/tests/test_webservice.py
@@ -2,10 +2,6 @@
22
3"""Test for the WADL generation."""3"""Test for the WADL generation."""
44
5from __future__ import absolute_import, print_function
6
7__metaclass__ = type
8
9from contextlib import contextmanager5from contextlib import contextmanager
10from io import (6from io import (
11 BytesIO,7 BytesIO,
@@ -19,7 +15,6 @@ import re
19import simplejson15import simplejson
20import unittest16import unittest
2117
22import six
23from zope.component import (18from zope.component import (
24 eventtesting,19 eventtesting,
25 getGlobalSiteManager,20 getGlobalSiteManager,
@@ -256,7 +251,7 @@ class EntryTestCase(WebServiceTestCase):
256class IHasOneField(Interface):251class IHasOneField(Interface):
257 """An entry with a single field."""252 """An entry with a single field."""
258253
259 a_field = exported(TextLine(title=u"A field."))254 a_field = exported(TextLine(title="A field."))
260255
261256
262@implementer(IHasOneField)257@implementer(IHasOneField)
@@ -271,8 +266,8 @@ class HasOneField:
271class IHasTwoFields(Interface):266class IHasTwoFields(Interface):
272 """An entry with two fields."""267 """An entry with two fields."""
273268
274 a_field = exported(TextLine(title=u"A field."))269 a_field = exported(TextLine(title="A field."))
275 another_field = exported(TextLine(title=u"Another field."))270 another_field = exported(TextLine(title="Another field."))
276271
277272
278@implementer(IHasTwoFields)273@implementer(IHasTwoFields)
@@ -353,7 +348,7 @@ class TestEntryWebLink(EntryTestCase):
353class IHasNoWebLink(Interface):348class IHasNoWebLink(Interface):
354 """An entry that does not publish a web_link."""349 """An entry that does not publish a web_link."""
355350
356 a_field = exported(TextLine(title=u"A field."))351 a_field = exported(TextLine(title="A field."))
357352
358353
359@implementer(IHasNoWebLink)354@implementer(IHasNoWebLink)
@@ -383,7 +378,7 @@ class InterfaceRestrictedField(TextLine):
383378
384 def __init__(self, restrict_to_interface, *args, **kwargs):379 def __init__(self, restrict_to_interface, *args, **kwargs):
385 self.restrict_to_interface = restrict_to_interface380 self.restrict_to_interface = restrict_to_interface
386 super(InterfaceRestrictedField, self).__init__(*args, **kwargs)381 super().__init__(*args, **kwargs)
387382
388 def bind(self, context):383 def bind(self, context):
389 if not self.restrict_to_interface.providedBy(context):384 if not self.restrict_to_interface.providedBy(context):
@@ -391,7 +386,7 @@ class InterfaceRestrictedField(TextLine):
391 "InterfaceRestrictedField can only be used with %s"386 "InterfaceRestrictedField can only be used with %s"
392 % self.restrict_to_interface.__name__387 % self.restrict_to_interface.__name__
393 )388 )
394 return super(InterfaceRestrictedField, self).bind(context)389 return super().bind(context)
395390
396391
397@exported_as_webservice_entry()392@exported_as_webservice_entry()
@@ -413,7 +408,7 @@ class HasRestrictedField:
413class IHasFieldExportedAsDifferentName(Interface):408class IHasFieldExportedAsDifferentName(Interface):
414 """An entry with a field exported as a different name."""409 """An entry with a field exported as a different name."""
415410
416 a_field = exported(TextLine(title=u"A field."), exported_as="field")411 a_field = exported(TextLine(title="A field."), exported_as="field")
417412
418413
419@implementer(IHasFieldExportedAsDifferentName)414@implementer(IHasFieldExportedAsDifferentName)
@@ -437,7 +432,7 @@ class TestEntryWrite(EntryTestCase):
437 # If web_link is not published, applyChanges rejects a request432 # If web_link is not published, applyChanges rejects a request
438 # that references it.433 # that references it.
439 with self.entry_resource(HasOneField, "") as resource:434 with self.entry_resource(HasOneField, "") as resource:
440 errors = resource.applyChanges({"web_link": u"some_value"})435 errors = resource.applyChanges({"web_link": "some_value"})
441 self.assertEqual(436 self.assertEqual(
442 errors,437 errors,
443 "web_link: You tried to modify a nonexistent attribute.",438 "web_link: You tried to modify a nonexistent attribute.",
@@ -448,7 +443,7 @@ class TestEntryWrite(EntryTestCase):
448 self._register_website_url_space(IHasOneField)443 self._register_website_url_space(IHasOneField)
449444
450 with self.entry_resource(HasOneField, "") as resource:445 with self.entry_resource(HasOneField, "") as resource:
451 errors = resource.applyChanges({"web_link": u"some_value"})446 errors = resource.applyChanges({"web_link": "some_value"})
452 self.assertEqual(447 self.assertEqual(
453 errors, "web_link: You tried to modify a read-only attribute."448 errors, "web_link: You tried to modify a read-only attribute."
454 )449 )
@@ -484,7 +479,7 @@ class TestEntryWrite(EntryTestCase):
484479
485 with self.entry_resource(480 with self.entry_resource(
486 HasFieldExportedAsDifferentName,481 HasFieldExportedAsDifferentName,
487 u"initial value",482 "initial value",
488 ) as resource:483 ) as resource:
489 # We have an entry that has a different name on the484 # We have an entry that has a different name on the
490 # entry than on its context.485 # entry than on its context.
@@ -492,13 +487,13 @@ class TestEntryWrite(EntryTestCase):
492 self.assertEqual(entry.field, entry.context.a_field)487 self.assertEqual(entry.field, entry.context.a_field)
493 # This populates the cache.488 # This populates the cache.
494 self.assertEqual(489 self.assertEqual(
495 u"initial value", resource.toDataForJSON()["field"]490 "initial value", resource.toDataForJSON()["field"]
496 )491 )
497 # This returns the changed value.492 # This returns the changed value.
498 representation = simplejson.loads(493 representation = simplejson.loads(
499 resource.applyChanges(dict(field=u"new value"))494 resource.applyChanges(dict(field="new value"))
500 )495 )
501 self.assertEqual(u"new value", representation["field"])496 self.assertEqual("new value", representation["field"])
502497
503498
504class TestEntryWriteForRestrictedField(EntryTestCase):499class TestEntryWriteForRestrictedField(EntryTestCase):
@@ -518,7 +513,7 @@ class TestEntryWriteForRestrictedField(EntryTestCase):
518 entry = resource.entry513 entry = resource.entry
519 entry.schema["a_field"].restrict_to_interface = IHasRestrictedField514 entry.schema["a_field"].restrict_to_interface = IHasRestrictedField
520 self.assertEqual(entry.a_field, "")515 self.assertEqual(entry.a_field, "")
521 resource.applyChanges({"a_field": u"a_value"})516 resource.applyChanges({"a_field": "a_value"})
522 self.assertEqual(entry.a_field, "a_value")517 self.assertEqual(entry.a_field, "a_value")
523518
524 # Make sure that IHasRestrictedField itself works correctly.519 # Make sure that IHasRestrictedField itself works correctly.
@@ -531,7 +526,7 @@ class TestEntryWriteForRestrictedField(EntryTestCase):
531 self.assertRaises(526 self.assertRaises(
532 AssertionError,527 AssertionError,
533 resource.applyChanges,528 resource.applyChanges,
534 {"a_field": u"a_new_value"},529 {"a_field": "a_new_value"},
535 )530 )
536 self.assertEqual(resource.entry.a_field, "a_value")531 self.assertEqual(resource.entry.a_field, "a_value")
537532
@@ -542,9 +537,9 @@ class HTMLRepresentationTest(EntryTestCase):
542 default_media_type = "application/xhtml+xml"537 default_media_type = "application/xhtml+xml"
543538
544 def setUp(self):539 def setUp(self):
545 super(HTMLRepresentationTest, self).setUp()540 super().setUp()
546 self._register_url_adapter(IHasOneField)541 self._register_url_adapter(IHasOneField)
547 self.unicode_message = u"Hello from a \N{SNOWMAN}"542 self.unicode_message = "Hello from a \N{SNOWMAN}"
548 self.utf8_message = self.unicode_message.encode("utf-8")543 self.utf8_message = self.unicode_message.encode("utf-8")
549544
550 def test_entry_html_representation_is_utf8(self):545 def test_entry_html_representation_is_utf8(self):
@@ -567,15 +562,13 @@ class JSONPlusHTMLRepresentationTest(EntryTestCase):
567 testmodule_objects = [HasTwoFields, IHasTwoFields]562 testmodule_objects = [HasTwoFields, IHasTwoFields]
568563
569 def setUp(self):564 def setUp(self):
570 super(JSONPlusHTMLRepresentationTest, self).setUp()565 super().setUp()
571 self.default_media_type = "application/json;include=lp_html"566 self.default_media_type = "application/json;include=lp_html"
572 self._register_url_adapter(IHasTwoFields)567 self._register_url_adapter(IHasTwoFields)
573568
574 def register_html_field_renderer(self, name=""):569 def register_html_field_renderer(self, name=""):
575 """Simplify the register_html_field_renderer call."""570 """Simplify the register_html_field_renderer call."""
576 super(571 super().register_html_field_renderer(
577 JSONPlusHTMLRepresentationTest, self
578 ).register_html_field_renderer(
579 IHasTwoFields, ITextLine, simple_renderer, name572 IHasTwoFields, ITextLine, simple_renderer, name
580 )573 )
581574
@@ -584,8 +577,8 @@ class JSONPlusHTMLRepresentationTest(EntryTestCase):
584 """Simplify the entry_resource call."""577 """Simplify the entry_resource call."""
585 with self.entry_resource(578 with self.entry_resource(
586 HasTwoFields,579 HasTwoFields,
587 six.text_type(value_1),580 str(value_1),
588 six.text_type(value_2),581 str(value_2),
589 ) as resource:582 ) as resource:
590 yield resource583 yield resource
591584
@@ -654,7 +647,7 @@ class JSONPlusHTMLRepresentationTest(EntryTestCase):
654 with self.resource() as resource:647 with self.resource() as resource:
655 json_plus_xhtml = resource.JSON_PLUS_XHTML_TYPE648 json_plus_xhtml = resource.JSON_PLUS_XHTML_TYPE
656 json = simplejson.loads(649 json = simplejson.loads(
657 six.text_type(resource._representation(json_plus_xhtml))650 str(resource._representation(json_plus_xhtml))
658 )651 )
659 resource.applyChanges(json, json_plus_xhtml)652 resource.applyChanges(json, json_plus_xhtml)
660 self.assertEqual(resource.request.response.getStatus(), 209)653 self.assertEqual(resource.request.response.getStatus(), 209)
@@ -664,9 +657,7 @@ class JSONPlusHTMLRepresentationTest(EntryTestCase):
664 json = None657 json = None
665 with self.resource() as resource:658 with self.resource() as resource:
666 json = simplejson.loads(659 json = simplejson.loads(
667 six.text_type(660 str(resource._representation(resource.JSON_PLUS_XHTML_TYPE))
668 resource._representation(resource.JSON_PLUS_XHTML_TYPE)
669 )
670 )661 )
671 resource.applyChanges(json, resource.JSON_TYPE)662 resource.applyChanges(json, resource.JSON_TYPE)
672 self.assertEqual(resource.request.response.getStatus(), 400)663 self.assertEqual(resource.request.response.getStatus(), 400)
@@ -676,7 +667,7 @@ class UnicodeChoice(EnumeratedType):
676 """A choice between an ASCII value and a Unicode value."""667 """A choice between an ASCII value and a Unicode value."""
677668
678 ASCII = Item("Ascii", "Ascii choice")669 ASCII = Item("Ascii", "Ascii choice")
679 UNICODE = Item(u"Uni\u00e7ode", "Uni\u00e7ode choice")670 UNICODE = Item("Uni\u00e7ode", "Uni\u00e7ode choice")
680671
681672
682@exported_as_webservice_entry()673@exported_as_webservice_entry()
@@ -686,7 +677,7 @@ class ICanBeSetToUnicodeValue(Interface):
686 a_field = exported(677 a_field = exported(
687 Choice(678 Choice(
688 vocabulary=UnicodeChoice,679 vocabulary=UnicodeChoice,
689 title=u"A value that might be ASCII or Unicode.",680 title="A value that might be ASCII or Unicode.",
690 required=False,681 required=False,
691 default=None,682 default=None,
692 )683 )
@@ -707,7 +698,7 @@ class UnicodeErrorTestCase(EntryTestCase):
707 testmodule_objects = [CanBeSetToUnicodeValue, ICanBeSetToUnicodeValue]698 testmodule_objects = [CanBeSetToUnicodeValue, ICanBeSetToUnicodeValue]
708699
709 def setUp(self):700 def setUp(self):
710 super(UnicodeErrorTestCase, self).setUp()701 super().setUp()
711 self._register_url_adapter(ICanBeSetToUnicodeValue)702 self._register_url_adapter(ICanBeSetToUnicodeValue)
712703
713 def test_unicode_error(self):704 def test_unicode_error(self):
@@ -715,14 +706,14 @@ class UnicodeErrorTestCase(EntryTestCase):
715706
716 # This will raise an exception, which will cause the request707 # This will raise an exception, which will cause the request
717 # to fail with a 400 error code.708 # to fail with a 400 error code.
718 error = resource.applyChanges({"a_field": u"No such value"})709 error = resource.applyChanges({"a_field": "No such value"})
719 self.assertEqual(resource.request.response.getStatus(), 400)710 self.assertEqual(resource.request.response.getStatus(), 400)
720711
721 # The error message is a Unicode string which mentions both712 # The error message is a Unicode string which mentions both
722 # the ASCII value and the Unicode value,713 # the ASCII value and the Unicode value,
723 expected_error = (714 expected_error = (
724 u'a_field: Invalid value "No such value". Acceptable values '715 'a_field: Invalid value "No such value". Acceptable values '
725 u"are: Ascii, Uni\u00e7ode"716 "are: Ascii, Uni\u00e7ode"
726 )717 )
727 self.assertEqual(error, expected_error)718 self.assertEqual(error, expected_error)
728719
@@ -887,7 +878,7 @@ class DuplicateNameTestCase(WebServiceTestCase):
887def make_entry(name):878def make_entry(name):
888 """Make an entity with some attibutes to expose as a web service."""879 """Make an entity with some attibutes to expose as a web service."""
889 fields = {880 fields = {
890 "%s_field" % letter: exported(TextLine(title=u"Field %s" % letter))881 "%s_field" % letter: exported(TextLine(title="Field %s" % letter))
891 for letter in "rstuvwxyz"882 for letter in "rstuvwxyz"
892 }883 }
893 cls = InterfaceClass(name, bases=(Interface,), attrs=fields)884 cls = InterfaceClass(name, bases=(Interface,), attrs=fields)
@@ -901,7 +892,7 @@ class TestWadlDeterminism(WebServiceTestCase):
901 # make some -- randomly ordered -- objects to use to build the WADL892 # make some -- randomly ordered -- objects to use to build the WADL
902 self.testmodule_objects = [make_entry(name) for name in "abcdefghijk"]893 self.testmodule_objects = [make_entry(name) for name in "abcdefghijk"]
903 random.shuffle(self.testmodule_objects)894 random.shuffle(self.testmodule_objects)
904 super(TestWadlDeterminism, self).__init__(*args, **kwargs)895 super().__init__(*args, **kwargs)
905896
906 @property897 @property
907 def wadl(self):898 def wadl(self):
@@ -1026,7 +1017,7 @@ class BaseBatchingTest:
1026 testmodule_objects = [HasRestrictedField, IHasRestrictedField]1017 testmodule_objects = [HasRestrictedField, IHasRestrictedField]
10271018
1028 def setUp(self):1019 def setUp(self):
1029 super(BaseBatchingTest, self).setUp()1020 super().setUp()
1030 # Register TestEntry as the IEntry implementation for ITestEntry.1021 # Register TestEntry as the IEntry implementation for ITestEntry.
1031 getGlobalSiteManager().registerAdapter(1022 getGlobalSiteManager().registerAdapter(
1032 TestEntry, [ITestEntry, IWebServiceClientRequest], provided=IEntry1023 TestEntry, [ITestEntry, IWebServiceClientRequest], provided=IEntry
@@ -1100,7 +1091,7 @@ class NotificationsProviderTest(EntryTestCase):
1100 ]1091 ]
11011092
1102 def setUp(self):1093 def setUp(self):
1103 super(NotificationsProviderTest, self).setUp()1094 super().setUp()
1104 self.default_media_type = "application/json;include=lp_html"1095 self.default_media_type = "application/json;include=lp_html"
1105 self._register_website_url_space(IHasOneField)1096 self._register_website_url_space(IHasOneField)
1106 self._register_notification_adapter()1097 self._register_notification_adapter()
@@ -1146,7 +1137,7 @@ class EventTestCase(EntryTestCase):
1146 testmodule_objects = [IHasOneField]1137 testmodule_objects = [IHasOneField]
11471138
1148 def setUp(self):1139 def setUp(self):
1149 super(EventTestCase, self).setUp()1140 super().setUp()
1150 self._register_url_adapter(IHasOneField)1141 self._register_url_adapter(IHasOneField)
1151 eventtesting.setUp()1142 eventtesting.setUp()
11521143
@@ -1154,7 +1145,7 @@ class EventTestCase(EntryTestCase):
1154 # Passing in a non-empty changeset spawns an1145 # Passing in a non-empty changeset spawns an
1155 # IObjectModifiedEvent.1146 # IObjectModifiedEvent.
1156 with self.entry_resource(HasOneField, "") as resource:1147 with self.entry_resource(HasOneField, "") as resource:
1157 resource.applyChanges({"a_field": u"Some value"})1148 resource.applyChanges({"a_field": "Some value"})
1158 events = eventtesting.getEvents()1149 events = eventtesting.getEvents()
1159 self.assertEqual(len(events), 1)1150 self.assertEqual(len(events), 1)
1160 event = events[0]1151 event = events[0]
@@ -1175,9 +1166,9 @@ class MalformedRequest(EntryTestCase):
1175 default_media_type = "application/xhtml+xml"1166 default_media_type = "application/xhtml+xml"
11761167
1177 def setUp(self):1168 def setUp(self):
1178 super(MalformedRequest, self).setUp()1169 super().setUp()
1179 self._register_url_adapter(IHasOneField)1170 self._register_url_adapter(IHasOneField)
1180 self.unicode_message = u"Hello from a \N{SNOWMAN}"1171 self.unicode_message = "Hello from a \N{SNOWMAN}"
11811172
1182 def test_multiple_named_operations_generate_error_on_GET(self):1173 def test_multiple_named_operations_generate_error_on_GET(self):
1183 with self.entry_resource(1174 with self.entry_resource(
diff --git a/src/lazr/restful/utils.py b/src/lazr/restful/utils.py
index 043ed87..2175977 100644
--- a/src/lazr/restful/utils.py
+++ b/src/lazr/restful/utils.py
@@ -2,9 +2,6 @@
22
3"""Various utility functions."""3"""Various utility functions."""
44
5from __future__ import absolute_import, print_function
6
7__metaclass__ = type
8__all__ = [5__all__ = [
9 "camelcase_to_underscore_separated",6 "camelcase_to_underscore_separated",
10 "get_current_browser_request",7 "get_current_browser_request",
@@ -20,7 +17,7 @@ __all__ = [
20 "VersionedObject",17 "VersionedObject",
21]18]
2219
2320import builtins
24import collections21import collections
25import copy22import copy
26import operator23import operator
@@ -28,8 +25,6 @@ import re
28import string25import string
29import subprocess26import subprocess
3027
31import six
32
33from zope.component import getUtility28from zope.component import getUtility
34from zope.schema import getFieldsInOrder29from zope.schema import getFieldsInOrder
35from zope.interface import alsoProvides, classImplements30from zope.interface import alsoProvides, classImplements
@@ -134,7 +129,7 @@ VersionedObject = collections.namedtuple(
134)129)
135130
136131
137class VersionedDict(object):132class VersionedDict:
138 """A stack of named dictionaries.133 """A stack of named dictionaries.
139134
140 Most access to the stack actually operates on the dictionary on135 Most access to the stack actually operates on the dictionary on
@@ -368,9 +363,11 @@ def safe_hasattr(ob, name):
368363
369def smartquote(str):364def smartquote(str):
370 """Return a copy of the string, with typographical quote marks applied."""365 """Return a copy of the string, with typographical quote marks applied."""
371 str = six.text_type(str)366 # Using builtins.str here is weird, but it lets us cope with the
372 str = re.compile(u'(^| )(")([^" ])').sub(u"\\1\u201c\\3", str)367 # unfortunate naming of our positional argument without breaking API.
373 str = re.compile(u'([^ "])(")($|[\\s.,;:!?])').sub(u"\\1\u201d\\3", str)368 str = builtins.str(str)
369 str = re.compile('(^| )(")([^" ])').sub("\\1\u201c\\3", str)
370 str = re.compile('([^ "])(")($|[\\s.,;:!?])').sub("\\1\u201d\\3", str)
374 return str371 return str
375372
376373
diff --git a/src/lazr/restful/wsgi.py b/src/lazr/restful/wsgi.py
index 2b03ab3..fc298e0 100644
--- a/src/lazr/restful/wsgi.py
+++ b/src/lazr/restful/wsgi.py
@@ -1,8 +1,5 @@
1"""A WSGI application for a lazr.restful web service."""1"""A WSGI application for a lazr.restful web service."""
22
3from __future__ import absolute_import, print_function
4
5__metaclass__ = type
6__all__ = [3__all__ = [
7 "BaseWSGIWebServiceConfiguration",4 "BaseWSGIWebServiceConfiguration",
8 "WSGIApplication",5 "WSGIApplication",

Subscribers

People subscribed via source and target branches