Merge lp:~cjwatson/lazr.restful/json-publishable-date into lp:lazr.restful

Proposed by Colin Watson
Status: Merged
Merged at revision: 300
Proposed branch: lp:~cjwatson/lazr.restful/json-publishable-date
Merge into: lp:lazr.restful
Diff against target: 136 lines (+45/-2)
4 files modified
NEWS.rst (+2/-0)
src/lazr/restful/_resource.py (+16/-1)
src/lazr/restful/configure.zcml (+1/-0)
src/lazr/restful/tests/test_etag.py (+26/-1)
To merge this branch: bzr merge lp:~cjwatson/lazr.restful/json-publishable-date
Reviewer Review Type Date Requested Status
Thiago F. Pappacena (community) Approve
Review via email: mp+403064@code.launchpad.net

Commit message

Fix encoding of date(time) fields for ETags.

To post a comment you must log in.
Revision history for this message
Thiago F. Pappacena (pappacena) wrote :

LGTM

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'NEWS.rst'
2--- NEWS.rst 2021-05-18 16:49:19 +0000
3+++ NEWS.rst 2021-05-20 14:25:47 +0000
4@@ -15,6 +15,8 @@
5 Stabilize ETags of entries containing collections of strings between Python
6 2 and 3 (bug 1928474).
7
8+Add an ``IJSONPublishable`` adapter for ``date`` and ``datetime``.
9+
10 1.0.2 (2021-05-14)
11 ==================
12
13
14=== modified file 'src/lazr/restful/_resource.py'
15--- src/lazr/restful/_resource.py 2021-05-18 16:49:19 +0000
16+++ src/lazr/restful/_resource.py 2021-05-20 14:25:47 +0000
17@@ -17,6 +17,7 @@
18 'EntryHTMLView',
19 'EntryResource',
20 'HTTPResource',
21+ 'JSONDate',
22 'JSONItem',
23 'ReadOnlyResource',
24 'RedirectResource',
25@@ -71,6 +72,7 @@
26 providedBy,
27 Interface,
28 )
29+from zope.interface.common.idatetime import IDate
30 from zope.interface.common.sequence import IFiniteSequence
31 from zope.interface.interfaces import (
32 ComponentLookupError,
33@@ -160,7 +162,7 @@
34 elif isinstance(value, bytes):
35 return value.decode("utf-8")
36 else:
37- return simplejson.dumps(value)
38+ return simplejson.dumps(value, cls=ResourceJSONEncoder)
39
40
41 def _default_html_renderer(value):
42@@ -242,6 +244,19 @@
43 return str(self.context.title)
44
45
46+@implementer(IJSONPublishable)
47+@adapter(IDate)
48+class JSONDate:
49+ """JSONPublishable adapter for date/datetime."""
50+
51+ def __init__(self, context):
52+ self.context = context
53+
54+ def toDataForJSON(self, media_type):
55+ """See `IJSONPublishable`."""
56+ return self.context.isoformat()
57+
58+
59 @implementer(IHTTPResource)
60 class RedirectResource(URLDereferencingMixin):
61 """A resource that redirects to another URL."""
62
63=== modified file 'src/lazr/restful/configure.zcml'
64--- src/lazr/restful/configure.zcml 2012-03-13 02:03:47 +0000
65+++ src/lazr/restful/configure.zcml 2021-05-20 14:25:47 +0000
66@@ -136,6 +136,7 @@
67 <adapter factory="lazr.restful.ScopedCollection" />
68
69 <adapter factory="lazr.restful.JSONItem" />
70+ <adapter factory="lazr.restful.JSONDate" />
71
72 <!-- Adapter for URL generation -->
73 <adapter
74
75=== modified file 'src/lazr/restful/tests/test_etag.py'
76--- src/lazr/restful/tests/test_etag.py 2021-05-18 16:49:19 +0000
77+++ src/lazr/restful/tests/test_etag.py 2021-05-20 14:25:47 +0000
78@@ -6,8 +6,16 @@
79 __metaclass__ = type
80
81 from collections import OrderedDict
82+from datetime import (
83+ date,
84+ datetime,
85+ )
86+import os.path
87 import unittest
88
89+from pkg_resources import resource_filename
90+import pytz
91+from van.testing.layer import zcml_layer
92 from zope.component import provideUtility
93
94 from lazr.restful.interfaces import IWebServiceConfiguration
95@@ -21,12 +29,22 @@
96 )
97
98
99+class FunctionalLayer:
100+ allow_teardown = False
101+ zcml = os.path.abspath(resource_filename('lazr.restful', 'ftesting.zcml'))
102+
103+
104+zcml_layer(FunctionalLayer)
105+
106+
107 class TestEntryResourceETags(unittest.TestCase):
108 # The EntryResource uses the field values that can be written or might
109 # othwerise change as the basis for its ETags. The make_entry_etag_cores
110 # function is passed the data about the fields and returns the read and
111 # write cores.
112
113+ layer = FunctionalLayer
114+
115 def test_no_field_details(self):
116 # If make_entry_etag_cores is given no field details (because no
117 # fields exist), the resulting cores empty strings.
118@@ -91,10 +109,17 @@
119 ('dict_field',
120 {'writable': False,
121 'value': OrderedDict((('first', 'one'), ('second', 'two')))}),
122+ ('date_field',
123+ {'writable': False,
124+ 'value': date(2009, 7, 7)}),
125+ ('datetime_field',
126+ {'writable': False,
127+ 'value': datetime(2009, 7, 7, 13, 45, 0, tzinfo=pytz.utc)}),
128 ]
129 self.assertEqual(
130 make_entry_etag_cores(field_details),
131- [b'["first", "second"]\0{"first": "one", "second": "two"}', b''])
132+ [b'["first", "second"]\x00{"first": "one", "second": "two"}\x00'
133+ b'"2009-07-07"\x00"2009-07-07T13:45:00+00:00"', b''])
134
135
136 class TestHTTPResourceETags(unittest.TestCase):

Subscribers

People subscribed via source and target branches