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