Merge lp:~sylvain-pineau/checkbox/ppa-packaging-plainbox-libxml2-removal into lp:checkbox
- ppa-packaging-plainbox-libxml2-removal
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~sylvain-pineau/checkbox/ppa-packaging-plainbox-libxml2-removal |
Merge into: | lp:checkbox |
Diff against target: |
4167 lines (+4052/-0) 22 files modified
debian/changelog (+221/-0) debian/clean (+2/-0) debian/compat (+1/-0) debian/control (+169/-0) debian/copyright (+213/-0) debian/patches/documentation-theme (+31/-0) debian/patches/series (+3/-0) debian/patches/silence-logging-failure (+24/-0) debian/patches/unvendorize (+3276/-0) debian/plainbox-insecure-policy.install (+1/-0) debian/plainbox-secure-policy.install (+1/-0) debian/plainbox.install (+1/-0) debian/plainbox.manpages (+33/-0) debian/python3-plainbox-doc.doc-base (+9/-0) debian/python3-plainbox-doc.docs (+1/-0) debian/python3-plainbox.install (+8/-0) debian/python3-plainbox.manpages (+2/-0) debian/rules (+42/-0) debian/source/format (+1/-0) debian/source/options (+1/-0) debian/tests/control (+2/-0) debian/tests/unit-tests (+10/-0) |
To merge this branch: | bzr merge lp:~sylvain-pineau/checkbox/ppa-packaging-plainbox-libxml2-removal |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Checkbox Developers | Pending | ||
Review via email: mp+263022@code.launchpad.net |
Commit message
Description of the change
this MR removes the libxml2 dependency and adds python3-xlsxwriter (previously just a suggested package)
- 31. By Sylvain Pineau
-
debian/control: Build dependencies update
Add python3-xlsxwriter and remove libxml2.
Unmerged revisions
- 31. By Sylvain Pineau
-
debian/control: Build dependencies update
Add python3-xlsxwriter and remove libxml2.
- 30. By Sylvain Pineau
-
debian/control: Remove the dependency on libxml2 and add python3-xlsxwriter
- 29. By Sylvain Pineau
-
"Release_
2015_Week18 [r=sylvain- pineau] [bug=][ author= checkbox- dev]" - 28. By Zygmunt Krynicki
-
"automatic merge of lp:~zyga/checkbox/ppa-packaging-plainbox/ by tarmac [r=sylvain-
pineau] [bug=][ author= zyga]" - 27. By Zygmunt Krynicki
-
"automatic merge of lp:~zyga/checkbox/ppa-packaging-plainbox/ by tarmac [r=roadmr]
[bug=][ author= zyga]" - 26. By Sylvain Pineau
-
"automatic merge of lp:~sylvain-pineau/checkbox/ppa-packaging-plainbox-python3-jinja2/ by tarmac [r=zyga]
[bug=][ author= sylvain- pineau] " - 25. By Sylvain Pineau
-
"Release_
2015_Week11 [r=sylvain- pineau] [bug=][ author= checkbox- dev]" - 24. By Zygmunt Krynicki
-
"automatic merge of lp:~zkrynicki/checkbox/ppa-packaging-plainbox/ by tarmac [r=roadmr]
[bug=][ author= zkrynicki] " - 23. By Maciej Kisielewski
-
"automatic merge of lp:~kissiel/checkbox/ppa-packaging-plainbox/ by tarmac [r=sylvain-
pineau] [bug=][ author= kissiel] " - 22. By Sylvain Pineau
-
"Release_2015_Week5 [r=sylvain-
pineau] [bug=][ author= checkbox- dev]"
Preview Diff
1 | === added directory 'debian' |
2 | === added file 'debian/changelog' |
3 | --- debian/changelog 1970-01-01 00:00:00 +0000 |
4 | +++ debian/changelog 2015-06-25 19:25:23 +0000 |
5 | @@ -0,0 +1,221 @@ |
6 | +plainbox (0.22) UNRELEASED; urgency=medium |
7 | + |
8 | + * Open for development (remove this message before releasing) |
9 | + |
10 | + -- Sylvain Pineau <sylvain.pineau@canonical.com> Mon, 27 Apr 2015 00:30:30 +0200 |
11 | + |
12 | +plainbox (0.21) unstable; urgency=medium |
13 | + |
14 | + [ Sylvain Pineau ] |
15 | + |
16 | + [ Zygmunt Krynicki ] |
17 | + * Remove the dependency on dh_python (which we're not using) as it is not |
18 | + available on precise. |
19 | + |
20 | + [ Sylvain Pineau ] |
21 | + * New upstream release |
22 | + |
23 | + -- Sylvain Pineau <sylvain.pineau@canonical.com> Mon, 27 Apr 2015 00:30:09 +0200 |
24 | + |
25 | +plainbox (0.20) unstable; urgency=medium |
26 | + |
27 | + [ Sylvain Pineau ] |
28 | + |
29 | + [ Zygmunt Krynicki ] |
30 | + * Ship several existing manual pages that were forgotten about |
31 | + |
32 | + [ Sylvain Pineau ] |
33 | + * New upstream release |
34 | + |
35 | + -- Sylvain Pineau <sylvain.pineau@canonical.com> Mon, 09 Mar 2015 11:56:52 +0100 |
36 | + |
37 | +plainbox (0.19) unstable; urgency=medium |
38 | + |
39 | + * New upstream release |
40 | + |
41 | + -- Sylvain Pineau <sylvain.pineau@canonical.com> Mon, 26 Jan 2015 16:24:49 +0100 |
42 | + |
43 | +plainbox (0.18) unstable; urgency=medium |
44 | + |
45 | + * New upstream release |
46 | + |
47 | + -- Sylvain Pineau <sylvain.pineau@canonical.com> Tue, 13 Jan 2015 14:35:46 +0100 |
48 | + |
49 | +plainbox (0.17) unstable; urgency=medium |
50 | + |
51 | + * New upstream release |
52 | + |
53 | + -- Sylvain Pineau <sylvain.pineau@canonical.com> Sun, 07 Dec 2014 23:22:10 +0100 |
54 | + |
55 | +plainbox (0.16) unstable; urgency=medium |
56 | + |
57 | + * New upstream release |
58 | + |
59 | + -- Sylvain Pineau <sylvain.pineau@canonical.com> Fri, 07 Nov 2014 17:15:12 +0100 |
60 | + |
61 | +plainbox (0.15) unstable; urgency=medium |
62 | + |
63 | + * New upstream release |
64 | + |
65 | + -- Sylvain Pineau <sylvain.pineau@canonical.com> Mon, 27 Oct 2014 09:15:51 +0100 |
66 | + |
67 | +plainbox (0.14) unstable; urgency=medium |
68 | + |
69 | + [ Daniel Manrique ] |
70 | + |
71 | + [ Sylvain Pineau ] |
72 | + * New upstream release |
73 | + |
74 | + -- Sylvain Pineau <sylvain.pineau@canonical.com> Sun, 12 Oct 2014 23:07:26 +0200 |
75 | + |
76 | +plainbox (0.13.1) unstable; urgency=medium |
77 | + |
78 | + * New upstream critical bugfix release |
79 | + |
80 | + -- Daniel Manrique <roadmr@ubuntu.com> Tue, 30 Sep 2014 17:59:08 -0400 |
81 | + |
82 | +plainbox (0.13) unstable; urgency=medium |
83 | + |
84 | + [ Sylvain Pineau ] |
85 | + |
86 | + [ Daniel Manrique ] |
87 | + * New upstream release |
88 | + |
89 | + -- Daniel Manrique <roadmr@ubuntu.com> Fri, 26 Sep 2014 17:10:04 -0400 |
90 | + |
91 | +plainbox (0.12) unstable; urgency=medium |
92 | + |
93 | + [ Daniel Manrique ] |
94 | + |
95 | + [ Sylvain Pineau ] |
96 | + * New upstream release |
97 | + |
98 | + -- Sylvain Pineau <sylvain.pineau@canonical.com> Sun, 14 Sep 2014 23:01:59 +0200 |
99 | + |
100 | +plainbox (0.11) unstable; urgency=medium |
101 | + |
102 | + * New upstream release |
103 | + |
104 | + -- Daniel Manrique <roadmr@ubuntu.com> Fri, 29 Aug 2014 13:06:04 -0400 |
105 | + |
106 | +plainbox (0.10) unstable; urgency=medium |
107 | + |
108 | + [ Sylvain Pineau ] |
109 | + |
110 | + [ Daniel Manrique ] |
111 | + * New upstream release |
112 | + |
113 | + -- Daniel Manrique <roadmr@ubuntu.com> Fri, 15 Aug 2014 16:13:19 -0400 |
114 | + |
115 | +plainbox (0.9) unstable; urgency=medium |
116 | + |
117 | + [ Sylvain Pineau ] |
118 | + * New upstream release |
119 | + |
120 | + [ Zygmunt Krynicki ] |
121 | + * Add all of the new manual pages to the plainbox package. |
122 | + |
123 | + -- Sylvain Pineau <sylvain.pineau@canonical.com> Fri, 01 Aug 2014 14:58:00 +0200 |
124 | + |
125 | +plainbox (0.8) unstable; urgency=medium |
126 | + |
127 | + * New upstream release |
128 | + |
129 | + -- Sylvain Pineau <sylvain.pineau@canonical.com> Sat, 19 Jul 2014 20:56:54 +0200 |
130 | + |
131 | +plainbox (0.7) unstable; urgency=medium |
132 | + |
133 | + * New upstream release |
134 | + |
135 | + -- Sylvain Pineau <sylvain.pineau@canonical.com> Mon, 07 Jul 2014 20:52:17 +0200 |
136 | + |
137 | +plainbox (0.6) unstable; urgency=medium |
138 | + |
139 | + * debian/control: make python3-plainbox, plainbox, plainbox-secure-policy |
140 | + and plainbox-insecure-policy all depend on one version on themselves. |
141 | + LP: #1298284 |
142 | + * fork of Debian packaging at 0.5.1-2 (unreleased) for PPA-specific builds |
143 | + * debian/control: don't depend on dh-python |
144 | + * debian/rules: don't use pybuild, do everything manually |
145 | + * debian/plainbox.install, debian/python3-plainbox.install: install required |
146 | + files manually without relying on pybuild |
147 | + * debian/control: don't depend and build-depend on python3-requests, |
148 | + plainbox doesn't depend on it anymore |
149 | + * debian/control: break checkbox-ng << 0.3 (synchronized from debian) |
150 | + * debian/control: build-depend on policykit-1 (LP: #1319442) |
151 | + |
152 | + -- Sylvain Pineau <sylvain.pineau@canonical.com> Mon, 16 Jun 2014 14:29:16 +0200 |
153 | + |
154 | +plainbox (0.5.1-1) unstable; urgency=medium |
155 | + |
156 | + * New upstream release |
157 | + * debian/control: drop X-Python3-Version << 3.5 |
158 | + * debian/patches/disable-development-option: dropped, applied upstream |
159 | + * debian/copyright: associate vendorized copies of argparse with appropriate |
160 | + copyright section |
161 | + |
162 | + -- Zygmunt Krynicki <zygmunt.krynicki@canonical.com> Wed, 19 Mar 2014 00:08:12 +0100 |
163 | + |
164 | +plainbox (0.5~b2-1) unstable; urgency=medium |
165 | + |
166 | + * New upstream release. |
167 | + * debian/control: build-depend on python3-distutils-extra for translations |
168 | + * debian/control: add support for python3.4 |
169 | + * debian/control: drop build dependency on help2man, the new release has |
170 | + native manual pages |
171 | + * debian/rules: build, install and clean up after translations |
172 | + * debian/clean: clean *.egg-info and *.pot files since those get |
173 | + regenerated |
174 | + * debian/source/options: ignore changes to .po files since intltools-update |
175 | + keeps bumping the timestamp embedded in them |
176 | + * debian/copyright: add license section for plainbox/impl/_argparse.py |
177 | + * debian/copyright: add new copyright entries for textland |
178 | + * debian/patches: refresh and reorder without any semantic changes |
179 | + * debian/patches: add patch to revert documentation theme to defaults |
180 | + * debian/watch: add mangling for alpha releases |
181 | + * debian/python3-plainbox.manpages, debian/plainbox.manpages: use manual |
182 | + pages build with sphinx |
183 | + |
184 | + -- Zygmunt Krynicki <zygmunt.krynicki@canonical.com> Thu, 13 Mar 2014 09:45:06 +0100 |
185 | + |
186 | +plainbox (0.4-4) unstable; urgency=medium |
187 | + |
188 | + * Team upload. |
189 | + * Autopkgtest improvements: enable verbose output, use $ADTTMP and stop |
190 | + redirecting output to /dev/null. |
191 | + * Export NO_PNG_PKG_MANGLE=1 in debian/rules to disable PNG stripping |
192 | + when pkgbinarymangler is installed (it breaks the testsuite). |
193 | + |
194 | + -- Dmitry Shachnev <mitya57@gmail.com> Wed, 22 Jan 2014 18:08:40 +0400 |
195 | + |
196 | +plainbox (0.4-3) unstable; urgency=medium |
197 | + |
198 | + * debian/tests/unit-tests: actually fail the test suite if unit tests fail. |
199 | + Thanks to Michael Terry for the fix. LP:#1265853 |
200 | + |
201 | + -- Zygmunt Krynicki <zygmunt.krynicki@canonical.com> Fri, 03 Jan 2014 16:55:54 +0100 |
202 | + |
203 | +plainbox (0.4-2) unstable; urgency=medium |
204 | + |
205 | + * debian/tests/control: Fix autopackage tests not to install all (including |
206 | + conflicting) packages blindly LP:#1264985 |
207 | + |
208 | + -- Zygmunt Krynicki <zygmunt.krynicki@canonical.com> Thu, 02 Jan 2014 10:33:29 +0100 |
209 | + |
210 | +plainbox (0.4-1) unstable; urgency=medium |
211 | + |
212 | + * New upstream release |
213 | + * plainbox-insecure-policy.install, plainbox-secure-policy.install: adjust |
214 | + packaging to install the same policykit .policy files under their new |
215 | + names |
216 | + * debian/copyright: update all Canonical-owned code to GPL-3 (not GPL-3+) |
217 | + * debian/control: mark python3.4 as unsupported as python3-lxml does not |
218 | + support python3.4 yet |
219 | + |
220 | + -- Zygmunt Krynicki <zygmunt.krynicki@canonical.com> Tue, 24 Dec 2013 14:27:09 +0100 |
221 | + |
222 | +plainbox (0.4~b2-1) unstable; urgency=low |
223 | + |
224 | + * Initial release (Closes: #730568) |
225 | + |
226 | + -- Zygmunt Krynicki <zygmunt.krynicki@canonical.com> Thu, 28 Nov 2013 23:38:28 +0000 |
227 | |
228 | === added file 'debian/clean' |
229 | --- debian/clean 1970-01-01 00:00:00 +0000 |
230 | +++ debian/clean 2015-06-25 19:25:23 +0000 |
231 | @@ -0,0 +1,2 @@ |
232 | +plainbox/vendor/sphinxarg/LICENSE |
233 | +plainbox/vendor/funcsigs/LICENSE |
234 | |
235 | === added file 'debian/compat' |
236 | --- debian/compat 1970-01-01 00:00:00 +0000 |
237 | +++ debian/compat 2015-06-25 19:25:23 +0000 |
238 | @@ -0,0 +1,1 @@ |
239 | +9 |
240 | |
241 | === added file 'debian/control' |
242 | --- debian/control 1970-01-01 00:00:00 +0000 |
243 | +++ debian/control 2015-06-25 19:25:23 +0000 |
244 | @@ -0,0 +1,169 @@ |
245 | +Source: plainbox |
246 | +Section: utils |
247 | +Priority: optional |
248 | +Maintainer: Zygmunt Krynicki <zygmunt.krynicki@canonical.com> |
249 | +Uploaders: Debian Python Modules Team <python-modules-team@lists.alioth.debian.org> |
250 | +Build-Depends: debhelper (>= 9), |
251 | + python3-all, |
252 | + python3-distutils-extra, |
253 | + python3-docutils, |
254 | + python3-jinja2, |
255 | + python3-lxml, |
256 | + python3-pkg-resources, |
257 | + python3-setuptools, |
258 | + python3-sphinx |
259 | +Standards-Version: 3.9.5 |
260 | +X-Python3-Version: >= 3.2 |
261 | +Vcs-Svn: svn://anonscm.debian.org/python-modules/packages/plainbox/trunk/ |
262 | +Vcs-Browser: http://anonscm.debian.org/viewvc/python-modules/packages/plainbox/trunk/ |
263 | +XS-Testsuite: autopkgtest |
264 | +Homepage: http://launchpad.net/checkbox |
265 | + |
266 | +Package: plainbox |
267 | +Architecture: all |
268 | +Depends: python3-pkg-resources, |
269 | + python3-plainbox (= ${binary:Version}), |
270 | + ${misc:Depends}, |
271 | + ${python3:Depends} |
272 | +Description: toolkit for software and hardware integration testing |
273 | + PlainBox is a toolkit consisting of python3 library, development tools, |
274 | + documentation and examples. It is targeted at developers working on testing or |
275 | + certification applications and authors creating tests for such applications. |
276 | + . |
277 | + PlainBox can be used to both create simple and comprehensive test tools as |
278 | + well as to develop and execute test jobs and test scenarios. It was created as |
279 | + a refined and rewritten core of the Checkbox project. It has a well tested and |
280 | + documented core, small but active development community and a collection of |
281 | + associated projects that use it as a lower-level engine/back-end library. |
282 | + . |
283 | + PlainBox has a novel approach to discovering (and probing) hardware and |
284 | + software that is extensible and not hardwired into the system. It allows test |
285 | + developers to express association between a particular test and the hardware, |
286 | + software and configuration constraints that must be met for the test to |
287 | + execute meaningfully. This feature, along with pluggable test definitions, |
288 | + makes plainbox flexible and applicable to many diverse testing situations, |
289 | + ranging from mobile phones, traditional desktop computers, servers and up to |
290 | + testing "cloud" installations. |
291 | + . |
292 | + This package contains the plainbox executable |
293 | + |
294 | +Package: python3-plainbox |
295 | +Architecture: all |
296 | +Section: python |
297 | +Depends: plainbox-secure-policy (= ${binary:Version}) | plainbox-insecure-policy (= ${binary:Version}), |
298 | + policykit-1, |
299 | + python3-jinja2, |
300 | + python3-xlsxwriter, |
301 | + python3-pkg-resources, |
302 | + ${misc:Depends}, |
303 | + ${python3:Depends} |
304 | +Breaks: python3-checkbox-ng (<< 0.18) |
305 | +Description: toolkit for software and hardware testing (python3 module) |
306 | + PlainBox is a toolkit consisting of python3 library, development tools, |
307 | + documentation and examples. It is targeted at developers working on testing or |
308 | + certification applications and authors creating tests for such applications. |
309 | + . |
310 | + PlainBox can be used to both create simple and comprehensive test tools as |
311 | + well as to develop and execute test jobs and test scenarios. It was created as |
312 | + a refined and rewritten core of the Checkbox project. It has a well tested and |
313 | + documented core, small but active development community and a collection of |
314 | + associated projects that use it as a lower-level engine/back-end library. |
315 | + . |
316 | + PlainBox has a novel approach to discovering (and probing) hardware and |
317 | + software that is extensible and not hardwired into the system. It allows test |
318 | + developers to express association between a particular test and the hardware, |
319 | + software and configuration constraints that must be met for the test to |
320 | + execute meaningfully. This feature, along with pluggable test definitions, |
321 | + makes plainbox flexible and applicable to many diverse testing situations, |
322 | + ranging from mobile phones, traditional desktop computers, servers and up to |
323 | + testing "cloud" installations. |
324 | + . |
325 | + This package contains the plainbox python3 library. |
326 | + |
327 | +Package: python3-plainbox-doc |
328 | +Architecture: all |
329 | +Section: doc |
330 | +Priority: extra |
331 | +Depends: ${misc:Depends}, ${sphinxdoc:Depends} |
332 | +Description: toolkit for software and hardware testing (documentation) |
333 | + PlainBox is a toolkit consisting of python3 library, development tools, |
334 | + documentation and examples. It is targeted at developers working on testing or |
335 | + certification applications and authors creating tests for such applications. |
336 | + . |
337 | + PlainBox can be used to both create simple and comprehensive test tools as |
338 | + well as to develop and execute test jobs and test scenarios. It was created as |
339 | + a refined and rewritten core of the Checkbox project. It has a well tested and |
340 | + documented core, small but active development community and a collection of |
341 | + associated projects that use it as a lower-level engine/back-end library. |
342 | + . |
343 | + PlainBox has a novel approach to discovering (and probing) hardware and |
344 | + software that is extensible and not hardwired into the system. It allows test |
345 | + developers to express association between a particular test and the hardware, |
346 | + software and configuration constraints that must be met for the test to |
347 | + execute meaningfully. This feature, along with pluggable test definitions, |
348 | + makes plainbox flexible and applicable to many diverse testing situations, |
349 | + ranging from mobile phones, traditional desktop computers, servers and up to |
350 | + testing "cloud" installations. |
351 | + . |
352 | + This package contains the documentation for the plainbox python3 library |
353 | + |
354 | +Package: plainbox-secure-policy |
355 | +Architecture: all |
356 | +Depends: ${misc:Depends} |
357 | +Conflicts: plainbox-insecure-policy |
358 | +Replaces: plainbox-insecure-policy |
359 | +Description: policykit policy required to use plainbox (secure version) |
360 | + PlainBox is a toolkit consisting of python3 library, development tools, |
361 | + documentation and examples. It is targeted at developers working on testing or |
362 | + certification applications and authors creating tests for such applications. |
363 | + . |
364 | + PlainBox can be used to both create simple and comprehensive test tools as |
365 | + well as to develop and execute test jobs and test scenarios. It was created as |
366 | + a refined and rewritten core of the Checkbox project. It has a well tested and |
367 | + documented core, small but active development community and a collection of |
368 | + associated projects that use it as a lower-level engine/back-end library. |
369 | + . |
370 | + PlainBox has a novel approach to discovering (and probing) hardware and |
371 | + software that is extensible and not hardwired into the system. It allows test |
372 | + developers to express association between a particular test and the hardware, |
373 | + software and configuration constraints that must be met for the test to |
374 | + execute meaningfully. This feature, along with pluggable test definitions, |
375 | + makes plainbox flexible and applicable to many diverse testing situations, |
376 | + ranging from mobile phones, traditional desktop computers, servers and up to |
377 | + testing "cloud" installations. |
378 | + . |
379 | + This package contains a PolicyKit .policy file that allows PlainBox to run |
380 | + plainbox-trusted-launcher-1 as root and ask for the user password only once |
381 | + per session. |
382 | + |
383 | +Package: plainbox-insecure-policy |
384 | +Architecture: all |
385 | +Depends: ${misc:Depends} |
386 | +Conflicts: plainbox-secure-policy |
387 | +Replaces: plainbox-secure-policy |
388 | +Description: policykit policy required to use plainbox (insecure version) |
389 | + PlainBox is a toolkit consisting of python3 library, development tools, |
390 | + documentation and examples. It is targeted at developers working on testing or |
391 | + certification applications and authors creating tests for such applications. |
392 | + . |
393 | + PlainBox can be used to both create simple and comprehensive test tools as |
394 | + well as to develop and execute test jobs and test scenarios. It was created as |
395 | + a refined and rewritten core of the Checkbox project. It has a well tested and |
396 | + documented core, small but active development community and a collection of |
397 | + associated projects that use it as a lower-level engine/back-end library. |
398 | + . |
399 | + PlainBox has a novel approach to discovering (and probing) hardware and |
400 | + software that is extensible and not hardwired into the system. It allows test |
401 | + developers to express association between a particular test and the hardware, |
402 | + software and configuration constraints that must be met for the test to |
403 | + execute meaningfully. This feature, along with pluggable test definitions, |
404 | + makes plainbox flexible and applicable to many diverse testing situations, |
405 | + ranging from mobile phones, traditional desktop computers, servers and up to |
406 | + testing "cloud" installations. |
407 | + . |
408 | + Note that installing this package will allow *any* local user to execute any |
409 | + of the plainbox jobs (test definitions), also installed on the same machine |
410 | + (in system-wide locations), without any confirmation. You should only install |
411 | + this package on machines where that is not a security problem. Typically this |
412 | + package is installed on test machines inside automatically deployed test |
413 | + farms. |
414 | |
415 | === added file 'debian/copyright' |
416 | --- debian/copyright 1970-01-01 00:00:00 +0000 |
417 | +++ debian/copyright 2015-06-25 19:25:23 +0000 |
418 | @@ -0,0 +1,213 @@ |
419 | +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ |
420 | +Upstream-Name: plainbox |
421 | +Source: https://launchpad.net/checkbox |
422 | + |
423 | +Files: * |
424 | +Copyright: Copyright 2012-2015 Canonical Ltd. |
425 | +License: GPL-3 |
426 | + This program is free software: you can redistribute it and/or modify |
427 | + it under the terms of the GNU General Public License version 3, |
428 | + as published by the Free Software Foundation. |
429 | + . |
430 | + This program is distributed in the hope that it will be useful, |
431 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
432 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
433 | + GNU General Public License for more details. |
434 | + . |
435 | + You should have received a copy of the GNU General Public License |
436 | + along with this program. If not, see <http://www.gnu.org/licenses/>. |
437 | + . |
438 | + On Debian-based systems the full text of the GPL, version 3, can be found at |
439 | + /usr/share/common-licenses/GPL-3. |
440 | + |
441 | +Files: plainbox/vendor/extcmd/* |
442 | +Copyright: |
443 | + Copyright (c) 2010-2012 Linaro Limited |
444 | + Copyright (c) 2013 Canonical Ltd. |
445 | +License: GPL-3+ |
446 | + This program is free software: you can redistribute it and/or modify |
447 | + it under the terms of the GNU General Public License as published by |
448 | + the Free Software Foundation, either version 3 of the License, or |
449 | + (at your option) any later version. |
450 | + . |
451 | + This program is distributed in the hope that it will be useful, |
452 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
453 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
454 | + GNU General Public License for more details. |
455 | + . |
456 | + You should have received a copy of the GNU General Public License |
457 | + along with this program. If not, see <http://www.gnu.org/licenses/>. |
458 | + . |
459 | + On Debian-based systems the full text of the GPL, version 3, can be found at |
460 | + /usr/share/common-licenses/GPL-3. |
461 | + |
462 | +Files: plainbox/vendor/funcsigs/* |
463 | +Copyright: |
464 | + Copyright 2013 Aaron Iles |
465 | + Copyright 2001-2013 Python Software Foundation; |
466 | +License: Apache-2.0 |
467 | + Licensed under the Apache License, Version 2.0 (the "License"); |
468 | + you may not use this file except in compliance with the License. |
469 | + You may obtain a copy of the License at |
470 | + . |
471 | + http://www.apache.org/licenses/LICENSE-2.0 |
472 | + . |
473 | + Unless required by applicable law or agreed to in writing, software |
474 | + distributed under the License is distributed on an "AS IS" BASIS, |
475 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
476 | + See the License for the specific language governing permissions and |
477 | + limitations under the License. |
478 | + . |
479 | + On Debian-based systems the full text of the Apache, version 2.0, can be found |
480 | + at /usr/share/common-licenses/Apache-2.0. |
481 | + |
482 | +Files: plainbox/vendor/mock.py |
483 | +Copyright: Copyright (C) 2007-2012 Michael Foord & the mock team |
484 | +License: BSD-3-clause |
485 | + Redistribution and use in source and binary forms, with or without |
486 | + modification, are permitted provided that the following conditions are |
487 | + met: |
488 | + . |
489 | + . |
490 | + * Redistributions of source code must retain the above copyright |
491 | + notice, this list of conditions and the following disclaimer. |
492 | + . |
493 | + * Redistributions in binary form must reproduce the above |
494 | + copyright notice, this list of conditions and the following |
495 | + disclaimer in the documentation and/or other materials provided |
496 | + with the distribution. |
497 | + . |
498 | + * Neither the name of Michael Foord nor the name of Voidspace |
499 | + may be used to endorse or promote products derived from this |
500 | + software without specific prior written permission. |
501 | + . |
502 | + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
503 | + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
504 | + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
505 | + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
506 | + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
507 | + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
508 | + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
509 | + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
510 | + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
511 | + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
512 | + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
513 | + |
514 | +Files: plainbox/vendor/argparse/*.py |
515 | +Copyright: Steven J. Bethard <steven.bethard@gmail.com>. |
516 | +License: Python |
517 | + |
518 | +Files: plainbox/vendor/sphinxarg/* |
519 | +Copyright: Copyright (c) 2013 Alex Rudakov |
520 | +License: MIT |
521 | + The MIT License (MIT) |
522 | + . |
523 | + Permission is hereby granted, free of charge, to any person obtaining a copy of |
524 | + this software and associated documentation files (the "Software"), to deal in |
525 | + the Software without restriction, including without limitation the rights to |
526 | + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of |
527 | + the Software, and to permit persons to whom the Software is furnished to do so, |
528 | + subject to the following conditions: |
529 | + . |
530 | + The above copyright notice and this permission notice shall be included in all |
531 | + copies or substantial portions of the Software. |
532 | + . |
533 | + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
534 | + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS |
535 | + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR |
536 | + COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
537 | + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
538 | + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
539 | + |
540 | +Files: plainbox/vendor/morris/* |
541 | +Copyright: Copyright (c) 2012-15 Canonical Ltd. |
542 | +License: LGPL-3+ |
543 | + This file is part of Morris. |
544 | + . |
545 | + Morris is free software: you can redistribute it and/or modify |
546 | + it under the terms of the GNU Lesser General Public License as published by |
547 | + the Free Software Foundation, either version 3 of the License. |
548 | + . |
549 | + Morris is distributed in the hope that it will be useful, |
550 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
551 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
552 | + GNU Lesser General Public License for more details. |
553 | + . |
554 | + You should have received a copy of the GNU Lesser General Public License |
555 | + along with Morris. If not, see <http://www.gnu.org/licenses/>. |
556 | + |
557 | +Files: plainbox/vendor/glibc/* |
558 | +Copyright: Copyright (c) 2014 Canonical Ltd. |
559 | +License: LGPL-3+ |
560 | + This program is free software: you can redistribute it and/or modify |
561 | + it under the terms of the GNU Lesser General Public License as published by |
562 | + the Free Software Foundation, either version 3 of the License, or |
563 | + (at your option) any later version. |
564 | + . |
565 | + This program is distributed in the hope that it will be useful, |
566 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
567 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
568 | + GNU Lesser General Public License for more details. |
569 | + . |
570 | + You should have received a copy of the GNU Lesser General Public License |
571 | + along with this program. If not, see <http://www.gnu.org/licenses/>. |
572 | + |
573 | +Files: plainbox/impl/_argparse.py |
574 | +Copyright: Steven J. Bethard <steven.bethard@gmail.com>. |
575 | +License: Python |
576 | + |
577 | +Files: plainbox/impl/_shlex.py |
578 | +Copyright: |
579 | + Module and documentation by Eric S. Raymond, 21 Dec 1998 |
580 | + Input stacking and error message cleanup added by ESR, March 2000 |
581 | + push_source() and pop_source() made explicit by ESR, January 2001. |
582 | + Posix compliance, split(), string arguments, and |
583 | + iterator interface by Gustavo Niemeyer, April 2003. |
584 | +License: Python |
585 | + |
586 | +License: Python |
587 | + PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 |
588 | + -------------------------------------------- |
589 | + . |
590 | + 1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), |
591 | + and the Individual or Organization ("Licensee") accessing and otherwise |
592 | + using this software ("Python") in source or binary form and its associated |
593 | + documentation. |
594 | + . |
595 | + 2. Subject to the terms and conditions of this License Agreement, PSF hereby |
596 | + grants Licensee a nonexclusive, royalty-free, world-wide license to |
597 | + reproduce, analyze, test, perform and/or display publicly, prepare |
598 | + derivative works, distribute, and otherwise use Python alone or in any |
599 | + derivative version, provided, however, that PSF's License Agreement and |
600 | + PSF's notice of copyright, i.e., "Copyright (c) 2001, 2002, 2003, 2004, |
601 | + 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Python Software |
602 | + Foundation; All Rights Reserved" are retained in Python alone or in any |
603 | + derivative version prepared by Licensee. |
604 | + . |
605 | + 3. In the event Licensee prepares a derivative work that is based on or |
606 | + incorporates Python or any part thereof, and wants to make the derivative |
607 | + work available to others as provided herein, then Licensee hereby agrees |
608 | + to include in any such work a brief summary of the changes made to Python. |
609 | + . |
610 | + 4. PSF is making Python available to Licensee on an "AS IS" basis. PSF MAKES |
611 | + NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, |
612 | + BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR |
613 | + WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT |
614 | + THE USE OF PYTHON WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. |
615 | + . |
616 | + 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON FOR ANY |
617 | + INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF |
618 | + MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, OR ANY DERIVATIVE |
619 | + THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. |
620 | + . |
621 | + 6. This License Agreement will automatically terminate upon a material breach |
622 | + of its terms and conditions. |
623 | + . |
624 | + 7. Nothing in this License Agreement shall be deemed to create any |
625 | + relationship of agency, partnership, or joint venture between PSF and |
626 | + Licensee. This License Agreement does not grant permission to use PSF |
627 | + trademarks or trade name in a trademark sense to endorse or promote |
628 | + products or services of Licensee, or any third party. |
629 | + . |
630 | + 8. By copying, installing or otherwise using Python, Licensee agrees to be |
631 | + bound by the terms and conditions of this License Agreement. |
632 | |
633 | === added directory 'debian/patches' |
634 | === added file 'debian/patches/documentation-theme' |
635 | --- debian/patches/documentation-theme 1970-01-01 00:00:00 +0000 |
636 | +++ debian/patches/documentation-theme 2015-06-25 19:25:23 +0000 |
637 | @@ -0,0 +1,31 @@ |
638 | +Description: Revert the documentation theme back to default |
639 | + PlainBox uses a customized sphinx theme that includes additional |
640 | + HTML to integrate with online comment service. This should not be |
641 | + a part of the offline documentation package. |
642 | +Author: Zygmunt Krynicki <zygmunt.krynicki@canonical.com> |
643 | +Origin: upstream |
644 | +Forwarded: not-needed |
645 | +Last-Update: 2014-03-18 |
646 | + |
647 | +--- a/docs/conf.py |
648 | ++++ b/docs/conf.py |
649 | +@@ -108,18 +108,11 @@ |
650 | + # Use our custom theme. For now it only adds Disqus.com support but we may |
651 | + # customize it further later on. The theme is called 'plainbox' and has one |
652 | + # option which controls if disqus is active or not. |
653 | +-html_theme = 'plainbox' |
654 | ++html_theme = 'default' |
655 | + |
656 | + # Theme options are theme-specific and customize the look and feel of a theme |
657 | + # further. For a list of options available for each theme, see the |
658 | + # documentation. |
659 | +-# |
660 | +-# Due to the way disqus works, it's only going to work on |
661 | +-# plainbox.readthedocs.org so only use it if building for readthedocs. |
662 | +- |
663 | +-html_theme_options = { |
664 | +- 'show_disqus': 'true' if os.environ.get("READTHEDOCS", None) == 'True' else '' |
665 | +-} |
666 | + |
667 | + # Add any paths that contain custom themes here, relative to this directory. |
668 | + html_theme_path = ['_theme'] |
669 | |
670 | === added file 'debian/patches/series' |
671 | --- debian/patches/series 1970-01-01 00:00:00 +0000 |
672 | +++ debian/patches/series 2015-06-25 19:25:23 +0000 |
673 | @@ -0,0 +1,3 @@ |
674 | +unvendorize |
675 | +silence-logging-failure |
676 | +documentation-theme |
677 | |
678 | === added file 'debian/patches/silence-logging-failure' |
679 | --- debian/patches/silence-logging-failure 1970-01-01 00:00:00 +0000 |
680 | +++ debian/patches/silence-logging-failure 2015-06-25 19:25:23 +0000 |
681 | @@ -0,0 +1,24 @@ |
682 | +Description: Silence setup failure of the logging subsystem |
683 | + The logging subsystem has a feature that displays two lines of warnings |
684 | + if the per-user log file cannot be created. This leads to spurious |
685 | + errors when plainbox is invoked from a build environment. Before a |
686 | + better solution is found this warning is disabled as all of the |
687 | + subsequent, relevant, logging messages are display either way. |
688 | +Author: Zygmunt Krynicki <zygmunt.krynicki@canonical.com> |
689 | +Bug-Ubuntu: https://bugs.launchpad.net/checkbox/+bug/1262898 |
690 | +Forwarded: yes |
691 | +Last-Update: 2014-03-18 |
692 | + |
693 | +--- a/plainbox/impl/logging.py |
694 | ++++ b/plainbox/impl/logging.py |
695 | +@@ -94,10 +94,6 @@ |
696 | + try: |
697 | + os.makedirs(self.log_dir, exist_ok=True) |
698 | + except OSError as error: |
699 | +- logger.warning( |
700 | +- _("Unable to create log directory: %s"), self.log_dir) |
701 | +- logger.warning(_("Reason: %s. All logs will go to " |
702 | +- "console instead."), error) |
703 | + config_dict = self.DEFAULT_CONSOLE_ONLY_CONFIG |
704 | + # Apply the selected configuration. This overrides anything currently |
705 | + # defined for all of the logging subsystem in this python runtime |
706 | |
707 | === added file 'debian/patches/unvendorize' |
708 | --- debian/patches/unvendorize 1970-01-01 00:00:00 +0000 |
709 | +++ debian/patches/unvendorize 2015-06-25 19:25:23 +0000 |
710 | @@ -0,0 +1,3276 @@ |
711 | +Description: Remove vendorized modules |
712 | + This patch replaces plainbox.vendor.{mock,funcsigs} with equivalent |
713 | + imports from the standard python3.3 library. Upstream will stop |
714 | + shipping those vendorized modules when support for python3.2 is no |
715 | + longer required. |
716 | +Author: Zygmunt Krynicki <zygmunt.krynicki@canonical.com> |
717 | +Upstream: not-needed |
718 | +Last-Update: 2014-03-18 |
719 | + |
720 | +--- a/plainbox/vendor/__init__.py |
721 | ++++ b/plainbox/vendor/__init__.py |
722 | +@@ -25,4 +25,9 @@ |
723 | + tree of another project) to simplify dependency management. There is no problem |
724 | + with expressing those dependencies at pypi level but it would be annoying to |
725 | + have to first package and introduce them to Ubuntu. |
726 | ++ |
727 | ++.. note:: |
728 | ++ The ``plainbox.vendor`` package is modified by Debian not to ship a copy of |
729 | ++ the ``unittest.mock`` and updated ``inspect`` modules that are already |
730 | ++ available in python3.3 |
731 | + """ |
732 | +--- a/plainbox/vendor/funcsigs/LICENSE |
733 | ++++ /dev/null |
734 | +@@ -1,13 +0,0 @@ |
735 | +-Copyright 2013 Aaron Iles |
736 | +- |
737 | +-Licensed under the Apache License, Version 2.0 (the "License"); |
738 | +-you may not use this file except in compliance with the License. |
739 | +-You may obtain a copy of the License at |
740 | +- |
741 | +- http://www.apache.org/licenses/LICENSE-2.0 |
742 | +- |
743 | +-Unless required by applicable law or agreed to in writing, software |
744 | +-distributed under the License is distributed on an "AS IS" BASIS, |
745 | +-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
746 | +-See the License for the specific language governing permissions and |
747 | +-limitations under the License. |
748 | +--- a/plainbox/vendor/funcsigs/__init__.py |
749 | ++++ b/plainbox/vendor/funcsigs/__init__.py |
750 | +@@ -1,810 +1,29 @@ |
751 | +-# Copyright 2001-2013 Python Software Foundation; All Rights Reserved |
752 | ++# This file is part of Checkbox. |
753 | + # |
754 | +-# MODIFICATIONS: |
755 | +-# - Vendorized for plainbox packaging needs. |
756 | +-# See https://pypi.python.org/pypi/plainbox |
757 | +-# - Removed the odict.py module as plainbox only supports python3.2+ |
758 | +-"""Function signature objects for callables |
759 | ++# Copyright 2013 Canonical Ltd. |
760 | ++# Written by: |
761 | ++# Zygmunt Krynicki <zygmunt.krynicki@canonical.com> |
762 | ++# |
763 | ++# Checkbox is free software: you can redistribute it and/or modify |
764 | ++# it under the terms of the GNU General Public License as published by |
765 | ++# the Free Software Foundation, either version 3 of the License, or |
766 | ++# (at your option) any later version. |
767 | ++# |
768 | ++# Checkbox is distributed in the hope that it will be useful, |
769 | ++# but WITHOUT ANY WARRANTY; without even the implied warranty of |
770 | ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
771 | ++# GNU General Public License for more details. |
772 | ++# |
773 | ++# You should have received a copy of the GNU General Public License |
774 | ++# along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
775 | + |
776 | +-Back port of Python 3.3's function signature tools from the inspect module, |
777 | +-modified to be compatible with Python 2.6, 2.7 and 3.2+. |
778 | + """ |
779 | +-from __future__ import absolute_import, division, print_function |
780 | +-import itertools |
781 | +-import functools |
782 | +-import re |
783 | +-import types |
784 | +- |
785 | +-from collections import OrderedDict |
786 | +- |
787 | +-from plainbox.vendor.funcsigs.version import __version__ |
788 | +- |
789 | +-__all__ = ['BoundArguments', 'Parameter', 'Signature', 'signature'] |
790 | +- |
791 | +- |
792 | +-_WrapperDescriptor = type(type.__call__) |
793 | +-_MethodWrapper = type(all.__call__) |
794 | +- |
795 | +-_NonUserDefinedCallables = (_WrapperDescriptor, |
796 | +- _MethodWrapper, |
797 | +- types.BuiltinFunctionType) |
798 | +- |
799 | +- |
800 | +-def formatannotation(annotation, base_module=None): |
801 | +- if isinstance(annotation, type): |
802 | +- if annotation.__module__ in ('builtins', '__builtin__', base_module): |
803 | +- return annotation.__name__ |
804 | +- return annotation.__module__+'.'+annotation.__name__ |
805 | +- return repr(annotation) |
806 | +- |
807 | +- |
808 | +-def _get_user_defined_method(cls, method_name, *nested): |
809 | +- try: |
810 | +- if cls is type: |
811 | +- return |
812 | +- meth = getattr(cls, method_name) |
813 | +- for name in nested: |
814 | +- meth = getattr(meth, name, meth) |
815 | +- except AttributeError: |
816 | +- return |
817 | +- else: |
818 | +- if not isinstance(meth, _NonUserDefinedCallables): |
819 | +- # Once '__signature__' will be added to 'C'-level |
820 | +- # callables, this check won't be necessary |
821 | +- return meth |
822 | +- |
823 | +- |
824 | +-def signature(obj): |
825 | +- '''Get a signature object for the passed callable.''' |
826 | +- |
827 | +- if not callable(obj): |
828 | +- raise TypeError('{0!r} is not a callable object'.format(obj)) |
829 | +- |
830 | +- if isinstance(obj, types.MethodType): |
831 | +- # In this case we skip the first parameter of the underlying |
832 | +- # function (usually `self` or `cls`). |
833 | +- sig = signature(obj.__func__) |
834 | +- return sig.replace(parameters=tuple(sig.parameters.values())[1:]) |
835 | +- |
836 | +- try: |
837 | +- sig = obj.__signature__ |
838 | +- except AttributeError: |
839 | +- pass |
840 | +- else: |
841 | +- if sig is not None: |
842 | +- return sig |
843 | +- |
844 | +- try: |
845 | +- # Was this function wrapped by a decorator? |
846 | +- wrapped = obj.__wrapped__ |
847 | +- except AttributeError: |
848 | +- pass |
849 | +- else: |
850 | +- return signature(wrapped) |
851 | +- |
852 | +- if isinstance(obj, types.FunctionType): |
853 | +- return Signature.from_function(obj) |
854 | +- |
855 | +- if isinstance(obj, functools.partial): |
856 | +- sig = signature(obj.func) |
857 | +- |
858 | +- new_params = OrderedDict(sig.parameters.items()) |
859 | +- |
860 | +- partial_args = obj.args or () |
861 | +- partial_keywords = obj.keywords or {} |
862 | +- try: |
863 | +- ba = sig.bind_partial(*partial_args, **partial_keywords) |
864 | +- except TypeError as ex: |
865 | +- msg = 'partial object {0!r} has incorrect arguments'.format(obj) |
866 | +- raise ValueError(msg) |
867 | +- |
868 | +- for arg_name, arg_value in ba.arguments.items(): |
869 | +- param = new_params[arg_name] |
870 | +- if arg_name in partial_keywords: |
871 | +- # We set a new default value, because the following code |
872 | +- # is correct: |
873 | +- # |
874 | +- # >>> def foo(a): print(a) |
875 | +- # >>> print(partial(partial(foo, a=10), a=20)()) |
876 | +- # 20 |
877 | +- # >>> print(partial(partial(foo, a=10), a=20)(a=30)) |
878 | +- # 30 |
879 | +- # |
880 | +- # So, with 'partial' objects, passing a keyword argument is |
881 | +- # like setting a new default value for the corresponding |
882 | +- # parameter |
883 | +- # |
884 | +- # We also mark this parameter with '_partial_kwarg' |
885 | +- # flag. Later, in '_bind', the 'default' value of this |
886 | +- # parameter will be added to 'kwargs', to simulate |
887 | +- # the 'functools.partial' real call. |
888 | +- new_params[arg_name] = param.replace(default=arg_value, |
889 | +- _partial_kwarg=True) |
890 | +- |
891 | +- elif (param.kind not in (_VAR_KEYWORD, _VAR_POSITIONAL) and |
892 | +- not param._partial_kwarg): |
893 | +- new_params.pop(arg_name) |
894 | +- |
895 | +- return sig.replace(parameters=new_params.values()) |
896 | +- |
897 | +- sig = None |
898 | +- if isinstance(obj, type): |
899 | +- # obj is a class or a metaclass |
900 | +- |
901 | +- # First, let's see if it has an overloaded __call__ defined |
902 | +- # in its metaclass |
903 | +- call = _get_user_defined_method(type(obj), '__call__') |
904 | +- if call is not None: |
905 | +- sig = signature(call) |
906 | +- else: |
907 | +- # Now we check if the 'obj' class has a '__new__' method |
908 | +- new = _get_user_defined_method(obj, '__new__') |
909 | +- if new is not None: |
910 | +- sig = signature(new) |
911 | +- else: |
912 | +- # Finally, we should have at least __init__ implemented |
913 | +- init = _get_user_defined_method(obj, '__init__') |
914 | +- if init is not None: |
915 | +- sig = signature(init) |
916 | +- elif not isinstance(obj, _NonUserDefinedCallables): |
917 | +- # An object with __call__ |
918 | +- # We also check that the 'obj' is not an instance of |
919 | +- # _WrapperDescriptor or _MethodWrapper to avoid |
920 | +- # infinite recursion (and even potential segfault) |
921 | +- call = _get_user_defined_method(type(obj), '__call__', 'im_func') |
922 | +- if call is not None: |
923 | +- sig = signature(call) |
924 | +- |
925 | +- if sig is not None: |
926 | +- # For classes and objects we skip the first parameter of their |
927 | +- # __call__, __new__, or __init__ methods |
928 | +- return sig.replace(parameters=tuple(sig.parameters.values())[1:]) |
929 | +- |
930 | +- if isinstance(obj, types.BuiltinFunctionType): |
931 | +- # Raise a nicer error message for builtins |
932 | +- msg = 'no signature found for builtin function {0!r}'.format(obj) |
933 | +- raise ValueError(msg) |
934 | +- |
935 | +- raise ValueError('callable {0!r} is not supported by signature'.format(obj)) |
936 | +- |
937 | +- |
938 | +-class _void(object): |
939 | +- '''A private marker - used in Parameter & Signature''' |
940 | +- |
941 | +- |
942 | +-class _empty(object): |
943 | +- pass |
944 | +- |
945 | +- |
946 | +-class _ParameterKind(int): |
947 | +- def __new__(self, *args, **kwargs): |
948 | +- obj = int.__new__(self, *args) |
949 | +- obj._name = kwargs['name'] |
950 | +- return obj |
951 | +- |
952 | +- def __str__(self): |
953 | +- return self._name |
954 | +- |
955 | +- def __repr__(self): |
956 | +- return '<_ParameterKind: {0!r}>'.format(self._name) |
957 | +- |
958 | +- |
959 | +-_POSITIONAL_ONLY = _ParameterKind(0, name='POSITIONAL_ONLY') |
960 | +-_POSITIONAL_OR_KEYWORD = _ParameterKind(1, name='POSITIONAL_OR_KEYWORD') |
961 | +-_VAR_POSITIONAL = _ParameterKind(2, name='VAR_POSITIONAL') |
962 | +-_KEYWORD_ONLY = _ParameterKind(3, name='KEYWORD_ONLY') |
963 | +-_VAR_KEYWORD = _ParameterKind(4, name='VAR_KEYWORD') |
964 | +- |
965 | +- |
966 | +-class Parameter(object): |
967 | +- '''Represents a parameter in a function signature. |
968 | +- |
969 | +- Has the following public attributes: |
970 | +- |
971 | +- * name : str |
972 | +- The name of the parameter as a string. |
973 | +- * default : object |
974 | +- The default value for the parameter if specified. If the |
975 | +- parameter has no default value, this attribute is not set. |
976 | +- * annotation |
977 | +- The annotation for the parameter if specified. If the |
978 | +- parameter has no annotation, this attribute is not set. |
979 | +- * kind : str |
980 | +- Describes how argument values are bound to the parameter. |
981 | +- Possible values: `Parameter.POSITIONAL_ONLY`, |
982 | +- `Parameter.POSITIONAL_OR_KEYWORD`, `Parameter.VAR_POSITIONAL`, |
983 | +- `Parameter.KEYWORD_ONLY`, `Parameter.VAR_KEYWORD`. |
984 | +- ''' |
985 | +- |
986 | +- __slots__ = ('_name', '_kind', '_default', '_annotation', '_partial_kwarg') |
987 | +- |
988 | +- POSITIONAL_ONLY = _POSITIONAL_ONLY |
989 | +- POSITIONAL_OR_KEYWORD = _POSITIONAL_OR_KEYWORD |
990 | +- VAR_POSITIONAL = _VAR_POSITIONAL |
991 | +- KEYWORD_ONLY = _KEYWORD_ONLY |
992 | +- VAR_KEYWORD = _VAR_KEYWORD |
993 | +- |
994 | +- empty = _empty |
995 | +- |
996 | +- def __init__(self, name, kind, default=_empty, annotation=_empty, |
997 | +- _partial_kwarg=False): |
998 | +- |
999 | +- if kind not in (_POSITIONAL_ONLY, _POSITIONAL_OR_KEYWORD, |
1000 | +- _VAR_POSITIONAL, _KEYWORD_ONLY, _VAR_KEYWORD): |
1001 | +- raise ValueError("invalid value for 'Parameter.kind' attribute") |
1002 | +- self._kind = kind |
1003 | +- |
1004 | +- if default is not _empty: |
1005 | +- if kind in (_VAR_POSITIONAL, _VAR_KEYWORD): |
1006 | +- msg = '{0} parameters cannot have default values'.format(kind) |
1007 | +- raise ValueError(msg) |
1008 | +- self._default = default |
1009 | +- self._annotation = annotation |
1010 | +- |
1011 | +- if name is None: |
1012 | +- if kind != _POSITIONAL_ONLY: |
1013 | +- raise ValueError("None is not a valid name for a " |
1014 | +- "non-positional-only parameter") |
1015 | +- self._name = name |
1016 | +- else: |
1017 | +- name = str(name) |
1018 | +- if kind != _POSITIONAL_ONLY and not re.match(r'[a-z_]\w*$', name, re.I): |
1019 | +- msg = '{0!r} is not a valid parameter name'.format(name) |
1020 | +- raise ValueError(msg) |
1021 | +- self._name = name |
1022 | +- |
1023 | +- self._partial_kwarg = _partial_kwarg |
1024 | +- |
1025 | +- @property |
1026 | +- def name(self): |
1027 | +- return self._name |
1028 | +- |
1029 | +- @property |
1030 | +- def default(self): |
1031 | +- return self._default |
1032 | +- |
1033 | +- @property |
1034 | +- def annotation(self): |
1035 | +- return self._annotation |
1036 | +- |
1037 | +- @property |
1038 | +- def kind(self): |
1039 | +- return self._kind |
1040 | +- |
1041 | +- def replace(self, name=_void, kind=_void, annotation=_void, |
1042 | +- default=_void, _partial_kwarg=_void): |
1043 | +- '''Creates a customized copy of the Parameter.''' |
1044 | +- |
1045 | +- if name is _void: |
1046 | +- name = self._name |
1047 | +- |
1048 | +- if kind is _void: |
1049 | +- kind = self._kind |
1050 | +- |
1051 | +- if annotation is _void: |
1052 | +- annotation = self._annotation |
1053 | +- |
1054 | +- if default is _void: |
1055 | +- default = self._default |
1056 | +- |
1057 | +- if _partial_kwarg is _void: |
1058 | +- _partial_kwarg = self._partial_kwarg |
1059 | +- |
1060 | +- return type(self)(name, kind, default=default, annotation=annotation, |
1061 | +- _partial_kwarg=_partial_kwarg) |
1062 | +- |
1063 | +- def __str__(self): |
1064 | +- kind = self.kind |
1065 | +- |
1066 | +- formatted = self._name |
1067 | +- if kind == _POSITIONAL_ONLY: |
1068 | +- if formatted is None: |
1069 | +- formatted = '' |
1070 | +- formatted = '<{0}>'.format(formatted) |
1071 | +- |
1072 | +- # Add annotation and default value |
1073 | +- if self._annotation is not _empty: |
1074 | +- formatted = '{0}:{1}'.format(formatted, |
1075 | +- formatannotation(self._annotation)) |
1076 | +- |
1077 | +- if self._default is not _empty: |
1078 | +- formatted = '{0}={1}'.format(formatted, repr(self._default)) |
1079 | +- |
1080 | +- if kind == _VAR_POSITIONAL: |
1081 | +- formatted = '*' + formatted |
1082 | +- elif kind == _VAR_KEYWORD: |
1083 | +- formatted = '**' + formatted |
1084 | +- |
1085 | +- return formatted |
1086 | +- |
1087 | +- def __repr__(self): |
1088 | +- return '<{0} at {1:#x} {2!r}>'.format(self.__class__.__name__, |
1089 | +- id(self), self.name) |
1090 | +- |
1091 | +- def __hash__(self): |
1092 | +- msg = "unhashable type: '{0}'".format(self.__class__.__name__) |
1093 | +- raise TypeError(msg) |
1094 | +- |
1095 | +- def __eq__(self, other): |
1096 | +- return (issubclass(other.__class__, Parameter) and |
1097 | +- self._name == other._name and |
1098 | +- self._kind == other._kind and |
1099 | +- self._default == other._default and |
1100 | +- self._annotation == other._annotation) |
1101 | +- |
1102 | +- def __ne__(self, other): |
1103 | +- return not self.__eq__(other) |
1104 | +- |
1105 | ++:mod:`plainbox.vendor.funcsigs` -- vendorized funcsigs module |
1106 | ++============================================================= |
1107 | + |
1108 | +-class BoundArguments(object): |
1109 | +- '''Result of `Signature.bind` call. Holds the mapping of arguments |
1110 | +- to the function's parameters. |
1111 | +- |
1112 | +- Has the following public attributes: |
1113 | +- |
1114 | +- * arguments : OrderedDict |
1115 | +- An ordered mutable mapping of parameters' names to arguments' values. |
1116 | +- Does not contain arguments' default values. |
1117 | +- * signature : Signature |
1118 | +- The Signature object that created this instance. |
1119 | +- * args : tuple |
1120 | +- Tuple of positional arguments values. |
1121 | +- * kwargs : dict |
1122 | +- Dict of keyword arguments values. |
1123 | +- ''' |
1124 | +- |
1125 | +- def __init__(self, signature, arguments): |
1126 | +- self.arguments = arguments |
1127 | +- self._signature = signature |
1128 | +- |
1129 | +- @property |
1130 | +- def signature(self): |
1131 | +- return self._signature |
1132 | +- |
1133 | +- @property |
1134 | +- def args(self): |
1135 | +- args = [] |
1136 | +- for param_name, param in self._signature.parameters.items(): |
1137 | +- if (param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY) or |
1138 | +- param._partial_kwarg): |
1139 | +- # Keyword arguments mapped by 'functools.partial' |
1140 | +- # (Parameter._partial_kwarg is True) are mapped |
1141 | +- # in 'BoundArguments.kwargs', along with VAR_KEYWORD & |
1142 | +- # KEYWORD_ONLY |
1143 | +- break |
1144 | +- |
1145 | +- try: |
1146 | +- arg = self.arguments[param_name] |
1147 | +- except KeyError: |
1148 | +- # We're done here. Other arguments |
1149 | +- # will be mapped in 'BoundArguments.kwargs' |
1150 | +- break |
1151 | +- else: |
1152 | +- if param.kind == _VAR_POSITIONAL: |
1153 | +- # *args |
1154 | +- args.extend(arg) |
1155 | +- else: |
1156 | +- # plain argument |
1157 | +- args.append(arg) |
1158 | +- |
1159 | +- return tuple(args) |
1160 | +- |
1161 | +- @property |
1162 | +- def kwargs(self): |
1163 | +- kwargs = {} |
1164 | +- kwargs_started = False |
1165 | +- for param_name, param in self._signature.parameters.items(): |
1166 | +- if not kwargs_started: |
1167 | +- if (param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY) or |
1168 | +- param._partial_kwarg): |
1169 | +- kwargs_started = True |
1170 | +- else: |
1171 | +- if param_name not in self.arguments: |
1172 | +- kwargs_started = True |
1173 | +- continue |
1174 | +- |
1175 | +- if not kwargs_started: |
1176 | +- continue |
1177 | +- |
1178 | +- try: |
1179 | +- arg = self.arguments[param_name] |
1180 | +- except KeyError: |
1181 | +- pass |
1182 | +- else: |
1183 | +- if param.kind == _VAR_KEYWORD: |
1184 | +- # **kwargs |
1185 | +- kwargs.update(arg) |
1186 | +- else: |
1187 | +- # plain keyword argument |
1188 | +- kwargs[param_name] = arg |
1189 | +- |
1190 | +- return kwargs |
1191 | +- |
1192 | +- def __hash__(self): |
1193 | +- msg = "unhashable type: '{0}'".format(self.__class__.__name__) |
1194 | +- raise TypeError(msg) |
1195 | +- |
1196 | +- def __eq__(self, other): |
1197 | +- return (issubclass(other.__class__, BoundArguments) and |
1198 | +- self.signature == other.signature and |
1199 | +- self.arguments == other.arguments) |
1200 | +- |
1201 | +- def __ne__(self, other): |
1202 | +- return not self.__eq__(other) |
1203 | +- |
1204 | +- |
1205 | +-class Signature(object): |
1206 | +- '''A Signature object represents the overall signature of a function. |
1207 | +- It stores a Parameter object for each parameter accepted by the |
1208 | +- function, as well as information specific to the function itself. |
1209 | +- |
1210 | +- A Signature object has the following public attributes and methods: |
1211 | +- |
1212 | +- * parameters : OrderedDict |
1213 | +- An ordered mapping of parameters' names to the corresponding |
1214 | +- Parameter objects (keyword-only arguments are in the same order |
1215 | +- as listed in `code.co_varnames`). |
1216 | +- * return_annotation : object |
1217 | +- The annotation for the return type of the function if specified. |
1218 | +- If the function has no annotation for its return type, this |
1219 | +- attribute is not set. |
1220 | +- * bind(*args, **kwargs) -> BoundArguments |
1221 | +- Creates a mapping from positional and keyword arguments to |
1222 | +- parameters. |
1223 | +- * bind_partial(*args, **kwargs) -> BoundArguments |
1224 | +- Creates a partial mapping from positional and keyword arguments |
1225 | +- to parameters (simulating 'functools.partial' behavior.) |
1226 | +- ''' |
1227 | +- |
1228 | +- __slots__ = ('_return_annotation', '_parameters') |
1229 | +- |
1230 | +- _parameter_cls = Parameter |
1231 | +- _bound_arguments_cls = BoundArguments |
1232 | +- |
1233 | +- empty = _empty |
1234 | +- |
1235 | +- def __init__(self, parameters=None, return_annotation=_empty, |
1236 | +- __validate_parameters__=True): |
1237 | +- '''Constructs Signature from the given list of Parameter |
1238 | +- objects and 'return_annotation'. All arguments are optional. |
1239 | +- ''' |
1240 | +- |
1241 | +- if parameters is None: |
1242 | +- params = OrderedDict() |
1243 | +- else: |
1244 | +- if __validate_parameters__: |
1245 | +- params = OrderedDict() |
1246 | +- top_kind = _POSITIONAL_ONLY |
1247 | +- |
1248 | +- for idx, param in enumerate(parameters): |
1249 | +- kind = param.kind |
1250 | +- if kind < top_kind: |
1251 | +- msg = 'wrong parameter order: {0} before {1}' |
1252 | +- msg = msg.format(top_kind, param.kind) |
1253 | +- raise ValueError(msg) |
1254 | +- else: |
1255 | +- top_kind = kind |
1256 | +- |
1257 | +- name = param.name |
1258 | +- if name is None: |
1259 | +- name = str(idx) |
1260 | +- param = param.replace(name=name) |
1261 | +- |
1262 | +- if name in params: |
1263 | +- msg = 'duplicate parameter name: {0!r}'.format(name) |
1264 | +- raise ValueError(msg) |
1265 | +- params[name] = param |
1266 | +- else: |
1267 | +- params = OrderedDict(((param.name, param) |
1268 | +- for param in parameters)) |
1269 | +- |
1270 | +- self._parameters = params |
1271 | +- self._return_annotation = return_annotation |
1272 | +- |
1273 | +- @classmethod |
1274 | +- def from_function(cls, func): |
1275 | +- '''Constructs Signature for the given python function''' |
1276 | +- |
1277 | +- if not isinstance(func, types.FunctionType): |
1278 | +- raise TypeError('{0!r} is not a Python function'.format(func)) |
1279 | +- |
1280 | +- Parameter = cls._parameter_cls |
1281 | +- |
1282 | +- # Parameter information. |
1283 | +- func_code = func.__code__ |
1284 | +- pos_count = func_code.co_argcount |
1285 | +- arg_names = func_code.co_varnames |
1286 | +- positional = tuple(arg_names[:pos_count]) |
1287 | +- keyword_only_count = getattr(func_code, 'co_kwonlyargcount', 0) |
1288 | +- keyword_only = arg_names[pos_count:(pos_count + keyword_only_count)] |
1289 | +- annotations = getattr(func, '__annotations__', {}) |
1290 | +- defaults = func.__defaults__ |
1291 | +- kwdefaults = getattr(func, '__kwdefaults__', None) |
1292 | +- |
1293 | +- if defaults: |
1294 | +- pos_default_count = len(defaults) |
1295 | +- else: |
1296 | +- pos_default_count = 0 |
1297 | +- |
1298 | +- parameters = [] |
1299 | +- |
1300 | +- # Non-keyword-only parameters w/o defaults. |
1301 | +- non_default_count = pos_count - pos_default_count |
1302 | +- for name in positional[:non_default_count]: |
1303 | +- annotation = annotations.get(name, _empty) |
1304 | +- parameters.append(Parameter(name, annotation=annotation, |
1305 | +- kind=_POSITIONAL_OR_KEYWORD)) |
1306 | +- |
1307 | +- # ... w/ defaults. |
1308 | +- for offset, name in enumerate(positional[non_default_count:]): |
1309 | +- annotation = annotations.get(name, _empty) |
1310 | +- parameters.append(Parameter(name, annotation=annotation, |
1311 | +- kind=_POSITIONAL_OR_KEYWORD, |
1312 | +- default=defaults[offset])) |
1313 | +- |
1314 | +- # *args |
1315 | +- if func_code.co_flags & 0x04: |
1316 | +- name = arg_names[pos_count + keyword_only_count] |
1317 | +- annotation = annotations.get(name, _empty) |
1318 | +- parameters.append(Parameter(name, annotation=annotation, |
1319 | +- kind=_VAR_POSITIONAL)) |
1320 | +- |
1321 | +- # Keyword-only parameters. |
1322 | +- for name in keyword_only: |
1323 | +- default = _empty |
1324 | +- if kwdefaults is not None: |
1325 | +- default = kwdefaults.get(name, _empty) |
1326 | +- |
1327 | +- annotation = annotations.get(name, _empty) |
1328 | +- parameters.append(Parameter(name, annotation=annotation, |
1329 | +- kind=_KEYWORD_ONLY, |
1330 | +- default=default)) |
1331 | +- # **kwargs |
1332 | +- if func_code.co_flags & 0x08: |
1333 | +- index = pos_count + keyword_only_count |
1334 | +- if func_code.co_flags & 0x04: |
1335 | +- index += 1 |
1336 | +- |
1337 | +- name = arg_names[index] |
1338 | +- annotation = annotations.get(name, _empty) |
1339 | +- parameters.append(Parameter(name, annotation=annotation, |
1340 | +- kind=_VAR_KEYWORD)) |
1341 | +- |
1342 | +- return cls(parameters, |
1343 | +- return_annotation=annotations.get('return', _empty), |
1344 | +- __validate_parameters__=False) |
1345 | +- |
1346 | +- @property |
1347 | +- def parameters(self): |
1348 | +- try: |
1349 | +- return types.MappingProxyType(self._parameters) |
1350 | +- except AttributeError: |
1351 | +- return OrderedDict(self._parameters.items()) |
1352 | +- |
1353 | +- @property |
1354 | +- def return_annotation(self): |
1355 | +- return self._return_annotation |
1356 | +- |
1357 | +- def replace(self, parameters=_void, return_annotation=_void): |
1358 | +- '''Creates a customized copy of the Signature. |
1359 | +- Pass 'parameters' and/or 'return_annotation' arguments |
1360 | +- to override them in the new copy. |
1361 | +- ''' |
1362 | +- |
1363 | +- if parameters is _void: |
1364 | +- parameters = self.parameters.values() |
1365 | +- |
1366 | +- if return_annotation is _void: |
1367 | +- return_annotation = self._return_annotation |
1368 | +- |
1369 | +- return type(self)(parameters, |
1370 | +- return_annotation=return_annotation) |
1371 | +- |
1372 | +- def __hash__(self): |
1373 | +- msg = "unhashable type: '{0}'".format(self.__class__.__name__) |
1374 | +- raise TypeError(msg) |
1375 | +- |
1376 | +- def __eq__(self, other): |
1377 | +- if (not issubclass(type(other), Signature) or |
1378 | +- self.return_annotation != other.return_annotation or |
1379 | +- len(self.parameters) != len(other.parameters)): |
1380 | +- return False |
1381 | +- |
1382 | +- other_positions = dict((param, idx) |
1383 | +- for idx, param in enumerate(other.parameters.keys())) |
1384 | +- |
1385 | +- for idx, (param_name, param) in enumerate(self.parameters.items()): |
1386 | +- if param.kind == _KEYWORD_ONLY: |
1387 | +- try: |
1388 | +- other_param = other.parameters[param_name] |
1389 | +- except KeyError: |
1390 | +- return False |
1391 | +- else: |
1392 | +- if param != other_param: |
1393 | +- return False |
1394 | +- else: |
1395 | +- try: |
1396 | +- other_idx = other_positions[param_name] |
1397 | +- except KeyError: |
1398 | +- return False |
1399 | +- else: |
1400 | +- if (idx != other_idx or |
1401 | +- param != other.parameters[param_name]): |
1402 | +- return False |
1403 | +- |
1404 | +- return True |
1405 | +- |
1406 | +- def __ne__(self, other): |
1407 | +- return not self.__eq__(other) |
1408 | +- |
1409 | +- def _bind(self, args, kwargs, partial=False): |
1410 | +- '''Private method. Don't use directly.''' |
1411 | +- |
1412 | +- arguments = OrderedDict() |
1413 | +- |
1414 | +- parameters = iter(self.parameters.values()) |
1415 | +- parameters_ex = () |
1416 | +- arg_vals = iter(args) |
1417 | +- |
1418 | +- if partial: |
1419 | +- # Support for binding arguments to 'functools.partial' objects. |
1420 | +- # See 'functools.partial' case in 'signature()' implementation |
1421 | +- # for details. |
1422 | +- for param_name, param in self.parameters.items(): |
1423 | +- if (param._partial_kwarg and param_name not in kwargs): |
1424 | +- # Simulating 'functools.partial' behavior |
1425 | +- kwargs[param_name] = param.default |
1426 | +- |
1427 | +- while True: |
1428 | +- # Let's iterate through the positional arguments and corresponding |
1429 | +- # parameters |
1430 | +- try: |
1431 | +- arg_val = next(arg_vals) |
1432 | +- except StopIteration: |
1433 | +- # No more positional arguments |
1434 | +- try: |
1435 | +- param = next(parameters) |
1436 | +- except StopIteration: |
1437 | +- # No more parameters. That's it. Just need to check that |
1438 | +- # we have no `kwargs` after this while loop |
1439 | +- break |
1440 | +- else: |
1441 | +- if param.kind == _VAR_POSITIONAL: |
1442 | +- # That's OK, just empty *args. Let's start parsing |
1443 | +- # kwargs |
1444 | +- break |
1445 | +- elif param.name in kwargs: |
1446 | +- if param.kind == _POSITIONAL_ONLY: |
1447 | +- msg = '{arg!r} parameter is positional only, ' \ |
1448 | +- 'but was passed as a keyword' |
1449 | +- msg = msg.format(arg=param.name) |
1450 | +- raise TypeError(msg) |
1451 | +- parameters_ex = (param,) |
1452 | +- break |
1453 | +- elif (param.kind == _VAR_KEYWORD or |
1454 | +- param.default is not _empty): |
1455 | +- # That's fine too - we have a default value for this |
1456 | +- # parameter. So, lets start parsing `kwargs`, starting |
1457 | +- # with the current parameter |
1458 | +- parameters_ex = (param,) |
1459 | +- break |
1460 | +- else: |
1461 | +- if partial: |
1462 | +- parameters_ex = (param,) |
1463 | +- break |
1464 | +- else: |
1465 | +- msg = '{arg!r} parameter lacking default value' |
1466 | +- msg = msg.format(arg=param.name) |
1467 | +- raise TypeError(msg) |
1468 | +- else: |
1469 | +- # We have a positional argument to process |
1470 | +- try: |
1471 | +- param = next(parameters) |
1472 | +- except StopIteration: |
1473 | +- raise TypeError('too many positional arguments') |
1474 | +- else: |
1475 | +- if param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY): |
1476 | +- # Looks like we have no parameter for this positional |
1477 | +- # argument |
1478 | +- raise TypeError('too many positional arguments') |
1479 | +- |
1480 | +- if param.kind == _VAR_POSITIONAL: |
1481 | +- # We have an '*args'-like argument, let's fill it with |
1482 | +- # all positional arguments we have left and move on to |
1483 | +- # the next phase |
1484 | +- values = [arg_val] |
1485 | +- values.extend(arg_vals) |
1486 | +- arguments[param.name] = tuple(values) |
1487 | +- break |
1488 | +- |
1489 | +- if param.name in kwargs: |
1490 | +- raise TypeError('multiple values for argument ' |
1491 | +- '{arg!r}'.format(arg=param.name)) |
1492 | +- |
1493 | +- arguments[param.name] = arg_val |
1494 | +- |
1495 | +- # Now, we iterate through the remaining parameters to process |
1496 | +- # keyword arguments |
1497 | +- kwargs_param = None |
1498 | +- for param in itertools.chain(parameters_ex, parameters): |
1499 | +- if param.kind == _POSITIONAL_ONLY: |
1500 | +- # This should never happen in case of a properly built |
1501 | +- # Signature object (but let's have this check here |
1502 | +- # to ensure correct behaviour just in case) |
1503 | +- raise TypeError('{arg!r} parameter is positional only, ' |
1504 | +- 'but was passed as a keyword'. \ |
1505 | +- format(arg=param.name)) |
1506 | +- |
1507 | +- if param.kind == _VAR_KEYWORD: |
1508 | +- # Memorize that we have a '**kwargs'-like parameter |
1509 | +- kwargs_param = param |
1510 | +- continue |
1511 | +- |
1512 | +- param_name = param.name |
1513 | +- try: |
1514 | +- arg_val = kwargs.pop(param_name) |
1515 | +- except KeyError: |
1516 | +- # We have no value for this parameter. It's fine though, |
1517 | +- # if it has a default value, or it is an '*args'-like |
1518 | +- # parameter, left alone by the processing of positional |
1519 | +- # arguments. |
1520 | +- if (not partial and param.kind != _VAR_POSITIONAL and |
1521 | +- param.default is _empty): |
1522 | +- raise TypeError('{arg!r} parameter lacking default value'. \ |
1523 | +- format(arg=param_name)) |
1524 | +- |
1525 | +- else: |
1526 | +- arguments[param_name] = arg_val |
1527 | +- |
1528 | +- if kwargs: |
1529 | +- if kwargs_param is not None: |
1530 | +- # Process our '**kwargs'-like parameter |
1531 | +- arguments[kwargs_param.name] = kwargs |
1532 | +- else: |
1533 | +- raise TypeError('too many keyword arguments') |
1534 | +- |
1535 | +- return self._bound_arguments_cls(self, arguments) |
1536 | +- |
1537 | +- def bind(self, *args, **kwargs): |
1538 | +- '''Get a BoundArguments object, that maps the passed `args` |
1539 | +- and `kwargs` to the function's signature. Raises `TypeError` |
1540 | +- if the passed arguments can not be bound. |
1541 | +- ''' |
1542 | +- return self._bind(args, kwargs) |
1543 | +- |
1544 | +- def bind_partial(self, *args, **kwargs): |
1545 | +- '''Get a BoundArguments object, that partially maps the |
1546 | +- passed `args` and `kwargs` to the function's signature. |
1547 | +- Raises `TypeError` if the passed arguments can not be bound. |
1548 | +- ''' |
1549 | +- return self._bind(args, kwargs, partial=True) |
1550 | +- |
1551 | +- def __str__(self): |
1552 | +- result = [] |
1553 | +- render_kw_only_separator = True |
1554 | +- for idx, param in enumerate(self.parameters.values()): |
1555 | +- formatted = str(param) |
1556 | +- |
1557 | +- kind = param.kind |
1558 | +- if kind == _VAR_POSITIONAL: |
1559 | +- # OK, we have an '*args'-like parameter, so we won't need |
1560 | +- # a '*' to separate keyword-only arguments |
1561 | +- render_kw_only_separator = False |
1562 | +- elif kind == _KEYWORD_ONLY and render_kw_only_separator: |
1563 | +- # We have a keyword-only parameter to render and we haven't |
1564 | +- # rendered an '*args'-like parameter before, so add a '*' |
1565 | +- # separator to the parameters list ("foo(arg1, *, arg2)" case) |
1566 | +- result.append('*') |
1567 | +- # This condition should be only triggered once, so |
1568 | +- # reset the flag |
1569 | +- render_kw_only_separator = False |
1570 | +- |
1571 | +- result.append(formatted) |
1572 | +- |
1573 | +- rendered = '({0})'.format(', '.join(result)) |
1574 | +- |
1575 | +- if self.return_annotation is not _empty: |
1576 | +- anno = formatannotation(self.return_annotation) |
1577 | +- rendered += ' -> {0}'.format(anno) |
1578 | ++This file has been patched-away by the Debian package as compared to the |
1579 | ++upstream version, not to ship a copy of a the 'funcsigs' module that is now |
1580 | ++integrated into the upstream python3.3 release. |
1581 | ++""" |
1582 | + |
1583 | +- return rendered |
1584 | ++from inspect import BoundArguments, Parameter, Signature, signature |
1585 | +--- a/plainbox/vendor/funcsigs/version.py |
1586 | ++++ /dev/null |
1587 | +@@ -1 +0,0 @@ |
1588 | +-__version__ = "0.3" |
1589 | +--- a/plainbox/vendor/mock.py |
1590 | ++++ b/plainbox/vendor/mock.py |
1591 | +@@ -1,2367 +1,29 @@ |
1592 | +-# mock.py |
1593 | +-# Test tools for mocking and patching. |
1594 | +-# Copyright (C) 2007-2012 Michael Foord & the mock team |
1595 | +-# E-mail: fuzzyman AT voidspace DOT org DOT uk |
1596 | ++# This file is part of Checkbox. |
1597 | ++# |
1598 | ++# Copyright 2013 Canonical Ltd. |
1599 | ++# Written by: |
1600 | ++# Zygmunt Krynicki <zygmunt.krynicki@canonical.com> |
1601 | ++# |
1602 | ++# Checkbox is free software: you can redistribute it and/or modify |
1603 | ++# it under the terms of the GNU General Public License as published by |
1604 | ++# the Free Software Foundation, either version 3 of the License, or |
1605 | ++# (at your option) any later version. |
1606 | ++# |
1607 | ++# Checkbox is distributed in the hope that it will be useful, |
1608 | ++# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1609 | ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1610 | ++# GNU General Public License for more details. |
1611 | ++# |
1612 | ++# You should have received a copy of the GNU General Public License |
1613 | ++# along with Checkbox. If not, see <http://www.gnu.org/licenses/>. |
1614 | ++ |
1615 | ++""" |
1616 | ++:mod:`plainbox.vendor.mock` -- vendorized mock module |
1617 | ++===================================================== |
1618 | ++ |
1619 | ++This file has been patched-away by the Debian package as compared to the |
1620 | ++upstream version, not to ship a copy of a the 'mock' module that is now |
1621 | ++integrated into the upstream python3.3 release. |
1622 | ++""" |
1623 | + |
1624 | +-# mock 1.0 |
1625 | +-# http://www.voidspace.org.uk/python/mock/ |
1626 | +- |
1627 | +-# Released subject to the BSD License |
1628 | +-# Please see http://www.voidspace.org.uk/python/license.shtml |
1629 | +- |
1630 | +-# Scripts maintained at http://www.voidspace.org.uk/python/index.shtml |
1631 | +-# Comments, suggestions and bug reports welcome. |
1632 | +- |
1633 | +- |
1634 | +-__all__ = ( |
1635 | +- 'Mock', |
1636 | +- 'MagicMock', |
1637 | +- 'patch', |
1638 | +- 'sentinel', |
1639 | +- 'DEFAULT', |
1640 | +- 'ANY', |
1641 | +- 'call', |
1642 | +- 'create_autospec', |
1643 | +- 'FILTER_DIR', |
1644 | +- 'NonCallableMock', |
1645 | +- 'NonCallableMagicMock', |
1646 | +- 'mock_open', |
1647 | +- 'PropertyMock', |
1648 | +-) |
1649 | +- |
1650 | +- |
1651 | +-__version__ = '1.0.1' |
1652 | +- |
1653 | +- |
1654 | +-import pprint |
1655 | +-import sys |
1656 | +- |
1657 | +-try: |
1658 | +- import inspect |
1659 | +-except ImportError: |
1660 | +- # for alternative platforms that |
1661 | +- # may not have inspect |
1662 | +- inspect = None |
1663 | +- |
1664 | +-try: |
1665 | +- from functools import wraps as original_wraps |
1666 | +-except ImportError: |
1667 | +- # Python 2.4 compatibility |
1668 | +- def wraps(original): |
1669 | +- def inner(f): |
1670 | +- f.__name__ = original.__name__ |
1671 | +- f.__doc__ = original.__doc__ |
1672 | +- f.__module__ = original.__module__ |
1673 | +- f.__wrapped__ = original |
1674 | +- return f |
1675 | +- return inner |
1676 | +-else: |
1677 | +- if sys.version_info[:2] >= (3, 3): |
1678 | +- wraps = original_wraps |
1679 | +- else: |
1680 | +- def wraps(func): |
1681 | +- def inner(f): |
1682 | +- f = original_wraps(func)(f) |
1683 | +- f.__wrapped__ = func |
1684 | +- return f |
1685 | +- return inner |
1686 | +- |
1687 | +-try: |
1688 | +- unicode |
1689 | +-except NameError: |
1690 | +- # Python 3 |
1691 | +- basestring = unicode = str |
1692 | +- |
1693 | +-try: |
1694 | +- long |
1695 | +-except NameError: |
1696 | +- # Python 3 |
1697 | +- long = int |
1698 | +- |
1699 | +-try: |
1700 | +- BaseException |
1701 | +-except NameError: |
1702 | +- # Python 2.4 compatibility |
1703 | +- BaseException = Exception |
1704 | +- |
1705 | +-try: |
1706 | +- next |
1707 | +-except NameError: |
1708 | +- def next(obj): |
1709 | +- return obj.next() |
1710 | +- |
1711 | +- |
1712 | +-BaseExceptions = (BaseException,) |
1713 | +-if 'java' in sys.platform: |
1714 | +- # jython |
1715 | +- import java |
1716 | +- BaseExceptions = (BaseException, java.lang.Throwable) |
1717 | +- |
1718 | +-try: |
1719 | +- _isidentifier = str.isidentifier |
1720 | +-except AttributeError: |
1721 | +- # Python 2.X |
1722 | +- import keyword |
1723 | +- import re |
1724 | +- regex = re.compile(r'^[a-z_][a-z0-9_]*$', re.I) |
1725 | +- def _isidentifier(string): |
1726 | +- if string in keyword.kwlist: |
1727 | +- return False |
1728 | +- return regex.match(string) |
1729 | +- |
1730 | +- |
1731 | +-inPy3k = sys.version_info[0] == 3 |
1732 | +- |
1733 | +-# Needed to work around Python 3 bug where use of "super" interferes with |
1734 | +-# defining __class__ as a descriptor |
1735 | +-_super = super |
1736 | +- |
1737 | +-self = 'im_self' |
1738 | +-builtin = '__builtin__' |
1739 | +-if inPy3k: |
1740 | +- self = '__self__' |
1741 | +- builtin = 'builtins' |
1742 | +- |
1743 | +-FILTER_DIR = True |
1744 | +- |
1745 | +- |
1746 | +-def _is_instance_mock(obj): |
1747 | +- # can't use isinstance on Mock objects because they override __class__ |
1748 | +- # The base class for all mocks is NonCallableMock |
1749 | +- return issubclass(type(obj), NonCallableMock) |
1750 | +- |
1751 | +- |
1752 | +-def _is_exception(obj): |
1753 | +- return ( |
1754 | +- isinstance(obj, BaseExceptions) or |
1755 | +- isinstance(obj, ClassTypes) and issubclass(obj, BaseExceptions) |
1756 | +- ) |
1757 | +- |
1758 | +- |
1759 | +-class _slotted(object): |
1760 | +- __slots__ = ['a'] |
1761 | +- |
1762 | +- |
1763 | +-DescriptorTypes = ( |
1764 | +- type(_slotted.a), |
1765 | +- property, |
1766 | +-) |
1767 | +- |
1768 | +- |
1769 | +-def _getsignature(func, skipfirst, instance=False): |
1770 | +- if inspect is None: |
1771 | +- raise ImportError('inspect module not available') |
1772 | +- |
1773 | +- if isinstance(func, ClassTypes) and not instance: |
1774 | +- try: |
1775 | +- func = func.__init__ |
1776 | +- except AttributeError: |
1777 | +- return |
1778 | +- skipfirst = True |
1779 | +- elif not isinstance(func, FunctionTypes): |
1780 | +- # for classes where instance is True we end up here too |
1781 | +- try: |
1782 | +- func = func.__call__ |
1783 | +- except AttributeError: |
1784 | +- return |
1785 | +- |
1786 | +- if inPy3k: |
1787 | +- try: |
1788 | +- argspec = inspect.getfullargspec(func) |
1789 | +- except TypeError: |
1790 | +- # C function / method, possibly inherited object().__init__ |
1791 | +- return |
1792 | +- regargs, varargs, varkw, defaults, kwonly, kwonlydef, ann = argspec |
1793 | +- else: |
1794 | +- try: |
1795 | +- regargs, varargs, varkwargs, defaults = inspect.getargspec(func) |
1796 | +- except TypeError: |
1797 | +- # C function / method, possibly inherited object().__init__ |
1798 | +- return |
1799 | +- |
1800 | +- # instance methods and classmethods need to lose the self argument |
1801 | +- if getattr(func, self, None) is not None: |
1802 | +- regargs = regargs[1:] |
1803 | +- if skipfirst: |
1804 | +- # this condition and the above one are never both True - why? |
1805 | +- regargs = regargs[1:] |
1806 | +- |
1807 | +- if inPy3k: |
1808 | +- signature = inspect.formatargspec( |
1809 | +- regargs, varargs, varkw, defaults, |
1810 | +- kwonly, kwonlydef, ann, formatvalue=lambda value: "") |
1811 | +- else: |
1812 | +- signature = inspect.formatargspec( |
1813 | +- regargs, varargs, varkwargs, defaults, |
1814 | +- formatvalue=lambda value: "") |
1815 | +- return signature[1:-1], func |
1816 | +- |
1817 | +- |
1818 | +-def _check_signature(func, mock, skipfirst, instance=False): |
1819 | +- if not _callable(func): |
1820 | +- return |
1821 | +- |
1822 | +- result = _getsignature(func, skipfirst, instance) |
1823 | +- if result is None: |
1824 | +- return |
1825 | +- signature, func = result |
1826 | +- |
1827 | +- # can't use self because "self" is common as an argument name |
1828 | +- # unfortunately even not in the first place |
1829 | +- src = "lambda _mock_self, %s: None" % signature |
1830 | +- checksig = eval(src, {}) |
1831 | +- _copy_func_details(func, checksig) |
1832 | +- type(mock)._mock_check_sig = checksig |
1833 | +- |
1834 | +- |
1835 | +-def _copy_func_details(func, funcopy): |
1836 | +- funcopy.__name__ = func.__name__ |
1837 | +- funcopy.__doc__ = func.__doc__ |
1838 | +- #funcopy.__dict__.update(func.__dict__) |
1839 | +- funcopy.__module__ = func.__module__ |
1840 | +- if not inPy3k: |
1841 | +- funcopy.func_defaults = func.func_defaults |
1842 | +- return |
1843 | +- funcopy.__defaults__ = func.__defaults__ |
1844 | +- funcopy.__kwdefaults__ = func.__kwdefaults__ |
1845 | +- |
1846 | +- |
1847 | +-def _callable(obj): |
1848 | +- if isinstance(obj, ClassTypes): |
1849 | +- return True |
1850 | +- if getattr(obj, '__call__', None) is not None: |
1851 | +- return True |
1852 | +- return False |
1853 | +- |
1854 | +- |
1855 | +-def _is_list(obj): |
1856 | +- # checks for list or tuples |
1857 | +- # XXXX badly named! |
1858 | +- return type(obj) in (list, tuple) |
1859 | +- |
1860 | +- |
1861 | +-def _instance_callable(obj): |
1862 | +- """Given an object, return True if the object is callable. |
1863 | +- For classes, return True if instances would be callable.""" |
1864 | +- if not isinstance(obj, ClassTypes): |
1865 | +- # already an instance |
1866 | +- return getattr(obj, '__call__', None) is not None |
1867 | +- |
1868 | +- klass = obj |
1869 | +- # uses __bases__ instead of __mro__ so that we work with old style classes |
1870 | +- if klass.__dict__.get('__call__') is not None: |
1871 | +- return True |
1872 | +- |
1873 | +- for base in klass.__bases__: |
1874 | +- if _instance_callable(base): |
1875 | +- return True |
1876 | +- return False |
1877 | +- |
1878 | +- |
1879 | +-def _set_signature(mock, original, instance=False): |
1880 | +- # creates a function with signature (*args, **kwargs) that delegates to a |
1881 | +- # mock. It still does signature checking by calling a lambda with the same |
1882 | +- # signature as the original. |
1883 | +- if not _callable(original): |
1884 | +- return |
1885 | +- |
1886 | +- skipfirst = isinstance(original, ClassTypes) |
1887 | +- result = _getsignature(original, skipfirst, instance) |
1888 | +- if result is None: |
1889 | +- # was a C function (e.g. object().__init__ ) that can't be mocked |
1890 | +- return |
1891 | +- |
1892 | +- signature, func = result |
1893 | +- |
1894 | +- src = "lambda %s: None" % signature |
1895 | +- checksig = eval(src, {}) |
1896 | +- _copy_func_details(func, checksig) |
1897 | +- |
1898 | +- name = original.__name__ |
1899 | +- if not _isidentifier(name): |
1900 | +- name = 'funcopy' |
1901 | +- context = {'_checksig_': checksig, 'mock': mock} |
1902 | +- src = """def %s(*args, **kwargs): |
1903 | +- _checksig_(*args, **kwargs) |
1904 | +- return mock(*args, **kwargs)""" % name |
1905 | +- exec (src, context) |
1906 | +- funcopy = context[name] |
1907 | +- _setup_func(funcopy, mock) |
1908 | +- return funcopy |
1909 | +- |
1910 | +- |
1911 | +-def _setup_func(funcopy, mock): |
1912 | +- funcopy.mock = mock |
1913 | +- |
1914 | +- # can't use isinstance with mocks |
1915 | +- if not _is_instance_mock(mock): |
1916 | +- return |
1917 | +- |
1918 | +- def assert_called_with(*args, **kwargs): |
1919 | +- return mock.assert_called_with(*args, **kwargs) |
1920 | +- def assert_called_once_with(*args, **kwargs): |
1921 | +- return mock.assert_called_once_with(*args, **kwargs) |
1922 | +- def assert_has_calls(*args, **kwargs): |
1923 | +- return mock.assert_has_calls(*args, **kwargs) |
1924 | +- def assert_any_call(*args, **kwargs): |
1925 | +- return mock.assert_any_call(*args, **kwargs) |
1926 | +- def reset_mock(): |
1927 | +- funcopy.method_calls = _CallList() |
1928 | +- funcopy.mock_calls = _CallList() |
1929 | +- mock.reset_mock() |
1930 | +- ret = funcopy.return_value |
1931 | +- if _is_instance_mock(ret) and not ret is mock: |
1932 | +- ret.reset_mock() |
1933 | +- |
1934 | +- funcopy.called = False |
1935 | +- funcopy.call_count = 0 |
1936 | +- funcopy.call_args = None |
1937 | +- funcopy.call_args_list = _CallList() |
1938 | +- funcopy.method_calls = _CallList() |
1939 | +- funcopy.mock_calls = _CallList() |
1940 | +- |
1941 | +- funcopy.return_value = mock.return_value |
1942 | +- funcopy.side_effect = mock.side_effect |
1943 | +- funcopy._mock_children = mock._mock_children |
1944 | +- |
1945 | +- funcopy.assert_called_with = assert_called_with |
1946 | +- funcopy.assert_called_once_with = assert_called_once_with |
1947 | +- funcopy.assert_has_calls = assert_has_calls |
1948 | +- funcopy.assert_any_call = assert_any_call |
1949 | +- funcopy.reset_mock = reset_mock |
1950 | +- |
1951 | +- mock._mock_delegate = funcopy |
1952 | +- |
1953 | +- |
1954 | +-def _is_magic(name): |
1955 | +- return '__%s__' % name[2:-2] == name |
1956 | +- |
1957 | +- |
1958 | +-class _SentinelObject(object): |
1959 | +- "A unique, named, sentinel object." |
1960 | +- def __init__(self, name): |
1961 | +- self.name = name |
1962 | +- |
1963 | +- def __repr__(self): |
1964 | +- return 'sentinel.%s' % self.name |
1965 | +- |
1966 | +- |
1967 | +-class _Sentinel(object): |
1968 | +- """Access attributes to return a named object, usable as a sentinel.""" |
1969 | +- def __init__(self): |
1970 | +- self._sentinels = {} |
1971 | +- |
1972 | +- def __getattr__(self, name): |
1973 | +- if name == '__bases__': |
1974 | +- # Without this help(mock) raises an exception |
1975 | +- raise AttributeError |
1976 | +- return self._sentinels.setdefault(name, _SentinelObject(name)) |
1977 | +- |
1978 | +- |
1979 | +-sentinel = _Sentinel() |
1980 | +- |
1981 | +-DEFAULT = sentinel.DEFAULT |
1982 | +-_missing = sentinel.MISSING |
1983 | +-_deleted = sentinel.DELETED |
1984 | +- |
1985 | +- |
1986 | +-class OldStyleClass: |
1987 | +- pass |
1988 | +-ClassType = type(OldStyleClass) |
1989 | +- |
1990 | +- |
1991 | +-def _copy(value): |
1992 | +- if type(value) in (dict, list, tuple, set): |
1993 | +- return type(value)(value) |
1994 | +- return value |
1995 | +- |
1996 | +- |
1997 | +-ClassTypes = (type,) |
1998 | +-if not inPy3k: |
1999 | +- ClassTypes = (type, ClassType) |
2000 | +- |
2001 | +-_allowed_names = set( |
2002 | +- [ |
2003 | +- 'return_value', '_mock_return_value', 'side_effect', |
2004 | +- '_mock_side_effect', '_mock_parent', '_mock_new_parent', |
2005 | +- '_mock_name', '_mock_new_name' |
2006 | +- ] |
2007 | +-) |
2008 | +- |
2009 | +- |
2010 | +-def _delegating_property(name): |
2011 | +- _allowed_names.add(name) |
2012 | +- _the_name = '_mock_' + name |
2013 | +- def _get(self, name=name, _the_name=_the_name): |
2014 | +- sig = self._mock_delegate |
2015 | +- if sig is None: |
2016 | +- return getattr(self, _the_name) |
2017 | +- return getattr(sig, name) |
2018 | +- def _set(self, value, name=name, _the_name=_the_name): |
2019 | +- sig = self._mock_delegate |
2020 | +- if sig is None: |
2021 | +- self.__dict__[_the_name] = value |
2022 | +- else: |
2023 | +- setattr(sig, name, value) |
2024 | +- |
2025 | +- return property(_get, _set) |
2026 | +- |
2027 | +- |
2028 | +- |
2029 | +-class _CallList(list): |
2030 | +- |
2031 | +- def __contains__(self, value): |
2032 | +- if not isinstance(value, list): |
2033 | +- return list.__contains__(self, value) |
2034 | +- len_value = len(value) |
2035 | +- len_self = len(self) |
2036 | +- if len_value > len_self: |
2037 | +- return False |
2038 | +- |
2039 | +- for i in range(0, len_self - len_value + 1): |
2040 | +- sub_list = self[i:i+len_value] |
2041 | +- if sub_list == value: |
2042 | +- return True |
2043 | +- return False |
2044 | +- |
2045 | +- def __repr__(self): |
2046 | +- return pprint.pformat(list(self)) |
2047 | +- |
2048 | +- |
2049 | +-def _check_and_set_parent(parent, value, name, new_name): |
2050 | +- if not _is_instance_mock(value): |
2051 | +- return False |
2052 | +- if ((value._mock_name or value._mock_new_name) or |
2053 | +- (value._mock_parent is not None) or |
2054 | +- (value._mock_new_parent is not None)): |
2055 | +- return False |
2056 | +- |
2057 | +- _parent = parent |
2058 | +- while _parent is not None: |
2059 | +- # setting a mock (value) as a child or return value of itself |
2060 | +- # should not modify the mock |
2061 | +- if _parent is value: |
2062 | +- return False |
2063 | +- _parent = _parent._mock_new_parent |
2064 | +- |
2065 | +- if new_name: |
2066 | +- value._mock_new_parent = parent |
2067 | +- value._mock_new_name = new_name |
2068 | +- if name: |
2069 | +- value._mock_parent = parent |
2070 | +- value._mock_name = name |
2071 | +- return True |
2072 | +- |
2073 | +- |
2074 | +- |
2075 | +-class Base(object): |
2076 | +- _mock_return_value = DEFAULT |
2077 | +- _mock_side_effect = None |
2078 | +- def __init__(self, *args, **kwargs): |
2079 | +- pass |
2080 | +- |
2081 | +- |
2082 | +- |
2083 | +-class NonCallableMock(Base): |
2084 | +- """A non-callable version of `Mock`""" |
2085 | +- |
2086 | +- def __new__(cls, *args, **kw): |
2087 | +- # every instance has its own class |
2088 | +- # so we can create magic methods on the |
2089 | +- # class without stomping on other mocks |
2090 | +- new = type(cls.__name__, (cls,), {'__doc__': cls.__doc__}) |
2091 | +- instance = object.__new__(new) |
2092 | +- return instance |
2093 | +- |
2094 | +- |
2095 | +- def __init__( |
2096 | +- self, spec=None, wraps=None, name=None, spec_set=None, |
2097 | +- parent=None, _spec_state=None, _new_name='', _new_parent=None, |
2098 | +- **kwargs |
2099 | +- ): |
2100 | +- if _new_parent is None: |
2101 | +- _new_parent = parent |
2102 | +- |
2103 | +- __dict__ = self.__dict__ |
2104 | +- __dict__['_mock_parent'] = parent |
2105 | +- __dict__['_mock_name'] = name |
2106 | +- __dict__['_mock_new_name'] = _new_name |
2107 | +- __dict__['_mock_new_parent'] = _new_parent |
2108 | +- |
2109 | +- if spec_set is not None: |
2110 | +- spec = spec_set |
2111 | +- spec_set = True |
2112 | +- |
2113 | +- self._mock_add_spec(spec, spec_set) |
2114 | +- |
2115 | +- __dict__['_mock_children'] = {} |
2116 | +- __dict__['_mock_wraps'] = wraps |
2117 | +- __dict__['_mock_delegate'] = None |
2118 | +- |
2119 | +- __dict__['_mock_called'] = False |
2120 | +- __dict__['_mock_call_args'] = None |
2121 | +- __dict__['_mock_call_count'] = 0 |
2122 | +- __dict__['_mock_call_args_list'] = _CallList() |
2123 | +- __dict__['_mock_mock_calls'] = _CallList() |
2124 | +- |
2125 | +- __dict__['method_calls'] = _CallList() |
2126 | +- |
2127 | +- if kwargs: |
2128 | +- self.configure_mock(**kwargs) |
2129 | +- |
2130 | +- _super(NonCallableMock, self).__init__( |
2131 | +- spec, wraps, name, spec_set, parent, |
2132 | +- _spec_state |
2133 | +- ) |
2134 | +- |
2135 | +- |
2136 | +- def attach_mock(self, mock, attribute): |
2137 | +- """ |
2138 | +- Attach a mock as an attribute of this one, replacing its name and |
2139 | +- parent. Calls to the attached mock will be recorded in the |
2140 | +- `method_calls` and `mock_calls` attributes of this one.""" |
2141 | +- mock._mock_parent = None |
2142 | +- mock._mock_new_parent = None |
2143 | +- mock._mock_name = '' |
2144 | +- mock._mock_new_name = None |
2145 | +- |
2146 | +- setattr(self, attribute, mock) |
2147 | +- |
2148 | +- |
2149 | +- def mock_add_spec(self, spec, spec_set=False): |
2150 | +- """Add a spec to a mock. `spec` can either be an object or a |
2151 | +- list of strings. Only attributes on the `spec` can be fetched as |
2152 | +- attributes from the mock. |
2153 | +- |
2154 | +- If `spec_set` is True then only attributes on the spec can be set.""" |
2155 | +- self._mock_add_spec(spec, spec_set) |
2156 | +- |
2157 | +- |
2158 | +- def _mock_add_spec(self, spec, spec_set): |
2159 | +- _spec_class = None |
2160 | +- |
2161 | +- if spec is not None and not _is_list(spec): |
2162 | +- if isinstance(spec, ClassTypes): |
2163 | +- _spec_class = spec |
2164 | +- else: |
2165 | +- _spec_class = _get_class(spec) |
2166 | +- |
2167 | +- spec = dir(spec) |
2168 | +- |
2169 | +- __dict__ = self.__dict__ |
2170 | +- __dict__['_spec_class'] = _spec_class |
2171 | +- __dict__['_spec_set'] = spec_set |
2172 | +- __dict__['_mock_methods'] = spec |
2173 | +- |
2174 | +- |
2175 | +- def __get_return_value(self): |
2176 | +- ret = self._mock_return_value |
2177 | +- if self._mock_delegate is not None: |
2178 | +- ret = self._mock_delegate.return_value |
2179 | +- |
2180 | +- if ret is DEFAULT: |
2181 | +- ret = self._get_child_mock( |
2182 | +- _new_parent=self, _new_name='()' |
2183 | +- ) |
2184 | +- self.return_value = ret |
2185 | +- return ret |
2186 | +- |
2187 | +- |
2188 | +- def __set_return_value(self, value): |
2189 | +- if self._mock_delegate is not None: |
2190 | +- self._mock_delegate.return_value = value |
2191 | +- else: |
2192 | +- self._mock_return_value = value |
2193 | +- _check_and_set_parent(self, value, None, '()') |
2194 | +- |
2195 | +- __return_value_doc = "The value to be returned when the mock is called." |
2196 | +- return_value = property(__get_return_value, __set_return_value, |
2197 | +- __return_value_doc) |
2198 | +- |
2199 | +- |
2200 | +- @property |
2201 | +- def __class__(self): |
2202 | +- if self._spec_class is None: |
2203 | +- return type(self) |
2204 | +- return self._spec_class |
2205 | +- |
2206 | +- called = _delegating_property('called') |
2207 | +- call_count = _delegating_property('call_count') |
2208 | +- call_args = _delegating_property('call_args') |
2209 | +- call_args_list = _delegating_property('call_args_list') |
2210 | +- mock_calls = _delegating_property('mock_calls') |
2211 | +- |
2212 | +- |
2213 | +- def __get_side_effect(self): |
2214 | +- sig = self._mock_delegate |
2215 | +- if sig is None: |
2216 | +- return self._mock_side_effect |
2217 | +- return sig.side_effect |
2218 | +- |
2219 | +- def __set_side_effect(self, value): |
2220 | +- value = _try_iter(value) |
2221 | +- sig = self._mock_delegate |
2222 | +- if sig is None: |
2223 | +- self._mock_side_effect = value |
2224 | +- else: |
2225 | +- sig.side_effect = value |
2226 | +- |
2227 | +- side_effect = property(__get_side_effect, __set_side_effect) |
2228 | +- |
2229 | +- |
2230 | +- def reset_mock(self): |
2231 | +- "Restore the mock object to its initial state." |
2232 | +- self.called = False |
2233 | +- self.call_args = None |
2234 | +- self.call_count = 0 |
2235 | +- self.mock_calls = _CallList() |
2236 | +- self.call_args_list = _CallList() |
2237 | +- self.method_calls = _CallList() |
2238 | +- |
2239 | +- for child in self._mock_children.values(): |
2240 | +- if isinstance(child, _SpecState): |
2241 | +- continue |
2242 | +- child.reset_mock() |
2243 | +- |
2244 | +- ret = self._mock_return_value |
2245 | +- if _is_instance_mock(ret) and ret is not self: |
2246 | +- ret.reset_mock() |
2247 | +- |
2248 | +- |
2249 | +- def configure_mock(self, **kwargs): |
2250 | +- """Set attributes on the mock through keyword arguments. |
2251 | +- |
2252 | +- Attributes plus return values and side effects can be set on child |
2253 | +- mocks using standard dot notation and unpacking a dictionary in the |
2254 | +- method call: |
2255 | +- |
2256 | +- >>> attrs = {'method.return_value': 3, 'other.side_effect': KeyError} |
2257 | +- >>> mock.configure_mock(**attrs)""" |
2258 | +- for arg, val in sorted(kwargs.items(), |
2259 | +- # we sort on the number of dots so that |
2260 | +- # attributes are set before we set attributes on |
2261 | +- # attributes |
2262 | +- key=lambda entry: entry[0].count('.')): |
2263 | +- args = arg.split('.') |
2264 | +- final = args.pop() |
2265 | +- obj = self |
2266 | +- for entry in args: |
2267 | +- obj = getattr(obj, entry) |
2268 | +- setattr(obj, final, val) |
2269 | +- |
2270 | +- |
2271 | +- def __getattr__(self, name): |
2272 | +- if name == '_mock_methods': |
2273 | +- raise AttributeError(name) |
2274 | +- elif self._mock_methods is not None: |
2275 | +- if name not in self._mock_methods or name in _all_magics: |
2276 | +- raise AttributeError("Mock object has no attribute %r" % name) |
2277 | +- elif _is_magic(name): |
2278 | +- raise AttributeError(name) |
2279 | +- |
2280 | +- result = self._mock_children.get(name) |
2281 | +- if result is _deleted: |
2282 | +- raise AttributeError(name) |
2283 | +- elif result is None: |
2284 | +- wraps = None |
2285 | +- if self._mock_wraps is not None: |
2286 | +- # XXXX should we get the attribute without triggering code |
2287 | +- # execution? |
2288 | +- wraps = getattr(self._mock_wraps, name) |
2289 | +- |
2290 | +- result = self._get_child_mock( |
2291 | +- parent=self, name=name, wraps=wraps, _new_name=name, |
2292 | +- _new_parent=self |
2293 | +- ) |
2294 | +- self._mock_children[name] = result |
2295 | +- |
2296 | +- elif isinstance(result, _SpecState): |
2297 | +- result = create_autospec( |
2298 | +- result.spec, result.spec_set, result.instance, |
2299 | +- result.parent, result.name |
2300 | +- ) |
2301 | +- self._mock_children[name] = result |
2302 | +- |
2303 | +- return result |
2304 | +- |
2305 | +- |
2306 | +- def __repr__(self): |
2307 | +- _name_list = [self._mock_new_name] |
2308 | +- _parent = self._mock_new_parent |
2309 | +- last = self |
2310 | +- |
2311 | +- dot = '.' |
2312 | +- if _name_list == ['()']: |
2313 | +- dot = '' |
2314 | +- seen = set() |
2315 | +- while _parent is not None: |
2316 | +- last = _parent |
2317 | +- |
2318 | +- _name_list.append(_parent._mock_new_name + dot) |
2319 | +- dot = '.' |
2320 | +- if _parent._mock_new_name == '()': |
2321 | +- dot = '' |
2322 | +- |
2323 | +- _parent = _parent._mock_new_parent |
2324 | +- |
2325 | +- # use ids here so as not to call __hash__ on the mocks |
2326 | +- if id(_parent) in seen: |
2327 | +- break |
2328 | +- seen.add(id(_parent)) |
2329 | +- |
2330 | +- _name_list = list(reversed(_name_list)) |
2331 | +- _first = last._mock_name or 'mock' |
2332 | +- if len(_name_list) > 1: |
2333 | +- if _name_list[1] not in ('()', '().'): |
2334 | +- _first += '.' |
2335 | +- _name_list[0] = _first |
2336 | +- name = ''.join(_name_list) |
2337 | +- |
2338 | +- name_string = '' |
2339 | +- if name not in ('mock', 'mock.'): |
2340 | +- name_string = ' name=%r' % name |
2341 | +- |
2342 | +- spec_string = '' |
2343 | +- if self._spec_class is not None: |
2344 | +- spec_string = ' spec=%r' |
2345 | +- if self._spec_set: |
2346 | +- spec_string = ' spec_set=%r' |
2347 | +- spec_string = spec_string % self._spec_class.__name__ |
2348 | +- return "<%s%s%s id='%s'>" % ( |
2349 | +- type(self).__name__, |
2350 | +- name_string, |
2351 | +- spec_string, |
2352 | +- id(self) |
2353 | +- ) |
2354 | +- |
2355 | +- |
2356 | +- def __dir__(self): |
2357 | +- """Filter the output of `dir(mock)` to only useful members. |
2358 | +- XXXX |
2359 | +- """ |
2360 | +- extras = self._mock_methods or [] |
2361 | +- from_type = dir(type(self)) |
2362 | +- from_dict = list(self.__dict__) |
2363 | +- |
2364 | +- if FILTER_DIR: |
2365 | +- from_type = [e for e in from_type if not e.startswith('_')] |
2366 | +- from_dict = [e for e in from_dict if not e.startswith('_') or |
2367 | +- _is_magic(e)] |
2368 | +- return sorted(set(extras + from_type + from_dict + |
2369 | +- list(self._mock_children))) |
2370 | +- |
2371 | +- |
2372 | +- def __setattr__(self, name, value): |
2373 | +- if name in _allowed_names: |
2374 | +- # property setters go through here |
2375 | +- return object.__setattr__(self, name, value) |
2376 | +- elif (self._spec_set and self._mock_methods is not None and |
2377 | +- name not in self._mock_methods and |
2378 | +- name not in self.__dict__): |
2379 | +- raise AttributeError("Mock object has no attribute '%s'" % name) |
2380 | +- elif name in _unsupported_magics: |
2381 | +- msg = 'Attempting to set unsupported magic method %r.' % name |
2382 | +- raise AttributeError(msg) |
2383 | +- elif name in _all_magics: |
2384 | +- if self._mock_methods is not None and name not in self._mock_methods: |
2385 | +- raise AttributeError("Mock object has no attribute '%s'" % name) |
2386 | +- |
2387 | +- if not _is_instance_mock(value): |
2388 | +- setattr(type(self), name, _get_method(name, value)) |
2389 | +- original = value |
2390 | +- value = lambda *args, **kw: original(self, *args, **kw) |
2391 | +- else: |
2392 | +- # only set _new_name and not name so that mock_calls is tracked |
2393 | +- # but not method calls |
2394 | +- _check_and_set_parent(self, value, None, name) |
2395 | +- setattr(type(self), name, value) |
2396 | +- self._mock_children[name] = value |
2397 | +- elif name == '__class__': |
2398 | +- self._spec_class = value |
2399 | +- return |
2400 | +- else: |
2401 | +- if _check_and_set_parent(self, value, name, name): |
2402 | +- self._mock_children[name] = value |
2403 | +- return object.__setattr__(self, name, value) |
2404 | +- |
2405 | +- |
2406 | +- def __delattr__(self, name): |
2407 | +- if name in _all_magics and name in type(self).__dict__: |
2408 | +- delattr(type(self), name) |
2409 | +- if name not in self.__dict__: |
2410 | +- # for magic methods that are still MagicProxy objects and |
2411 | +- # not set on the instance itself |
2412 | +- return |
2413 | +- |
2414 | +- if name in self.__dict__: |
2415 | +- object.__delattr__(self, name) |
2416 | +- |
2417 | +- obj = self._mock_children.get(name, _missing) |
2418 | +- if obj is _deleted: |
2419 | +- raise AttributeError(name) |
2420 | +- if obj is not _missing: |
2421 | +- del self._mock_children[name] |
2422 | +- self._mock_children[name] = _deleted |
2423 | +- |
2424 | +- |
2425 | +- |
2426 | +- def _format_mock_call_signature(self, args, kwargs): |
2427 | +- name = self._mock_name or 'mock' |
2428 | +- return _format_call_signature(name, args, kwargs) |
2429 | +- |
2430 | +- |
2431 | +- def _format_mock_failure_message(self, args, kwargs): |
2432 | +- message = 'Expected call: %s\nActual call: %s' |
2433 | +- expected_string = self._format_mock_call_signature(args, kwargs) |
2434 | +- call_args = self.call_args |
2435 | +- if len(call_args) == 3: |
2436 | +- call_args = call_args[1:] |
2437 | +- actual_string = self._format_mock_call_signature(*call_args) |
2438 | +- return message % (expected_string, actual_string) |
2439 | +- |
2440 | +- |
2441 | +- def assert_called_with(_mock_self, *args, **kwargs): |
2442 | +- """assert that the mock was called with the specified arguments. |
2443 | +- |
2444 | +- Raises an AssertionError if the args and keyword args passed in are |
2445 | +- different to the last call to the mock.""" |
2446 | +- self = _mock_self |
2447 | +- if self.call_args is None: |
2448 | +- expected = self._format_mock_call_signature(args, kwargs) |
2449 | +- raise AssertionError('Expected call: %s\nNot called' % (expected,)) |
2450 | +- |
2451 | +- if self.call_args != (args, kwargs): |
2452 | +- msg = self._format_mock_failure_message(args, kwargs) |
2453 | +- raise AssertionError(msg) |
2454 | +- |
2455 | +- |
2456 | +- def assert_called_once_with(_mock_self, *args, **kwargs): |
2457 | +- """assert that the mock was called exactly once and with the specified |
2458 | +- arguments.""" |
2459 | +- self = _mock_self |
2460 | +- if not self.call_count == 1: |
2461 | +- msg = ("Expected to be called once. Called %s times." % |
2462 | +- self.call_count) |
2463 | +- raise AssertionError(msg) |
2464 | +- return self.assert_called_with(*args, **kwargs) |
2465 | +- |
2466 | +- |
2467 | +- def assert_has_calls(self, calls, any_order=False): |
2468 | +- """assert the mock has been called with the specified calls. |
2469 | +- The `mock_calls` list is checked for the calls. |
2470 | +- |
2471 | +- If `any_order` is False (the default) then the calls must be |
2472 | +- sequential. There can be extra calls before or after the |
2473 | +- specified calls. |
2474 | +- |
2475 | +- If `any_order` is True then the calls can be in any order, but |
2476 | +- they must all appear in `mock_calls`.""" |
2477 | +- if not any_order: |
2478 | +- if calls not in self.mock_calls: |
2479 | +- raise AssertionError( |
2480 | +- 'Calls not found.\nExpected: %r\n' |
2481 | +- 'Actual: %r' % (calls, self.mock_calls) |
2482 | +- ) |
2483 | +- return |
2484 | +- |
2485 | +- all_calls = list(self.mock_calls) |
2486 | +- |
2487 | +- not_found = [] |
2488 | +- for kall in calls: |
2489 | +- try: |
2490 | +- all_calls.remove(kall) |
2491 | +- except ValueError: |
2492 | +- not_found.append(kall) |
2493 | +- if not_found: |
2494 | +- raise AssertionError( |
2495 | +- '%r not all found in call list' % (tuple(not_found),) |
2496 | +- ) |
2497 | +- |
2498 | +- |
2499 | +- def assert_any_call(self, *args, **kwargs): |
2500 | +- """assert the mock has been called with the specified arguments. |
2501 | +- |
2502 | +- The assert passes if the mock has *ever* been called, unlike |
2503 | +- `assert_called_with` and `assert_called_once_with` that only pass if |
2504 | +- the call is the most recent one.""" |
2505 | +- kall = call(*args, **kwargs) |
2506 | +- if kall not in self.call_args_list: |
2507 | +- expected_string = self._format_mock_call_signature(args, kwargs) |
2508 | +- raise AssertionError( |
2509 | +- '%s call not found' % expected_string |
2510 | +- ) |
2511 | +- |
2512 | +- |
2513 | +- def _get_child_mock(self, **kw): |
2514 | +- """Create the child mocks for attributes and return value. |
2515 | +- By default child mocks will be the same type as the parent. |
2516 | +- Subclasses of Mock may want to override this to customize the way |
2517 | +- child mocks are made. |
2518 | +- |
2519 | +- For non-callable mocks the callable variant will be used (rather than |
2520 | +- any custom subclass).""" |
2521 | +- _type = type(self) |
2522 | +- if not issubclass(_type, CallableMixin): |
2523 | +- if issubclass(_type, NonCallableMagicMock): |
2524 | +- klass = MagicMock |
2525 | +- elif issubclass(_type, NonCallableMock) : |
2526 | +- klass = Mock |
2527 | +- else: |
2528 | +- klass = _type.__mro__[1] |
2529 | +- return klass(**kw) |
2530 | +- |
2531 | +- |
2532 | +- |
2533 | +-def _try_iter(obj): |
2534 | +- if obj is None: |
2535 | +- return obj |
2536 | +- if _is_exception(obj): |
2537 | +- return obj |
2538 | +- if _callable(obj): |
2539 | +- return obj |
2540 | +- try: |
2541 | +- return iter(obj) |
2542 | +- except TypeError: |
2543 | +- # XXXX backwards compatibility |
2544 | +- # but this will blow up on first call - so maybe we should fail early? |
2545 | +- return obj |
2546 | +- |
2547 | +- |
2548 | +- |
2549 | +-class CallableMixin(Base): |
2550 | +- |
2551 | +- def __init__(self, spec=None, side_effect=None, return_value=DEFAULT, |
2552 | +- wraps=None, name=None, spec_set=None, parent=None, |
2553 | +- _spec_state=None, _new_name='', _new_parent=None, **kwargs): |
2554 | +- self.__dict__['_mock_return_value'] = return_value |
2555 | +- |
2556 | +- _super(CallableMixin, self).__init__( |
2557 | +- spec, wraps, name, spec_set, parent, |
2558 | +- _spec_state, _new_name, _new_parent, **kwargs |
2559 | +- ) |
2560 | +- |
2561 | +- self.side_effect = side_effect |
2562 | +- |
2563 | +- |
2564 | +- def _mock_check_sig(self, *args, **kwargs): |
2565 | +- # stub method that can be replaced with one with a specific signature |
2566 | +- pass |
2567 | +- |
2568 | +- |
2569 | +- def __call__(_mock_self, *args, **kwargs): |
2570 | +- # can't use self in-case a function / method we are mocking uses self |
2571 | +- # in the signature |
2572 | +- _mock_self._mock_check_sig(*args, **kwargs) |
2573 | +- return _mock_self._mock_call(*args, **kwargs) |
2574 | +- |
2575 | +- |
2576 | +- def _mock_call(_mock_self, *args, **kwargs): |
2577 | +- self = _mock_self |
2578 | +- self.called = True |
2579 | +- self.call_count += 1 |
2580 | +- self.call_args = _Call((args, kwargs), two=True) |
2581 | +- self.call_args_list.append(_Call((args, kwargs), two=True)) |
2582 | +- |
2583 | +- _new_name = self._mock_new_name |
2584 | +- _new_parent = self._mock_new_parent |
2585 | +- self.mock_calls.append(_Call(('', args, kwargs))) |
2586 | +- |
2587 | +- seen = set() |
2588 | +- skip_next_dot = _new_name == '()' |
2589 | +- do_method_calls = self._mock_parent is not None |
2590 | +- name = self._mock_name |
2591 | +- while _new_parent is not None: |
2592 | +- this_mock_call = _Call((_new_name, args, kwargs)) |
2593 | +- if _new_parent._mock_new_name: |
2594 | +- dot = '.' |
2595 | +- if skip_next_dot: |
2596 | +- dot = '' |
2597 | +- |
2598 | +- skip_next_dot = False |
2599 | +- if _new_parent._mock_new_name == '()': |
2600 | +- skip_next_dot = True |
2601 | +- |
2602 | +- _new_name = _new_parent._mock_new_name + dot + _new_name |
2603 | +- |
2604 | +- if do_method_calls: |
2605 | +- if _new_name == name: |
2606 | +- this_method_call = this_mock_call |
2607 | +- else: |
2608 | +- this_method_call = _Call((name, args, kwargs)) |
2609 | +- _new_parent.method_calls.append(this_method_call) |
2610 | +- |
2611 | +- do_method_calls = _new_parent._mock_parent is not None |
2612 | +- if do_method_calls: |
2613 | +- name = _new_parent._mock_name + '.' + name |
2614 | +- |
2615 | +- _new_parent.mock_calls.append(this_mock_call) |
2616 | +- _new_parent = _new_parent._mock_new_parent |
2617 | +- |
2618 | +- # use ids here so as not to call __hash__ on the mocks |
2619 | +- _new_parent_id = id(_new_parent) |
2620 | +- if _new_parent_id in seen: |
2621 | +- break |
2622 | +- seen.add(_new_parent_id) |
2623 | +- |
2624 | +- ret_val = DEFAULT |
2625 | +- effect = self.side_effect |
2626 | +- if effect is not None: |
2627 | +- if _is_exception(effect): |
2628 | +- raise effect |
2629 | +- |
2630 | +- if not _callable(effect): |
2631 | +- result = next(effect) |
2632 | +- if _is_exception(result): |
2633 | +- raise result |
2634 | +- return result |
2635 | +- |
2636 | +- ret_val = effect(*args, **kwargs) |
2637 | +- if ret_val is DEFAULT: |
2638 | +- ret_val = self.return_value |
2639 | +- |
2640 | +- if (self._mock_wraps is not None and |
2641 | +- self._mock_return_value is DEFAULT): |
2642 | +- return self._mock_wraps(*args, **kwargs) |
2643 | +- if ret_val is DEFAULT: |
2644 | +- ret_val = self.return_value |
2645 | +- return ret_val |
2646 | +- |
2647 | +- |
2648 | +- |
2649 | +-class Mock(CallableMixin, NonCallableMock): |
2650 | +- """ |
2651 | +- Create a new `Mock` object. `Mock` takes several optional arguments |
2652 | +- that specify the behaviour of the Mock object: |
2653 | +- |
2654 | +- * `spec`: This can be either a list of strings or an existing object (a |
2655 | +- class or instance) that acts as the specification for the mock object. If |
2656 | +- you pass in an object then a list of strings is formed by calling dir on |
2657 | +- the object (excluding unsupported magic attributes and methods). Accessing |
2658 | +- any attribute not in this list will raise an `AttributeError`. |
2659 | +- |
2660 | +- If `spec` is an object (rather than a list of strings) then |
2661 | +- `mock.__class__` returns the class of the spec object. This allows mocks |
2662 | +- to pass `isinstance` tests. |
2663 | +- |
2664 | +- * `spec_set`: A stricter variant of `spec`. If used, attempting to *set* |
2665 | +- or get an attribute on the mock that isn't on the object passed as |
2666 | +- `spec_set` will raise an `AttributeError`. |
2667 | +- |
2668 | +- * `side_effect`: A function to be called whenever the Mock is called. See |
2669 | +- the `side_effect` attribute. Useful for raising exceptions or |
2670 | +- dynamically changing return values. The function is called with the same |
2671 | +- arguments as the mock, and unless it returns `DEFAULT`, the return |
2672 | +- value of this function is used as the return value. |
2673 | +- |
2674 | +- Alternatively `side_effect` can be an exception class or instance. In |
2675 | +- this case the exception will be raised when the mock is called. |
2676 | +- |
2677 | +- If `side_effect` is an iterable then each call to the mock will return |
2678 | +- the next value from the iterable. If any of the members of the iterable |
2679 | +- are exceptions they will be raised instead of returned. |
2680 | +- |
2681 | +- * `return_value`: The value returned when the mock is called. By default |
2682 | +- this is a new Mock (created on first access). See the |
2683 | +- `return_value` attribute. |
2684 | +- |
2685 | +- * `wraps`: Item for the mock object to wrap. If `wraps` is not None then |
2686 | +- calling the Mock will pass the call through to the wrapped object |
2687 | +- (returning the real result). Attribute access on the mock will return a |
2688 | +- Mock object that wraps the corresponding attribute of the wrapped object |
2689 | +- (so attempting to access an attribute that doesn't exist will raise an |
2690 | +- `AttributeError`). |
2691 | +- |
2692 | +- If the mock has an explicit `return_value` set then calls are not passed |
2693 | +- to the wrapped object and the `return_value` is returned instead. |
2694 | +- |
2695 | +- * `name`: If the mock has a name then it will be used in the repr of the |
2696 | +- mock. This can be useful for debugging. The name is propagated to child |
2697 | +- mocks. |
2698 | +- |
2699 | +- Mocks can also be called with arbitrary keyword arguments. These will be |
2700 | +- used to set attributes on the mock after it is created. |
2701 | +- """ |
2702 | +- |
2703 | +- |
2704 | +- |
2705 | +-def _dot_lookup(thing, comp, import_path): |
2706 | +- try: |
2707 | +- return getattr(thing, comp) |
2708 | +- except AttributeError: |
2709 | +- __import__(import_path) |
2710 | +- return getattr(thing, comp) |
2711 | +- |
2712 | +- |
2713 | +-def _importer(target): |
2714 | +- components = target.split('.') |
2715 | +- import_path = components.pop(0) |
2716 | +- thing = __import__(import_path) |
2717 | +- |
2718 | +- for comp in components: |
2719 | +- import_path += ".%s" % comp |
2720 | +- thing = _dot_lookup(thing, comp, import_path) |
2721 | +- return thing |
2722 | +- |
2723 | +- |
2724 | +-def _is_started(patcher): |
2725 | +- # XXXX horrible |
2726 | +- return hasattr(patcher, 'is_local') |
2727 | +- |
2728 | +- |
2729 | +-class _patch(object): |
2730 | +- |
2731 | +- attribute_name = None |
2732 | +- _active_patches = set() |
2733 | +- |
2734 | +- def __init__( |
2735 | +- self, getter, attribute, new, spec, create, |
2736 | +- spec_set, autospec, new_callable, kwargs |
2737 | +- ): |
2738 | +- if new_callable is not None: |
2739 | +- if new is not DEFAULT: |
2740 | +- raise ValueError( |
2741 | +- "Cannot use 'new' and 'new_callable' together" |
2742 | +- ) |
2743 | +- if autospec is not None: |
2744 | +- raise ValueError( |
2745 | +- "Cannot use 'autospec' and 'new_callable' together" |
2746 | +- ) |
2747 | +- |
2748 | +- self.getter = getter |
2749 | +- self.attribute = attribute |
2750 | +- self.new = new |
2751 | +- self.new_callable = new_callable |
2752 | +- self.spec = spec |
2753 | +- self.create = create |
2754 | +- self.has_local = False |
2755 | +- self.spec_set = spec_set |
2756 | +- self.autospec = autospec |
2757 | +- self.kwargs = kwargs |
2758 | +- self.additional_patchers = [] |
2759 | +- |
2760 | +- |
2761 | +- def copy(self): |
2762 | +- patcher = _patch( |
2763 | +- self.getter, self.attribute, self.new, self.spec, |
2764 | +- self.create, self.spec_set, |
2765 | +- self.autospec, self.new_callable, self.kwargs |
2766 | +- ) |
2767 | +- patcher.attribute_name = self.attribute_name |
2768 | +- patcher.additional_patchers = [ |
2769 | +- p.copy() for p in self.additional_patchers |
2770 | +- ] |
2771 | +- return patcher |
2772 | +- |
2773 | +- |
2774 | +- def __call__(self, func): |
2775 | +- if isinstance(func, ClassTypes): |
2776 | +- return self.decorate_class(func) |
2777 | +- return self.decorate_callable(func) |
2778 | +- |
2779 | +- |
2780 | +- def decorate_class(self, klass): |
2781 | +- for attr in dir(klass): |
2782 | +- if not attr.startswith(patch.TEST_PREFIX): |
2783 | +- continue |
2784 | +- |
2785 | +- attr_value = getattr(klass, attr) |
2786 | +- if not hasattr(attr_value, "__call__"): |
2787 | +- continue |
2788 | +- |
2789 | +- patcher = self.copy() |
2790 | +- setattr(klass, attr, patcher(attr_value)) |
2791 | +- return klass |
2792 | +- |
2793 | +- |
2794 | +- def decorate_callable(self, func): |
2795 | +- if hasattr(func, 'patchings'): |
2796 | +- func.patchings.append(self) |
2797 | +- return func |
2798 | +- |
2799 | +- @wraps(func) |
2800 | +- def patched(*args, **keywargs): |
2801 | +- # don't use a with here (backwards compatability with Python 2.4) |
2802 | +- extra_args = [] |
2803 | +- entered_patchers = [] |
2804 | +- |
2805 | +- # can't use try...except...finally because of Python 2.4 |
2806 | +- # compatibility |
2807 | +- exc_info = tuple() |
2808 | +- try: |
2809 | +- try: |
2810 | +- for patching in patched.patchings: |
2811 | +- arg = patching.__enter__() |
2812 | +- entered_patchers.append(patching) |
2813 | +- if patching.attribute_name is not None: |
2814 | +- keywargs.update(arg) |
2815 | +- elif patching.new is DEFAULT: |
2816 | +- extra_args.append(arg) |
2817 | +- |
2818 | +- args += tuple(extra_args) |
2819 | +- return func(*args, **keywargs) |
2820 | +- except: |
2821 | +- if (patching not in entered_patchers and |
2822 | +- _is_started(patching)): |
2823 | +- # the patcher may have been started, but an exception |
2824 | +- # raised whilst entering one of its additional_patchers |
2825 | +- entered_patchers.append(patching) |
2826 | +- # Pass the exception to __exit__ |
2827 | +- exc_info = sys.exc_info() |
2828 | +- # re-raise the exception |
2829 | +- raise |
2830 | +- finally: |
2831 | +- for patching in reversed(entered_patchers): |
2832 | +- patching.__exit__(*exc_info) |
2833 | +- |
2834 | +- patched.patchings = [self] |
2835 | +- if hasattr(func, 'func_code'): |
2836 | +- # not in Python 3 |
2837 | +- patched.compat_co_firstlineno = getattr( |
2838 | +- func, "compat_co_firstlineno", |
2839 | +- func.func_code.co_firstlineno |
2840 | +- ) |
2841 | +- return patched |
2842 | +- |
2843 | +- |
2844 | +- def get_original(self): |
2845 | +- target = self.getter() |
2846 | +- name = self.attribute |
2847 | +- |
2848 | +- original = DEFAULT |
2849 | +- local = False |
2850 | +- |
2851 | +- try: |
2852 | +- original = target.__dict__[name] |
2853 | +- except (AttributeError, KeyError): |
2854 | +- original = getattr(target, name, DEFAULT) |
2855 | +- else: |
2856 | +- local = True |
2857 | +- |
2858 | +- if not self.create and original is DEFAULT: |
2859 | +- raise AttributeError( |
2860 | +- "%s does not have the attribute %r" % (target, name) |
2861 | +- ) |
2862 | +- return original, local |
2863 | +- |
2864 | +- |
2865 | +- def __enter__(self): |
2866 | +- """Perform the patch.""" |
2867 | +- new, spec, spec_set = self.new, self.spec, self.spec_set |
2868 | +- autospec, kwargs = self.autospec, self.kwargs |
2869 | +- new_callable = self.new_callable |
2870 | +- self.target = self.getter() |
2871 | +- |
2872 | +- # normalise False to None |
2873 | +- if spec is False: |
2874 | +- spec = None |
2875 | +- if spec_set is False: |
2876 | +- spec_set = None |
2877 | +- if autospec is False: |
2878 | +- autospec = None |
2879 | +- |
2880 | +- if spec is not None and autospec is not None: |
2881 | +- raise TypeError("Can't specify spec and autospec") |
2882 | +- if ((spec is not None or autospec is not None) and |
2883 | +- spec_set not in (True, None)): |
2884 | +- raise TypeError("Can't provide explicit spec_set *and* spec or autospec") |
2885 | +- |
2886 | +- original, local = self.get_original() |
2887 | +- |
2888 | +- if new is DEFAULT and autospec is None: |
2889 | +- inherit = False |
2890 | +- if spec is True: |
2891 | +- # set spec to the object we are replacing |
2892 | +- spec = original |
2893 | +- if spec_set is True: |
2894 | +- spec_set = original |
2895 | +- spec = None |
2896 | +- elif spec is not None: |
2897 | +- if spec_set is True: |
2898 | +- spec_set = spec |
2899 | +- spec = None |
2900 | +- elif spec_set is True: |
2901 | +- spec_set = original |
2902 | +- |
2903 | +- if spec is not None or spec_set is not None: |
2904 | +- if original is DEFAULT: |
2905 | +- raise TypeError("Can't use 'spec' with create=True") |
2906 | +- if isinstance(original, ClassTypes): |
2907 | +- # If we're patching out a class and there is a spec |
2908 | +- inherit = True |
2909 | +- |
2910 | +- Klass = MagicMock |
2911 | +- _kwargs = {} |
2912 | +- if new_callable is not None: |
2913 | +- Klass = new_callable |
2914 | +- elif spec is not None or spec_set is not None: |
2915 | +- this_spec = spec |
2916 | +- if spec_set is not None: |
2917 | +- this_spec = spec_set |
2918 | +- if _is_list(this_spec): |
2919 | +- not_callable = '__call__' not in this_spec |
2920 | +- else: |
2921 | +- not_callable = not _callable(this_spec) |
2922 | +- if not_callable: |
2923 | +- Klass = NonCallableMagicMock |
2924 | +- |
2925 | +- if spec is not None: |
2926 | +- _kwargs['spec'] = spec |
2927 | +- if spec_set is not None: |
2928 | +- _kwargs['spec_set'] = spec_set |
2929 | +- |
2930 | +- # add a name to mocks |
2931 | +- if (isinstance(Klass, type) and |
2932 | +- issubclass(Klass, NonCallableMock) and self.attribute): |
2933 | +- _kwargs['name'] = self.attribute |
2934 | +- |
2935 | +- _kwargs.update(kwargs) |
2936 | +- new = Klass(**_kwargs) |
2937 | +- |
2938 | +- if inherit and _is_instance_mock(new): |
2939 | +- # we can only tell if the instance should be callable if the |
2940 | +- # spec is not a list |
2941 | +- this_spec = spec |
2942 | +- if spec_set is not None: |
2943 | +- this_spec = spec_set |
2944 | +- if (not _is_list(this_spec) and not |
2945 | +- _instance_callable(this_spec)): |
2946 | +- Klass = NonCallableMagicMock |
2947 | +- |
2948 | +- _kwargs.pop('name') |
2949 | +- new.return_value = Klass(_new_parent=new, _new_name='()', |
2950 | +- **_kwargs) |
2951 | +- elif autospec is not None: |
2952 | +- # spec is ignored, new *must* be default, spec_set is treated |
2953 | +- # as a boolean. Should we check spec is not None and that spec_set |
2954 | +- # is a bool? |
2955 | +- if new is not DEFAULT: |
2956 | +- raise TypeError( |
2957 | +- "autospec creates the mock for you. Can't specify " |
2958 | +- "autospec and new." |
2959 | +- ) |
2960 | +- if original is DEFAULT: |
2961 | +- raise TypeError("Can't use 'autospec' with create=True") |
2962 | +- spec_set = bool(spec_set) |
2963 | +- if autospec is True: |
2964 | +- autospec = original |
2965 | +- |
2966 | +- new = create_autospec(autospec, spec_set=spec_set, |
2967 | +- _name=self.attribute, **kwargs) |
2968 | +- elif kwargs: |
2969 | +- # can't set keyword args when we aren't creating the mock |
2970 | +- # XXXX If new is a Mock we could call new.configure_mock(**kwargs) |
2971 | +- raise TypeError("Can't pass kwargs to a mock we aren't creating") |
2972 | +- |
2973 | +- new_attr = new |
2974 | +- |
2975 | +- self.temp_original = original |
2976 | +- self.is_local = local |
2977 | +- setattr(self.target, self.attribute, new_attr) |
2978 | +- if self.attribute_name is not None: |
2979 | +- extra_args = {} |
2980 | +- if self.new is DEFAULT: |
2981 | +- extra_args[self.attribute_name] = new |
2982 | +- for patching in self.additional_patchers: |
2983 | +- arg = patching.__enter__() |
2984 | +- if patching.new is DEFAULT: |
2985 | +- extra_args.update(arg) |
2986 | +- return extra_args |
2987 | +- |
2988 | +- return new |
2989 | +- |
2990 | +- |
2991 | +- def __exit__(self, *exc_info): |
2992 | +- """Undo the patch.""" |
2993 | +- if not _is_started(self): |
2994 | +- raise RuntimeError('stop called on unstarted patcher') |
2995 | +- |
2996 | +- if self.is_local and self.temp_original is not DEFAULT: |
2997 | +- setattr(self.target, self.attribute, self.temp_original) |
2998 | +- else: |
2999 | +- delattr(self.target, self.attribute) |
3000 | +- if not self.create and not hasattr(self.target, self.attribute): |
3001 | +- # needed for proxy objects like django settings |
3002 | +- setattr(self.target, self.attribute, self.temp_original) |
3003 | +- |
3004 | +- del self.temp_original |
3005 | +- del self.is_local |
3006 | +- del self.target |
3007 | +- for patcher in reversed(self.additional_patchers): |
3008 | +- if _is_started(patcher): |
3009 | +- patcher.__exit__(*exc_info) |
3010 | +- |
3011 | +- |
3012 | +- def start(self): |
3013 | +- """Activate a patch, returning any created mock.""" |
3014 | +- result = self.__enter__() |
3015 | +- self._active_patches.add(self) |
3016 | +- return result |
3017 | +- |
3018 | +- |
3019 | +- def stop(self): |
3020 | +- """Stop an active patch.""" |
3021 | +- self._active_patches.discard(self) |
3022 | +- return self.__exit__() |
3023 | +- |
3024 | +- |
3025 | +- |
3026 | +-def _get_target(target): |
3027 | +- try: |
3028 | +- target, attribute = target.rsplit('.', 1) |
3029 | +- except (TypeError, ValueError): |
3030 | +- raise TypeError("Need a valid target to patch. You supplied: %r" % |
3031 | +- (target,)) |
3032 | +- getter = lambda: _importer(target) |
3033 | +- return getter, attribute |
3034 | +- |
3035 | +- |
3036 | +-def _patch_object( |
3037 | +- target, attribute, new=DEFAULT, spec=None, |
3038 | +- create=False, spec_set=None, autospec=None, |
3039 | +- new_callable=None, **kwargs |
3040 | +- ): |
3041 | +- """ |
3042 | +- patch.object(target, attribute, new=DEFAULT, spec=None, create=False, |
3043 | +- spec_set=None, autospec=None, new_callable=None, **kwargs) |
3044 | +- |
3045 | +- patch the named member (`attribute`) on an object (`target`) with a mock |
3046 | +- object. |
3047 | +- |
3048 | +- `patch.object` can be used as a decorator, class decorator or a context |
3049 | +- manager. Arguments `new`, `spec`, `create`, `spec_set`, |
3050 | +- `autospec` and `new_callable` have the same meaning as for `patch`. Like |
3051 | +- `patch`, `patch.object` takes arbitrary keyword arguments for configuring |
3052 | +- the mock object it creates. |
3053 | +- |
3054 | +- When used as a class decorator `patch.object` honours `patch.TEST_PREFIX` |
3055 | +- for choosing which methods to wrap. |
3056 | +- """ |
3057 | +- getter = lambda: target |
3058 | +- return _patch( |
3059 | +- getter, attribute, new, spec, create, |
3060 | +- spec_set, autospec, new_callable, kwargs |
3061 | +- ) |
3062 | +- |
3063 | +- |
3064 | +-def _patch_multiple(target, spec=None, create=False, spec_set=None, |
3065 | +- autospec=None, new_callable=None, **kwargs): |
3066 | +- """Perform multiple patches in a single call. It takes the object to be |
3067 | +- patched (either as an object or a string to fetch the object by importing) |
3068 | +- and keyword arguments for the patches:: |
3069 | +- |
3070 | +- with patch.multiple(settings, FIRST_PATCH='one', SECOND_PATCH='two'): |
3071 | +- ... |
3072 | +- |
3073 | +- Use `DEFAULT` as the value if you want `patch.multiple` to create |
3074 | +- mocks for you. In this case the created mocks are passed into a decorated |
3075 | +- function by keyword, and a dictionary is returned when `patch.multiple` is |
3076 | +- used as a context manager. |
3077 | +- |
3078 | +- `patch.multiple` can be used as a decorator, class decorator or a context |
3079 | +- manager. The arguments `spec`, `spec_set`, `create`, |
3080 | +- `autospec` and `new_callable` have the same meaning as for `patch`. These |
3081 | +- arguments will be applied to *all* patches done by `patch.multiple`. |
3082 | +- |
3083 | +- When used as a class decorator `patch.multiple` honours `patch.TEST_PREFIX` |
3084 | +- for choosing which methods to wrap. |
3085 | +- """ |
3086 | +- if type(target) in (unicode, str): |
3087 | +- getter = lambda: _importer(target) |
3088 | +- else: |
3089 | +- getter = lambda: target |
3090 | +- |
3091 | +- if not kwargs: |
3092 | +- raise ValueError( |
3093 | +- 'Must supply at least one keyword argument with patch.multiple' |
3094 | +- ) |
3095 | +- # need to wrap in a list for python 3, where items is a view |
3096 | +- items = list(kwargs.items()) |
3097 | +- attribute, new = items[0] |
3098 | +- patcher = _patch( |
3099 | +- getter, attribute, new, spec, create, spec_set, |
3100 | +- autospec, new_callable, {} |
3101 | +- ) |
3102 | +- patcher.attribute_name = attribute |
3103 | +- for attribute, new in items[1:]: |
3104 | +- this_patcher = _patch( |
3105 | +- getter, attribute, new, spec, create, spec_set, |
3106 | +- autospec, new_callable, {} |
3107 | +- ) |
3108 | +- this_patcher.attribute_name = attribute |
3109 | +- patcher.additional_patchers.append(this_patcher) |
3110 | +- return patcher |
3111 | +- |
3112 | +- |
3113 | +-def patch( |
3114 | +- target, new=DEFAULT, spec=None, create=False, |
3115 | +- spec_set=None, autospec=None, new_callable=None, **kwargs |
3116 | +- ): |
3117 | +- """ |
3118 | +- `patch` acts as a function decorator, class decorator or a context |
3119 | +- manager. Inside the body of the function or with statement, the `target` |
3120 | +- is patched with a `new` object. When the function/with statement exits |
3121 | +- the patch is undone. |
3122 | +- |
3123 | +- If `new` is omitted, then the target is replaced with a |
3124 | +- `MagicMock`. If `patch` is used as a decorator and `new` is |
3125 | +- omitted, the created mock is passed in as an extra argument to the |
3126 | +- decorated function. If `patch` is used as a context manager the created |
3127 | +- mock is returned by the context manager. |
3128 | +- |
3129 | +- `target` should be a string in the form `'package.module.ClassName'`. The |
3130 | +- `target` is imported and the specified object replaced with the `new` |
3131 | +- object, so the `target` must be importable from the environment you are |
3132 | +- calling `patch` from. The target is imported when the decorated function |
3133 | +- is executed, not at decoration time. |
3134 | +- |
3135 | +- The `spec` and `spec_set` keyword arguments are passed to the `MagicMock` |
3136 | +- if patch is creating one for you. |
3137 | +- |
3138 | +- In addition you can pass `spec=True` or `spec_set=True`, which causes |
3139 | +- patch to pass in the object being mocked as the spec/spec_set object. |
3140 | +- |
3141 | +- `new_callable` allows you to specify a different class, or callable object, |
3142 | +- that will be called to create the `new` object. By default `MagicMock` is |
3143 | +- used. |
3144 | +- |
3145 | +- A more powerful form of `spec` is `autospec`. If you set `autospec=True` |
3146 | +- then the mock with be created with a spec from the object being replaced. |
3147 | +- All attributes of the mock will also have the spec of the corresponding |
3148 | +- attribute of the object being replaced. Methods and functions being |
3149 | +- mocked will have their arguments checked and will raise a `TypeError` if |
3150 | +- they are called with the wrong signature. For mocks replacing a class, |
3151 | +- their return value (the 'instance') will have the same spec as the class. |
3152 | +- |
3153 | +- Instead of `autospec=True` you can pass `autospec=some_object` to use an |
3154 | +- arbitrary object as the spec instead of the one being replaced. |
3155 | +- |
3156 | +- By default `patch` will fail to replace attributes that don't exist. If |
3157 | +- you pass in `create=True`, and the attribute doesn't exist, patch will |
3158 | +- create the attribute for you when the patched function is called, and |
3159 | +- delete it again afterwards. This is useful for writing tests against |
3160 | +- attributes that your production code creates at runtime. It is off by by |
3161 | +- default because it can be dangerous. With it switched on you can write |
3162 | +- passing tests against APIs that don't actually exist! |
3163 | +- |
3164 | +- Patch can be used as a `TestCase` class decorator. It works by |
3165 | +- decorating each test method in the class. This reduces the boilerplate |
3166 | +- code when your test methods share a common patchings set. `patch` finds |
3167 | +- tests by looking for method names that start with `patch.TEST_PREFIX`. |
3168 | +- By default this is `test`, which matches the way `unittest` finds tests. |
3169 | +- You can specify an alternative prefix by setting `patch.TEST_PREFIX`. |
3170 | +- |
3171 | +- Patch can be used as a context manager, with the with statement. Here the |
3172 | +- patching applies to the indented block after the with statement. If you |
3173 | +- use "as" then the patched object will be bound to the name after the |
3174 | +- "as"; very useful if `patch` is creating a mock object for you. |
3175 | +- |
3176 | +- `patch` takes arbitrary keyword arguments. These will be passed to |
3177 | +- the `Mock` (or `new_callable`) on construction. |
3178 | +- |
3179 | +- `patch.dict(...)`, `patch.multiple(...)` and `patch.object(...)` are |
3180 | +- available for alternate use-cases. |
3181 | +- """ |
3182 | +- getter, attribute = _get_target(target) |
3183 | +- return _patch( |
3184 | +- getter, attribute, new, spec, create, |
3185 | +- spec_set, autospec, new_callable, kwargs |
3186 | +- ) |
3187 | +- |
3188 | +- |
3189 | +-class _patch_dict(object): |
3190 | +- """ |
3191 | +- Patch a dictionary, or dictionary like object, and restore the dictionary |
3192 | +- to its original state after the test. |
3193 | +- |
3194 | +- `in_dict` can be a dictionary or a mapping like container. If it is a |
3195 | +- mapping then it must at least support getting, setting and deleting items |
3196 | +- plus iterating over keys. |
3197 | +- |
3198 | +- `in_dict` can also be a string specifying the name of the dictionary, which |
3199 | +- will then be fetched by importing it. |
3200 | +- |
3201 | +- `values` can be a dictionary of values to set in the dictionary. `values` |
3202 | +- can also be an iterable of `(key, value)` pairs. |
3203 | +- |
3204 | +- If `clear` is True then the dictionary will be cleared before the new |
3205 | +- values are set. |
3206 | +- |
3207 | +- `patch.dict` can also be called with arbitrary keyword arguments to set |
3208 | +- values in the dictionary:: |
3209 | +- |
3210 | +- with patch.dict('sys.modules', mymodule=Mock(), other_module=Mock()): |
3211 | +- ... |
3212 | +- |
3213 | +- `patch.dict` can be used as a context manager, decorator or class |
3214 | +- decorator. When used as a class decorator `patch.dict` honours |
3215 | +- `patch.TEST_PREFIX` for choosing which methods to wrap. |
3216 | +- """ |
3217 | +- |
3218 | +- def __init__(self, in_dict, values=(), clear=False, **kwargs): |
3219 | +- if isinstance(in_dict, basestring): |
3220 | +- in_dict = _importer(in_dict) |
3221 | +- self.in_dict = in_dict |
3222 | +- # support any argument supported by dict(...) constructor |
3223 | +- self.values = dict(values) |
3224 | +- self.values.update(kwargs) |
3225 | +- self.clear = clear |
3226 | +- self._original = None |
3227 | +- |
3228 | +- |
3229 | +- def __call__(self, f): |
3230 | +- if isinstance(f, ClassTypes): |
3231 | +- return self.decorate_class(f) |
3232 | +- @wraps(f) |
3233 | +- def _inner(*args, **kw): |
3234 | +- self._patch_dict() |
3235 | +- try: |
3236 | +- return f(*args, **kw) |
3237 | +- finally: |
3238 | +- self._unpatch_dict() |
3239 | +- |
3240 | +- return _inner |
3241 | +- |
3242 | +- |
3243 | +- def decorate_class(self, klass): |
3244 | +- for attr in dir(klass): |
3245 | +- attr_value = getattr(klass, attr) |
3246 | +- if (attr.startswith(patch.TEST_PREFIX) and |
3247 | +- hasattr(attr_value, "__call__")): |
3248 | +- decorator = _patch_dict(self.in_dict, self.values, self.clear) |
3249 | +- decorated = decorator(attr_value) |
3250 | +- setattr(klass, attr, decorated) |
3251 | +- return klass |
3252 | +- |
3253 | +- |
3254 | +- def __enter__(self): |
3255 | +- """Patch the dict.""" |
3256 | +- self._patch_dict() |
3257 | +- |
3258 | +- |
3259 | +- def _patch_dict(self): |
3260 | +- values = self.values |
3261 | +- in_dict = self.in_dict |
3262 | +- clear = self.clear |
3263 | +- |
3264 | +- try: |
3265 | +- original = in_dict.copy() |
3266 | +- except AttributeError: |
3267 | +- # dict like object with no copy method |
3268 | +- # must support iteration over keys |
3269 | +- original = {} |
3270 | +- for key in in_dict: |
3271 | +- original[key] = in_dict[key] |
3272 | +- self._original = original |
3273 | +- |
3274 | +- if clear: |
3275 | +- _clear_dict(in_dict) |
3276 | +- |
3277 | +- try: |
3278 | +- in_dict.update(values) |
3279 | +- except AttributeError: |
3280 | +- # dict like object with no update method |
3281 | +- for key in values: |
3282 | +- in_dict[key] = values[key] |
3283 | +- |
3284 | +- |
3285 | +- def _unpatch_dict(self): |
3286 | +- in_dict = self.in_dict |
3287 | +- original = self._original |
3288 | +- |
3289 | +- _clear_dict(in_dict) |
3290 | +- |
3291 | +- try: |
3292 | +- in_dict.update(original) |
3293 | +- except AttributeError: |
3294 | +- for key in original: |
3295 | +- in_dict[key] = original[key] |
3296 | +- |
3297 | +- |
3298 | +- def __exit__(self, *args): |
3299 | +- """Unpatch the dict.""" |
3300 | +- self._unpatch_dict() |
3301 | +- return False |
3302 | +- |
3303 | +- start = __enter__ |
3304 | +- stop = __exit__ |
3305 | +- |
3306 | +- |
3307 | +-def _clear_dict(in_dict): |
3308 | +- try: |
3309 | +- in_dict.clear() |
3310 | +- except AttributeError: |
3311 | +- keys = list(in_dict) |
3312 | +- for key in keys: |
3313 | +- del in_dict[key] |
3314 | +- |
3315 | +- |
3316 | +-def _patch_stopall(): |
3317 | +- """Stop all active patches.""" |
3318 | +- for patch in list(_patch._active_patches): |
3319 | +- patch.stop() |
3320 | +- |
3321 | +- |
3322 | +-patch.object = _patch_object |
3323 | +-patch.dict = _patch_dict |
3324 | +-patch.multiple = _patch_multiple |
3325 | +-patch.stopall = _patch_stopall |
3326 | +-patch.TEST_PREFIX = 'test' |
3327 | +- |
3328 | +-magic_methods = ( |
3329 | +- "lt le gt ge eq ne " |
3330 | +- "getitem setitem delitem " |
3331 | +- "len contains iter " |
3332 | +- "hash str sizeof " |
3333 | +- "enter exit " |
3334 | +- "divmod neg pos abs invert " |
3335 | +- "complex int float index " |
3336 | +- "trunc floor ceil " |
3337 | +-) |
3338 | +- |
3339 | +-numerics = "add sub mul div floordiv mod lshift rshift and xor or pow " |
3340 | +-inplace = ' '.join('i%s' % n for n in numerics.split()) |
3341 | +-right = ' '.join('r%s' % n for n in numerics.split()) |
3342 | +-extra = '' |
3343 | +-if inPy3k: |
3344 | +- extra = 'bool next ' |
3345 | +-else: |
3346 | +- extra = 'unicode long nonzero oct hex truediv rtruediv ' |
3347 | +- |
3348 | +-# not including __prepare__, __instancecheck__, __subclasscheck__ |
3349 | +-# (as they are metaclass methods) |
3350 | +-# __del__ is not supported at all as it causes problems if it exists |
3351 | +- |
3352 | +-_non_defaults = set('__%s__' % method for method in [ |
3353 | +- 'cmp', 'getslice', 'setslice', 'coerce', 'subclasses', |
3354 | +- 'format', 'get', 'set', 'delete', 'reversed', |
3355 | +- 'missing', 'reduce', 'reduce_ex', 'getinitargs', |
3356 | +- 'getnewargs', 'getstate', 'setstate', 'getformat', |
3357 | +- 'setformat', 'repr', 'dir' |
3358 | +-]) |
3359 | +- |
3360 | +- |
3361 | +-def _get_method(name, func): |
3362 | +- "Turns a callable object (like a mock) into a real function" |
3363 | +- def method(self, *args, **kw): |
3364 | +- return func(self, *args, **kw) |
3365 | +- method.__name__ = name |
3366 | +- return method |
3367 | +- |
3368 | +- |
3369 | +-_magics = set( |
3370 | +- '__%s__' % method for method in |
3371 | +- ' '.join([magic_methods, numerics, inplace, right, extra]).split() |
3372 | +-) |
3373 | +- |
3374 | +-_all_magics = _magics | _non_defaults |
3375 | +- |
3376 | +-_unsupported_magics = set([ |
3377 | +- '__getattr__', '__setattr__', |
3378 | +- '__init__', '__new__', '__prepare__' |
3379 | +- '__instancecheck__', '__subclasscheck__', |
3380 | +- '__del__' |
3381 | +-]) |
3382 | +- |
3383 | +-_calculate_return_value = { |
3384 | +- '__hash__': lambda self: object.__hash__(self), |
3385 | +- '__str__': lambda self: object.__str__(self), |
3386 | +- '__sizeof__': lambda self: object.__sizeof__(self), |
3387 | +- '__unicode__': lambda self: unicode(object.__str__(self)), |
3388 | +-} |
3389 | +- |
3390 | +-_return_values = { |
3391 | +- '__lt__': NotImplemented, |
3392 | +- '__gt__': NotImplemented, |
3393 | +- '__le__': NotImplemented, |
3394 | +- '__ge__': NotImplemented, |
3395 | +- '__int__': 1, |
3396 | +- '__contains__': False, |
3397 | +- '__len__': 0, |
3398 | +- '__exit__': False, |
3399 | +- '__complex__': 1j, |
3400 | +- '__float__': 1.0, |
3401 | +- '__bool__': True, |
3402 | +- '__nonzero__': True, |
3403 | +- '__oct__': '1', |
3404 | +- '__hex__': '0x1', |
3405 | +- '__long__': long(1), |
3406 | +- '__index__': 1, |
3407 | +-} |
3408 | +- |
3409 | +- |
3410 | +-def _get_eq(self): |
3411 | +- def __eq__(other): |
3412 | +- ret_val = self.__eq__._mock_return_value |
3413 | +- if ret_val is not DEFAULT: |
3414 | +- return ret_val |
3415 | +- return self is other |
3416 | +- return __eq__ |
3417 | +- |
3418 | +-def _get_ne(self): |
3419 | +- def __ne__(other): |
3420 | +- if self.__ne__._mock_return_value is not DEFAULT: |
3421 | +- return DEFAULT |
3422 | +- return self is not other |
3423 | +- return __ne__ |
3424 | +- |
3425 | +-def _get_iter(self): |
3426 | +- def __iter__(): |
3427 | +- ret_val = self.__iter__._mock_return_value |
3428 | +- if ret_val is DEFAULT: |
3429 | +- return iter([]) |
3430 | +- # if ret_val was already an iterator, then calling iter on it should |
3431 | +- # return the iterator unchanged |
3432 | +- return iter(ret_val) |
3433 | +- return __iter__ |
3434 | +- |
3435 | +-_side_effect_methods = { |
3436 | +- '__eq__': _get_eq, |
3437 | +- '__ne__': _get_ne, |
3438 | +- '__iter__': _get_iter, |
3439 | +-} |
3440 | +- |
3441 | +- |
3442 | +- |
3443 | +-def _set_return_value(mock, method, name): |
3444 | +- fixed = _return_values.get(name, DEFAULT) |
3445 | +- if fixed is not DEFAULT: |
3446 | +- method.return_value = fixed |
3447 | +- return |
3448 | +- |
3449 | +- return_calulator = _calculate_return_value.get(name) |
3450 | +- if return_calulator is not None: |
3451 | +- try: |
3452 | +- return_value = return_calulator(mock) |
3453 | +- except AttributeError: |
3454 | +- # XXXX why do we return AttributeError here? |
3455 | +- # set it as a side_effect instead? |
3456 | +- return_value = AttributeError(name) |
3457 | +- method.return_value = return_value |
3458 | +- return |
3459 | +- |
3460 | +- side_effector = _side_effect_methods.get(name) |
3461 | +- if side_effector is not None: |
3462 | +- method.side_effect = side_effector(mock) |
3463 | +- |
3464 | +- |
3465 | +- |
3466 | +-class MagicMixin(object): |
3467 | +- def __init__(self, *args, **kw): |
3468 | +- _super(MagicMixin, self).__init__(*args, **kw) |
3469 | +- self._mock_set_magics() |
3470 | +- |
3471 | +- |
3472 | +- def _mock_set_magics(self): |
3473 | +- these_magics = _magics |
3474 | +- |
3475 | +- if self._mock_methods is not None: |
3476 | +- these_magics = _magics.intersection(self._mock_methods) |
3477 | +- |
3478 | +- remove_magics = set() |
3479 | +- remove_magics = _magics - these_magics |
3480 | +- |
3481 | +- for entry in remove_magics: |
3482 | +- if entry in type(self).__dict__: |
3483 | +- # remove unneeded magic methods |
3484 | +- delattr(self, entry) |
3485 | +- |
3486 | +- # don't overwrite existing attributes if called a second time |
3487 | +- these_magics = these_magics - set(type(self).__dict__) |
3488 | +- |
3489 | +- _type = type(self) |
3490 | +- for entry in these_magics: |
3491 | +- setattr(_type, entry, MagicProxy(entry, self)) |
3492 | +- |
3493 | +- |
3494 | +- |
3495 | +-class NonCallableMagicMock(MagicMixin, NonCallableMock): |
3496 | +- """A version of `MagicMock` that isn't callable.""" |
3497 | +- def mock_add_spec(self, spec, spec_set=False): |
3498 | +- """Add a spec to a mock. `spec` can either be an object or a |
3499 | +- list of strings. Only attributes on the `spec` can be fetched as |
3500 | +- attributes from the mock. |
3501 | +- |
3502 | +- If `spec_set` is True then only attributes on the spec can be set.""" |
3503 | +- self._mock_add_spec(spec, spec_set) |
3504 | +- self._mock_set_magics() |
3505 | +- |
3506 | +- |
3507 | +- |
3508 | +-class MagicMock(MagicMixin, Mock): |
3509 | +- """ |
3510 | +- MagicMock is a subclass of Mock with default implementations |
3511 | +- of most of the magic methods. You can use MagicMock without having to |
3512 | +- configure the magic methods yourself. |
3513 | +- |
3514 | +- If you use the `spec` or `spec_set` arguments then *only* magic |
3515 | +- methods that exist in the spec will be created. |
3516 | +- |
3517 | +- Attributes and the return value of a `MagicMock` will also be `MagicMocks`. |
3518 | +- """ |
3519 | +- def mock_add_spec(self, spec, spec_set=False): |
3520 | +- """Add a spec to a mock. `spec` can either be an object or a |
3521 | +- list of strings. Only attributes on the `spec` can be fetched as |
3522 | +- attributes from the mock. |
3523 | +- |
3524 | +- If `spec_set` is True then only attributes on the spec can be set.""" |
3525 | +- self._mock_add_spec(spec, spec_set) |
3526 | +- self._mock_set_magics() |
3527 | +- |
3528 | +- |
3529 | +- |
3530 | +-class MagicProxy(object): |
3531 | +- def __init__(self, name, parent): |
3532 | +- self.name = name |
3533 | +- self.parent = parent |
3534 | +- |
3535 | +- def __call__(self, *args, **kwargs): |
3536 | +- m = self.create_mock() |
3537 | +- return m(*args, **kwargs) |
3538 | +- |
3539 | +- def create_mock(self): |
3540 | +- entry = self.name |
3541 | +- parent = self.parent |
3542 | +- m = parent._get_child_mock(name=entry, _new_name=entry, |
3543 | +- _new_parent=parent) |
3544 | +- setattr(parent, entry, m) |
3545 | +- _set_return_value(parent, m, entry) |
3546 | +- return m |
3547 | +- |
3548 | +- def __get__(self, obj, _type=None): |
3549 | +- return self.create_mock() |
3550 | +- |
3551 | +- |
3552 | +- |
3553 | +-class _ANY(object): |
3554 | +- "A helper object that compares equal to everything." |
3555 | +- |
3556 | +- def __eq__(self, other): |
3557 | +- return True |
3558 | +- |
3559 | +- def __ne__(self, other): |
3560 | +- return False |
3561 | +- |
3562 | +- def __repr__(self): |
3563 | +- return '<ANY>' |
3564 | +- |
3565 | +-ANY = _ANY() |
3566 | +- |
3567 | +- |
3568 | +- |
3569 | +-def _format_call_signature(name, args, kwargs): |
3570 | +- message = '%s(%%s)' % name |
3571 | +- formatted_args = '' |
3572 | +- args_string = ', '.join([repr(arg) for arg in args]) |
3573 | +- kwargs_string = ', '.join([ |
3574 | +- '%s=%r' % (key, value) for key, value in kwargs.items() |
3575 | +- ]) |
3576 | +- if args_string: |
3577 | +- formatted_args = args_string |
3578 | +- if kwargs_string: |
3579 | +- if formatted_args: |
3580 | +- formatted_args += ', ' |
3581 | +- formatted_args += kwargs_string |
3582 | +- |
3583 | +- return message % formatted_args |
3584 | +- |
3585 | +- |
3586 | +- |
3587 | +-class _Call(tuple): |
3588 | +- """ |
3589 | +- A tuple for holding the results of a call to a mock, either in the form |
3590 | +- `(args, kwargs)` or `(name, args, kwargs)`. |
3591 | +- |
3592 | +- If args or kwargs are empty then a call tuple will compare equal to |
3593 | +- a tuple without those values. This makes comparisons less verbose:: |
3594 | +- |
3595 | +- _Call(('name', (), {})) == ('name',) |
3596 | +- _Call(('name', (1,), {})) == ('name', (1,)) |
3597 | +- _Call(((), {'a': 'b'})) == ({'a': 'b'},) |
3598 | +- |
3599 | +- The `_Call` object provides a useful shortcut for comparing with call:: |
3600 | +- |
3601 | +- _Call(((1, 2), {'a': 3})) == call(1, 2, a=3) |
3602 | +- _Call(('foo', (1, 2), {'a': 3})) == call.foo(1, 2, a=3) |
3603 | +- |
3604 | +- If the _Call has no name then it will match any name. |
3605 | +- """ |
3606 | +- def __new__(cls, value=(), name=None, parent=None, two=False, |
3607 | +- from_kall=True): |
3608 | +- name = '' |
3609 | +- args = () |
3610 | +- kwargs = {} |
3611 | +- _len = len(value) |
3612 | +- if _len == 3: |
3613 | +- name, args, kwargs = value |
3614 | +- elif _len == 2: |
3615 | +- first, second = value |
3616 | +- if isinstance(first, basestring): |
3617 | +- name = first |
3618 | +- if isinstance(second, tuple): |
3619 | +- args = second |
3620 | +- else: |
3621 | +- kwargs = second |
3622 | +- else: |
3623 | +- args, kwargs = first, second |
3624 | +- elif _len == 1: |
3625 | +- value, = value |
3626 | +- if isinstance(value, basestring): |
3627 | +- name = value |
3628 | +- elif isinstance(value, tuple): |
3629 | +- args = value |
3630 | +- else: |
3631 | +- kwargs = value |
3632 | +- |
3633 | +- if two: |
3634 | +- return tuple.__new__(cls, (args, kwargs)) |
3635 | +- |
3636 | +- return tuple.__new__(cls, (name, args, kwargs)) |
3637 | +- |
3638 | +- |
3639 | +- def __init__(self, value=(), name=None, parent=None, two=False, |
3640 | +- from_kall=True): |
3641 | +- self.name = name |
3642 | +- self.parent = parent |
3643 | +- self.from_kall = from_kall |
3644 | +- |
3645 | +- |
3646 | +- def __eq__(self, other): |
3647 | +- if other is ANY: |
3648 | +- return True |
3649 | +- try: |
3650 | +- len_other = len(other) |
3651 | +- except TypeError: |
3652 | +- return False |
3653 | +- |
3654 | +- self_name = '' |
3655 | +- if len(self) == 2: |
3656 | +- self_args, self_kwargs = self |
3657 | +- else: |
3658 | +- self_name, self_args, self_kwargs = self |
3659 | +- |
3660 | +- other_name = '' |
3661 | +- if len_other == 0: |
3662 | +- other_args, other_kwargs = (), {} |
3663 | +- elif len_other == 3: |
3664 | +- other_name, other_args, other_kwargs = other |
3665 | +- elif len_other == 1: |
3666 | +- value, = other |
3667 | +- if isinstance(value, tuple): |
3668 | +- other_args = value |
3669 | +- other_kwargs = {} |
3670 | +- elif isinstance(value, basestring): |
3671 | +- other_name = value |
3672 | +- other_args, other_kwargs = (), {} |
3673 | +- else: |
3674 | +- other_args = () |
3675 | +- other_kwargs = value |
3676 | +- else: |
3677 | +- # len 2 |
3678 | +- # could be (name, args) or (name, kwargs) or (args, kwargs) |
3679 | +- first, second = other |
3680 | +- if isinstance(first, basestring): |
3681 | +- other_name = first |
3682 | +- if isinstance(second, tuple): |
3683 | +- other_args, other_kwargs = second, {} |
3684 | +- else: |
3685 | +- other_args, other_kwargs = (), second |
3686 | +- else: |
3687 | +- other_args, other_kwargs = first, second |
3688 | +- |
3689 | +- if self_name and other_name != self_name: |
3690 | +- return False |
3691 | +- |
3692 | +- # this order is important for ANY to work! |
3693 | +- return (other_args, other_kwargs) == (self_args, self_kwargs) |
3694 | +- |
3695 | +- |
3696 | +- def __ne__(self, other): |
3697 | +- return not self.__eq__(other) |
3698 | +- |
3699 | +- |
3700 | +- def __call__(self, *args, **kwargs): |
3701 | +- if self.name is None: |
3702 | +- return _Call(('', args, kwargs), name='()') |
3703 | +- |
3704 | +- name = self.name + '()' |
3705 | +- return _Call((self.name, args, kwargs), name=name, parent=self) |
3706 | +- |
3707 | +- |
3708 | +- def __getattr__(self, attr): |
3709 | +- if self.name is None: |
3710 | +- return _Call(name=attr, from_kall=False) |
3711 | +- name = '%s.%s' % (self.name, attr) |
3712 | +- return _Call(name=name, parent=self, from_kall=False) |
3713 | +- |
3714 | +- |
3715 | +- def __repr__(self): |
3716 | +- if not self.from_kall: |
3717 | +- name = self.name or 'call' |
3718 | +- if name.startswith('()'): |
3719 | +- name = 'call%s' % name |
3720 | +- return name |
3721 | +- |
3722 | +- if len(self) == 2: |
3723 | +- name = 'call' |
3724 | +- args, kwargs = self |
3725 | +- else: |
3726 | +- name, args, kwargs = self |
3727 | +- if not name: |
3728 | +- name = 'call' |
3729 | +- elif not name.startswith('()'): |
3730 | +- name = 'call.%s' % name |
3731 | +- else: |
3732 | +- name = 'call%s' % name |
3733 | +- return _format_call_signature(name, args, kwargs) |
3734 | +- |
3735 | +- |
3736 | +- def call_list(self): |
3737 | +- """For a call object that represents multiple calls, `call_list` |
3738 | +- returns a list of all the intermediate calls as well as the |
3739 | +- final call.""" |
3740 | +- vals = [] |
3741 | +- thing = self |
3742 | +- while thing is not None: |
3743 | +- if thing.from_kall: |
3744 | +- vals.append(thing) |
3745 | +- thing = thing.parent |
3746 | +- return _CallList(reversed(vals)) |
3747 | +- |
3748 | +- |
3749 | +-call = _Call(from_kall=False) |
3750 | +- |
3751 | +- |
3752 | +- |
3753 | +-def create_autospec(spec, spec_set=False, instance=False, _parent=None, |
3754 | +- _name=None, **kwargs): |
3755 | +- """Create a mock object using another object as a spec. Attributes on the |
3756 | +- mock will use the corresponding attribute on the `spec` object as their |
3757 | +- spec. |
3758 | +- |
3759 | +- Functions or methods being mocked will have their arguments checked |
3760 | +- to check that they are called with the correct signature. |
3761 | +- |
3762 | +- If `spec_set` is True then attempting to set attributes that don't exist |
3763 | +- on the spec object will raise an `AttributeError`. |
3764 | +- |
3765 | +- If a class is used as a spec then the return value of the mock (the |
3766 | +- instance of the class) will have the same spec. You can use a class as the |
3767 | +- spec for an instance object by passing `instance=True`. The returned mock |
3768 | +- will only be callable if instances of the mock are callable. |
3769 | +- |
3770 | +- `create_autospec` also takes arbitrary keyword arguments that are passed to |
3771 | +- the constructor of the created mock.""" |
3772 | +- if _is_list(spec): |
3773 | +- # can't pass a list instance to the mock constructor as it will be |
3774 | +- # interpreted as a list of strings |
3775 | +- spec = type(spec) |
3776 | +- |
3777 | +- is_type = isinstance(spec, ClassTypes) |
3778 | +- |
3779 | +- _kwargs = {'spec': spec} |
3780 | +- if spec_set: |
3781 | +- _kwargs = {'spec_set': spec} |
3782 | +- elif spec is None: |
3783 | +- # None we mock with a normal mock without a spec |
3784 | +- _kwargs = {} |
3785 | +- |
3786 | +- _kwargs.update(kwargs) |
3787 | +- |
3788 | +- Klass = MagicMock |
3789 | +- if type(spec) in DescriptorTypes: |
3790 | +- # descriptors don't have a spec |
3791 | +- # because we don't know what type they return |
3792 | +- _kwargs = {} |
3793 | +- elif not _callable(spec): |
3794 | +- Klass = NonCallableMagicMock |
3795 | +- elif is_type and instance and not _instance_callable(spec): |
3796 | +- Klass = NonCallableMagicMock |
3797 | +- |
3798 | +- _new_name = _name |
3799 | +- if _parent is None: |
3800 | +- # for a top level object no _new_name should be set |
3801 | +- _new_name = '' |
3802 | +- |
3803 | +- mock = Klass(parent=_parent, _new_parent=_parent, _new_name=_new_name, |
3804 | +- name=_name, **_kwargs) |
3805 | +- |
3806 | +- if isinstance(spec, FunctionTypes): |
3807 | +- # should only happen at the top level because we don't |
3808 | +- # recurse for functions |
3809 | +- mock = _set_signature(mock, spec) |
3810 | +- else: |
3811 | +- _check_signature(spec, mock, is_type, instance) |
3812 | +- |
3813 | +- if _parent is not None and not instance: |
3814 | +- _parent._mock_children[_name] = mock |
3815 | +- |
3816 | +- if is_type and not instance and 'return_value' not in kwargs: |
3817 | +- mock.return_value = create_autospec(spec, spec_set, instance=True, |
3818 | +- _name='()', _parent=mock) |
3819 | +- |
3820 | +- for entry in dir(spec): |
3821 | +- if _is_magic(entry): |
3822 | +- # MagicMock already does the useful magic methods for us |
3823 | +- continue |
3824 | +- |
3825 | +- if isinstance(spec, FunctionTypes) and entry in FunctionAttributes: |
3826 | +- # allow a mock to actually be a function |
3827 | +- continue |
3828 | +- |
3829 | +- # XXXX do we need a better way of getting attributes without |
3830 | +- # triggering code execution (?) Probably not - we need the actual |
3831 | +- # object to mock it so we would rather trigger a property than mock |
3832 | +- # the property descriptor. Likewise we want to mock out dynamically |
3833 | +- # provided attributes. |
3834 | +- # XXXX what about attributes that raise exceptions other than |
3835 | +- # AttributeError on being fetched? |
3836 | +- # we could be resilient against it, or catch and propagate the |
3837 | +- # exception when the attribute is fetched from the mock |
3838 | +- try: |
3839 | +- original = getattr(spec, entry) |
3840 | +- except AttributeError: |
3841 | +- continue |
3842 | +- |
3843 | +- kwargs = {'spec': original} |
3844 | +- if spec_set: |
3845 | +- kwargs = {'spec_set': original} |
3846 | +- |
3847 | +- if not isinstance(original, FunctionTypes): |
3848 | +- new = _SpecState(original, spec_set, mock, entry, instance) |
3849 | +- mock._mock_children[entry] = new |
3850 | +- else: |
3851 | +- parent = mock |
3852 | +- if isinstance(spec, FunctionTypes): |
3853 | +- parent = mock.mock |
3854 | +- |
3855 | +- new = MagicMock(parent=parent, name=entry, _new_name=entry, |
3856 | +- _new_parent=parent, **kwargs) |
3857 | +- mock._mock_children[entry] = new |
3858 | +- skipfirst = _must_skip(spec, entry, is_type) |
3859 | +- _check_signature(original, new, skipfirst=skipfirst) |
3860 | +- |
3861 | +- # so functions created with _set_signature become instance attributes, |
3862 | +- # *plus* their underlying mock exists in _mock_children of the parent |
3863 | +- # mock. Adding to _mock_children may be unnecessary where we are also |
3864 | +- # setting as an instance attribute? |
3865 | +- if isinstance(new, FunctionTypes): |
3866 | +- setattr(mock, entry, new) |
3867 | +- |
3868 | +- return mock |
3869 | +- |
3870 | +- |
3871 | +-def _must_skip(spec, entry, is_type): |
3872 | +- if not isinstance(spec, ClassTypes): |
3873 | +- if entry in getattr(spec, '__dict__', {}): |
3874 | +- # instance attribute - shouldn't skip |
3875 | +- return False |
3876 | +- spec = spec.__class__ |
3877 | +- if not hasattr(spec, '__mro__'): |
3878 | +- # old style class: can't have descriptors anyway |
3879 | +- return is_type |
3880 | +- |
3881 | +- for klass in spec.__mro__: |
3882 | +- result = klass.__dict__.get(entry, DEFAULT) |
3883 | +- if result is DEFAULT: |
3884 | +- continue |
3885 | +- if isinstance(result, (staticmethod, classmethod)): |
3886 | +- return False |
3887 | +- return is_type |
3888 | +- |
3889 | +- # shouldn't get here unless function is a dynamically provided attribute |
3890 | +- # XXXX untested behaviour |
3891 | +- return is_type |
3892 | +- |
3893 | +- |
3894 | +-def _get_class(obj): |
3895 | +- try: |
3896 | +- return obj.__class__ |
3897 | +- except AttributeError: |
3898 | +- # in Python 2, _sre.SRE_Pattern objects have no __class__ |
3899 | +- return type(obj) |
3900 | +- |
3901 | +- |
3902 | +-class _SpecState(object): |
3903 | +- |
3904 | +- def __init__(self, spec, spec_set=False, parent=None, |
3905 | +- name=None, ids=None, instance=False): |
3906 | +- self.spec = spec |
3907 | +- self.ids = ids |
3908 | +- self.spec_set = spec_set |
3909 | +- self.parent = parent |
3910 | +- self.instance = instance |
3911 | +- self.name = name |
3912 | +- |
3913 | +- |
3914 | +-FunctionTypes = ( |
3915 | +- # python function |
3916 | +- type(create_autospec), |
3917 | +- # instance method |
3918 | +- type(ANY.__eq__), |
3919 | +- # unbound method |
3920 | +- type(_ANY.__eq__), |
3921 | +-) |
3922 | +- |
3923 | +-FunctionAttributes = set([ |
3924 | +- 'func_closure', |
3925 | +- 'func_code', |
3926 | +- 'func_defaults', |
3927 | +- 'func_dict', |
3928 | +- 'func_doc', |
3929 | +- 'func_globals', |
3930 | +- 'func_name', |
3931 | +-]) |
3932 | +- |
3933 | +- |
3934 | +-file_spec = None |
3935 | +- |
3936 | +- |
3937 | +-def mock_open(mock=None, read_data=''): |
3938 | +- """ |
3939 | +- A helper function to create a mock to replace the use of `open`. It works |
3940 | +- for `open` called directly or used as a context manager. |
3941 | +- |
3942 | +- The `mock` argument is the mock object to configure. If `None` (the |
3943 | +- default) then a `MagicMock` will be created for you, with the API limited |
3944 | +- to methods or attributes available on standard file handles. |
3945 | +- |
3946 | +- `read_data` is a string for the `read` method of the file handle to return. |
3947 | +- This is an empty string by default. |
3948 | +- """ |
3949 | +- global file_spec |
3950 | +- if file_spec is None: |
3951 | +- # set on first use |
3952 | +- if inPy3k: |
3953 | +- import _io |
3954 | +- file_spec = list(set(dir(_io.TextIOWrapper)).union(set(dir(_io.BytesIO)))) |
3955 | +- else: |
3956 | +- file_spec = file |
3957 | +- |
3958 | +- if mock is None: |
3959 | +- mock = MagicMock(name='open', spec=open) |
3960 | +- |
3961 | +- handle = MagicMock(spec=file_spec) |
3962 | +- handle.write.return_value = None |
3963 | +- handle.__enter__.return_value = handle |
3964 | +- handle.read.return_value = read_data |
3965 | +- |
3966 | +- mock.return_value = handle |
3967 | +- return mock |
3968 | +- |
3969 | +- |
3970 | +-class PropertyMock(Mock): |
3971 | +- """ |
3972 | +- A mock intended to be used as a property, or other descriptor, on a class. |
3973 | +- `PropertyMock` provides `__get__` and `__set__` methods so you can specify |
3974 | +- a return value when it is fetched. |
3975 | +- |
3976 | +- Fetching a `PropertyMock` instance from an object calls the mock, with |
3977 | +- no args. Setting it calls the mock with the value being set. |
3978 | +- """ |
3979 | +- def _get_child_mock(self, **kwargs): |
3980 | +- return MagicMock(**kwargs) |
3981 | +- |
3982 | +- def __get__(self, obj, obj_type): |
3983 | +- return self() |
3984 | +- def __set__(self, obj, val): |
3985 | +- self(val) |
3986 | ++from unittest.mock import * |
3987 | |
3988 | === added file 'debian/plainbox-insecure-policy.install' |
3989 | --- debian/plainbox-insecure-policy.install 1970-01-01 00:00:00 +0000 |
3990 | +++ debian/plainbox-insecure-policy.install 2015-06-25 19:25:23 +0000 |
3991 | @@ -0,0 +1,1 @@ |
3992 | +plainbox/contrib/policykit_yes/org.freedesktop.policykit.pkexec.run-plainbox-job.policy usr/share/polkit-1/actions/ |
3993 | |
3994 | === added file 'debian/plainbox-secure-policy.install' |
3995 | --- debian/plainbox-secure-policy.install 1970-01-01 00:00:00 +0000 |
3996 | +++ debian/plainbox-secure-policy.install 2015-06-25 19:25:23 +0000 |
3997 | @@ -0,0 +1,1 @@ |
3998 | +plainbox/contrib/policykit_auth_admin_keep/org.freedesktop.policykit.pkexec.run-plainbox-job.policy usr/share/polkit-1/actions/ |
3999 | |
4000 | === added file 'debian/plainbox.install' |
4001 | --- debian/plainbox.install 1970-01-01 00:00:00 +0000 |
4002 | +++ debian/plainbox.install 2015-06-25 19:25:23 +0000 |
4003 | @@ -0,0 +1,1 @@ |
4004 | +usr/bin/plainbox |
4005 | |
4006 | === added file 'debian/plainbox.manpages' |
4007 | --- debian/plainbox.manpages 1970-01-01 00:00:00 +0000 |
4008 | +++ debian/plainbox.manpages 2015-06-25 19:25:23 +0000 |
4009 | @@ -0,0 +1,33 @@ |
4010 | +plainbox/build/sphinx/man/CHECKBOX_DATA.7 |
4011 | +plainbox/build/sphinx/man/CHECKBOX_SHARE.7 |
4012 | +plainbox/build/sphinx/man/PLAINBOX_PROVIDER_DATA.7 |
4013 | +plainbox/build/sphinx/man/PLAINBOX_SESSION_SHARE.7 |
4014 | +plainbox/build/sphinx/man/manage.py.1 |
4015 | +plainbox/build/sphinx/man/plainbox-category-units.7 |
4016 | +plainbox/build/sphinx/man/plainbox-check-config.1 |
4017 | +plainbox/build/sphinx/man/plainbox-dev-analyze.1 |
4018 | +plainbox/build/sphinx/man/plainbox-dev-crash.1 |
4019 | +plainbox/build/sphinx/man/plainbox-dev-list.1 |
4020 | +plainbox/build/sphinx/man/plainbox-dev-logtest.1 |
4021 | +plainbox/build/sphinx/man/plainbox-dev-parse.1 |
4022 | +plainbox/build/sphinx/man/plainbox-dev-script.1 |
4023 | +plainbox/build/sphinx/man/plainbox-dev-special.1 |
4024 | +plainbox/build/sphinx/man/plainbox-dev.1 |
4025 | +plainbox/build/sphinx/man/plainbox-device.1 |
4026 | +plainbox/build/sphinx/man/plainbox-file-units.7 |
4027 | +plainbox/build/sphinx/man/plainbox-job-units.7 |
4028 | +plainbox/build/sphinx/man/plainbox-packaging-meta-data-units.7 |
4029 | +plainbox/build/sphinx/man/plainbox-run.1 |
4030 | +plainbox/build/sphinx/man/plainbox-self-test.1 |
4031 | +plainbox/build/sphinx/man/plainbox-session-archive.1 |
4032 | +plainbox/build/sphinx/man/plainbox-session-export.1 |
4033 | +plainbox/build/sphinx/man/plainbox-session-list.1 |
4034 | +plainbox/build/sphinx/man/plainbox-session-remove.1 |
4035 | +plainbox/build/sphinx/man/plainbox-session-show.1 |
4036 | +plainbox/build/sphinx/man/plainbox-session-structure.7 |
4037 | +plainbox/build/sphinx/man/plainbox-session.1 |
4038 | +plainbox/build/sphinx/man/plainbox-startprovider.1 |
4039 | +plainbox/build/sphinx/man/plainbox-template-units.7 |
4040 | +plainbox/build/sphinx/man/plainbox-test-plan-units.7 |
4041 | +plainbox/build/sphinx/man/plainbox.1 |
4042 | +plainbox/build/sphinx/man/plainbox.conf.5 |
4043 | |
4044 | === added file 'debian/python3-plainbox-doc.doc-base' |
4045 | --- debian/python3-plainbox-doc.doc-base 1970-01-01 00:00:00 +0000 |
4046 | +++ debian/python3-plainbox-doc.doc-base 2015-06-25 19:25:23 +0000 |
4047 | @@ -0,0 +1,9 @@ |
4048 | +Document: plainbox |
4049 | +Title: Plainbox Manual |
4050 | +Author: Canonical Ltd. |
4051 | +Abstract: This manual describes what Plainbox is, and how it can be used. |
4052 | +Section: Programming/Python |
4053 | + |
4054 | +Format: HTML |
4055 | +Index: /usr/share/doc/python3-plainbox-doc/html/index.html |
4056 | +Files: /usr/share/doc/python3-plainbox-doc/html/*.html |
4057 | \ No newline at end of file |
4058 | |
4059 | === added file 'debian/python3-plainbox-doc.docs' |
4060 | --- debian/python3-plainbox-doc.docs 1970-01-01 00:00:00 +0000 |
4061 | +++ debian/python3-plainbox-doc.docs 2015-06-25 19:25:23 +0000 |
4062 | @@ -0,0 +1,1 @@ |
4063 | +plainbox/build/sphinx/html |
4064 | |
4065 | === added file 'debian/python3-plainbox.install' |
4066 | --- debian/python3-plainbox.install 1970-01-01 00:00:00 +0000 |
4067 | +++ debian/python3-plainbox.install 2015-06-25 19:25:23 +0000 |
4068 | @@ -0,0 +1,8 @@ |
4069 | +plainbox/build/mo/* usr/share/locale |
4070 | +plainbox/plainbox/impl/providers/categories/build/mo/* usr/share/locale |
4071 | +plainbox/plainbox/impl/providers/manifest/build/mo/* usr/share/locale |
4072 | +plainbox/plainbox/impl/providers/stubbox/build/mo/* usr/share/locale |
4073 | +usr/bin/plainbox-qml-shell |
4074 | +usr/bin/plainbox-trusted-launcher-1 |
4075 | +usr/lib/python3/dist-packages/plainbox-*.egg-info |
4076 | +usr/lib/python3/dist-packages/plainbox/ |
4077 | |
4078 | === added file 'debian/python3-plainbox.manpages' |
4079 | --- debian/python3-plainbox.manpages 1970-01-01 00:00:00 +0000 |
4080 | +++ debian/python3-plainbox.manpages 2015-06-25 19:25:23 +0000 |
4081 | @@ -0,0 +1,2 @@ |
4082 | +plainbox/build/sphinx/man/plainbox-trusted-launcher-1.1 |
4083 | +plainbox/build/sphinx/man/plainbox-qml-shell.1 |
4084 | \ No newline at end of file |
4085 | |
4086 | === added file 'debian/rules' |
4087 | --- debian/rules 1970-01-01 00:00:00 +0000 |
4088 | +++ debian/rules 2015-06-25 19:25:23 +0000 |
4089 | @@ -0,0 +1,42 @@ |
4090 | +#!/usr/bin/make -f |
4091 | +export NO_PNG_PKG_MANGLE=1 |
4092 | +export LANG= |
4093 | +export LANGUAGE= |
4094 | +export http_proxy=http://127.0.0.9:9 |
4095 | + |
4096 | +%: |
4097 | + dh $@ --with=python3,sphinxdoc --sourcedirectory=plainbox |
4098 | + |
4099 | +override_dh_auto_build: |
4100 | + set -e |
4101 | + cd plainbox && python3 setup.py build |
4102 | + # Build sphinx html documentation and man pages |
4103 | + cd plainbox && python3 setup.py build_sphinx -b html |
4104 | + cd plainbox && python3 setup.py build_sphinx -b man |
4105 | + # Build i18n catalogs for plainbox and bundled providers |
4106 | + ./support/build-i18n -d plainbox/po/ |
4107 | + ./support/build-i18n -d plainbox/plainbox/impl/providers/stubbox/po |
4108 | + ./support/build-i18n -d plainbox/plainbox/impl/providers/categories/po |
4109 | + ./support/build-i18n -d plainbox/plainbox/impl/providers/manifest/po |
4110 | + |
4111 | +override_dh_auto_test: |
4112 | + set -e |
4113 | + cd plainbox && python3 setup.py test --quiet |
4114 | + cd plainbox && PYTHONPATH=. ./plainbox/impl/providers/stubbox/manage.py validate |
4115 | + cd plainbox && PYTHONPATH=. ./plainbox/impl/providers/categories/manage.py validate |
4116 | + cd plainbox && PYTHONPATH=. ./plainbox/impl/providers/manifest/manage.py validate |
4117 | + |
4118 | +override_dh_auto_install: |
4119 | + set -e |
4120 | + cd plainbox && python3 setup.py install \ |
4121 | + --force --root=$(CURDIR)/debian/tmp \ |
4122 | + --no-compile -O0 --install-layout=deb |
4123 | + rm -rf $(CURDIR)/debian/tmp/usr/lib/python3/dist-packages/plainbox/vendor/argparse |
4124 | + |
4125 | +override_dh_auto_clean: |
4126 | + set -e |
4127 | + cd plainbox && python3 setup.py clean |
4128 | + rm -rf plainbox/build |
4129 | + rm -rf plainbox/plainbox/impl/providers/stubbox/build |
4130 | + rm -rf plainbox/plainbox/impl/providers/categories/build |
4131 | + rm -rf plainbox/plainbox/impl/providers/manifest/build |
4132 | |
4133 | === added directory 'debian/source' |
4134 | === added file 'debian/source/format' |
4135 | --- debian/source/format 1970-01-01 00:00:00 +0000 |
4136 | +++ debian/source/format 2015-06-25 19:25:23 +0000 |
4137 | @@ -0,0 +1,1 @@ |
4138 | +3.0 (native) |
4139 | |
4140 | === added file 'debian/source/options' |
4141 | --- debian/source/options 1970-01-01 00:00:00 +0000 |
4142 | +++ debian/source/options 2015-06-25 19:25:23 +0000 |
4143 | @@ -0,0 +1,1 @@ |
4144 | +extend-diff-ignore = ".*\.po$" |
4145 | |
4146 | === added directory 'debian/tests' |
4147 | === added file 'debian/tests/control' |
4148 | --- debian/tests/control 1970-01-01 00:00:00 +0000 |
4149 | +++ debian/tests/control 2015-06-25 19:25:23 +0000 |
4150 | @@ -0,0 +1,2 @@ |
4151 | +Tests: unit-tests |
4152 | +Depends: plainbox |
4153 | |
4154 | === added file 'debian/tests/unit-tests' |
4155 | --- debian/tests/unit-tests 1970-01-01 00:00:00 +0000 |
4156 | +++ debian/tests/unit-tests 2015-06-25 19:25:23 +0000 |
4157 | @@ -0,0 +1,10 @@ |
4158 | +#!/bin/sh |
4159 | +# autopkgtest check: run plainbox unit tests and ensure everything passes |
4160 | +# (C) 2013 Canonical Ltd. |
4161 | +# Author: Zygmunt Krynicki <zygmunt.krynicki@canonical.com> |
4162 | + |
4163 | +set -e |
4164 | + |
4165 | +cd $ADTTMP |
4166 | +plainbox self-test -u -v 2>&1 |
4167 | +echo "unit-tests: OK" |