Merge ~cjwatson/lazr.restful:remove-class-advisors into lazr.restful:main
- Git
- lp:~cjwatson/lazr.restful
- remove-class-advisors
- Merge into main
Proposed by
Colin Watson
Status: | Merged |
---|---|
Merged at revision: | 9a607fdf66cf658ad60ac2cdacea2aa718f1d1a0 |
Proposed branch: | ~cjwatson/lazr.restful:remove-class-advisors |
Merge into: | lazr.restful:main |
Diff against target: |
396 lines (+17/-277) 3 files modified
NEWS.rst (+5/-0) src/lazr/restful/declarations.py (+12/-112) src/lazr/restful/tests/test_declarations.py (+0/-165) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jürgen Gmach | Approve | ||
Review via email: mp+413739@code.launchpad.net |
Commit message
Remove old class advisors
Description of the change
The deprecated `export_
This doesn't require a new major version, because we declare `python_
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/NEWS.rst b/NEWS.rst |
2 | index c9dff29..e2477fb 100644 |
3 | --- a/NEWS.rst |
4 | +++ b/NEWS.rst |
5 | @@ -20,6 +20,11 @@ NEWS for lazr.restful |
6 | => ``lazr.restful.testing.webservice.StubRootResourceURL`` |
7 | - Apply black code formatter via pre-commit. |
8 | - Drop Python 2 support. |
9 | +- Remove ``export_as_webservice_entry`` and |
10 | + ``export_as_webservice_collection``; these were deprecated in 0.22.0 and |
11 | + cannot work on Python 3. Use the class decorators |
12 | + ``@exported_as_webservice_entry`` and |
13 | + ``@exported_as_webservice_collection`` instead. |
14 | |
15 | 1.1.0 (2021-10-07) |
16 | ================== |
17 | diff --git a/src/lazr/restful/declarations.py b/src/lazr/restful/declarations.py |
18 | index f717592..886eedb 100644 |
19 | --- a/src/lazr/restful/declarations.py |
20 | +++ b/src/lazr/restful/declarations.py |
21 | @@ -16,8 +16,6 @@ __all__ = [ |
22 | "call_with", |
23 | "collection_default_content", |
24 | "error_status", |
25 | - "export_as_webservice_collection", |
26 | - "export_as_webservice_entry", |
27 | "export_destructor_operation", |
28 | "export_factory_operation", |
29 | "export_operation_as", |
30 | @@ -49,7 +47,6 @@ import sys |
31 | import six |
32 | from zope.component import getUtility, getGlobalSiteManager |
33 | from zope.interface import classImplements |
34 | -from zope.interface.advice import addClassAdvisor |
35 | from zope.interface.interface import fromFunction, InterfaceClass, TAGGED_DATA |
36 | from zope.interface.interfaces import IInterface, IMethod |
37 | from zope.schema import ( |
38 | @@ -179,8 +176,7 @@ def _export_as_webservice_entry( |
39 | ): |
40 | """Tag an interface as exported on the web service as an entry. |
41 | |
42 | - This is the core of export_as_webservice_entry and |
43 | - exported_as_webservice_entry. |
44 | + This is the core of exported_as_webservice_entry. |
45 | """ |
46 | annotation_stack = VersionedDict() |
47 | |
48 | @@ -261,66 +257,6 @@ def _export_as_webservice_entry( |
49 | annotate_exported_methods(interface) |
50 | |
51 | |
52 | -def export_as_webservice_entry( |
53 | - singular_name=None, |
54 | - plural_name=None, |
55 | - contributes_to=None, |
56 | - publish_web_link=True, |
57 | - as_of=None, |
58 | - versioned_annotations=None, |
59 | -): |
60 | - """Mark the content interface as exported on the web service as an entry. |
61 | - |
62 | - If contributes_to is a non-empty sequence of Interfaces, this entry will |
63 | - actually not be exported on its own but instead will contribute its |
64 | - attributes/methods to other exported entries. |
65 | - |
66 | - This function does not work with Python 3. Rather than calling this |
67 | - within the class definition, decorate the class with |
68 | - @exported_as_webservice_entry instead. |
69 | - |
70 | - :param singular_name: The human-readable singular name of the entry, |
71 | - eg. "paintbrush". |
72 | - :param plural_name: The human-readable plural name of the entry, |
73 | - eg. "paintbrushes" |
74 | - :param contributes_to: An optional list of exported interfaces to which |
75 | - this interface contributes. |
76 | - :param publish_web_link: This parameter is ignored unless there is |
77 | - a correspondence between this web service's entries and the |
78 | - pages on some website. If that is so, and if this parameter is |
79 | - set to True, the representation of this entry will include a |
80 | - web_link pointing to the corresponding page on the website. If |
81 | - False, web_link will be omitted. |
82 | - :param as_of: The first version of the web service to feature this entry. |
83 | - :param versioned_annotations: A list of 2-tuples (version, |
84 | - {params}), with more recent web service versions earlier in |
85 | - the list and older versions later in the list. |
86 | - |
87 | - A 'params' dictionary may contain the key 'exported', which |
88 | - controls whether or not to publish the entry at all in the |
89 | - given version. It may also contain the keys 'singular_name', |
90 | - 'plural_name', 'contributes_to', or 'publish_web_link', which |
91 | - work just like the corresponding arguments to this method. |
92 | - """ |
93 | - _check_called_from_interface_def("export_as_webservice_entry()") |
94 | - |
95 | - def mark_entry(interface): |
96 | - """Class advisor that tags the interface once it is created.""" |
97 | - _check_interface("export_as_webservice_entry()", interface) |
98 | - _export_as_webservice_entry( |
99 | - interface, |
100 | - singular_name=singular_name, |
101 | - plural_name=plural_name, |
102 | - contributes_to=contributes_to, |
103 | - publish_web_link=publish_web_link, |
104 | - as_of=as_of, |
105 | - versioned_annotations=versioned_annotations, |
106 | - ) |
107 | - return interface |
108 | - |
109 | - addClassAdvisor(mark_entry) |
110 | - |
111 | - |
112 | class exported_as_webservice_entry: |
113 | """Mark the content interface as exported on the web service as an entry. |
114 | |
115 | @@ -497,40 +433,6 @@ def _check_collection_default_content(name, interface): |
116 | ) |
117 | |
118 | |
119 | -def export_as_webservice_collection(entry_schema): |
120 | - """Mark the interface as exported on the web service as a collection. |
121 | - |
122 | - This function does not work with Python 3. Rather than calling this |
123 | - within the class definition, decorate the class with |
124 | - @exported_as_webservice_collection instead. |
125 | - |
126 | - :raises TypeError: if the interface doesn't have a method decorated with |
127 | - @collection_default_content. |
128 | - """ |
129 | - _check_called_from_interface_def("export_as_webservice_collection()") |
130 | - |
131 | - if not IInterface.providedBy(entry_schema): |
132 | - raise TypeError("entry_schema must be an interface.") |
133 | - |
134 | - # Set the tags at this point, so that future declarations can |
135 | - # check it. |
136 | - tags = _get_interface_tags() |
137 | - tags[LAZR_WEBSERVICE_EXPORTED] = dict( |
138 | - type=COLLECTION_TYPE, collection_entry_schema=entry_schema |
139 | - ) |
140 | - |
141 | - def mark_collection(interface): |
142 | - """Class advisor that tags the interface once it is created.""" |
143 | - _check_interface("export_as_webservice_collection()", interface) |
144 | - _check_collection_default_content( |
145 | - "export_as_webservice_collection()", interface |
146 | - ) |
147 | - annotate_exported_methods(interface) |
148 | - return interface |
149 | - |
150 | - addClassAdvisor(mark_collection) |
151 | - |
152 | - |
153 | class exported_as_webservice_collection: |
154 | """Mark the interface as exported on the web service as a collection. |
155 | |
156 | @@ -580,14 +482,14 @@ class collection_default_content: |
157 | # We used to check that this decorator is being used from within an |
158 | # interface exported as a collection. However, it isn't possible to |
159 | # do this when using the @exported_as_webservice_collection |
160 | - # decorator rather than the export_as_webservice_collection function |
161 | - # (which is based on class advice, and so cannot work in Python 3): |
162 | - # that decorator isn't called until the rest of the interface has |
163 | - # been defined, so it hasn't had a chance to set any tags on the |
164 | - # interface by the time decorators of methods in that interface are |
165 | - # called. The best we can do is to check that we don't already |
166 | - # positively know that the interface is exported as an entry |
167 | - # instead. |
168 | + # decorator rather than the old export_as_webservice_collection |
169 | + # function (which was based on class advice, and so cannot work in |
170 | + # Python 3): that decorator isn't called until the rest of the |
171 | + # interface has been defined, so it hasn't had a chance to set any |
172 | + # tags on the interface by the time decorators of methods in that |
173 | + # interface are called. The best we can do is to check that we |
174 | + # don't already positively know that the interface is exported as an |
175 | + # entry instead. |
176 | tags = _get_interface_tags() |
177 | tag = tags.setdefault(LAZR_WEBSERVICE_EXPORTED, {}) |
178 | if "type" in tag and tag["type"] != COLLECTION_TYPE: |
179 | @@ -684,9 +586,7 @@ class _method_annotator: |
180 | |
181 | The actual method will be wrapped in an IMethod specification once the |
182 | Interface is complete. So we save the annotations in an attribute of the |
183 | - method, and either the class advisor invoked by |
184 | - export_as_webservice_entry() and export_as_webservice_collection() or |
185 | - the @exported_as_webservice_entry() and |
186 | + method, and the @exported_as_webservice_entry() and |
187 | @exported_as_webservice_collection() decorators will do the final |
188 | tagging. |
189 | """ |
190 | @@ -729,8 +629,8 @@ class _method_annotator: |
191 | :param f: the method being annotated. |
192 | :param annotations: the dict containing the method annotations. |
193 | |
194 | - The annotations will copied to the lazr.webservice.exported tag |
195 | - by a class advisor. |
196 | + The annotations will be copied to the lazr.webservice.exported tag |
197 | + by a class decorator. |
198 | """ |
199 | raise NotImplementedError |
200 | |
201 | diff --git a/src/lazr/restful/tests/test_declarations.py b/src/lazr/restful/tests/test_declarations.py |
202 | index 305709b..6a2313b 100644 |
203 | --- a/src/lazr/restful/tests/test_declarations.py |
204 | +++ b/src/lazr/restful/tests/test_declarations.py |
205 | @@ -2,8 +2,6 @@ |
206 | |
207 | """Unit tests for the conversion of interfaces into a web service.""" |
208 | |
209 | -import sys |
210 | - |
211 | import testtools |
212 | from zope.component import ( |
213 | adapter, |
214 | @@ -35,17 +33,13 @@ from zope.security.management import ( |
215 | from lazr.restful.declarations import ( |
216 | accessor_for, |
217 | call_with, |
218 | - collection_default_content, |
219 | error_status, |
220 | - export_as_webservice_collection, |
221 | - export_as_webservice_entry, |
222 | export_read_operation, |
223 | export_write_operation, |
224 | exported, |
225 | exported_as_webservice_entry, |
226 | generate_entry_interfaces, |
227 | generate_operation_adapter, |
228 | - LAZR_WEBSERVICE_EXPORTED, |
229 | LAZR_WEBSERVICE_NAME, |
230 | mutator_for, |
231 | operation_for_version, |
232 | @@ -430,165 +424,6 @@ class ContributingInterfacesTestCase(TestCaseWithWebServiceFixtures): |
233 | ) |
234 | |
235 | |
236 | -class TestExportAsWebserviceEntry(testtools.TestCase): |
237 | - """Tests for export_as_webservice_entry.""" |
238 | - |
239 | - def setUp(self): |
240 | - super().setUp() |
241 | - if sys.version_info[0] >= 3: |
242 | - self.skipTest( |
243 | - "export_as_webservice_entry is only supported on Python 2" |
244 | - ) |
245 | - |
246 | - def test_works_on_interface(self): |
247 | - # export_as_webservice_entry works on an interface. |
248 | - class IFoo(Interface): |
249 | - export_as_webservice_entry() |
250 | - |
251 | - self.assertTrue( |
252 | - IFoo.queryTaggedValue(LAZR_WEBSERVICE_EXPORTED)["exported"] |
253 | - ) |
254 | - |
255 | - def test_requires_interface(self): |
256 | - # export_as_webservice_entry can only be used on Interface. |
257 | - def export_non_interface(): |
258 | - class NotAnInterface: |
259 | - export_as_webservice_entry() |
260 | - |
261 | - exception = self.assertRaises(TypeError, export_non_interface) |
262 | - self.assertEqual( |
263 | - "export_as_webservice_entry() can only be used on an interface.", |
264 | - str(exception), |
265 | - ) |
266 | - |
267 | - def test_must_be_within_interface_definition(self): |
268 | - # export_as_webservice_entry can only be used from within a |
269 | - # interface definition. |
270 | - exception = self.assertRaises(TypeError, export_as_webservice_entry) |
271 | - self.assertEqual( |
272 | - "export_as_webservice_entry() can only be used from within an " |
273 | - "interface definition.", |
274 | - str(exception), |
275 | - ) |
276 | - |
277 | - |
278 | -class TestExportAsWebserviceCollection(testtools.TestCase): |
279 | - """Tests for export_as_webservice_collection.""" |
280 | - |
281 | - def setUp(self): |
282 | - super().setUp() |
283 | - if sys.version_info[0] >= 3: |
284 | - self.skipTest( |
285 | - "export_as_webservice_collection is only supported on " |
286 | - "Python 2" |
287 | - ) |
288 | - |
289 | - def test_works_on_interface_with_tagged_method(self): |
290 | - # export_as_webservice_collection works on an interface that has an |
291 | - # entry schema and a method tagged with @collection_default_content. |
292 | - class IFoo(Interface): |
293 | - export_as_webservice_collection(Interface) |
294 | - |
295 | - @collection_default_content() |
296 | - def getAll(): |
297 | - pass |
298 | - |
299 | - self.assertEqual( |
300 | - {None: ("getAll", {})}, |
301 | - IFoo.queryTaggedValue(LAZR_WEBSERVICE_EXPORTED)[ |
302 | - "collection_default_content" |
303 | - ], |
304 | - ) |
305 | - |
306 | - def test_requires_entry_schema(self): |
307 | - # export_as_webservice_collection requires an entry schema. |
308 | - def export_without_entry_schema(): |
309 | - class MissingEntrySchema(Interface): |
310 | - export_as_webservice_collection() |
311 | - |
312 | - exception = self.assertRaises(TypeError, export_without_entry_schema) |
313 | - self.assertEqual( |
314 | - "export_as_webservice_collection() takes exactly 1 argument (0 " |
315 | - "given)", |
316 | - str(exception), |
317 | - ) |
318 | - |
319 | - def test_requires_entry_schema_as_interface(self): |
320 | - # export_as_webservice_collection requires the entry schema to be an |
321 | - # interface. |
322 | - def export_with_invalid_entry_schema(): |
323 | - class InvalidEntrySchema(Interface): |
324 | - export_as_webservice_collection("not an interface") |
325 | - |
326 | - exception = self.assertRaises( |
327 | - TypeError, export_with_invalid_entry_schema |
328 | - ) |
329 | - self.assertEqual("entry_schema must be an interface.", str(exception)) |
330 | - |
331 | - def test_requires_tagged_method(self): |
332 | - # export_as_webservice_collection can only be used on a collection |
333 | - # that has a method marked as exporting the default content. |
334 | - def export_missing_default_content(): |
335 | - class MissingDefaultContent(Interface): |
336 | - export_as_webservice_collection(Interface) |
337 | - |
338 | - exception = self.assertRaises( |
339 | - TypeError, export_missing_default_content |
340 | - ) |
341 | - self.assertEqual( |
342 | - "export_as_webservice_collection() is missing a method tagged " |
343 | - "with @collection_default_content.", |
344 | - str(exception), |
345 | - ) |
346 | - |
347 | - def test_refuses_multiple_tagged_methods(self): |
348 | - # export_as_webservice_collection cannot be used on a collection |
349 | - # that has multiple methods marked as exporting the default content. |
350 | - def export_two_default_content(): |
351 | - class TwoDefaultContent(Interface): |
352 | - export_as_webservice_collection(Interface) |
353 | - |
354 | - @collection_default_content() |
355 | - def getAll1(): |
356 | - """A first getAll().""" |
357 | - |
358 | - @collection_default_content() |
359 | - def getAll2(): |
360 | - """Another getAll().""" |
361 | - |
362 | - exception = self.assertRaises(TypeError, export_two_default_content) |
363 | - self.assertEqual( |
364 | - "Only one method can be marked with @collection_default_content " |
365 | - "for version '(earliest version)'.", |
366 | - str(exception), |
367 | - ) |
368 | - |
369 | - def test_requires_interface(self): |
370 | - # export_as_webservice_collection can only be used on Interface. |
371 | - def export_non_interface(): |
372 | - class NotAnInterface: |
373 | - export_as_webservice_collection(Interface) |
374 | - |
375 | - exception = self.assertRaises(TypeError, export_non_interface) |
376 | - self.assertEqual( |
377 | - "export_as_webservice_collection() can only be used on an " |
378 | - "interface.", |
379 | - str(exception), |
380 | - ) |
381 | - |
382 | - def test_must_be_within_interface_definition(self): |
383 | - # export_as_webservice_collection can only be used from within an |
384 | - # interface definition. |
385 | - exception = self.assertRaises( |
386 | - TypeError, export_as_webservice_collection, Interface |
387 | - ) |
388 | - self.assertEqual( |
389 | - "export_as_webservice_collection() can only be used from within " |
390 | - "an interface definition.", |
391 | - str(exception), |
392 | - ) |
393 | - |
394 | - |
395 | class NotExportedException(Exception): |
396 | pass |
397 |
LGTM
> because we declare `python_ requires= ">=3.5" ` and so pip on Python 2 won't upgrade to this version
pip >= 9 :-)