Merge lp:~zyga/checkbox/padme-switch into lp:checkbox
- padme-switch
- Merge into trunk
Proposed by
Zygmunt Krynicki
Status: | Merged |
---|---|
Approved by: | Sylvain Pineau |
Approved revision: | 3972 |
Merged at revision: | 3971 |
Proposed branch: | lp:~zyga/checkbox/padme-switch |
Merge into: | lp:checkbox |
Diff against target: |
829 lines (+4/-780) 5 files modified
plainbox/plainbox/impl/censoREd.py (+2/-3) plainbox/plainbox/impl/proxy.py (+0/-401) plainbox/plainbox/impl/test_proxy.py (+0/-376) plainbox/requirements/deb-core.txt (+1/-0) plainbox/setup.py (+1/-0) |
To merge this branch: | bzr merge lp:~zyga/checkbox/padme-switch |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Sylvain Pineau | Approve | ||
Review via email: mp+269644@code.launchpad.net |
Commit message
Description of the change
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 | === modified file 'plainbox/plainbox/impl/censoREd.py' |
2 | --- plainbox/plainbox/impl/censoREd.py 2015-07-13 09:57:16 +0000 |
3 | +++ plainbox/plainbox/impl/censoREd.py 2015-08-31 14:17:15 +0000 |
4 | @@ -56,8 +56,7 @@ |
5 | The last resort, aka, the proxy approach. Let's use a bit of magic to work |
6 | around the problem. This way we won't have to subclass or override anything. |
7 | """ |
8 | -from plainbox.impl.proxy import proxy |
9 | -from plainbox.impl.proxy import unproxied |
10 | +from padme import proxy |
11 | |
12 | |
13 | __all__ = ["PatternProxy"] |
14 | @@ -86,6 +85,6 @@ |
15 | |
16 | **Yes** (gets another drink). |
17 | """ |
18 | - @unproxied |
19 | + @proxy.direct |
20 | def __repr__(self): |
21 | return "re.compile({!r})".format(self.pattern) |
22 | |
23 | === removed file 'plainbox/plainbox/impl/proxy.py' |
24 | --- plainbox/plainbox/impl/proxy.py 2015-01-29 01:57:26 +0000 |
25 | +++ plainbox/plainbox/impl/proxy.py 1970-01-01 00:00:00 +0000 |
26 | @@ -1,401 +0,0 @@ |
27 | -# This file is part of Checkbox. |
28 | -# |
29 | -# Copyright 2012-2015 Canonical Ltd. |
30 | -# Written by: |
31 | -# Zygmunt Krynicki <zygmunt.krynicki@canonical.com> |
32 | -# |
33 | -# Checkbox is free software: you can redistribute it and/or modify |
34 | -# it under the terms of the GNU General Public License version 3, |
35 | -# as published by the Free Software Foundation. |
36 | -# |
37 | -# Checkbox is distributed in the hope that it will be useful, |
38 | -# but WITHOUT ANY WARRANTY; without even the implied warranty of |
39 | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
40 | -# GNU General Public License for more details. |
41 | -# |
42 | -# You should have received a copy of the GNU General Public License |
43 | -# along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
44 | -""" |
45 | -:mod:`plainbox.impl.proxy ` -- mostly transparent proxy |
46 | -======================================================= |
47 | - |
48 | -.. note:: |
49 | - There are a number of classes and meta-classes but the only public |
50 | - interface is the :class:`proxy` class. See below for examples. |
51 | -""" |
52 | -import logging |
53 | -import itertools |
54 | - |
55 | -_logger = logging.getLogger("plainbox.proxy") |
56 | - |
57 | - |
58 | -__all__ = ['proxy'] |
59 | - |
60 | - |
61 | -class proxy_meta(type): |
62 | - """ |
63 | - Meta-class for all proxy types |
64 | - |
65 | - This meta-class is responsible for gathering the __unproxied__ attribute on |
66 | - each created class. The attribute is a frosenset of names that will not be |
67 | - forwarded to the ``proxxie`` but instead will be looked up on the proxy |
68 | - itself. |
69 | - """ |
70 | - |
71 | - def __new__(mcls, name, bases, ns): |
72 | - _logger.debug( |
73 | - "__new__ on proxy_meta with name: %r, bases: %r", name, bases) |
74 | - unproxied_set = set() |
75 | - for base in bases: |
76 | - if hasattr(base, '__unproxied__'): |
77 | - unproxied_set.update(base.__unproxied__) |
78 | - for ns_attr, ns_value in ns.items(): |
79 | - if getattr(ns_value, 'unproxied', False): |
80 | - unproxied_set.add(ns_attr) |
81 | - if unproxied_set: |
82 | - _logger.debug( |
83 | - "proxy type %r will pass-thru %r", name, unproxied_set) |
84 | - ns['__unproxied__'] = frozenset(unproxied_set) |
85 | - return super().__new__(mcls, name, bases, ns) |
86 | - |
87 | - |
88 | -cnt = itertools.count() |
89 | - |
90 | - |
91 | -def make_boundproxy_meta(proxiee): |
92 | - """ |
93 | - Make a new bound proxy meta-class for the specified object |
94 | - |
95 | - :param proxiee: |
96 | - The object that will be proxied |
97 | - :returns: |
98 | - A new meta-class that lexically wraps ``proxiee`` and subclasses |
99 | - :class:`proxy_meta`. |
100 | - """ |
101 | - |
102 | - class boundproxy_meta(proxy_meta): |
103 | - """ |
104 | - Meta-class for all bound proxies. |
105 | - |
106 | - This meta-class is responsible for generating an unique name for each |
107 | - created class and setting the setting the ``__proxiee__`` attribute to |
108 | - the proxiee object itself. |
109 | - |
110 | - In addition, it implements two methods that participate in instance and |
111 | - class checks: ``__instancecheck__`` and ``__subclasscheck__``. |
112 | - """ |
113 | - |
114 | - def __new__(mcls, name, bases, ns): |
115 | - name = 'boundproxy[{!r}]'.format(next(cnt)) |
116 | - _logger.debug( |
117 | - "__new__ on boundproxy_meta with name %r and bases %r", |
118 | - name, bases) |
119 | - ns['__proxiee__'] = proxiee |
120 | - return super().__new__(mcls, name, bases, ns) |
121 | - |
122 | - def __instancecheck__(mcls, instance): |
123 | - # NOTE: this is never called in practice since |
124 | - # proxy(obj).__class__ is really obj.__class__. |
125 | - _logger.debug("__instancecheck__ %r on %r", instance, proxiee) |
126 | - return isinstance(instance, type(proxiee)) |
127 | - |
128 | - def __subclasscheck__(mcls, subclass): |
129 | - # This is still called though since type(proxy(obj)) is |
130 | - # something else |
131 | - _logger.debug("__subclasscheck__ %r on %r", subclass, proxiee) |
132 | - return issubclass(type(proxiee), subclass) |
133 | - |
134 | - return boundproxy_meta |
135 | - |
136 | - |
137 | -class proxy_base: |
138 | - """ |
139 | - Base class for all proxies. |
140 | - |
141 | - This class implements the bulk of the proxy work by having a lot of dunder |
142 | - methods that delegate their work to a ``proxiee`` object. The ``proxiee`` |
143 | - object must be available as the ``__proxiee__`` attribute on a class |
144 | - deriving from ``base_proxy``. Apart from ``__proxiee__`, the |
145 | - ``__unproxied__`` attribute, which should be a frozenset, must also be |
146 | - present in all derived classes. |
147 | - |
148 | - In practice, the two special attributes are injected via |
149 | - ``boundproxy_meta`` created by :func:`make_boundproxy_meta()`. This class |
150 | - is also used as a base class for the tricky :class:`proxy` below. |
151 | - |
152 | - NOTE: Look at ``pydoc3 SPECIALMETHODS`` section titled ``Special method |
153 | - lookup`` for a rationale of why we have all those dunder methods while |
154 | - still having __getattribute__() |
155 | - """ |
156 | - # NOTE: the order of methods below matches that of ``pydoc3 |
157 | - # SPECIALMETHODS``. The "N/A to instances" text means that it makes no |
158 | - # sense to add proxy support to the specified method because that method |
159 | - # makes no sense on instances. Proxy is designed to intercept access to |
160 | - # *objects*, not construction of such objects in the first place. |
161 | - |
162 | - # N/A to instances: __new__ |
163 | - |
164 | - # N/A to instances: __init__ |
165 | - |
166 | - def __del__(self): |
167 | - """ |
168 | - NOTE: this method is handled specially since it must be called |
169 | - after an object becomes unreachable. As long as the proxy object |
170 | - itself exits, it holds a strong reference to the original object. |
171 | - """ |
172 | - |
173 | - def __repr__(self): |
174 | - proxiee = type(self).__proxiee__ |
175 | - _logger.debug("__repr__ on proxiee (%r)", proxiee) |
176 | - return repr(proxiee) |
177 | - |
178 | - def __str__(self): |
179 | - proxiee = type(self).__proxiee__ |
180 | - _logger.debug("__str__ on proxiee (%r)", proxiee) |
181 | - return str(proxiee) |
182 | - |
183 | - def __bytes__(self): |
184 | - proxiee = type(self).__proxiee__ |
185 | - _logger.debug("__bytes__ on proxiee (%r)", proxiee) |
186 | - return bytes(proxiee) |
187 | - |
188 | - def __format__(self, format_spec): |
189 | - proxiee = type(self).__proxiee__ |
190 | - _logger.debug("__format__ on proxiee (%r)", proxiee) |
191 | - return format(proxiee, format_spec) |
192 | - |
193 | - def __lt__(self, other): |
194 | - proxiee = type(self).__proxiee__ |
195 | - _logger.debug("__lt__ on proxiee (%r)", proxiee) |
196 | - return proxiee < other |
197 | - |
198 | - def __le__(self, other): |
199 | - proxiee = type(self).__proxiee__ |
200 | - _logger.debug("__le__ on proxiee (%r)", proxiee) |
201 | - return proxiee <= other |
202 | - |
203 | - def __eq__(self, other): |
204 | - proxiee = type(self).__proxiee__ |
205 | - _logger.debug("__eq__ on proxiee (%r)", proxiee) |
206 | - return proxiee == other |
207 | - |
208 | - def __ne__(self, other): |
209 | - proxiee = type(self).__proxiee__ |
210 | - _logger.debug("__ne__ on proxiee (%r)", proxiee) |
211 | - return proxiee != other |
212 | - |
213 | - def __gt__(self, other): |
214 | - proxiee = type(self).__proxiee__ |
215 | - _logger.debug("__gt__ on proxiee (%r)", proxiee) |
216 | - return proxiee > other |
217 | - |
218 | - def __ge__(self, other): |
219 | - proxiee = type(self).__proxiee__ |
220 | - _logger.debug("__ge__ on proxiee (%r)", proxiee) |
221 | - return proxiee >= other |
222 | - |
223 | - def __hash__(self): |
224 | - proxiee = type(self).__proxiee__ |
225 | - _logger.debug("__hash__ on proxiee (%r)", proxiee) |
226 | - return hash(proxiee) |
227 | - |
228 | - def __bool__(self): |
229 | - proxiee = type(self).__proxiee__ |
230 | - _logger.debug("__bool__ on proxiee (%r)", proxiee) |
231 | - return bool(proxiee) |
232 | - |
233 | - def __getattr__(self, name): |
234 | - proxiee = type(self).__proxiee__ |
235 | - _logger.debug("__getattr__ %r on proxiee (%r)", name, proxiee) |
236 | - return getattr(proxiee, name) |
237 | - |
238 | - def __getattribute__(self, name): |
239 | - cls = type(self) |
240 | - if name not in cls.__unproxied__: |
241 | - proxiee = cls.__proxiee__ |
242 | - _logger.debug("__getattribute__ %r on proxiee (%r)", name, proxiee) |
243 | - return getattr(proxiee, name) |
244 | - else: |
245 | - _logger.debug("__getattribute__ %r on proxy itself", name) |
246 | - return object.__getattribute__(self, name) |
247 | - |
248 | - def __setattr__(self, attr, value): |
249 | - proxiee = type(self).__proxiee__ |
250 | - _logger.debug("__setattr__ %r on proxiee (%r)", attr, proxiee) |
251 | - setattr(proxiee, attr, value) |
252 | - |
253 | - def __delattr__(self, attr): |
254 | - proxiee = type(self).__proxiee__ |
255 | - _logger.debug("__delattr__ %r on proxiee (%r)", attr, proxiee) |
256 | - delattr(proxiee, attr) |
257 | - |
258 | - def __dir__(self): |
259 | - proxiee = type(self).__proxiee__ |
260 | - _logger.debug("__dir__ on proxiee (%r)", proxiee) |
261 | - return dir(proxiee) |
262 | - |
263 | - def __get__(self, instance, owner): |
264 | - proxiee = type(self).__proxiee__ |
265 | - _logger.debug("__get__ on proxiee (%r)", proxiee) |
266 | - return proxiee.__get__(instance, owner) |
267 | - |
268 | - def __set__(self, instance, value): |
269 | - proxiee = type(self).__proxiee__ |
270 | - _logger.debug("__set__ on proxiee (%r)", proxiee) |
271 | - proxiee.__set__(instance, value) |
272 | - |
273 | - def __delete__(self, instance): |
274 | - proxiee = type(self).__proxiee__ |
275 | - _logger.debug("__delete__ on proxiee (%r)", proxiee) |
276 | - proxiee.__delete__(instance) |
277 | - |
278 | - def __call__(self, *args, **kwargs): |
279 | - proxiee = type(self).__proxiee__ |
280 | - _logger.debug("call on proxiee (%r)", proxiee) |
281 | - return proxiee(*args, **kwargs) |
282 | - |
283 | - def __len__(self): |
284 | - proxiee = type(self).__proxiee__ |
285 | - _logger.debug("__len__ on proxiee (%r)", proxiee) |
286 | - return len(proxiee) |
287 | - |
288 | - def __length_hint__(self): |
289 | - proxiee = type(self).__proxiee__ |
290 | - _logger.debug("__length_hint__ on proxiee (%r)", proxiee) |
291 | - return proxiee.__length_hint__() |
292 | - |
293 | - def __getitem__(self, item): |
294 | - proxiee = type(self).__proxiee__ |
295 | - _logger.debug("__getitem__ on proxiee (%r)", proxiee) |
296 | - return proxiee[item] |
297 | - |
298 | - def __setitem__(self, item, value): |
299 | - proxiee = type(self).__proxiee__ |
300 | - _logger.debug("__setitem__ on proxiee (%r)", proxiee) |
301 | - proxiee[item] = value |
302 | - |
303 | - def __delitem__(self, item): |
304 | - proxiee = type(self).__proxiee__ |
305 | - _logger.debug("__delitem__ on proxiee (%r)", proxiee) |
306 | - del proxiee[item] |
307 | - |
308 | - def __iter__(self): |
309 | - proxiee = type(self).__proxiee__ |
310 | - _logger.debug("__iter__ on proxiee (%r)", proxiee) |
311 | - return iter(proxiee) |
312 | - |
313 | - def __reversed__(self): |
314 | - proxiee = type(self).__proxiee__ |
315 | - _logger.debug("__reversed__ on proxiee (%r)", proxiee) |
316 | - return reversed(proxiee) |
317 | - |
318 | - def __contains__(self, item): |
319 | - proxiee = type(self).__proxiee__ |
320 | - _logger.debug("__contains__ on proxiee (%r)", proxiee) |
321 | - return item in proxiee |
322 | - |
323 | - # TODO: all numeric methods |
324 | - |
325 | - def __enter__(self): |
326 | - proxiee = type(self).__proxiee__ |
327 | - _logger.debug("__enter__ on proxiee (%r)", proxiee) |
328 | - return proxiee.__enter__() |
329 | - |
330 | - def __exit__(self, exc_type, exc_value, traceback): |
331 | - proxiee = type(self).__proxiee__ |
332 | - _logger.debug("__exit__ on proxiee (%r)", proxiee) |
333 | - return proxiee.__exit__(exc_type, exc_value, traceback) |
334 | - |
335 | - |
336 | -class proxy(proxy_base, metaclass=proxy_meta): |
337 | - """ |
338 | - A mostly transparent proxy type |
339 | - |
340 | - The proxy class can be used in two different ways. First, as a callable |
341 | - ``proxy(obj)``. This simply returns a proxy for a single object. |
342 | - |
343 | - >>> truth = ['trust no one'] |
344 | - >>> lie = proxy(truth) |
345 | - |
346 | - This will return an instance of a new ``proxy`` sub-class which for all |
347 | - intents and purposes, to the extent possible in CPython, forwards all |
348 | - requests to the original object. |
349 | - |
350 | - One can still examine the proxy with some ways:: |
351 | - |
352 | - >>> lie is truth |
353 | - False |
354 | - >>> type(lie) is type(truth) |
355 | - False |
356 | - |
357 | - Having said that, the vast majority of stuff will make the proxy behave |
358 | - identically to the original object. |
359 | - |
360 | - >>> lie[0] |
361 | - 'trust no one' |
362 | - >>> lie[0] = 'trust the government' |
363 | - >>> truth[0] |
364 | - 'trust the government' |
365 | - |
366 | - The second way of using the ``proxy`` class is as a base class. In this |
367 | - way, one can actually override certain methods. To ensure that all the |
368 | - dunder methods work correctly please use the ``@unproxied`` decorator on |
369 | - them. |
370 | - |
371 | - >>> import codecs |
372 | - >>> class crypto(proxy): |
373 | - ... |
374 | - ... @unproxied |
375 | - ... def __repr__(self): |
376 | - ... return codecs.encode(super().__repr__(), "rot_13") |
377 | - |
378 | - With this weird class, we can change the repr() of any object we want to be |
379 | - ROT-13 encoded. Let's see: |
380 | - |
381 | - >>> orig = ['ala ma kota', 'a kot ma ale'] |
382 | - >>> prox = crypto(orig) |
383 | - |
384 | - We can sill access all of the data through the proxy: |
385 | - |
386 | - >>> prox[0] |
387 | - 'ala ma kota' |
388 | - |
389 | - But the whole repr() is now a bit different than usual: |
390 | - |
391 | - >>> prox |
392 | - ['nyn zn xbgn', 'n xbg zn nyr'] |
393 | - """ |
394 | - |
395 | - def __new__(proxy_cls, proxiee): |
396 | - """ |
397 | - Create a new instance of ``proxy()`` wrapping ``proxiee`` |
398 | - |
399 | - :param proxiee: |
400 | - The object to proxy |
401 | - :returns: |
402 | - An instance of new subclass of ``proxy``, called |
403 | - ``boundproxy[proxiee]`` that uses a new meta-class that lexically |
404 | - bounds the ``proxiee`` argument. The new sub-class has a different |
405 | - implementation of ``__new__`` and can be instantiated without |
406 | - additional arguments. |
407 | - """ |
408 | - _logger.debug("__new__ on proxy with proxiee: %r", proxiee) |
409 | - boundproxy_meta = make_boundproxy_meta(proxiee) |
410 | - |
411 | - class boundproxy(proxy_cls, metaclass=boundproxy_meta): |
412 | - |
413 | - def __new__(boundproxy_cls): |
414 | - _logger.debug("__new__ on boundproxy %r", boundproxy_cls) |
415 | - return object.__new__(boundproxy_cls) |
416 | - return boundproxy() |
417 | - |
418 | - |
419 | -def unproxied(fn): |
420 | - """ |
421 | - Mark an object (attribute) as not-to-be-proxied. |
422 | - |
423 | - This decorator can be used inside :class:`proxy` sub-classes. Please |
424 | - consult the documentation of ``proxy`` for details. |
425 | - """ |
426 | - fn.unproxied = True |
427 | - return fn |
428 | |
429 | === removed file 'plainbox/plainbox/impl/test_proxy.py' |
430 | --- plainbox/plainbox/impl/test_proxy.py 2015-08-31 10:05:19 +0000 |
431 | +++ plainbox/plainbox/impl/test_proxy.py 1970-01-01 00:00:00 +0000 |
432 | @@ -1,376 +0,0 @@ |
433 | -# This file is part of Checkbox. |
434 | -# |
435 | -# Copyright 2012-2015 Canonical Ltd. |
436 | -# Written by: |
437 | -# Zygmunt Krynicki <zygmunt.krynicki@canonical.com> |
438 | -# |
439 | -# Checkbox is free software: you can redistribute it and/or modify |
440 | -# it under the terms of the GNU General Public License version 3, |
441 | -# as published by the Free Software Foundation. |
442 | -# |
443 | -# Checkbox is distributed in the hope that it will be useful, |
444 | -# but WITHOUT ANY WARRANTY; without even the implied warranty of |
445 | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
446 | -# GNU General Public License for more details. |
447 | -# |
448 | -# You should have received a copy of the GNU General Public License |
449 | -# along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
450 | -import doctest |
451 | -import operator |
452 | -import sys |
453 | -import unittest |
454 | - |
455 | -from plainbox.impl.proxy import _logger |
456 | -from plainbox.impl.proxy import proxy |
457 | -from plainbox.impl.proxy import unproxied |
458 | -from plainbox.vendor import mock |
459 | - |
460 | - |
461 | -# XXX: Set to True for revelation |
462 | -reality_is_broken = False |
463 | - |
464 | - |
465 | -def load_tests(loader, tests, ignore): |
466 | - tests.addTests( |
467 | - doctest.DocTestSuite('plainbox.impl.proxy', |
468 | - optionflags=doctest.REPORT_NDIFF)) |
469 | - return tests |
470 | - |
471 | - |
472 | -def setUpModule(): |
473 | - if reality_is_broken: |
474 | - # If you start to doubt reality |
475 | - from plainbox.impl.logging import adjust_logging |
476 | - from plainbox.impl.logging import setup_logging |
477 | - setup_logging() |
478 | - adjust_logging('DEBUG', ['plainbox.proxy'], True) |
479 | - |
480 | - |
481 | -class proxy_as_function(unittest.TestCase): |
482 | - |
483 | - def setUp(self): |
484 | - if reality_is_broken: |
485 | - print() |
486 | - _logger.debug("STARTING") |
487 | - _logger.debug("[%s]", self._testMethodName) |
488 | - self.obj = mock.MagicMock(name='obj') |
489 | - self.proxy = proxy(self.obj) |
490 | - |
491 | - def tearDown(self): |
492 | - if reality_is_broken: |
493 | - _logger.debug("DONE") |
494 | - |
495 | - # NOTE: order of test methods matches implementation |
496 | - |
497 | - def test_repr(self): |
498 | - self.assertEqual(repr(self.proxy), repr(self.obj)) |
499 | - self.assertEqual(self.proxy.__repr__(), repr(self.obj)) |
500 | - |
501 | - def test_str(self): |
502 | - self.assertEqual(str(self.proxy), str(self.obj)) |
503 | - self.assertEqual(self.proxy.__str__(), str(self.obj)) |
504 | - |
505 | - def test_bytes(self): |
506 | - # NOTE: bytes() is unlike str() or repr() in that it is not a function |
507 | - # that converts an arbitrary object into a bytes object. We cannot |
508 | - # just call it on a random object. What we must do is implement |
509 | - # __bytes__() on a new class and use instances of that class. |
510 | - class C: |
511 | - def __bytes__(self): |
512 | - return b'good' |
513 | - self.obj = C() |
514 | - self.proxy = proxy(self.obj) |
515 | - self.assertEqual(bytes(self.proxy), bytes(self.obj)) |
516 | - self.assertEqual(self.proxy.__bytes__(), bytes(self.obj)) |
517 | - |
518 | - def test_format(self): |
519 | - self.assertEqual(format(self.proxy), format(self.obj)) |
520 | - self.assertEqual(self.proxy.__format__(""), format(self.obj)) |
521 | - |
522 | - def test_lt(self): |
523 | - # NOTE: MagicMock is not ordered so let's just use an integer |
524 | - self.obj = 0 |
525 | - self.proxy = proxy(self.obj) |
526 | - self.assertLess(self.proxy, 1) |
527 | - self.assertLess(self.obj, 1) |
528 | - |
529 | - def test_le(self): |
530 | - # NOTE: MagicMock is not ordered so let's just use an integer |
531 | - self.obj = 0 |
532 | - self.proxy = proxy(self.obj) |
533 | - self.assertLessEqual(self.proxy, 0) |
534 | - self.assertLessEqual(self.proxy, 1) |
535 | - self.assertLessEqual(self.obj, 0) |
536 | - self.assertLessEqual(self.obj, 1) |
537 | - |
538 | - def test_eq(self): |
539 | - self.assertEqual(self.proxy, self.obj) |
540 | - self.obj.__eq__.assert_called_once_with(self.obj) |
541 | - self.assertEqual(self.obj, self.obj) |
542 | - |
543 | - def test_ne(self): |
544 | - other = object() |
545 | - self.assertNotEqual(self.proxy, other) |
546 | - self.obj.__ne__.assert_called_once_with(other) |
547 | - self.assertNotEqual(self.obj, object()) |
548 | - |
549 | - def test_gt(self): |
550 | - # NOTE: MagicMock is not ordered so let's just use an integer |
551 | - self.obj = 0 |
552 | - self.proxy = proxy(self.obj) |
553 | - self.assertGreater(self.proxy, -1) |
554 | - self.assertGreater(self.obj, -1) |
555 | - |
556 | - def test_ge(self): |
557 | - # NOTE: MagicMock is not ordered so let's just use an integer |
558 | - self.obj = 0 |
559 | - self.proxy = proxy(self.obj) |
560 | - self.assertGreaterEqual(self.proxy, 0) |
561 | - self.assertGreaterEqual(self.proxy, -1) |
562 | - self.assertGreaterEqual(self.obj, 0) |
563 | - self.assertGreaterEqual(self.obj, -1) |
564 | - |
565 | - def test_hash(self): |
566 | - self.assertEqual(hash(self.proxy), hash(self.obj)) |
567 | - self.assertEqual(self.proxy.__hash__(), hash(self.obj)) |
568 | - |
569 | - def test_bool(self): |
570 | - self.assertEqual(bool(self.proxy), bool(self.obj)) |
571 | - self.assertEqual(self.proxy.__bool__(), bool(self.obj)) |
572 | - |
573 | - def test_attr_get(self): |
574 | - self.assertIs(self.proxy.attr, self.obj.attr) |
575 | - |
576 | - def test_attr_set(self): |
577 | - value = mock.Mock(name='value') |
578 | - self.proxy.attr = value |
579 | - self.assertIs(self.obj.attr, value) |
580 | - |
581 | - def test_attr_del(self): |
582 | - del self.proxy.attr |
583 | - with self.assertRaises(AttributeError): |
584 | - self.obj.attr |
585 | - |
586 | - def test_dir(self): |
587 | - self.assertEqual(dir(self.proxy), dir(self.obj)) |
588 | - self.assertEqual(self.proxy.__dir__(), dir(self.obj)) |
589 | - |
590 | - def test_descriptor_methods(self): |
591 | - # NOTE: this tests __get__, __set__ and __delete__ in one test, for |
592 | - # brevity |
593 | - property_proxy = proxy(property) |
594 | - |
595 | - class C: |
596 | - _ok = "default" |
597 | - |
598 | - @property_proxy |
599 | - def ok(self): |
600 | - return self._ok |
601 | - |
602 | - @ok.setter |
603 | - def ok(self, value): |
604 | - self._ok = value |
605 | - |
606 | - @ok.deleter |
607 | - def ok(self): |
608 | - del self._ok |
609 | - obj = C() |
610 | - self.assertEqual(obj._ok, "default") |
611 | - # __set__ assigns the new value |
612 | - obj.ok = True |
613 | - self.assertTrue(obj._ok) |
614 | - # __get__ returns the current value |
615 | - self.assertTrue(obj.ok) |
616 | - # __delete__ removes the current value |
617 | - del obj.ok |
618 | - self.assertEqual(obj._ok, "default") |
619 | - |
620 | - def test_call(self): |
621 | - self.assertEqual(self.proxy(), self.obj()) |
622 | - self.assertEqual(self.proxy.__call__(), self.obj()) |
623 | - |
624 | - def test_len(self): |
625 | - self.assertEqual(len(self.proxy), len(self.obj)) |
626 | - self.assertEqual(self.proxy.__len__(), len(self.obj)) |
627 | - |
628 | - @unittest.skipIf(lambda: sys.version_info[0:2] < 3, 4) |
629 | - def test_length_hint(self): |
630 | - # NOTE: apparently MagicMock doesn't support this method |
631 | - class C: |
632 | - def __length_hint__(self): |
633 | - return 42 |
634 | - self.obj = C() |
635 | - self.proxy = proxy(self.obj) |
636 | - self.assertEqual( |
637 | - operator.length_hint(self.proxy), operator.length_hint(self.obj)) |
638 | - self.assertEqual( |
639 | - self.proxy.__length_hint__(), operator.length_hint(self.obj)) |
640 | - |
641 | - def test_getitem(self): |
642 | - self.assertEqual(self.proxy['item'], self.obj['item']) |
643 | - self.assertEqual(self.proxy.__getitem__('item'), self.obj['item']) |
644 | - |
645 | - def test_setitem_v1(self): |
646 | - # NOTE: MagicMock doesn't store item assignment |
647 | - self.obj = ["old"] |
648 | - self.proxy = proxy(self.obj) |
649 | - self.proxy[0] = "new" |
650 | - self.assertEqual(self.obj[0], "new") |
651 | - |
652 | - def test_setitem_v2(self): |
653 | - # NOTE: MagicMock doesn't store item assignment |
654 | - self.obj = ["old"] |
655 | - self.proxy = proxy(self.obj) |
656 | - self.proxy.__setitem__(0, "value") |
657 | - self.assertEqual(self.obj[0], "value") |
658 | - |
659 | - def test_delitem(self): |
660 | - obj = {'k': 'v'} |
661 | - del proxy(obj)['k'] |
662 | - self.assertEqual(obj, {}) |
663 | - obj = {'k': 'v'} |
664 | - proxy(obj).__delitem__('k') |
665 | - self.assertEqual(obj, {}) |
666 | - |
667 | - def test_iter(self): |
668 | - # NOTE: MagicMock.__iter__ needs to return a deterministic iterator as |
669 | - # by default a new iterator is returned each time. |
670 | - self.obj.__iter__.return_value = iter([]) |
671 | - self.assertEqual(iter(self.proxy), iter(self.obj)) |
672 | - self.assertEqual(self.proxy.__iter__(), iter(self.obj)) |
673 | - |
674 | - def test_reversed(self): |
675 | - # NOTE: apparently MagicMock.doesn't support __reversed__ so we fall |
676 | - # back to the approach with a custom class. The same comment, as above, |
677 | - # for __iter__() applies though. |
678 | - with self.assertRaises(AttributeError): |
679 | - self.obj.__reversed__.return_value = reversed([]) |
680 | - |
681 | - class C: |
682 | - reversed_retval = iter([]) |
683 | - |
684 | - def __reversed__(self): |
685 | - return self.reversed_retval |
686 | - self.obj = C() |
687 | - self.proxy = proxy(self.obj) |
688 | - self.assertEqual(reversed(self.proxy), reversed(self.obj)) |
689 | - self.assertEqual(self.proxy.__reversed__(), reversed(self.obj)) |
690 | - |
691 | - def test_contains(self): |
692 | - item = object() |
693 | - self.assertEqual(item in self.proxy, item in self.obj) |
694 | - self.assertEqual(self.proxy.__contains__(item), item in self.obj) |
695 | - self.assertEqual(self.proxy.__contains__(item), False) |
696 | - self.obj.__contains__.return_value = True |
697 | - self.assertEqual(item in self.proxy, item in self.obj) |
698 | - self.assertEqual(self.proxy.__contains__(item), item in self.obj) |
699 | - self.assertEqual(self.proxy.__contains__(item), True) |
700 | - |
701 | - # TODO, tests and implementation for all the numeric methods |
702 | - |
703 | - def test_context_manager_methods_v1(self): |
704 | - with self.proxy: |
705 | - pass |
706 | - self.obj.__enter__.assert_called_once_with() |
707 | - self.obj.__exit__.assert_called_once_with(None, None, None) |
708 | - |
709 | - def test_context_manager_methods_v2(self): |
710 | - exc = Exception("boom") |
711 | - exc_info = () |
712 | - with self.assertRaisesRegex(Exception, "boom"): |
713 | - try: |
714 | - with self.proxy: |
715 | - raise exc |
716 | - except Exception: |
717 | - exc_info = sys.exc_info() |
718 | - raise |
719 | - self.obj.__enter__.assert_called_once_with() |
720 | - self.obj.__exit__.assert_called_once_with(*exc_info) |
721 | - |
722 | - def test_hasattr_parity(self): |
723 | - class C(): |
724 | - pass |
725 | - special_methods = ''' |
726 | - __del__ |
727 | - __repr__ |
728 | - __str__ |
729 | - __bytes__ |
730 | - __format__ |
731 | - __lt__ |
732 | - __le__ |
733 | - __eq__ |
734 | - __ne__ |
735 | - __gt__ |
736 | - __ge__ |
737 | - __hash__ |
738 | - __bool__ |
739 | - __getattr__ |
740 | - __getattribute__ |
741 | - __setattr__ |
742 | - __delattr__ |
743 | - __dir__ |
744 | - __get__ |
745 | - __set__ |
746 | - __delete__ |
747 | - __call__ |
748 | - __len__ |
749 | - __length_hint__ |
750 | - __getitem__ |
751 | - __setitem__ |
752 | - __delitem__ |
753 | - __iter__ |
754 | - __reversed__ |
755 | - __contains__ |
756 | - __enter__ |
757 | - __exit__ |
758 | - '''.split() |
759 | - for obj in [C(), 42, property(lambda x: x), int, None]: |
760 | - self.obj = obj |
761 | - self.proxy = proxy(self.obj) |
762 | - for attr in special_methods: |
763 | - self.assertEqual( |
764 | - hasattr(self.obj, attr), |
765 | - hasattr(self.proxy, attr), |
766 | - "attribute presence mismatch on attr %r and object %r" % ( |
767 | - attr, self.obj)) |
768 | - |
769 | - def test_isinstance(self): |
770 | - # NOTE: this method tests the metaclass |
771 | - self.assertIsInstance(self.obj, type(self.obj)) |
772 | - self.assertIsInstance(self.proxy, type(self.obj)) |
773 | - |
774 | - def test_issubclass(self): |
775 | - # NOTE: this method tests the metaclass |
776 | - # NOTE: mock doesn't support subclasscheck |
777 | - obj = "something other than mock" |
778 | - self.assertTrue(issubclass(str, type(obj))) |
779 | - self.assertTrue(issubclass(str, type(proxy(obj)))) |
780 | - |
781 | - def test_class(self): |
782 | - self.assertEqual(self.proxy.__class__, self.obj.__class__) |
783 | - # NOTE: The proxy cannot hide the fact, that it is a proxy |
784 | - self.assertNotEqual(type(self.proxy), type(self.obj)) |
785 | - |
786 | - |
787 | -class proxy_as_class(unittest.TestCase): |
788 | - |
789 | - def setUp(self): |
790 | - if reality_is_broken: |
791 | - print() |
792 | - _logger.debug("STARTING") |
793 | - _logger.debug("[%s]", self._testMethodName) |
794 | - |
795 | - def tearDown(self): |
796 | - if reality_is_broken: |
797 | - _logger.debug("DONE") |
798 | - |
799 | - def test_proxy_subclass(self): |
800 | - # NOTE: bring your comb, because this is the extra-hairy land |
801 | - class censored(proxy): |
802 | - |
803 | - @unproxied |
804 | - def __str__(self): |
805 | - return "*" * len(super().__str__()) |
806 | - self.assertTrue(issubclass(censored, proxy)) |
807 | - self.assertEqual(str(censored("freedom")), "*******") |
808 | - self.assertEqual(censored("freedom").__str__(), "*******") |
809 | |
810 | === modified file 'plainbox/requirements/deb-core.txt' |
811 | --- plainbox/requirements/deb-core.txt 2015-06-25 16:46:15 +0000 |
812 | +++ plainbox/requirements/deb-core.txt 2015-08-31 14:17:15 +0000 |
813 | @@ -1,3 +1,4 @@ |
814 | policykit-1 |
815 | python3-jinja2 |
816 | +python3-padme |
817 | python3-xlsxwriter |
818 | |
819 | === modified file 'plainbox/setup.py' |
820 | --- plainbox/setup.py 2015-08-03 14:10:44 +0000 |
821 | +++ plainbox/setup.py 2015-08-31 14:17:15 +0000 |
822 | @@ -72,6 +72,7 @@ |
823 | ], |
824 | install_requires=[ |
825 | 'Jinja2 >= 2.7', |
826 | + 'padme >= 1.1.1', |
827 | 'requests >= 1.0', |
828 | ], |
829 | extras_require={ |
the devendorization continues, +1