Merge ~sylvain-pineau/plainbox/+git/packaging:fix-transition into plainbox:master

Proposed by Sylvain Pineau
Status: Superseded
Proposed branch: ~sylvain-pineau/plainbox/+git/packaging:fix-transition
Merge into: plainbox:master
Diff against target: 81883 lines (+77900/-0) (has conflicts)
172 files modified
MANIFEST.in (+10/-0)
PKG-INFO (+62/-0)
debian/.git-dpm (+8/-0)
debian/changelog (+257/-0)
debian/clean (+5/-0)
debian/compat (+1/-0)
debian/control (+106/-0)
debian/copyright (+207/-0)
debian/patches/documentation-theme (+42/-0)
debian/patches/series (+3/-0)
debian/patches/silence-logging-failure (+37/-0)
debian/patches/unvendorize (+2434/-0)
debian/plainbox.manpages (+32/-0)
debian/python3-plainbox-doc.doc-base (+9/-0)
debian/python3-plainbox-doc.docs (+1/-0)
debian/python3-plainbox.install (+2/-0)
debian/python3-plainbox.links (+2/-0)
debian/python3-plainbox.manpages (+2/-0)
debian/python3-plainbox.preinst (+44/-0)
debian/rules (+49/-0)
debian/source/format (+1/-0)
debian/source/options (+1/-0)
debian/tests/control (+2/-0)
debian/tests/unit-tests (+10/-0)
debian/watch (+3/-0)
docs/author/index.rst (+7/-0)
docs/author/intro.rst (+190/-0)
docs/author/provider-files.rst (+12/-0)
docs/author/provider-namespaces.rst (+14/-0)
docs/author/provider-template.rst (+44/-0)
docs/author/providers.rst (+4/-0)
docs/author/tutorial.rst (+177/-0)
docs/author/whitelists.rst (+120/-0)
docs/conf.py (+7/-0)
docs/dev/old.rst (+63/-0)
docs/dev/trusted-launcher.rst (+22/-0)
docs/glossary.rst (+17/-0)
docs/manpages/plainbox-dev-analyze.rst (+18/-0)
docs/manpages/plainbox-exporter-units.rst (+36/-0)
docs/manpages/plainbox-file-units.rst (+10/-0)
docs/manpages/plainbox-job-units.rst (+6/-0)
docs/manpages/plainbox-run.rst (+150/-0)
docs/manpages/plainbox-test-plan-units.rst (+12/-0)
docs/manpages/plainbox-trusted-launcher-1.rst (+10/-0)
docs/usage.rst (+43/-0)
plainbox.egg-info/PKG-INFO (+62/-0)
plainbox.egg-info/SOURCES.txt (+479/-0)
plainbox.egg-info/dependency_links.txt (+1/-0)
plainbox.egg-info/entry_points.txt (+38/-0)
plainbox.egg-info/requires.txt (+7/-0)
plainbox.egg-info/top_level.txt (+1/-0)
plainbox/__init__.py (+22/-0)
plainbox/__main__.py (+32/-0)
plainbox/_lazymod.py (+138/-0)
plainbox/abc.py (+36/-0)
plainbox/data/report/hardware-1_0.rng (+552/-0)
plainbox/impl/applogic.py (+26/-0)
plainbox/impl/buildsystems.py (+10/-0)
plainbox/impl/censoREd.py (+90/-0)
plainbox/impl/commands/__init__.py (+4/-0)
plainbox/impl/commands/cmd_analyze.py (+14/-0)
plainbox/impl/commands/cmd_checkbox.py (+12/-0)
plainbox/impl/commands/inv_analyze.py (+52/-0)
plainbox/impl/commands/inv_checkbox.py (+61/-0)
plainbox/impl/commands/inv_run.py (+25/-0)
plainbox/impl/commands/inv_special.py (+6/-0)
plainbox/impl/commands/test_run.py (+30/-0)
plainbox/impl/ctrl.py (+158/-0)
plainbox/impl/depmgr.py (+6/-0)
plainbox/impl/exporter/__init__.py (+18/-0)
plainbox/impl/exporter/jinja2.py (+25/-0)
plainbox/impl/exporter/rfc822.py (+48/-0)
plainbox/impl/exporter/tar.py (+15/-0)
plainbox/impl/exporter/test_hexr.py (+661/-0)
plainbox/impl/exporter/test_html.py (+20/-0)
plainbox/impl/exporter/test_init.py (+8/-0)
plainbox/impl/exporter/test_rfc822.py (+47/-0)
plainbox/impl/exporter/xlsx.py (+69/-0)
plainbox/impl/highlevel.py (+18/-0)
plainbox/impl/launcher.py (+106/-0)
plainbox/impl/logging.py (+14/-0)
plainbox/impl/providers/__init__.py (+21/-0)
plainbox/impl/providers/exporters/data/checkbox.html (+314/-0)
plainbox/impl/providers/exporters/data/checkbox.json (+16/-0)
plainbox/impl/providers/exporters/data/hexr.xml (+161/-0)
plainbox/impl/providers/exporters/data/junit.xml (+4/-0)
plainbox/impl/providers/exporters/units/exporter.pxu (+23/-0)
plainbox/impl/providers/stubbox/units/jobs/local.pxu (+9/-0)
plainbox/impl/providers/stubbox/units/jobs/multilevel.pxu (+25/-0)
plainbox/impl/providers/stubbox/units/jobs/representative.pxu (+12/-0)
plainbox/impl/providers/stubbox/units/jobs/stub.pxu (+27/-0)
plainbox/impl/providers/stubbox/whitelists/stub.whitelist (+23/-0)
plainbox/impl/providers/stubbox/whitelists/stub1.whitelist (+7/-0)
plainbox/impl/providers/stubbox/whitelists/stub2.whitelist (+7/-0)
plainbox/impl/result.py (+105/-0)
plainbox/impl/runner.py (+55/-0)
plainbox/impl/secure/config.py (+12/-0)
plainbox/impl/secure/launcher1.py (+18/-0)
plainbox/impl/secure/providers/__init__.py (+21/-0)
plainbox/impl/secure/providers/test_v1.py (+155/-0)
plainbox/impl/secure/providers/v1.py (+288/-0)
plainbox/impl/secure/qualifiers.py (+232/-0)
plainbox/impl/secure/test_config.py (+6/-0)
plainbox/impl/secure/test_launcher1.py (+53/-0)
plainbox/impl/secure/test_qualifiers.py (+243/-0)
plainbox/impl/session/assistant.py (+116/-0)
plainbox/impl/session/jobs.py (+7/-0)
plainbox/impl/session/manager.py (+72/-0)
plainbox/impl/session/state.py (+53/-0)
plainbox/impl/session/storage.py (+503/-0)
plainbox/impl/session/test_manager.py (+12/-0)
plainbox/impl/session/test_resume.py (+314/-0)
plainbox/impl/session/test_state.py (+100/-0)
plainbox/impl/session/test_storage.py (+93/-0)
plainbox/impl/session/test_suspend.py (+220/-0)
plainbox/impl/test_box.py (+103/-0)
plainbox/impl/test_censoREd.py (+25/-0)
plainbox/impl/test_ctrl.py (+181/-0)
plainbox/impl/test_launcher.py (+34/-0)
plainbox/impl/transport.py (+149/-0)
plainbox/impl/unit/concrete_validators.py (+8/-0)
plainbox/impl/unit/file.py (+4/-0)
plainbox/impl/unit/job.py (+36/-0)
plainbox/impl/unit/test_job.py (+27/-0)
plainbox/impl/unit/test_template.py (+3/-0)
plainbox/impl/unit/test_unit.py (+5/-0)
plainbox/impl/unit/testplan.py (+6/-0)
plainbox/impl/unit/unit.py (+35/-0)
plainbox/impl/xparsers.py (+119/-0)
plainbox/impl/xscanners.py (+4/-0)
plainbox/provider_manager.py (+54/-0)
plainbox/public.py (+47/-0)
plainbox/test-data/html-exporter/with_both_certification_status.html (+290/-0)
plainbox/test-data/html-exporter/with_certification_blocker.html (+262/-0)
plainbox/test-data/html-exporter/with_certification_non_blocker.html (+260/-0)
plainbox/test-data/html-exporter/without_certification_status.html (+243/-0)
plainbox/test-data/xml-exporter/example-data-certification-status.json (+19045/-0)
plainbox/test-data/xml-exporter/example-data.json (+19043/-0)
plainbox/test-data/xml-exporter/example-data.xml (+15754/-0)
plainbox/test-data/xml-exporter/test_dump_with_binary_attachment.json (+7/-0)
plainbox/test-data/xml-exporter/test_dump_with_binary_attachment.xml (+21/-0)
plainbox/test-data/xml-exporter/test_dump_with_comments.json (+13/-0)
plainbox/test-data/xml-exporter/test_dump_with_comments.xml (+30/-0)
plainbox/test-data/xml-exporter/test_dump_with_hardware_info.json (+10/-0)
plainbox/test-data/xml-exporter/test_dump_with_hardware_info.xml (+22/-0)
plainbox/test-data/xml-exporter/test_dump_with_io_log.json (+14/-0)
plainbox/test-data/xml-exporter/test_dump_with_io_log.xml (+30/-0)
plainbox/test-data/xml-exporter/test_dump_with_text_attachment.json (+7/-0)
plainbox/test-data/xml-exporter/test_dump_with_text_attachment.xml (+21/-0)
plainbox/test_provider_manager.py (+9/-0)
plainbox/test_public.py (+36/-0)
plainbox/vendor/__init__.py (+8/-0)
plainbox/vendor/argparse/py32-argparse.py (+2372/-0)
plainbox/vendor/argparse/py33-argparse.py (+2377/-0)
plainbox/vendor/argparse/py34-argparse.py (+2384/-0)
plainbox/vendor/enum.py (+676/-0)
plainbox/vendor/extcmd/glibc.py (+339/-0)
plainbox/vendor/funcsigs/__init__.py (+29/-0)
plainbox/vendor/glibc.py (+987/-0)
plainbox/vendor/mock.py (+32/-0)
plainbox/vendor/phablet.py (+599/-0)
plainbox/vendor/pyglibc/__init__.py (+45/-0)
plainbox/vendor/pyglibc/_abc.py (+42/-0)
plainbox/vendor/pyglibc/_pipe.py (+61/-0)
plainbox/vendor/pyglibc/_pthread_sigmask.py (+242/-0)
plainbox/vendor/pyglibc/_signalfd.py (+227/-0)
plainbox/vendor/pyglibc/_subreaper.py (+167/-0)
plainbox/vendor/pyglibc/select.py (+290/-0)
plainbox/vendor/pyglibc/selectors.py (+459/-0)
po/POTFILES.in (+39/-0)
setup.cfg (+12/-0)
setup.py (+26/-0)
Conflict in MANIFEST.in
Conflict in docs/author/index.rst
Conflict in docs/author/intro.rst
Conflict in docs/author/provider-files.rst
Conflict in docs/author/provider-namespaces.rst
Conflict in docs/author/provider-template.rst
Conflict in docs/author/providers.rst
Conflict in docs/conf.py
Conflict in docs/dev/old.rst
Conflict in docs/dev/trusted-launcher.rst
Conflict in docs/glossary.rst
Conflict in docs/manpages/plainbox-dev-analyze.rst
Conflict in docs/manpages/plainbox-exporter-units.rst
Conflict in docs/manpages/plainbox-file-units.rst
Conflict in docs/manpages/plainbox-job-units.rst
Conflict in docs/manpages/plainbox-run.rst
Conflict in docs/manpages/plainbox-test-plan-units.rst
Conflict in docs/manpages/plainbox-trusted-launcher-1.rst
Conflict in docs/usage.rst
Conflict in plainbox/__init__.py
Conflict in plainbox/abc.py
Conflict in plainbox/impl/applogic.py
Conflict in plainbox/impl/buildsystems.py
Conflict in plainbox/impl/commands/__init__.py
Conflict in plainbox/impl/commands/cmd_analyze.py
Conflict in plainbox/impl/commands/cmd_checkbox.py
Conflict in plainbox/impl/commands/inv_analyze.py
Conflict in plainbox/impl/commands/inv_checkbox.py
Conflict in plainbox/impl/commands/inv_run.py
Conflict in plainbox/impl/commands/inv_special.py
Conflict in plainbox/impl/commands/test_run.py
Conflict in plainbox/impl/ctrl.py
Conflict in plainbox/impl/depmgr.py
Conflict in plainbox/impl/exporter/__init__.py
Conflict in plainbox/impl/exporter/jinja2.py
Conflict in plainbox/impl/exporter/tar.py
Conflict in plainbox/impl/exporter/test_html.py
Conflict in plainbox/impl/exporter/test_init.py
Conflict in plainbox/impl/exporter/xlsx.py
Conflict in plainbox/impl/highlevel.py
Conflict in plainbox/impl/launcher.py
Conflict in plainbox/impl/logging.py
Conflict in plainbox/impl/providers/__init__.py
Conflict in plainbox/impl/providers/exporters/data/checkbox.html
Conflict in plainbox/impl/providers/exporters/data/checkbox.json
Conflict in plainbox/impl/providers/exporters/data/junit.xml
Conflict in plainbox/impl/providers/exporters/units/exporter.pxu
Conflict in plainbox/impl/providers/stubbox/units/jobs/representative.pxu
Conflict in plainbox/impl/providers/stubbox/units/jobs/stub.pxu
Conflict in plainbox/impl/result.py
Conflict in plainbox/impl/runner.py
Conflict in plainbox/impl/secure/config.py
Conflict in plainbox/impl/secure/launcher1.py
Conflict in plainbox/impl/secure/providers/__init__.py
Conflict in plainbox/impl/secure/providers/test_v1.py
Conflict in plainbox/impl/secure/providers/v1.py
Conflict in plainbox/impl/secure/qualifiers.py
Conflict in plainbox/impl/secure/test_config.py
Conflict in plainbox/impl/secure/test_launcher1.py
Conflict in plainbox/impl/secure/test_qualifiers.py
Conflict in plainbox/impl/session/assistant.py
Conflict in plainbox/impl/session/jobs.py
Conflict in plainbox/impl/session/manager.py
Conflict in plainbox/impl/session/state.py
Conflict in plainbox/impl/session/storage.py
Conflict in plainbox/impl/session/test_manager.py
Conflict in plainbox/impl/session/test_resume.py
Conflict in plainbox/impl/session/test_state.py
Conflict in plainbox/impl/session/test_storage.py
Conflict in plainbox/impl/session/test_suspend.py
Conflict in plainbox/impl/test_box.py
Conflict in plainbox/impl/test_ctrl.py
Conflict in plainbox/impl/test_launcher.py
Conflict in plainbox/impl/transport.py
Conflict in plainbox/impl/unit/concrete_validators.py
Conflict in plainbox/impl/unit/file.py
Conflict in plainbox/impl/unit/job.py
Conflict in plainbox/impl/unit/test_job.py
Conflict in plainbox/impl/unit/test_template.py
Conflict in plainbox/impl/unit/test_unit.py
Conflict in plainbox/impl/unit/testplan.py
Conflict in plainbox/impl/unit/unit.py
Conflict in plainbox/impl/xparsers.py
Conflict in plainbox/impl/xscanners.py
Conflict in plainbox/provider_manager.py
Conflict in plainbox/test-data/html-exporter/with_both_certification_status.html
Conflict in plainbox/test-data/html-exporter/with_certification_blocker.html
Conflict in plainbox/test-data/html-exporter/with_certification_non_blocker.html
Conflict in plainbox/test-data/html-exporter/without_certification_status.html
Conflict in plainbox/test_provider_manager.py
Conflict in plainbox/vendor/__init__.py
Conflict in plainbox/vendor/mock.py
Conflict in po/POTFILES.in
Conflict in setup.cfg
Conflict in setup.py
Reviewer Review Type Date Requested Status
Checkbox Developers Pending
Review via email: mp+343976@code.launchpad.net

This proposal has been superseded by a proposal from 2018-04-24.

Description of the change

fix transition to checkbox-ng

To post a comment you must log in.

Unmerged commits

25fa201... by Sylvain Pineau

Make plainbox a transitional package

https://wiki.debian.org/PackageTransition

cdd25c1... by Sylvain Pineau

Update silence logging failure patch

See https://bugs.launchpad.net/plainbox/+bug/1262898

4cf370b... by Sylvain Pineau

Update unvendorize patch (-funcsigs)

b2de646... by PMR <pmr@pmr-lander>

Merge #333833 from ~kissiel/plainbox/+git/packaging:add-pycrypto-dep

227148e... by Maciej Kisielewski

add python3-crypto dependency

Signed-off-by: Maciej Kisielewski <email address hidden>

90bce32... by Sylvain Pineau

change version to 0.38.0-1
"new upstream version"

c2d46ce... by Zygmunt Krynicki

Revert the documentation theme back to default

 PlainBox uses a customized sphinx theme that includes additional
 HTML to integrate with online comment service. This should not be
 a part of the offline documentation package.
Origin: upstream
Forwarded: not-needed
Last-Update: 2015-07-21

Patch-Name: documentation-theme

648f8eb... by Zygmunt Krynicki

Silence setup failure of the logging subsystem

 The logging subsystem has a feature that displays two lines of warnings
 if the per-user log file cannot be created. This leads to spurious
 errors when plainbox is invoked from a build environment. Before a
 better solution is found this warning is disabled as all of the
 subsequent, relevant, logging messages are display either way.
Bug-Ubuntu: https://bugs.launchpad.net/checkbox/+bug/1262898
Forwarded: yes
Last-Update: 2014-03-18

Patch-Name: silence-logging-failure

e112ce0... by Zygmunt Krynicki

Remove vendorized modules

 This patch replaces plainbox.vendor.{mock,funcsigs} with equivalent
 imports from the standard python3.3 library. Upstream will stop
 shipping those vendorized modules when support for python3.2 is no
 longer required.
Upstream: not-needed
Last-Update: 2014-03-18

Patch-Name: unvendorize

0b21cff... by Sylvain Pineau

record new upstream branch created by importing plainbox_0.38.0.orig.tar.gz

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/MANIFEST.in b/MANIFEST.in
2index 0eed38a..8a92fdb 100644
3--- a/MANIFEST.in
4+++ b/MANIFEST.in
5@@ -35,6 +35,12 @@ include plainbox/impl/providers/stubbox/po/*.pot
6 include plainbox/impl/providers/stubbox/po/POTFILES.in
7 include plainbox/impl/providers/stubbox/units/jobs/*.pxu
8 include plainbox/impl/providers/stubbox/units/testplans/*.pxu
9+<<<<<<< MANIFEST.in
10+=======
11+include plainbox/impl/providers/stubbox/whitelists/*.whitelist
12+
13+include plainbox/vendor/argparse/py*-argparse.py
14+>>>>>>> MANIFEST.in
15
16 include plainbox/qml_shell/qml_shell.qml
17
18@@ -45,4 +51,8 @@ recursive-exclude daily-package-testing *
19 recursive-include contrib *.policy
20 recursive-include docs *.rst *.py *.html *.conf
21 recursive-include plainbox/data *.rng
22+<<<<<<< MANIFEST.in
23 recursive-include plainbox/test-data *.json *.html *.tar.xz
24+=======
25+recursive-include plainbox/test-data *.json *.xml *.html
26+>>>>>>> MANIFEST.in
27diff --git a/PKG-INFO b/PKG-INFO
28new file mode 100644
29index 0000000..fafbf3f
30--- /dev/null
31+++ b/PKG-INFO
32@@ -0,0 +1,62 @@
33+Metadata-Version: 1.1
34+Name: plainbox
35+Version: 0.38.0
36+Summary: Toolkit for software and hardware integration testing
37+Home-page: https://launchpad.net/plainbox/
38+Author: Zygmunt Krynicki
39+Author-email: zygmunt.krynicki@canonical.com
40+License: GPLv3
41+Description: PlainBox
42+ ========
43+
44+ PlainBox is a toolkit consisting of python3 library, development tools,
45+ documentation and examples. It is targeted at developers working on testing or
46+ certification applications and authors creating tests for such applications.
47+
48+ PlainBox can be used to both create simple and comprehensive test tools as well
49+ as to develop and execute test jobs and test scenarios. It was created as a
50+ refined and rewritten core of the CheckBox project. It has a well tested and
51+ documented core, small but active development community and a collection of
52+ associated projects that use it as a lower-level engine/back-end library.
53+
54+ PlainBox has a novel approach to discovering (and probing) hardware and
55+ software that is extensible and not hardwired into the system. It allows test
56+ developers to express association between a particular test and the hardware,
57+ software and configuration constraints that must be met for the test to execute
58+ meaningfully. This feature, along with pluggable test definitions, makes
59+ PlainBox flexible and applicable to many diverse testing situations, ranging
60+ from mobile phones, traditional desktop computers, servers and up to testing
61+ "cloud" installations.
62+
63+ External Documentation Links
64+ ============================
65+
66+ * `Using PlainBox <http://plainbox.readthedocs.org/en/latest/usage.html>`_
67+ * `Hacking on PlainBox <http://plainbox.readthedocs.org/en/latest/dev/index.html>`_
68+ * `Testing PlainBox <http://plainbox.readthedocs.org/en/latest/dev/intro.html#running-plainbox-tests>`_
69+
70+ Known Issues
71+ ============
72+
73+ https://bugs.launchpad.net/plainbox
74+
75+Platform: POSIX
76+Classifier: Development Status :: 5 - Production/Stable
77+Classifier: Environment :: Console
78+Classifier: Environment :: Console :: Curses
79+Classifier: Intended Audience :: Developers
80+Classifier: Intended Audience :: Information Technology
81+Classifier: Intended Audience :: Manufacturing
82+Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
83+Classifier: Natural Language :: English
84+Classifier: Natural Language :: Polish
85+Classifier: Operating System :: POSIX
86+Classifier: Operating System :: POSIX :: Linux
87+Classifier: Programming Language :: Python :: 3.2
88+Classifier: Programming Language :: Python :: 3.3
89+Classifier: Programming Language :: Python :: 3.4
90+Classifier: Topic :: Software Development :: Libraries :: Python Modules
91+Classifier: Topic :: Software Development :: Quality Assurance
92+Classifier: Topic :: Software Development :: Testing
93+Classifier: Topic :: System :: Benchmark
94+Classifier: Topic :: Utilities
95diff --git a/debian/.git-dpm b/debian/.git-dpm
96new file mode 100644
97index 0000000..6322bd6
98--- /dev/null
99+++ b/debian/.git-dpm
100@@ -0,0 +1,8 @@
101+# see git-dpm(1) from git-dpm package
102+c2d46ce5be7fb38b74c536e85865128af008d864
103+c2d46ce5be7fb38b74c536e85865128af008d864
104+8d70019e76acb28b201b59f0e0d578e15973723b
105+8d70019e76acb28b201b59f0e0d578e15973723b
106+plainbox_0.38.0.orig.tar.gz
107+93dbb907b96d266b3a0e0c761cc975f10e2ae669
108+1491112
109diff --git a/debian/changelog b/debian/changelog
110new file mode 100644
111index 0000000..ab529e2
112--- /dev/null
113+++ b/debian/changelog
114@@ -0,0 +1,257 @@
115+plainbox (0.38.0-1) UNRELEASED; urgency=medium
116+
117+ [ Pierre Equoy ]
118+ * Open for development (remove this message before releasing)
119+ * "new upstream version"
120+ * "new upstream version"
121+
122+ [ Sylvain Pineau ]
123+ * "new upstream version"
124+ * "new upstream version"
125+ * "new upstream version"
126+
127+ [ Pierre Equoy ]
128+ * "new upstream version"
129+ * "new upstream version"
130+ * "new upstream version"
131+
132+ [ Sylvain Pineau ]
133+ * "new upstream version"
134+ * "new upstream version"
135+ * "new upstream version"
136+ * "new upstream version"
137+ * "new upstream version"
138+ * "new upstream version"
139+ * "new upstream version"
140+ * "new upstream version"
141+ * "new upstream version"
142+ * "new upstream version"
143+ * "new upstream version"
144+
145+ -- Sylvain Pineau <sylvain.pineau@canonical.com> Thu, 16 Nov 2017 11:39:52 +0100
146+
147+plainbox (0.31-1) UNRELEASED; urgency=medium
148+
149+ [ Ondřej Nový ]
150+ * Fixed homepage (https)
151+ * Fixed VCS URL (https)
152+
153+ [ Sylvain Pineau ]
154+ * new upstream version
155+
156+ -- Sylvain Pineau <sylvain.pineau@canonical.com> Tue, 04 Oct 2016 13:53:56 +0200
157+
158+plainbox (0.25-1) unstable; urgency=medium
159+
160+ * New upstream release
161+ * List of fixed bugs: https://launchpad.net/plainbox/+milestone/0.25
162+
163+ -- Sylvain Pineau <sylvain.pineau@canonical.com> Tue, 05 Jan 2016 17:26:37 +0100
164+
165+plainbox (0.24-1) unstable; urgency=medium
166+
167+ * New upstream release with multiple fixes and new features.
168+ * One important feature is the introduction of the SessionAssistant class.
169+ It allows Plainbox to simplify common testing scenarios.
170+ The assistant acts as a middle-man between the session manager and the
171+ application.
172+ It handles all currently known stages of the testing work-flow.
173+ * Add a dependency on python3 guacamole, padme, requests and tk.
174+ * Plainbox now supports a new way to express estimated durations that is much
175+ easier for humans to read and write.
176+ * Plainbox now supports an *after* job ordering constraint. This constraint
177+ is very similar to the existing *depends* constraint, except that the
178+ outcome of the referenced job is not important. In practical terms, even if
179+ one job runs and fails, another job that runs *after* it, will run.
180+ * Plainbox now allows more than one resource object to be used in a resource
181+ expression (e.g. the manifest resource with something else).
182+ * Plainbox ignores trailing garbage after EOF while reading IOLog zip.
183+ See https://bugs.python.org/issue24301.
184+
185+ -- Sylvain Pineau <sylvain.pineau@canonical.com> Fri, 04 Dec 2015 15:44:14 +0100
186+
187+plainbox (0.22.2-2.1) unstable; urgency=medium
188+
189+ * Non-maintainer upload.
190+ * Fix "FTBFS: dh_clean: rm: cannot remove 'plainbox.egg-info': d/clean did
191+ miss the final '/*' to be recognized as directory. (Closes: #805677)
192+ * Also clean a mo file to allow build twice in a row
193+
194+ -- Tobias Frost <tobi@debian.org> Sun, 22 Nov 2015 13:07:43 +0100
195+
196+plainbox (0.22.2-2) unstable; urgency=medium
197+
198+ * debian/patches: add a pile of patches that bring in cherry-picked or
199+ brand-new fixes for issues uncovered by python 3.5.
200+
201+ -- Zygmunt Krynicki <zygmunt.krynicki@canonical.com> Wed, 02 Sep 2015 16:21:41 +0200
202+
203+plainbox (0.22.2-1) unstable; urgency=medium
204+
205+ * New upstream maintenance release
206+ * Use a temporary HOME to work around LP: #1478906
207+ * Build i18n catalogs for the exporters and categories providers.
208+ * Move myself to Uploaders and set the checkbox-devel@lists.ubuntu.com
209+ mailing list as the Maintainer.
210+ * Remove duplicate dependency on python3-xlsxwriter (via suggests and
211+ depends) from python3-plainbox.
212+ * Remove XS-Testsuite: autopkgtest as recommend by lintian.
213+ * De-duplicate licenses in debian/copyright
214+ * Correct filename patterns for pyglibc/glibc files.
215+
216+ -- Zygmunt Krynicki <zygmunt.krynicki@canonical.com> Tue, 28 Jul 2015 12:23:17 +0200
217+
218+plainbox (0.22-1) unstable; urgency=medium
219+
220+ * New upstream release (sorry for skipping 0.21) with multiple fixes and new
221+ features.
222+ * One important feature is the introduction of exporter units that allow
223+ test developers to put any customized report directly into the test
224+ provider package. This allows us to remove all association with Ubuntu or
225+ Canonical from the core plainbox package and make it more universal for
226+ Debian and other distributions.
227+ * debian/control: Drop dependency on python3-lxml (and the associated
228+ security issues). Upstream moved away from lxml and has adopted Jinja2 as
229+ a more flexible system for creating arbitrary text-based reports.
230+ * debian/control: Make the dependency on python3-xlsxwriter explicit as it
231+ is now more directly tested and not so much optional.
232+ * debian/patches/documentation-theme: refresh patch
233+ * debian/patches/fix-packaging-metadata-units: add a combined patch that
234+ addresses three Debian-affecting bugs that prevent providers from
235+ generating some of their dependencies.
236+
237+ -- Zygmunt Krynicki <zygmunt.krynicki@canonical.com> Tue, 21 Jul 2015 12:22:03 +0200
238+
239+plainbox (0.20-1) unstable; urgency=medium
240+
241+ * Use the new pypi redirector
242+ * Correct debian/copyright paths
243+ * Correct debian/copyright license names
244+ * Update Standards-Version to 3.9.6 (no change required)
245+ * New upstream release
246+ * Add debian/copyright entry for sphinxarg
247+ * Remove stubbox so that it's not packaged / installed
248+ * Break checkbox-ng << 0.18 so that upgrades work (packages are bound by
249+ unstable API and this is the matching release)
250+ * Ship plainbox-qml-shell manual page along with python3-plainbox package
251+ * Tweak how i18n catalogs are built not to corrupt the tree
252+ * Build i18n catalog for the 'categories' provider
253+ * Update generic copyright to -2015
254+ * Remove textland-specific copyright (it's now the same as the rest of
255+ plainbox), GPL-3 (not 3+)
256+ * Add license specific to vendorized python-morris
257+ * Add license specific to vendorized python-glibc
258+ * Wrap-and-sort everything
259+
260+ -- Zygmunt Krynicki <zygmunt.krynicki@canonical.com> Wed, 04 Mar 2015 18:49:06 +0100
261+
262+plainbox (0.5.4-1) unstable; urgency=medium
263+
264+ * New upstream release
265+ * List of fixed bugs:
266+ https://launchpad.net/plainbox/+milestone/0.5.4
267+
268+ -- Zygmunt Krynicki <zygmunt.krynicki@canonical.com> Thu, 10 Apr 2014 22:31:50 +0200
269+
270+plainbox (0.5.3-2) unstable; urgency=medium
271+
272+ * debian/python3-plainbox.preinst: remove
273+ /usr/lib/python3/dist-packages/{data,testdata} on upgrades (if they are
274+ not symbolic links). This fixes upgrades from the previous version.
275+
276+ -- Zygmunt Krynicki <zygmunt.krynicki@canonical.com> Tue, 08 Apr 2014 00:11:37 +0200
277+
278+plainbox (0.5.3-1) unstable; urgency=medium
279+
280+ * New upstream release
281+ * debian/control: make python3-plainbox, plainbox, plainbox-secure-policy
282+ and plainbox-insecure-policy all depend on one version on themselves.
283+ LP: #1298284
284+ * debian/control: break python3-checkbox-ng << 0.3
285+ * debian/control: drop build and runtime dependency on python3-requests
286+ * debian/copyright: add entry for new file (_shlex.py)
287+ * debian/copyright: move python license to dedicated license section (reused
288+ by three modules) per example 2 on http://dep.debian.net/deps/dep5/
289+ * debian/rules: regenerate translation templates
290+ * debian/rules: move plainbox/data and plainbox/test-data to
291+ /usr/share/python3-plainbox/ and use symlinks to keep original directories
292+ available.
293+ * List of fixed bugs:
294+ https://launchpad.net/checkbox/+milestone/plainbox-0.5.2
295+ https://launchpad.net/plainbox/+milestone/0.5.3
296+
297+ -- Zygmunt Krynicki <zygmunt.krynicki@canonical.com> Tue, 01 Apr 2014 01:36:20 +0200
298+
299+plainbox (0.5.1-1) unstable; urgency=medium
300+
301+ * New upstream release
302+ * debian/control: drop X-Python3-Version << 3.5
303+ * debian/patches/disable-development-option: dropped, applied upstream
304+ * debian/copyright: associate vendorized copies of argparse with appropriate
305+ copyright section
306+
307+ -- Zygmunt Krynicki <zygmunt.krynicki@canonical.com> Wed, 19 Mar 2014 00:08:12 +0100
308+
309+plainbox (0.5~b2-1) unstable; urgency=medium
310+
311+ * New upstream release.
312+ * debian/control: build-depend on python3-distutils-extra for translations
313+ * debian/control: add support for python3.4
314+ * debian/control: drop build dependency on help2man, the new release has
315+ native manual pages
316+ * debian/rules: build, install and clean up after translations
317+ * debian/clean: clean *.egg-info and *.pot files since those get
318+ regenerated
319+ * debian/source/options: ignore changes to .po files since intltools-update
320+ keeps bumping the timestamp embedded in them
321+ * debian/copyright: add license section for plainbox/impl/_argparse.py
322+ * debian/copyright: add new copyright entries for textland
323+ * debian/patches: refresh and reorder without any semantic changes
324+ * debian/patches: add patch to revert documentation theme to defaults
325+ * debian/watch: add mangling for alpha releases
326+ * debian/python3-plainbox.manpages, debian/plainbox.manpages: use manual
327+ pages build with sphinx
328+
329+ -- Zygmunt Krynicki <zygmunt.krynicki@canonical.com> Thu, 13 Mar 2014 09:45:06 +0100
330+
331+plainbox (0.4-4) unstable; urgency=medium
332+
333+ * Team upload.
334+ * Autopkgtest improvements: enable verbose output, use $ADTTMP and stop
335+ redirecting output to /dev/null.
336+ * Export NO_PNG_PKG_MANGLE=1 in debian/rules to disable PNG stripping
337+ when pkgbinarymangler is installed (it breaks the testsuite).
338+
339+ -- Dmitry Shachnev <mitya57@gmail.com> Wed, 22 Jan 2014 18:08:40 +0400
340+
341+plainbox (0.4-3) unstable; urgency=medium
342+
343+ * debian/tests/unit-tests: actually fail the test suite if unit tests fail.
344+ Thanks to Michael Terry for the fix. LP:#1265853
345+
346+ -- Zygmunt Krynicki <zygmunt.krynicki@canonical.com> Fri, 03 Jan 2014 16:55:54 +0100
347+
348+plainbox (0.4-2) unstable; urgency=medium
349+
350+ * debian/tests/control: Fix autopackage tests not to install all (including
351+ conflicting) packages blindly LP:#1264985
352+
353+ -- Zygmunt Krynicki <zygmunt.krynicki@canonical.com> Thu, 02 Jan 2014 10:33:29 +0100
354+
355+plainbox (0.4-1) unstable; urgency=medium
356+
357+ * New upstream release
358+ * plainbox-insecure-policy.install, plainbox-secure-policy.install: adjust
359+ packaging to install the same policykit .policy files under their new
360+ names
361+ * debian/copyright: update all Canonical-owned code to GPL-3 (not GPL-3+)
362+ * debian/control: mark python3.4 as unsupported as python3-lxml does not
363+ support python3.4 yet
364+
365+ -- Zygmunt Krynicki <zygmunt.krynicki@canonical.com> Tue, 24 Dec 2013 14:27:09 +0100
366+
367+plainbox (0.4~b2-1) unstable; urgency=low
368+
369+ * Initial release (Closes: #730568)
370+
371+ -- Zygmunt Krynicki <zygmunt.krynicki@canonical.com> Thu, 28 Nov 2013 23:38:28 +0000
372diff --git a/debian/clean b/debian/clean
373new file mode 100644
374index 0000000..8f5ba15
375--- /dev/null
376+++ b/debian/clean
377@@ -0,0 +1,5 @@
378+plainbox.egg-info/*
379+plainbox/impl/providers/stubbox/po/stubbox.pot
380+po/plainbox.pot
381+plainbox/vendor/sphinxarg/LICENSE
382+plainbox/impl/providers/manifest/build/mo/pl/LC_MESSAGES/plainbox-provider-manifest.mo
383diff --git a/debian/compat b/debian/compat
384new file mode 100644
385index 0000000..ec63514
386--- /dev/null
387+++ b/debian/compat
388@@ -0,0 +1 @@
389+9
390diff --git a/debian/control b/debian/control
391new file mode 100644
392index 0000000..7f675ae
393--- /dev/null
394+++ b/debian/control
395@@ -0,0 +1,106 @@
396+Source: plainbox
397+Section: utils
398+Priority: optional
399+Maintainer: Checkbox Developers <checkbox-devel@lists.ubuntu.com>
400+Uploaders: Sylvain Pineau <sylvain.pineau@canonical.com>,
401+ Zygmunt Krynicki <zygmunt.krynicki@canonical.com>,
402+ Debian Python Modules Team <python-modules-team@lists.alioth.debian.org>
403+Build-Depends: debhelper (>= 9),
404+ dh-python,
405+ python3-all,
406+ python3-crypto,
407+ python3-distutils-extra,
408+ python3-docutils,
409+ python3-guacamole,
410+ python3-jinja2,
411+ python3-padme,
412+ python3-pkg-resources,
413+ python3-requests,
414+ python3-requests-oauthlib,
415+ python3-setuptools,
416+ python3-sphinx,
417+ python3-tk,
418+ python3-xlsxwriter
419+Standards-Version: 3.9.6
420+X-Python3-Version: >= 3.2
421+Vcs-Git: https://anonscm.debian.org/git/python-modules/packages/plainbox.git
422+Vcs-Browser: https://anonscm.debian.org/cgit/python-modules/packages/plainbox.git
423+Homepage: https://launchpad.net/plainbox
424+
425+Package: plainbox
426+Architecture: all
427+Depends: checkbox-ng (>=1)
428+Description: toolkit for software and hardware integration testing
429+ PlainBox is a toolkit consisting of python3 library, development tools,
430+ documentation and examples. It is targeted at developers working on testing or
431+ certification applications and authors creating tests for such applications.
432+ .
433+ PlainBox can be used to both create simple and comprehensive test tools as
434+ well as to develop and execute test jobs and test scenarios. It was created as
435+ a refined and rewritten core of the Checkbox project. It has a well tested and
436+ documented core, small but active development community and a collection of
437+ associated projects that use it as a lower-level engine/back-end library.
438+ .
439+ PlainBox has a novel approach to discovering (and probing) hardware and
440+ software that is extensible and not hardwired into the system. It allows test
441+ developers to express association between a particular test and the hardware,
442+ software and configuration constraints that must be met for the test to
443+ execute meaningfully. This feature, along with pluggable test definitions,
444+ makes plainbox flexible and applicable to many diverse testing situations,
445+ ranging from mobile phones, traditional desktop computers, servers and up to
446+ testing "cloud" installations.
447+ .
448+ This package contains the plainbox executable
449+
450+Package: python3-plainbox
451+Architecture: all
452+Section: python
453+Depends: python3-checkbox-ng (>=1)
454+Description: toolkit for software and hardware testing (python3 module)
455+ PlainBox is a toolkit consisting of python3 library, development tools,
456+ documentation and examples. It is targeted at developers working on testing or
457+ certification applications and authors creating tests for such applications.
458+ .
459+ PlainBox can be used to both create simple and comprehensive test tools as
460+ well as to develop and execute test jobs and test scenarios. It was created as
461+ a refined and rewritten core of the Checkbox project. It has a well tested and
462+ documented core, small but active development community and a collection of
463+ associated projects that use it as a lower-level engine/back-end library.
464+ .
465+ PlainBox has a novel approach to discovering (and probing) hardware and
466+ software that is extensible and not hardwired into the system. It allows test
467+ developers to express association between a particular test and the hardware,
468+ software and configuration constraints that must be met for the test to
469+ execute meaningfully. This feature, along with pluggable test definitions,
470+ makes plainbox flexible and applicable to many diverse testing situations,
471+ ranging from mobile phones, traditional desktop computers, servers and up to
472+ testing "cloud" installations.
473+ .
474+ This package contains the plainbox python3 library.
475+
476+Package: python3-plainbox-doc
477+Architecture: all
478+Section: doc
479+Priority: extra
480+Depends: ${misc:Depends}, ${sphinxdoc:Depends}
481+Description: toolkit for software and hardware testing (documentation)
482+ PlainBox is a toolkit consisting of python3 library, development tools,
483+ documentation and examples. It is targeted at developers working on testing or
484+ certification applications and authors creating tests for such applications.
485+ .
486+ PlainBox can be used to both create simple and comprehensive test tools as
487+ well as to develop and execute test jobs and test scenarios. It was created as
488+ a refined and rewritten core of the Checkbox project. It has a well tested and
489+ documented core, small but active development community and a collection of
490+ associated projects that use it as a lower-level engine/back-end library.
491+ .
492+ PlainBox has a novel approach to discovering (and probing) hardware and
493+ software that is extensible and not hardwired into the system. It allows test
494+ developers to express association between a particular test and the hardware,
495+ software and configuration constraints that must be met for the test to
496+ execute meaningfully. This feature, along with pluggable test definitions,
497+ makes plainbox flexible and applicable to many diverse testing situations,
498+ ranging from mobile phones, traditional desktop computers, servers and up to
499+ testing "cloud" installations.
500+ .
501+ This package contains the documentation for the plainbox python3 library
502diff --git a/debian/copyright b/debian/copyright
503new file mode 100644
504index 0000000..5784a09
505--- /dev/null
506+++ b/debian/copyright
507@@ -0,0 +1,207 @@
508+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
509+Upstream-Name: plainbox
510+Source: https://launchpad.net/checkbox
511+
512+Files: *
513+Copyright: Copyright 2012-2015 Canonical Ltd.
514+License: GPL-3
515+ This program is free software: you can redistribute it and/or modify
516+ it under the terms of the GNU General Public License version 3,
517+ as published by the Free Software Foundation.
518+ .
519+ This program is distributed in the hope that it will be useful,
520+ but WITHOUT ANY WARRANTY; without even the implied warranty of
521+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
522+ GNU General Public License for more details.
523+ .
524+ You should have received a copy of the GNU General Public License
525+ along with this program. If not, see <http://www.gnu.org/licenses/>.
526+ .
527+ On Debian-based systems the full text of the GPL, version 3, can be found at
528+ /usr/share/common-licenses/GPL-3.
529+
530+Files: plainbox/vendor/extcmd/*
531+Copyright:
532+ Copyright (c) 2010-2012 Linaro Limited
533+ Copyright (c) 2013 Canonical Ltd.
534+License: GPL-3+
535+ This program is free software: you can redistribute it and/or modify
536+ it under the terms of the GNU General Public License as published by
537+ the Free Software Foundation, either version 3 of the License, or
538+ (at your option) any later version.
539+ .
540+ This program is distributed in the hope that it will be useful,
541+ but WITHOUT ANY WARRANTY; without even the implied warranty of
542+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
543+ GNU General Public License for more details.
544+ .
545+ You should have received a copy of the GNU General Public License
546+ along with this program. If not, see <http://www.gnu.org/licenses/>.
547+ .
548+ On Debian-based systems the full text of the GPL, version 3, can be found at
549+ /usr/share/common-licenses/GPL-3.
550+
551+Files: plainbox/vendor/funcsigs/*
552+Copyright:
553+ Copyright 2013 Aaron Iles
554+ Copyright 2001-2013 Python Software Foundation;
555+License: Apache-2.0
556+ Licensed under the Apache License, Version 2.0 (the "License");
557+ you may not use this file except in compliance with the License.
558+ You may obtain a copy of the License at
559+ .
560+ http://www.apache.org/licenses/LICENSE-2.0
561+ .
562+ Unless required by applicable law or agreed to in writing, software
563+ distributed under the License is distributed on an "AS IS" BASIS,
564+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
565+ See the License for the specific language governing permissions and
566+ limitations under the License.
567+ .
568+ On Debian-based systems the full text of the Apache, version 2.0, can be found
569+ at /usr/share/common-licenses/Apache-2.0.
570+
571+Files: plainbox/vendor/mock.py
572+Copyright: Copyright (C) 2007-2012 Michael Foord & the mock team
573+License: BSD-3-clause
574+ Redistribution and use in source and binary forms, with or without
575+ modification, are permitted provided that the following conditions are
576+ met:
577+ .
578+ .
579+ * Redistributions of source code must retain the above copyright
580+ notice, this list of conditions and the following disclaimer.
581+ .
582+ * Redistributions in binary form must reproduce the above
583+ copyright notice, this list of conditions and the following
584+ disclaimer in the documentation and/or other materials provided
585+ with the distribution.
586+ .
587+ * Neither the name of Michael Foord nor the name of Voidspace
588+ may be used to endorse or promote products derived from this
589+ software without specific prior written permission.
590+ .
591+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
592+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
593+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
594+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
595+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
596+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
597+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
598+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
599+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
600+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
601+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
602+
603+Files: plainbox/vendor/argparse/*.py
604+Copyright: Steven J. Bethard <steven.bethard@gmail.com>.
605+License: Python
606+
607+Files: plainbox/vendor/sphinxarg/*
608+Copyright: Copyright (c) 2013 Alex Rudakov
609+License: MIT
610+ The MIT License (MIT)
611+ .
612+ Permission is hereby granted, free of charge, to any person obtaining a copy of
613+ this software and associated documentation files (the "Software"), to deal in
614+ the Software without restriction, including without limitation the rights to
615+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
616+ the Software, and to permit persons to whom the Software is furnished to do so,
617+ subject to the following conditions:
618+ .
619+ The above copyright notice and this permission notice shall be included in all
620+ copies or substantial portions of the Software.
621+ .
622+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
623+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
624+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
625+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
626+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
627+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
628+
629+Files: plainbox/vendor/morris/*
630+Copyright: Copyright (c) 2012-15 Canonical Ltd.
631+License: LGPL-3+
632+
633+Files: plainbox/vendor/glibc.py
634+Copyright: Copyright (c) 2014 Canonical Ltd.
635+License: LGPL-3+
636+
637+Files: plainbox/vendor/pyglibc/*
638+Copyright: Copyright (c) 2014 Canonical Ltd.
639+License: LGPL-3+
640+
641+Files: plainbox/impl/_argparse.py
642+Copyright: Steven J. Bethard <steven.bethard@gmail.com>.
643+License: Python
644+
645+Files: plainbox/impl/_shlex.py
646+Copyright:
647+ Module and documentation by Eric S. Raymond, 21 Dec 1998
648+ Input stacking and error message cleanup added by ESR, March 2000
649+ push_source() and pop_source() made explicit by ESR, January 2001.
650+ Posix compliance, split(), string arguments, and
651+ iterator interface by Gustavo Niemeyer, April 2003.
652+License: Python
653+
654+License: Python
655+ PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
656+ --------------------------------------------
657+ .
658+ 1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"),
659+ and the Individual or Organization ("Licensee") accessing and otherwise
660+ using this software ("Python") in source or binary form and its associated
661+ documentation.
662+ .
663+ 2. Subject to the terms and conditions of this License Agreement, PSF hereby
664+ grants Licensee a nonexclusive, royalty-free, world-wide license to
665+ reproduce, analyze, test, perform and/or display publicly, prepare
666+ derivative works, distribute, and otherwise use Python alone or in any
667+ derivative version, provided, however, that PSF's License Agreement and
668+ PSF's notice of copyright, i.e., "Copyright (c) 2001, 2002, 2003, 2004,
669+ 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Python Software
670+ Foundation; All Rights Reserved" are retained in Python alone or in any
671+ derivative version prepared by Licensee.
672+ .
673+ 3. In the event Licensee prepares a derivative work that is based on or
674+ incorporates Python or any part thereof, and wants to make the derivative
675+ work available to others as provided herein, then Licensee hereby agrees
676+ to include in any such work a brief summary of the changes made to Python.
677+ .
678+ 4. PSF is making Python available to Licensee on an "AS IS" basis. PSF MAKES
679+ NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE,
680+ BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR
681+ WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT
682+ THE USE OF PYTHON WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
683+ .
684+ 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON FOR ANY
685+ INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF
686+ MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, OR ANY DERIVATIVE
687+ THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
688+ .
689+ 6. This License Agreement will automatically terminate upon a material breach
690+ of its terms and conditions.
691+ .
692+ 7. Nothing in this License Agreement shall be deemed to create any
693+ relationship of agency, partnership, or joint venture between PSF and
694+ Licensee. This License Agreement does not grant permission to use PSF
695+ trademarks or trade name in a trademark sense to endorse or promote
696+ products or services of Licensee, or any third party.
697+ .
698+ 8. By copying, installing or otherwise using Python, Licensee agrees to be
699+ bound by the terms and conditions of this License Agreement.
700+
701+License: LGPL-3+
702+ This file is part of Morris.
703+ .
704+ Morris is free software: you can redistribute it and/or modify
705+ it under the terms of the GNU Lesser General Public License as published by
706+ the Free Software Foundation, either version 3 of the License.
707+ .
708+ Morris is distributed in the hope that it will be useful,
709+ but WITHOUT ANY WARRANTY; without even the implied warranty of
710+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
711+ GNU Lesser General Public License for more details.
712+ .
713+ You should have received a copy of the GNU Lesser General Public License
714+ along with Morris. If not, see <http://www.gnu.org/licenses/>.
715diff --git a/debian/patches/documentation-theme b/debian/patches/documentation-theme
716new file mode 100644
717index 0000000..d0306e7
718--- /dev/null
719+++ b/debian/patches/documentation-theme
720@@ -0,0 +1,42 @@
721+From c2d46ce5be7fb38b74c536e85865128af008d864 Mon Sep 17 00:00:00 2001
722+From: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
723+Date: Thu, 8 Oct 2015 10:13:55 -0700
724+Subject: Revert the documentation theme back to default
725+
726+ PlainBox uses a customized sphinx theme that includes additional
727+ HTML to integrate with online comment service. This should not be
728+ a part of the offline documentation package.
729+Origin: upstream
730+Forwarded: not-needed
731+Last-Update: 2015-07-21
732+
733+Patch-Name: documentation-theme
734+---
735+ docs/conf.py | 10 +---------
736+ 1 file changed, 1 insertion(+), 9 deletions(-)
737+
738+diff --git a/docs/conf.py b/docs/conf.py
739+index 07bd76e..ab2ab04 100644
740+--- a/docs/conf.py
741++++ b/docs/conf.py
742+@@ -124,19 +124,11 @@ pygments_style = 'sphinx'
743+ # Use our custom theme. For now it only adds Disqus.com support but we may
744+ # customize it further later on. The theme is called 'plainbox' and has one
745+ # option which controls if disqus is active or not.
746+-html_theme = 'plainbox'
747++html_theme = 'default'
748+
749+ # Theme options are theme-specific and customize the look and feel of a theme
750+ # further. For a list of options available for each theme, see the
751+ # documentation.
752+-#
753+-# Due to the way disqus works, it's only going to work on
754+-# plainbox.readthedocs.org so only use it if building for readthedocs.
755+-
756+-html_theme_options = {
757+- 'show_disqus': 'true' if os.environ.get(
758+- "READTHEDOCS", None) == 'True' else ''
759+-}
760+
761+ # Add any paths that contain custom themes here, relative to this directory.
762+ html_theme_path = ['_theme']
763diff --git a/debian/patches/series b/debian/patches/series
764new file mode 100644
765index 0000000..5313c71
766--- /dev/null
767+++ b/debian/patches/series
768@@ -0,0 +1,3 @@
769+unvendorize
770+silence-logging-failure
771+documentation-theme
772diff --git a/debian/patches/silence-logging-failure b/debian/patches/silence-logging-failure
773new file mode 100644
774index 0000000..c61779b
775--- /dev/null
776+++ b/debian/patches/silence-logging-failure
777@@ -0,0 +1,37 @@
778+From 648f8eb6ebd6465b85608915bb7ae1b021f5e809 Mon Sep 17 00:00:00 2001
779+From: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
780+Date: Thu, 8 Oct 2015 10:13:54 -0700
781+Subject: Silence setup failure of the logging subsystem
782+
783+ The logging subsystem has a feature that displays two lines of warnings
784+ if the per-user log file cannot be created. This leads to spurious
785+ errors when plainbox is invoked from a build environment. Before a
786+ better solution is found this warning is disabled as all of the
787+ subsequent, relevant, logging messages are display either way.
788+Bug-Ubuntu: https://bugs.launchpad.net/checkbox/+bug/1262898
789+Forwarded: yes
790+Last-Update: 2014-03-18
791+
792+Patch-Name: silence-logging-failure
793+---
794+ plainbox/impl/logging.py | 5 -----
795+ 1 file changed, 5 deletions(-)
796+
797+diff --git a/plainbox/impl/logging.py b/plainbox/impl/logging.py
798+index 85fe7dd..6e66da0 100644
799+--- a/plainbox/impl/logging.py
800++++ b/plainbox/impl/logging.py
801+@@ -95,12 +95,6 @@ class LoggingHelper:
802+ try:
803+ os.makedirs(self.log_dir, exist_ok=True)
804+ except OSError as error:
805+- if not config_dict.get(
806+- 'silence_eperm_on_logdir_warning', False):
807+- logger.warning(
808+- _("Unable to create log directory: %s"), self.log_dir)
809+- logger.warning(_("Reason: %s. All logs will go to "
810+- "console instead."), error)
811+ config_dict = self.DEFAULT_CONSOLE_ONLY_CONFIG
812+ # Apply the selected configuration. This overrides anything currently
813+ # defined for all of the logging subsystem in this python runtime
814+
815diff --git a/debian/patches/unvendorize b/debian/patches/unvendorize
816new file mode 100644
817index 0000000..fce9d34
818--- /dev/null
819+++ b/debian/patches/unvendorize
820@@ -0,0 +1,2434 @@
821+From e112ce0246c305cba81c457e8aa3a7c40e87ab13 Mon Sep 17 00:00:00 2001
822+From: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
823+Date: Thu, 8 Oct 2015 10:13:53 -0700
824+Subject: Remove vendorized modules
825+
826+ This patch replaces plainbox.vendor.mock with equivalent imports from the
827+ standard python3.3 library. Upstream will stop shipping those vendorized
828+ modules when support for python3.2 is no longer required.
829+Upstream: not-needed
830+Last-Update: 2018-01-12
831+
832+Patch-Name: unvendorize
833+---
834+ plainbox/vendor/__init__.py | 5 +
835+ plainbox/vendor/mock.py | 2398 +------------------------------------------
836+ 2 files changed, 34 insertions(+), 2369 deletions(-)
837+
838+diff --git a/plainbox/vendor/__init__.py b/plainbox/vendor/__init__.py
839+index d4ed746..188c398 100644
840+--- a/plainbox/vendor/__init__.py
841++++ b/plainbox/vendor/__init__.py
842+@@ -25,4 +25,9 @@ This module contains external packages that were vendorized (shipped with a
843+ tree of another project) to simplify dependency management. There is no problem
844+ with expressing those dependencies at pypi level but it would be annoying to
845+ have to first package and introduce them to Ubuntu.
846++
847++.. note::
848++ The ``plainbox.vendor`` package is modified by Debian not to ship a copy of
849++ the ``unittest.mock`` and updated ``inspect`` modules that are already
850++ available in python3.3
851+ """
852+diff --git a/plainbox/vendor/mock.py b/plainbox/vendor/mock.py
853+index ca77df6..9916e39 100644
854+--- a/plainbox/vendor/mock.py
855++++ b/plainbox/vendor/mock.py
856+@@ -1,2369 +1,29 @@
857+-# mock.py
858+-# Test tools for mocking and patching.
859+-# Copyright (C) 2007-2012 Michael Foord & the mock team
860+-# E-mail: fuzzyman AT voidspace DOT org DOT uk
861+-
862+-# mock 1.0
863+-# http://www.voidspace.org.uk/python/mock/
864+-
865+-# Released subject to the BSD License
866+-# Please see http://www.voidspace.org.uk/python/license.shtml
867+-
868+-# Scripts maintained at http://www.voidspace.org.uk/python/index.shtml
869+-# Comments, suggestions and bug reports welcome.
870+-
871+-
872+-__all__ = (
873+- 'Mock',
874+- 'MagicMock',
875+- 'patch',
876+- 'sentinel',
877+- 'DEFAULT',
878+- 'ANY',
879+- 'call',
880+- 'create_autospec',
881+- 'FILTER_DIR',
882+- 'NonCallableMock',
883+- 'NonCallableMagicMock',
884+- 'mock_open',
885+- 'PropertyMock',
886+-)
887+-
888+-
889+-__version__ = '1.0.1'
890+-
891+-
892+-import pprint
893+-import sys
894+-
895+-try:
896+- import inspect
897+-except ImportError:
898+- # for alternative platforms that
899+- # may not have inspect
900+- inspect = None
901+-
902+-try:
903+- from functools import wraps as original_wraps
904+-except ImportError:
905+- # Python 2.4 compatibility
906+- def wraps(original):
907+- def inner(f):
908+- f.__name__ = original.__name__
909+- f.__doc__ = original.__doc__
910+- f.__module__ = original.__module__
911+- f.__wrapped__ = original
912+- return f
913+- return inner
914+-else:
915+- if sys.version_info[:2] >= (3, 3):
916+- wraps = original_wraps
917+- else:
918+- def wraps(func):
919+- def inner(f):
920+- f = original_wraps(func)(f)
921+- f.__wrapped__ = func
922+- return f
923+- return inner
924+-
925+-try:
926+- unicode
927+-except NameError:
928+- # Python 3
929+- basestring = unicode = str
930+-
931+-try:
932+- long
933+-except NameError:
934+- # Python 3
935+- long = int
936+-
937+-try:
938+- BaseException
939+-except NameError:
940+- # Python 2.4 compatibility
941+- BaseException = Exception
942+-
943+-try:
944+- next
945+-except NameError:
946+- def next(obj):
947+- return obj.next()
948+-
949+-
950+-BaseExceptions = (BaseException,)
951+-if 'java' in sys.platform:
952+- # jython
953+- import java
954+- BaseExceptions = (BaseException, java.lang.Throwable)
955+-
956+-try:
957+- _isidentifier = str.isidentifier
958+-except AttributeError:
959+- # Python 2.X
960+- import keyword
961+- import re
962+- regex = re.compile(r'^[a-z_][a-z0-9_]*$', re.I)
963+- def _isidentifier(string):
964+- if string in keyword.kwlist:
965+- return False
966+- return regex.match(string)
967+-
968+-
969+-inPy3k = sys.version_info[0] == 3
970+-
971+-# Needed to work around Python 3 bug where use of "super" interferes with
972+-# defining __class__ as a descriptor
973+-_super = super
974+-
975+-self = 'im_self'
976+-builtin = '__builtin__'
977+-if inPy3k:
978+- self = '__self__'
979+- builtin = 'builtins'
980+-
981+-FILTER_DIR = True
982+-
983+-
984+-def _is_instance_mock(obj):
985+- # can't use isinstance on Mock objects because they override __class__
986+- # The base class for all mocks is NonCallableMock
987+- return issubclass(type(obj), NonCallableMock)
988+-
989+-
990+-def _is_exception(obj):
991+- return (
992+- isinstance(obj, BaseExceptions) or
993+- isinstance(obj, ClassTypes) and issubclass(obj, BaseExceptions)
994+- )
995+-
996+-
997+-class _slotted(object):
998+- __slots__ = ['a']
999+-
1000+-
1001+-DescriptorTypes = (
1002+- type(_slotted.a),
1003+- property,
1004+-)
1005+-
1006+-
1007+-def _getsignature(func, skipfirst, instance=False):
1008+- if inspect is None:
1009+- raise ImportError('inspect module not available')
1010+-
1011+- if isinstance(func, ClassTypes) and not instance:
1012+- try:
1013+- func = func.__init__
1014+- except AttributeError:
1015+- return
1016+- skipfirst = True
1017+- elif not isinstance(func, FunctionTypes):
1018+- # for classes where instance is True we end up here too
1019+- try:
1020+- func = func.__call__
1021+- except AttributeError:
1022+- return
1023+-
1024+- if inPy3k:
1025+- try:
1026+- argspec = inspect.getfullargspec(func)
1027+- except TypeError:
1028+- # C function / method, possibly inherited object().__init__
1029+- return
1030+- regargs, varargs, varkw, defaults, kwonly, kwonlydef, ann = argspec
1031+- else:
1032+- try:
1033+- regargs, varargs, varkwargs, defaults = inspect.getargspec(func)
1034+- except TypeError:
1035+- # C function / method, possibly inherited object().__init__
1036+- return
1037+-
1038+- # instance methods and classmethods need to lose the self argument
1039+- if getattr(func, self, None) is not None:
1040+- regargs = regargs[1:]
1041+- if skipfirst:
1042+- # this condition and the above one are never both True - why?
1043+- regargs = regargs[1:]
1044+-
1045+- if inPy3k:
1046+- signature = inspect.formatargspec(
1047+- regargs, varargs, varkw, defaults,
1048+- kwonly, kwonlydef, ann, formatvalue=lambda value: "")
1049+- else:
1050+- signature = inspect.formatargspec(
1051+- regargs, varargs, varkwargs, defaults,
1052+- formatvalue=lambda value: "")
1053+- return signature[1:-1], func
1054+-
1055+-
1056+-def _check_signature(func, mock, skipfirst, instance=False):
1057+- if not _callable(func):
1058+- return
1059+-
1060+- result = _getsignature(func, skipfirst, instance)
1061+- if result is None:
1062+- return
1063+- signature, func = result
1064+-
1065+- # can't use self because "self" is common as an argument name
1066+- # unfortunately even not in the first place
1067+- src = "lambda _mock_self, %s: None" % signature
1068+- checksig = eval(src, {})
1069+- _copy_func_details(func, checksig)
1070+- type(mock)._mock_check_sig = checksig
1071+-
1072+-
1073+-def _copy_func_details(func, funcopy):
1074+- funcopy.__name__ = func.__name__
1075+- funcopy.__doc__ = func.__doc__
1076+- #funcopy.__dict__.update(func.__dict__)
1077+- funcopy.__module__ = func.__module__
1078+- if not inPy3k:
1079+- funcopy.func_defaults = func.func_defaults
1080+- return
1081+- funcopy.__defaults__ = func.__defaults__
1082+- funcopy.__kwdefaults__ = func.__kwdefaults__
1083+-
1084+-
1085+-def _callable(obj):
1086+- if isinstance(obj, ClassTypes):
1087+- return True
1088+- if getattr(obj, '__call__', None) is not None:
1089+- return True
1090+- return False
1091+-
1092+-
1093+-def _is_list(obj):
1094+- # checks for list or tuples
1095+- # XXXX badly named!
1096+- return type(obj) in (list, tuple)
1097+-
1098+-
1099+-def _instance_callable(obj):
1100+- """Given an object, return True if the object is callable.
1101+- For classes, return True if instances would be callable."""
1102+- if not isinstance(obj, ClassTypes):
1103+- # already an instance
1104+- return getattr(obj, '__call__', None) is not None
1105+-
1106+- klass = obj
1107+- # uses __bases__ instead of __mro__ so that we work with old style classes
1108+- if klass.__dict__.get('__call__') is not None:
1109+- return True
1110+-
1111+- for base in klass.__bases__:
1112+- if _instance_callable(base):
1113+- return True
1114+- return False
1115+-
1116+-
1117+-def _set_signature(mock, original, instance=False):
1118+- # creates a function with signature (*args, **kwargs) that delegates to a
1119+- # mock. It still does signature checking by calling a lambda with the same
1120+- # signature as the original.
1121+- if not _callable(original):
1122+- return
1123+-
1124+- skipfirst = isinstance(original, ClassTypes)
1125+- result = _getsignature(original, skipfirst, instance)
1126+- if result is None:
1127+- # was a C function (e.g. object().__init__ ) that can't be mocked
1128+- return
1129+-
1130+- signature, func = result
1131+-
1132+- src = "lambda %s: None" % signature
1133+- checksig = eval(src, {})
1134+- _copy_func_details(func, checksig)
1135+-
1136+- name = original.__name__
1137+- if not _isidentifier(name):
1138+- name = 'funcopy'
1139+- context = {'_checksig_': checksig, 'mock': mock}
1140+- src = """def %s(*args, **kwargs):
1141+- _checksig_(*args, **kwargs)
1142+- return mock(*args, **kwargs)""" % name
1143+- exec (src, context)
1144+- funcopy = context[name]
1145+- _setup_func(funcopy, mock)
1146+- return funcopy
1147+-
1148+-
1149+-def _setup_func(funcopy, mock):
1150+- funcopy.mock = mock
1151+-
1152+- # can't use isinstance with mocks
1153+- if not _is_instance_mock(mock):
1154+- return
1155+-
1156+- def assert_called_with(*args, **kwargs):
1157+- return mock.assert_called_with(*args, **kwargs)
1158+- def assert_called_once_with(*args, **kwargs):
1159+- return mock.assert_called_once_with(*args, **kwargs)
1160+- def assert_has_calls(*args, **kwargs):
1161+- return mock.assert_has_calls(*args, **kwargs)
1162+- def assert_any_call(*args, **kwargs):
1163+- return mock.assert_any_call(*args, **kwargs)
1164+- def reset_mock():
1165+- funcopy.method_calls = _CallList()
1166+- funcopy.mock_calls = _CallList()
1167+- mock.reset_mock()
1168+- ret = funcopy.return_value
1169+- if _is_instance_mock(ret) and not ret is mock:
1170+- ret.reset_mock()
1171+-
1172+- funcopy.called = False
1173+- funcopy.call_count = 0
1174+- funcopy.call_args = None
1175+- funcopy.call_args_list = _CallList()
1176+- funcopy.method_calls = _CallList()
1177+- funcopy.mock_calls = _CallList()
1178+-
1179+- funcopy.return_value = mock.return_value
1180+- funcopy.side_effect = mock.side_effect
1181+- funcopy._mock_children = mock._mock_children
1182+-
1183+- funcopy.assert_called_with = assert_called_with
1184+- funcopy.assert_called_once_with = assert_called_once_with
1185+- funcopy.assert_has_calls = assert_has_calls
1186+- funcopy.assert_any_call = assert_any_call
1187+- funcopy.reset_mock = reset_mock
1188+-
1189+- mock._mock_delegate = funcopy
1190+-
1191+-
1192+-def _is_magic(name):
1193+- return '__%s__' % name[2:-2] == name
1194+-
1195+-
1196+-class _SentinelObject(object):
1197+- "A unique, named, sentinel object."
1198+- def __init__(self, name):
1199+- self.name = name
1200+-
1201+- def __repr__(self):
1202+- return 'sentinel.%s' % self.name
1203+-
1204+-
1205+-class _Sentinel(object):
1206+- """Access attributes to return a named object, usable as a sentinel."""
1207+- def __init__(self):
1208+- self._sentinels = {}
1209+-
1210+- def __getattr__(self, name):
1211+- if name == '__bases__':
1212+- # Without this help(mock) raises an exception
1213+- raise AttributeError
1214+- return self._sentinels.setdefault(name, _SentinelObject(name))
1215+-
1216+-
1217+-sentinel = _Sentinel()
1218+-
1219+-DEFAULT = sentinel.DEFAULT
1220+-_missing = sentinel.MISSING
1221+-_deleted = sentinel.DELETED
1222+-
1223+-
1224+-class OldStyleClass:
1225+- pass
1226+-ClassType = type(OldStyleClass)
1227+-
1228+-
1229+-def _copy(value):
1230+- if type(value) in (dict, list, tuple, set):
1231+- return type(value)(value)
1232+- return value
1233+-
1234+-
1235+-ClassTypes = (type,)
1236+-if not inPy3k:
1237+- ClassTypes = (type, ClassType)
1238+-
1239+-_allowed_names = set(
1240+- [
1241+- 'return_value', '_mock_return_value', 'side_effect',
1242+- '_mock_side_effect', '_mock_parent', '_mock_new_parent',
1243+- '_mock_name', '_mock_new_name'
1244+- ]
1245+-)
1246+-
1247+-
1248+-def _delegating_property(name):
1249+- _allowed_names.add(name)
1250+- _the_name = '_mock_' + name
1251+- def _get(self, name=name, _the_name=_the_name):
1252+- sig = self._mock_delegate
1253+- if sig is None:
1254+- return getattr(self, _the_name)
1255+- return getattr(sig, name)
1256+- def _set(self, value, name=name, _the_name=_the_name):
1257+- sig = self._mock_delegate
1258+- if sig is None:
1259+- self.__dict__[_the_name] = value
1260+- else:
1261+- setattr(sig, name, value)
1262+-
1263+- return property(_get, _set)
1264+-
1265+-
1266+-
1267+-class _CallList(list):
1268+-
1269+- def __contains__(self, value):
1270+- if not isinstance(value, list):
1271+- return list.__contains__(self, value)
1272+- len_value = len(value)
1273+- len_self = len(self)
1274+- if len_value > len_self:
1275+- return False
1276+-
1277+- for i in range(0, len_self - len_value + 1):
1278+- sub_list = self[i:i+len_value]
1279+- if sub_list == value:
1280+- return True
1281+- return False
1282+-
1283+- def __repr__(self):
1284+- return pprint.pformat(list(self))
1285+-
1286+-
1287+-def _check_and_set_parent(parent, value, name, new_name):
1288+- if not _is_instance_mock(value):
1289+- return False
1290+- if ((value._mock_name or value._mock_new_name) or
1291+- (value._mock_parent is not None) or
1292+- (value._mock_new_parent is not None)):
1293+- return False
1294+-
1295+- _parent = parent
1296+- while _parent is not None:
1297+- # setting a mock (value) as a child or return value of itself
1298+- # should not modify the mock
1299+- if _parent is value:
1300+- return False
1301+- _parent = _parent._mock_new_parent
1302+-
1303+- if new_name:
1304+- value._mock_new_parent = parent
1305+- value._mock_new_name = new_name
1306+- if name:
1307+- value._mock_parent = parent
1308+- value._mock_name = name
1309+- return True
1310+-
1311+-
1312+-
1313+-class Base(object):
1314+- _mock_return_value = DEFAULT
1315+- _mock_side_effect = None
1316+- def __init__(self, *args, **kwargs):
1317+- pass
1318+-
1319+-
1320+-
1321+-class NonCallableMock(Base):
1322+- """A non-callable version of `Mock`"""
1323+-
1324+- def __new__(cls, *args, **kw):
1325+- # every instance has its own class
1326+- # so we can create magic methods on the
1327+- # class without stomping on other mocks
1328+- new = type(cls.__name__, (cls,), {'__doc__': cls.__doc__})
1329+- instance = object.__new__(new)
1330+- return instance
1331+-
1332+-
1333+- def __init__(
1334+- self, spec=None, wraps=None, name=None, spec_set=None,
1335+- parent=None, _spec_state=None, _new_name='', _new_parent=None,
1336+- **kwargs
1337+- ):
1338+- if _new_parent is None:
1339+- _new_parent = parent
1340+-
1341+- __dict__ = self.__dict__
1342+- __dict__['_mock_parent'] = parent
1343+- __dict__['_mock_name'] = name
1344+- __dict__['_mock_new_name'] = _new_name
1345+- __dict__['_mock_new_parent'] = _new_parent
1346+-
1347+- if spec_set is not None:
1348+- spec = spec_set
1349+- spec_set = True
1350+-
1351+- self._mock_add_spec(spec, spec_set)
1352+-
1353+- __dict__['_mock_children'] = {}
1354+- __dict__['_mock_wraps'] = wraps
1355+- __dict__['_mock_delegate'] = None
1356+-
1357+- __dict__['_mock_called'] = False
1358+- __dict__['_mock_call_args'] = None
1359+- __dict__['_mock_call_count'] = 0
1360+- __dict__['_mock_call_args_list'] = _CallList()
1361+- __dict__['_mock_mock_calls'] = _CallList()
1362+-
1363+- __dict__['method_calls'] = _CallList()
1364+-
1365+- if kwargs:
1366+- self.configure_mock(**kwargs)
1367+-
1368+- _super(NonCallableMock, self).__init__(
1369+- spec, wraps, name, spec_set, parent,
1370+- _spec_state
1371+- )
1372+-
1373+-
1374+- def attach_mock(self, mock, attribute):
1375+- """
1376+- Attach a mock as an attribute of this one, replacing its name and
1377+- parent. Calls to the attached mock will be recorded in the
1378+- `method_calls` and `mock_calls` attributes of this one."""
1379+- mock._mock_parent = None
1380+- mock._mock_new_parent = None
1381+- mock._mock_name = ''
1382+- mock._mock_new_name = None
1383+-
1384+- setattr(self, attribute, mock)
1385+-
1386+-
1387+- def mock_add_spec(self, spec, spec_set=False):
1388+- """Add a spec to a mock. `spec` can either be an object or a
1389+- list of strings. Only attributes on the `spec` can be fetched as
1390+- attributes from the mock.
1391+-
1392+- If `spec_set` is True then only attributes on the spec can be set."""
1393+- self._mock_add_spec(spec, spec_set)
1394+-
1395+-
1396+- def _mock_add_spec(self, spec, spec_set):
1397+- _spec_class = None
1398+-
1399+- if spec is not None and not _is_list(spec):
1400+- if isinstance(spec, ClassTypes):
1401+- _spec_class = spec
1402+- else:
1403+- _spec_class = _get_class(spec)
1404+-
1405+- spec = dir(spec)
1406+-
1407+- __dict__ = self.__dict__
1408+- __dict__['_spec_class'] = _spec_class
1409+- __dict__['_spec_set'] = spec_set
1410+- __dict__['_mock_methods'] = spec
1411+-
1412+-
1413+- def __get_return_value(self):
1414+- ret = self._mock_return_value
1415+- if self._mock_delegate is not None:
1416+- ret = self._mock_delegate.return_value
1417+-
1418+- if ret is DEFAULT:
1419+- ret = self._get_child_mock(
1420+- _new_parent=self, _new_name='()'
1421+- )
1422+- self.return_value = ret
1423+- return ret
1424+-
1425+-
1426+- def __set_return_value(self, value):
1427+- if self._mock_delegate is not None:
1428+- self._mock_delegate.return_value = value
1429+- else:
1430+- self._mock_return_value = value
1431+- _check_and_set_parent(self, value, None, '()')
1432+-
1433+- __return_value_doc = "The value to be returned when the mock is called."
1434+- return_value = property(__get_return_value, __set_return_value,
1435+- __return_value_doc)
1436+-
1437+-
1438+- @property
1439+- def __class__(self):
1440+- if self._spec_class is None:
1441+- return type(self)
1442+- return self._spec_class
1443+-
1444+- called = _delegating_property('called')
1445+- call_count = _delegating_property('call_count')
1446+- call_args = _delegating_property('call_args')
1447+- call_args_list = _delegating_property('call_args_list')
1448+- mock_calls = _delegating_property('mock_calls')
1449+-
1450+-
1451+- def __get_side_effect(self):
1452+- sig = self._mock_delegate
1453+- if sig is None:
1454+- return self._mock_side_effect
1455+- return sig.side_effect
1456+-
1457+- def __set_side_effect(self, value):
1458+- value = _try_iter(value)
1459+- sig = self._mock_delegate
1460+- if sig is None:
1461+- self._mock_side_effect = value
1462+- else:
1463+- sig.side_effect = value
1464+-
1465+- side_effect = property(__get_side_effect, __set_side_effect)
1466+-
1467+-
1468+- def reset_mock(self):
1469+- "Restore the mock object to its initial state."
1470+- self.called = False
1471+- self.call_args = None
1472+- self.call_count = 0
1473+- self.mock_calls = _CallList()
1474+- self.call_args_list = _CallList()
1475+- self.method_calls = _CallList()
1476+-
1477+- for child in self._mock_children.values():
1478+- if isinstance(child, _SpecState):
1479+- continue
1480+- child.reset_mock()
1481+-
1482+- ret = self._mock_return_value
1483+- if _is_instance_mock(ret) and ret is not self:
1484+- ret.reset_mock()
1485+-
1486+-
1487+- def configure_mock(self, **kwargs):
1488+- """Set attributes on the mock through keyword arguments.
1489+-
1490+- Attributes plus return values and side effects can be set on child
1491+- mocks using standard dot notation and unpacking a dictionary in the
1492+- method call:
1493+-
1494+- >>> attrs = {'method.return_value': 3, 'other.side_effect': KeyError}
1495+- >>> mock.configure_mock(**attrs)"""
1496+- for arg, val in sorted(kwargs.items(),
1497+- # we sort on the number of dots so that
1498+- # attributes are set before we set attributes on
1499+- # attributes
1500+- key=lambda entry: entry[0].count('.')):
1501+- args = arg.split('.')
1502+- final = args.pop()
1503+- obj = self
1504+- for entry in args:
1505+- obj = getattr(obj, entry)
1506+- setattr(obj, final, val)
1507+-
1508+-
1509+- def __getattr__(self, name):
1510+- if name == '_mock_methods':
1511+- raise AttributeError(name)
1512+- elif self._mock_methods is not None:
1513+- if name not in self._mock_methods or name in _all_magics:
1514+- raise AttributeError("Mock object has no attribute %r" % name)
1515+- elif _is_magic(name):
1516+- raise AttributeError(name)
1517+- if name.startswith(('assert', 'assret')):
1518+- raise AttributeError(name)
1519+-
1520+- result = self._mock_children.get(name)
1521+- if result is _deleted:
1522+- raise AttributeError(name)
1523+- elif result is None:
1524+- wraps = None
1525+- if self._mock_wraps is not None:
1526+- # XXXX should we get the attribute without triggering code
1527+- # execution?
1528+- wraps = getattr(self._mock_wraps, name)
1529+-
1530+- result = self._get_child_mock(
1531+- parent=self, name=name, wraps=wraps, _new_name=name,
1532+- _new_parent=self
1533+- )
1534+- self._mock_children[name] = result
1535+-
1536+- elif isinstance(result, _SpecState):
1537+- result = create_autospec(
1538+- result.spec, result.spec_set, result.instance,
1539+- result.parent, result.name
1540+- )
1541+- self._mock_children[name] = result
1542+-
1543+- return result
1544+-
1545+-
1546+- def __repr__(self):
1547+- _name_list = [self._mock_new_name]
1548+- _parent = self._mock_new_parent
1549+- last = self
1550+-
1551+- dot = '.'
1552+- if _name_list == ['()']:
1553+- dot = ''
1554+- seen = set()
1555+- while _parent is not None:
1556+- last = _parent
1557+-
1558+- _name_list.append(_parent._mock_new_name + dot)
1559+- dot = '.'
1560+- if _parent._mock_new_name == '()':
1561+- dot = ''
1562+-
1563+- _parent = _parent._mock_new_parent
1564+-
1565+- # use ids here so as not to call __hash__ on the mocks
1566+- if id(_parent) in seen:
1567+- break
1568+- seen.add(id(_parent))
1569+-
1570+- _name_list = list(reversed(_name_list))
1571+- _first = last._mock_name or 'mock'
1572+- if len(_name_list) > 1:
1573+- if _name_list[1] not in ('()', '().'):
1574+- _first += '.'
1575+- _name_list[0] = _first
1576+- name = ''.join(_name_list)
1577+-
1578+- name_string = ''
1579+- if name not in ('mock', 'mock.'):
1580+- name_string = ' name=%r' % name
1581+-
1582+- spec_string = ''
1583+- if self._spec_class is not None:
1584+- spec_string = ' spec=%r'
1585+- if self._spec_set:
1586+- spec_string = ' spec_set=%r'
1587+- spec_string = spec_string % self._spec_class.__name__
1588+- return "<%s%s%s id='%s'>" % (
1589+- type(self).__name__,
1590+- name_string,
1591+- spec_string,
1592+- id(self)
1593+- )
1594+-
1595+-
1596+- def __dir__(self):
1597+- """Filter the output of `dir(mock)` to only useful members.
1598+- XXXX
1599+- """
1600+- extras = self._mock_methods or []
1601+- from_type = dir(type(self))
1602+- from_dict = list(self.__dict__)
1603+-
1604+- if FILTER_DIR:
1605+- from_type = [e for e in from_type if not e.startswith('_')]
1606+- from_dict = [e for e in from_dict if not e.startswith('_') or
1607+- _is_magic(e)]
1608+- return sorted(set(extras + from_type + from_dict +
1609+- list(self._mock_children)))
1610+-
1611+-
1612+- def __setattr__(self, name, value):
1613+- if name in _allowed_names:
1614+- # property setters go through here
1615+- return object.__setattr__(self, name, value)
1616+- elif (self._spec_set and self._mock_methods is not None and
1617+- name not in self._mock_methods and
1618+- name not in self.__dict__):
1619+- raise AttributeError("Mock object has no attribute '%s'" % name)
1620+- elif name in _unsupported_magics:
1621+- msg = 'Attempting to set unsupported magic method %r.' % name
1622+- raise AttributeError(msg)
1623+- elif name in _all_magics:
1624+- if self._mock_methods is not None and name not in self._mock_methods:
1625+- raise AttributeError("Mock object has no attribute '%s'" % name)
1626+-
1627+- if not _is_instance_mock(value):
1628+- setattr(type(self), name, _get_method(name, value))
1629+- original = value
1630+- value = lambda *args, **kw: original(self, *args, **kw)
1631+- else:
1632+- # only set _new_name and not name so that mock_calls is tracked
1633+- # but not method calls
1634+- _check_and_set_parent(self, value, None, name)
1635+- setattr(type(self), name, value)
1636+- self._mock_children[name] = value
1637+- elif name == '__class__':
1638+- self._spec_class = value
1639+- return
1640+- else:
1641+- if _check_and_set_parent(self, value, name, name):
1642+- self._mock_children[name] = value
1643+- return object.__setattr__(self, name, value)
1644+-
1645+-
1646+- def __delattr__(self, name):
1647+- if name in _all_magics and name in type(self).__dict__:
1648+- delattr(type(self), name)
1649+- if name not in self.__dict__:
1650+- # for magic methods that are still MagicProxy objects and
1651+- # not set on the instance itself
1652+- return
1653+-
1654+- if name in self.__dict__:
1655+- object.__delattr__(self, name)
1656+-
1657+- obj = self._mock_children.get(name, _missing)
1658+- if obj is _deleted:
1659+- raise AttributeError(name)
1660+- if obj is not _missing:
1661+- del self._mock_children[name]
1662+- self._mock_children[name] = _deleted
1663+-
1664+-
1665+-
1666+- def _format_mock_call_signature(self, args, kwargs):
1667+- name = self._mock_name or 'mock'
1668+- return _format_call_signature(name, args, kwargs)
1669+-
1670+-
1671+- def _format_mock_failure_message(self, args, kwargs):
1672+- message = 'Expected call: %s\nActual call: %s'
1673+- expected_string = self._format_mock_call_signature(args, kwargs)
1674+- call_args = self.call_args
1675+- if len(call_args) == 3:
1676+- call_args = call_args[1:]
1677+- actual_string = self._format_mock_call_signature(*call_args)
1678+- return message % (expected_string, actual_string)
1679+-
1680+-
1681+- def assert_called_with(_mock_self, *args, **kwargs):
1682+- """assert that the mock was called with the specified arguments.
1683+-
1684+- Raises an AssertionError if the args and keyword args passed in are
1685+- different to the last call to the mock."""
1686+- self = _mock_self
1687+- if self.call_args is None:
1688+- expected = self._format_mock_call_signature(args, kwargs)
1689+- raise AssertionError('Expected call: %s\nNot called' % (expected,))
1690+-
1691+- if self.call_args != (args, kwargs):
1692+- msg = self._format_mock_failure_message(args, kwargs)
1693+- raise AssertionError(msg)
1694+-
1695+-
1696+- def assert_called_once_with(_mock_self, *args, **kwargs):
1697+- """assert that the mock was called exactly once and with the specified
1698+- arguments."""
1699+- self = _mock_self
1700+- if not self.call_count == 1:
1701+- msg = ("Expected to be called once. Called %s times." %
1702+- self.call_count)
1703+- raise AssertionError(msg)
1704+- return self.assert_called_with(*args, **kwargs)
1705+-
1706+-
1707+- def assert_has_calls(self, calls, any_order=False):
1708+- """assert the mock has been called with the specified calls.
1709+- The `mock_calls` list is checked for the calls.
1710+-
1711+- If `any_order` is False (the default) then the calls must be
1712+- sequential. There can be extra calls before or after the
1713+- specified calls.
1714+-
1715+- If `any_order` is True then the calls can be in any order, but
1716+- they must all appear in `mock_calls`."""
1717+- if not any_order:
1718+- if calls not in self.mock_calls:
1719+- raise AssertionError(
1720+- 'Calls not found.\nExpected: %r\n'
1721+- 'Actual: %r' % (calls, self.mock_calls)
1722+- )
1723+- return
1724+-
1725+- all_calls = list(self.mock_calls)
1726+-
1727+- not_found = []
1728+- for kall in calls:
1729+- try:
1730+- all_calls.remove(kall)
1731+- except ValueError:
1732+- not_found.append(kall)
1733+- if not_found:
1734+- raise AssertionError(
1735+- '%r not all found in call list' % (tuple(not_found),)
1736+- )
1737+-
1738+-
1739+- def assert_any_call(self, *args, **kwargs):
1740+- """assert the mock has been called with the specified arguments.
1741+-
1742+- The assert passes if the mock has *ever* been called, unlike
1743+- `assert_called_with` and `assert_called_once_with` that only pass if
1744+- the call is the most recent one."""
1745+- kall = call(*args, **kwargs)
1746+- if kall not in self.call_args_list:
1747+- expected_string = self._format_mock_call_signature(args, kwargs)
1748+- raise AssertionError(
1749+- '%s call not found' % expected_string
1750+- )
1751+-
1752+-
1753+- def _get_child_mock(self, **kw):
1754+- """Create the child mocks for attributes and return value.
1755+- By default child mocks will be the same type as the parent.
1756+- Subclasses of Mock may want to override this to customize the way
1757+- child mocks are made.
1758+-
1759+- For non-callable mocks the callable variant will be used (rather than
1760+- any custom subclass)."""
1761+- _type = type(self)
1762+- if not issubclass(_type, CallableMixin):
1763+- if issubclass(_type, NonCallableMagicMock):
1764+- klass = MagicMock
1765+- elif issubclass(_type, NonCallableMock) :
1766+- klass = Mock
1767+- else:
1768+- klass = _type.__mro__[1]
1769+- return klass(**kw)
1770+-
1771+-
1772+-
1773+-def _try_iter(obj):
1774+- if obj is None:
1775+- return obj
1776+- if _is_exception(obj):
1777+- return obj
1778+- if _callable(obj):
1779+- return obj
1780+- try:
1781+- return iter(obj)
1782+- except TypeError:
1783+- # XXXX backwards compatibility
1784+- # but this will blow up on first call - so maybe we should fail early?
1785+- return obj
1786+-
1787+-
1788+-
1789+-class CallableMixin(Base):
1790+-
1791+- def __init__(self, spec=None, side_effect=None, return_value=DEFAULT,
1792+- wraps=None, name=None, spec_set=None, parent=None,
1793+- _spec_state=None, _new_name='', _new_parent=None, **kwargs):
1794+- self.__dict__['_mock_return_value'] = return_value
1795+-
1796+- _super(CallableMixin, self).__init__(
1797+- spec, wraps, name, spec_set, parent,
1798+- _spec_state, _new_name, _new_parent, **kwargs
1799+- )
1800+-
1801+- self.side_effect = side_effect
1802+-
1803+-
1804+- def _mock_check_sig(self, *args, **kwargs):
1805+- # stub method that can be replaced with one with a specific signature
1806+- pass
1807+-
1808+-
1809+- def __call__(_mock_self, *args, **kwargs):
1810+- # can't use self in-case a function / method we are mocking uses self
1811+- # in the signature
1812+- _mock_self._mock_check_sig(*args, **kwargs)
1813+- return _mock_self._mock_call(*args, **kwargs)
1814+-
1815+-
1816+- def _mock_call(_mock_self, *args, **kwargs):
1817+- self = _mock_self
1818+- self.called = True
1819+- self.call_count += 1
1820+- self.call_args = _Call((args, kwargs), two=True)
1821+- self.call_args_list.append(_Call((args, kwargs), two=True))
1822+-
1823+- _new_name = self._mock_new_name
1824+- _new_parent = self._mock_new_parent
1825+- self.mock_calls.append(_Call(('', args, kwargs)))
1826+-
1827+- seen = set()
1828+- skip_next_dot = _new_name == '()'
1829+- do_method_calls = self._mock_parent is not None
1830+- name = self._mock_name
1831+- while _new_parent is not None:
1832+- this_mock_call = _Call((_new_name, args, kwargs))
1833+- if _new_parent._mock_new_name:
1834+- dot = '.'
1835+- if skip_next_dot:
1836+- dot = ''
1837+-
1838+- skip_next_dot = False
1839+- if _new_parent._mock_new_name == '()':
1840+- skip_next_dot = True
1841+-
1842+- _new_name = _new_parent._mock_new_name + dot + _new_name
1843+-
1844+- if do_method_calls:
1845+- if _new_name == name:
1846+- this_method_call = this_mock_call
1847+- else:
1848+- this_method_call = _Call((name, args, kwargs))
1849+- _new_parent.method_calls.append(this_method_call)
1850+-
1851+- do_method_calls = _new_parent._mock_parent is not None
1852+- if do_method_calls:
1853+- name = _new_parent._mock_name + '.' + name
1854+-
1855+- _new_parent.mock_calls.append(this_mock_call)
1856+- _new_parent = _new_parent._mock_new_parent
1857+-
1858+- # use ids here so as not to call __hash__ on the mocks
1859+- _new_parent_id = id(_new_parent)
1860+- if _new_parent_id in seen:
1861+- break
1862+- seen.add(_new_parent_id)
1863+-
1864+- ret_val = DEFAULT
1865+- effect = self.side_effect
1866+- if effect is not None:
1867+- if _is_exception(effect):
1868+- raise effect
1869+-
1870+- if not _callable(effect):
1871+- result = next(effect)
1872+- if _is_exception(result):
1873+- raise result
1874+- return result
1875+-
1876+- ret_val = effect(*args, **kwargs)
1877+- if ret_val is DEFAULT:
1878+- ret_val = self.return_value
1879+-
1880+- if (self._mock_wraps is not None and
1881+- self._mock_return_value is DEFAULT):
1882+- return self._mock_wraps(*args, **kwargs)
1883+- if ret_val is DEFAULT:
1884+- ret_val = self.return_value
1885+- return ret_val
1886+-
1887+-
1888+-
1889+-class Mock(CallableMixin, NonCallableMock):
1890+- """
1891+- Create a new `Mock` object. `Mock` takes several optional arguments
1892+- that specify the behaviour of the Mock object:
1893+-
1894+- * `spec`: This can be either a list of strings or an existing object (a
1895+- class or instance) that acts as the specification for the mock object. If
1896+- you pass in an object then a list of strings is formed by calling dir on
1897+- the object (excluding unsupported magic attributes and methods). Accessing
1898+- any attribute not in this list will raise an `AttributeError`.
1899+-
1900+- If `spec` is an object (rather than a list of strings) then
1901+- `mock.__class__` returns the class of the spec object. This allows mocks
1902+- to pass `isinstance` tests.
1903+-
1904+- * `spec_set`: A stricter variant of `spec`. If used, attempting to *set*
1905+- or get an attribute on the mock that isn't on the object passed as
1906+- `spec_set` will raise an `AttributeError`.
1907+-
1908+- * `side_effect`: A function to be called whenever the Mock is called. See
1909+- the `side_effect` attribute. Useful for raising exceptions or
1910+- dynamically changing return values. The function is called with the same
1911+- arguments as the mock, and unless it returns `DEFAULT`, the return
1912+- value of this function is used as the return value.
1913+-
1914+- Alternatively `side_effect` can be an exception class or instance. In
1915+- this case the exception will be raised when the mock is called.
1916+-
1917+- If `side_effect` is an iterable then each call to the mock will return
1918+- the next value from the iterable. If any of the members of the iterable
1919+- are exceptions they will be raised instead of returned.
1920+-
1921+- * `return_value`: The value returned when the mock is called. By default
1922+- this is a new Mock (created on first access). See the
1923+- `return_value` attribute.
1924+-
1925+- * `wraps`: Item for the mock object to wrap. If `wraps` is not None then
1926+- calling the Mock will pass the call through to the wrapped object
1927+- (returning the real result). Attribute access on the mock will return a
1928+- Mock object that wraps the corresponding attribute of the wrapped object
1929+- (so attempting to access an attribute that doesn't exist will raise an
1930+- `AttributeError`).
1931+-
1932+- If the mock has an explicit `return_value` set then calls are not passed
1933+- to the wrapped object and the `return_value` is returned instead.
1934+-
1935+- * `name`: If the mock has a name then it will be used in the repr of the
1936+- mock. This can be useful for debugging. The name is propagated to child
1937+- mocks.
1938+-
1939+- Mocks can also be called with arbitrary keyword arguments. These will be
1940+- used to set attributes on the mock after it is created.
1941+- """
1942+-
1943+-
1944+-
1945+-def _dot_lookup(thing, comp, import_path):
1946+- try:
1947+- return getattr(thing, comp)
1948+- except AttributeError:
1949+- __import__(import_path)
1950+- return getattr(thing, comp)
1951+-
1952+-
1953+-def _importer(target):
1954+- components = target.split('.')
1955+- import_path = components.pop(0)
1956+- thing = __import__(import_path)
1957+-
1958+- for comp in components:
1959+- import_path += ".%s" % comp
1960+- thing = _dot_lookup(thing, comp, import_path)
1961+- return thing
1962+-
1963+-
1964+-def _is_started(patcher):
1965+- # XXXX horrible
1966+- return hasattr(patcher, 'is_local')
1967+-
1968+-
1969+-class _patch(object):
1970+-
1971+- attribute_name = None
1972+- _active_patches = set()
1973+-
1974+- def __init__(
1975+- self, getter, attribute, new, spec, create,
1976+- spec_set, autospec, new_callable, kwargs
1977+- ):
1978+- if new_callable is not None:
1979+- if new is not DEFAULT:
1980+- raise ValueError(
1981+- "Cannot use 'new' and 'new_callable' together"
1982+- )
1983+- if autospec is not None:
1984+- raise ValueError(
1985+- "Cannot use 'autospec' and 'new_callable' together"
1986+- )
1987+-
1988+- self.getter = getter
1989+- self.attribute = attribute
1990+- self.new = new
1991+- self.new_callable = new_callable
1992+- self.spec = spec
1993+- self.create = create
1994+- self.has_local = False
1995+- self.spec_set = spec_set
1996+- self.autospec = autospec
1997+- self.kwargs = kwargs
1998+- self.additional_patchers = []
1999+-
2000+-
2001+- def copy(self):
2002+- patcher = _patch(
2003+- self.getter, self.attribute, self.new, self.spec,
2004+- self.create, self.spec_set,
2005+- self.autospec, self.new_callable, self.kwargs
2006+- )
2007+- patcher.attribute_name = self.attribute_name
2008+- patcher.additional_patchers = [
2009+- p.copy() for p in self.additional_patchers
2010+- ]
2011+- return patcher
2012+-
2013+-
2014+- def __call__(self, func):
2015+- if isinstance(func, ClassTypes):
2016+- return self.decorate_class(func)
2017+- return self.decorate_callable(func)
2018+-
2019+-
2020+- def decorate_class(self, klass):
2021+- for attr in dir(klass):
2022+- if not attr.startswith(patch.TEST_PREFIX):
2023+- continue
2024+-
2025+- attr_value = getattr(klass, attr)
2026+- if not hasattr(attr_value, "__call__"):
2027+- continue
2028+-
2029+- patcher = self.copy()
2030+- setattr(klass, attr, patcher(attr_value))
2031+- return klass
2032+-
2033+-
2034+- def decorate_callable(self, func):
2035+- if hasattr(func, 'patchings'):
2036+- func.patchings.append(self)
2037+- return func
2038+-
2039+- @wraps(func)
2040+- def patched(*args, **keywargs):
2041+- # don't use a with here (backwards compatability with Python 2.4)
2042+- extra_args = []
2043+- entered_patchers = []
2044+-
2045+- # can't use try...except...finally because of Python 2.4
2046+- # compatibility
2047+- exc_info = tuple()
2048+- try:
2049+- try:
2050+- for patching in patched.patchings:
2051+- arg = patching.__enter__()
2052+- entered_patchers.append(patching)
2053+- if patching.attribute_name is not None:
2054+- keywargs.update(arg)
2055+- elif patching.new is DEFAULT:
2056+- extra_args.append(arg)
2057+-
2058+- args += tuple(extra_args)
2059+- return func(*args, **keywargs)
2060+- except:
2061+- if (patching not in entered_patchers and
2062+- _is_started(patching)):
2063+- # the patcher may have been started, but an exception
2064+- # raised whilst entering one of its additional_patchers
2065+- entered_patchers.append(patching)
2066+- # Pass the exception to __exit__
2067+- exc_info = sys.exc_info()
2068+- # re-raise the exception
2069+- raise
2070+- finally:
2071+- for patching in reversed(entered_patchers):
2072+- patching.__exit__(*exc_info)
2073+-
2074+- patched.patchings = [self]
2075+- if hasattr(func, 'func_code'):
2076+- # not in Python 3
2077+- patched.compat_co_firstlineno = getattr(
2078+- func, "compat_co_firstlineno",
2079+- func.func_code.co_firstlineno
2080+- )
2081+- return patched
2082+-
2083+-
2084+- def get_original(self):
2085+- target = self.getter()
2086+- name = self.attribute
2087+-
2088+- original = DEFAULT
2089+- local = False
2090+-
2091+- try:
2092+- original = target.__dict__[name]
2093+- except (AttributeError, KeyError):
2094+- original = getattr(target, name, DEFAULT)
2095+- else:
2096+- local = True
2097+-
2098+- if not self.create and original is DEFAULT:
2099+- raise AttributeError(
2100+- "%s does not have the attribute %r" % (target, name)
2101+- )
2102+- return original, local
2103+-
2104+-
2105+- def __enter__(self):
2106+- """Perform the patch."""
2107+- new, spec, spec_set = self.new, self.spec, self.spec_set
2108+- autospec, kwargs = self.autospec, self.kwargs
2109+- new_callable = self.new_callable
2110+- self.target = self.getter()
2111+-
2112+- # normalise False to None
2113+- if spec is False:
2114+- spec = None
2115+- if spec_set is False:
2116+- spec_set = None
2117+- if autospec is False:
2118+- autospec = None
2119+-
2120+- if spec is not None and autospec is not None:
2121+- raise TypeError("Can't specify spec and autospec")
2122+- if ((spec is not None or autospec is not None) and
2123+- spec_set not in (True, None)):
2124+- raise TypeError("Can't provide explicit spec_set *and* spec or autospec")
2125+-
2126+- original, local = self.get_original()
2127+-
2128+- if new is DEFAULT and autospec is None:
2129+- inherit = False
2130+- if spec is True:
2131+- # set spec to the object we are replacing
2132+- spec = original
2133+- if spec_set is True:
2134+- spec_set = original
2135+- spec = None
2136+- elif spec is not None:
2137+- if spec_set is True:
2138+- spec_set = spec
2139+- spec = None
2140+- elif spec_set is True:
2141+- spec_set = original
2142+-
2143+- if spec is not None or spec_set is not None:
2144+- if original is DEFAULT:
2145+- raise TypeError("Can't use 'spec' with create=True")
2146+- if isinstance(original, ClassTypes):
2147+- # If we're patching out a class and there is a spec
2148+- inherit = True
2149+-
2150+- Klass = MagicMock
2151+- _kwargs = {}
2152+- if new_callable is not None:
2153+- Klass = new_callable
2154+- elif spec is not None or spec_set is not None:
2155+- this_spec = spec
2156+- if spec_set is not None:
2157+- this_spec = spec_set
2158+- if _is_list(this_spec):
2159+- not_callable = '__call__' not in this_spec
2160+- else:
2161+- not_callable = not _callable(this_spec)
2162+- if not_callable:
2163+- Klass = NonCallableMagicMock
2164+-
2165+- if spec is not None:
2166+- _kwargs['spec'] = spec
2167+- if spec_set is not None:
2168+- _kwargs['spec_set'] = spec_set
2169+-
2170+- # add a name to mocks
2171+- if (isinstance(Klass, type) and
2172+- issubclass(Klass, NonCallableMock) and self.attribute):
2173+- _kwargs['name'] = self.attribute
2174+-
2175+- _kwargs.update(kwargs)
2176+- new = Klass(**_kwargs)
2177+-
2178+- if inherit and _is_instance_mock(new):
2179+- # we can only tell if the instance should be callable if the
2180+- # spec is not a list
2181+- this_spec = spec
2182+- if spec_set is not None:
2183+- this_spec = spec_set
2184+- if (not _is_list(this_spec) and not
2185+- _instance_callable(this_spec)):
2186+- Klass = NonCallableMagicMock
2187+-
2188+- _kwargs.pop('name')
2189+- new.return_value = Klass(_new_parent=new, _new_name='()',
2190+- **_kwargs)
2191+- elif autospec is not None:
2192+- # spec is ignored, new *must* be default, spec_set is treated
2193+- # as a boolean. Should we check spec is not None and that spec_set
2194+- # is a bool?
2195+- if new is not DEFAULT:
2196+- raise TypeError(
2197+- "autospec creates the mock for you. Can't specify "
2198+- "autospec and new."
2199+- )
2200+- if original is DEFAULT:
2201+- raise TypeError("Can't use 'autospec' with create=True")
2202+- spec_set = bool(spec_set)
2203+- if autospec is True:
2204+- autospec = original
2205+-
2206+- new = create_autospec(autospec, spec_set=spec_set,
2207+- _name=self.attribute, **kwargs)
2208+- elif kwargs:
2209+- # can't set keyword args when we aren't creating the mock
2210+- # XXXX If new is a Mock we could call new.configure_mock(**kwargs)
2211+- raise TypeError("Can't pass kwargs to a mock we aren't creating")
2212+-
2213+- new_attr = new
2214+-
2215+- self.temp_original = original
2216+- self.is_local = local
2217+- setattr(self.target, self.attribute, new_attr)
2218+- if self.attribute_name is not None:
2219+- extra_args = {}
2220+- if self.new is DEFAULT:
2221+- extra_args[self.attribute_name] = new
2222+- for patching in self.additional_patchers:
2223+- arg = patching.__enter__()
2224+- if patching.new is DEFAULT:
2225+- extra_args.update(arg)
2226+- return extra_args
2227+-
2228+- return new
2229+-
2230+-
2231+- def __exit__(self, *exc_info):
2232+- """Undo the patch."""
2233+- if not _is_started(self):
2234+- raise RuntimeError('stop called on unstarted patcher')
2235+-
2236+- if self.is_local and self.temp_original is not DEFAULT:
2237+- setattr(self.target, self.attribute, self.temp_original)
2238+- else:
2239+- delattr(self.target, self.attribute)
2240+- if not self.create and not hasattr(self.target, self.attribute):
2241+- # needed for proxy objects like django settings
2242+- setattr(self.target, self.attribute, self.temp_original)
2243+-
2244+- del self.temp_original
2245+- del self.is_local
2246+- del self.target
2247+- for patcher in reversed(self.additional_patchers):
2248+- if _is_started(patcher):
2249+- patcher.__exit__(*exc_info)
2250+-
2251+-
2252+- def start(self):
2253+- """Activate a patch, returning any created mock."""
2254+- result = self.__enter__()
2255+- self._active_patches.add(self)
2256+- return result
2257+-
2258+-
2259+- def stop(self):
2260+- """Stop an active patch."""
2261+- self._active_patches.discard(self)
2262+- return self.__exit__()
2263+-
2264+-
2265+-
2266+-def _get_target(target):
2267+- try:
2268+- target, attribute = target.rsplit('.', 1)
2269+- except (TypeError, ValueError):
2270+- raise TypeError("Need a valid target to patch. You supplied: %r" %
2271+- (target,))
2272+- getter = lambda: _importer(target)
2273+- return getter, attribute
2274+-
2275+-
2276+-def _patch_object(
2277+- target, attribute, new=DEFAULT, spec=None,
2278+- create=False, spec_set=None, autospec=None,
2279+- new_callable=None, **kwargs
2280+- ):
2281+- """
2282+- patch.object(target, attribute, new=DEFAULT, spec=None, create=False,
2283+- spec_set=None, autospec=None, new_callable=None, **kwargs)
2284+-
2285+- patch the named member (`attribute`) on an object (`target`) with a mock
2286+- object.
2287+-
2288+- `patch.object` can be used as a decorator, class decorator or a context
2289+- manager. Arguments `new`, `spec`, `create`, `spec_set`,
2290+- `autospec` and `new_callable` have the same meaning as for `patch`. Like
2291+- `patch`, `patch.object` takes arbitrary keyword arguments for configuring
2292+- the mock object it creates.
2293+-
2294+- When used as a class decorator `patch.object` honours `patch.TEST_PREFIX`
2295+- for choosing which methods to wrap.
2296+- """
2297+- getter = lambda: target
2298+- return _patch(
2299+- getter, attribute, new, spec, create,
2300+- spec_set, autospec, new_callable, kwargs
2301+- )
2302+-
2303+-
2304+-def _patch_multiple(target, spec=None, create=False, spec_set=None,
2305+- autospec=None, new_callable=None, **kwargs):
2306+- """Perform multiple patches in a single call. It takes the object to be
2307+- patched (either as an object or a string to fetch the object by importing)
2308+- and keyword arguments for the patches::
2309+-
2310+- with patch.multiple(settings, FIRST_PATCH='one', SECOND_PATCH='two'):
2311+- ...
2312+-
2313+- Use `DEFAULT` as the value if you want `patch.multiple` to create
2314+- mocks for you. In this case the created mocks are passed into a decorated
2315+- function by keyword, and a dictionary is returned when `patch.multiple` is
2316+- used as a context manager.
2317+-
2318+- `patch.multiple` can be used as a decorator, class decorator or a context
2319+- manager. The arguments `spec`, `spec_set`, `create`,
2320+- `autospec` and `new_callable` have the same meaning as for `patch`. These
2321+- arguments will be applied to *all* patches done by `patch.multiple`.
2322+-
2323+- When used as a class decorator `patch.multiple` honours `patch.TEST_PREFIX`
2324+- for choosing which methods to wrap.
2325+- """
2326+- if type(target) in (unicode, str):
2327+- getter = lambda: _importer(target)
2328+- else:
2329+- getter = lambda: target
2330+-
2331+- if not kwargs:
2332+- raise ValueError(
2333+- 'Must supply at least one keyword argument with patch.multiple'
2334+- )
2335+- # need to wrap in a list for python 3, where items is a view
2336+- items = list(kwargs.items())
2337+- attribute, new = items[0]
2338+- patcher = _patch(
2339+- getter, attribute, new, spec, create, spec_set,
2340+- autospec, new_callable, {}
2341+- )
2342+- patcher.attribute_name = attribute
2343+- for attribute, new in items[1:]:
2344+- this_patcher = _patch(
2345+- getter, attribute, new, spec, create, spec_set,
2346+- autospec, new_callable, {}
2347+- )
2348+- this_patcher.attribute_name = attribute
2349+- patcher.additional_patchers.append(this_patcher)
2350+- return patcher
2351+-
2352+-
2353+-def patch(
2354+- target, new=DEFAULT, spec=None, create=False,
2355+- spec_set=None, autospec=None, new_callable=None, **kwargs
2356+- ):
2357+- """
2358+- `patch` acts as a function decorator, class decorator or a context
2359+- manager. Inside the body of the function or with statement, the `target`
2360+- is patched with a `new` object. When the function/with statement exits
2361+- the patch is undone.
2362+-
2363+- If `new` is omitted, then the target is replaced with a
2364+- `MagicMock`. If `patch` is used as a decorator and `new` is
2365+- omitted, the created mock is passed in as an extra argument to the
2366+- decorated function. If `patch` is used as a context manager the created
2367+- mock is returned by the context manager.
2368+-
2369+- `target` should be a string in the form `'package.module.ClassName'`. The
2370+- `target` is imported and the specified object replaced with the `new`
2371+- object, so the `target` must be importable from the environment you are
2372+- calling `patch` from. The target is imported when the decorated function
2373+- is executed, not at decoration time.
2374+-
2375+- The `spec` and `spec_set` keyword arguments are passed to the `MagicMock`
2376+- if patch is creating one for you.
2377+-
2378+- In addition you can pass `spec=True` or `spec_set=True`, which causes
2379+- patch to pass in the object being mocked as the spec/spec_set object.
2380+-
2381+- `new_callable` allows you to specify a different class, or callable object,
2382+- that will be called to create the `new` object. By default `MagicMock` is
2383+- used.
2384+-
2385+- A more powerful form of `spec` is `autospec`. If you set `autospec=True`
2386+- then the mock with be created with a spec from the object being replaced.
2387+- All attributes of the mock will also have the spec of the corresponding
2388+- attribute of the object being replaced. Methods and functions being
2389+- mocked will have their arguments checked and will raise a `TypeError` if
2390+- they are called with the wrong signature. For mocks replacing a class,
2391+- their return value (the 'instance') will have the same spec as the class.
2392+-
2393+- Instead of `autospec=True` you can pass `autospec=some_object` to use an
2394+- arbitrary object as the spec instead of the one being replaced.
2395+-
2396+- By default `patch` will fail to replace attributes that don't exist. If
2397+- you pass in `create=True`, and the attribute doesn't exist, patch will
2398+- create the attribute for you when the patched function is called, and
2399+- delete it again afterwards. This is useful for writing tests against
2400+- attributes that your production code creates at runtime. It is off by by
2401+- default because it can be dangerous. With it switched on you can write
2402+- passing tests against APIs that don't actually exist!
2403+-
2404+- Patch can be used as a `TestCase` class decorator. It works by
2405+- decorating each test method in the class. This reduces the boilerplate
2406+- code when your test methods share a common patchings set. `patch` finds
2407+- tests by looking for method names that start with `patch.TEST_PREFIX`.
2408+- By default this is `test`, which matches the way `unittest` finds tests.
2409+- You can specify an alternative prefix by setting `patch.TEST_PREFIX`.
2410+-
2411+- Patch can be used as a context manager, with the with statement. Here the
2412+- patching applies to the indented block after the with statement. If you
2413+- use "as" then the patched object will be bound to the name after the
2414+- "as"; very useful if `patch` is creating a mock object for you.
2415+-
2416+- `patch` takes arbitrary keyword arguments. These will be passed to
2417+- the `Mock` (or `new_callable`) on construction.
2418+-
2419+- `patch.dict(...)`, `patch.multiple(...)` and `patch.object(...)` are
2420+- available for alternate use-cases.
2421+- """
2422+- getter, attribute = _get_target(target)
2423+- return _patch(
2424+- getter, attribute, new, spec, create,
2425+- spec_set, autospec, new_callable, kwargs
2426+- )
2427+-
2428+-
2429+-class _patch_dict(object):
2430+- """
2431+- Patch a dictionary, or dictionary like object, and restore the dictionary
2432+- to its original state after the test.
2433+-
2434+- `in_dict` can be a dictionary or a mapping like container. If it is a
2435+- mapping then it must at least support getting, setting and deleting items
2436+- plus iterating over keys.
2437+-
2438+- `in_dict` can also be a string specifying the name of the dictionary, which
2439+- will then be fetched by importing it.
2440+-
2441+- `values` can be a dictionary of values to set in the dictionary. `values`
2442+- can also be an iterable of `(key, value)` pairs.
2443+-
2444+- If `clear` is True then the dictionary will be cleared before the new
2445+- values are set.
2446+-
2447+- `patch.dict` can also be called with arbitrary keyword arguments to set
2448+- values in the dictionary::
2449+-
2450+- with patch.dict('sys.modules', mymodule=Mock(), other_module=Mock()):
2451+- ...
2452+-
2453+- `patch.dict` can be used as a context manager, decorator or class
2454+- decorator. When used as a class decorator `patch.dict` honours
2455+- `patch.TEST_PREFIX` for choosing which methods to wrap.
2456+- """
2457+-
2458+- def __init__(self, in_dict, values=(), clear=False, **kwargs):
2459+- if isinstance(in_dict, basestring):
2460+- in_dict = _importer(in_dict)
2461+- self.in_dict = in_dict
2462+- # support any argument supported by dict(...) constructor
2463+- self.values = dict(values)
2464+- self.values.update(kwargs)
2465+- self.clear = clear
2466+- self._original = None
2467+-
2468+-
2469+- def __call__(self, f):
2470+- if isinstance(f, ClassTypes):
2471+- return self.decorate_class(f)
2472+- @wraps(f)
2473+- def _inner(*args, **kw):
2474+- self._patch_dict()
2475+- try:
2476+- return f(*args, **kw)
2477+- finally:
2478+- self._unpatch_dict()
2479+-
2480+- return _inner
2481+-
2482+-
2483+- def decorate_class(self, klass):
2484+- for attr in dir(klass):
2485+- attr_value = getattr(klass, attr)
2486+- if (attr.startswith(patch.TEST_PREFIX) and
2487+- hasattr(attr_value, "__call__")):
2488+- decorator = _patch_dict(self.in_dict, self.values, self.clear)
2489+- decorated = decorator(attr_value)
2490+- setattr(klass, attr, decorated)
2491+- return klass
2492+-
2493+-
2494+- def __enter__(self):
2495+- """Patch the dict."""
2496+- self._patch_dict()
2497+-
2498+-
2499+- def _patch_dict(self):
2500+- values = self.values
2501+- in_dict = self.in_dict
2502+- clear = self.clear
2503+-
2504+- try:
2505+- original = in_dict.copy()
2506+- except AttributeError:
2507+- # dict like object with no copy method
2508+- # must support iteration over keys
2509+- original = {}
2510+- for key in in_dict:
2511+- original[key] = in_dict[key]
2512+- self._original = original
2513+-
2514+- if clear:
2515+- _clear_dict(in_dict)
2516+-
2517+- try:
2518+- in_dict.update(values)
2519+- except AttributeError:
2520+- # dict like object with no update method
2521+- for key in values:
2522+- in_dict[key] = values[key]
2523+-
2524+-
2525+- def _unpatch_dict(self):
2526+- in_dict = self.in_dict
2527+- original = self._original
2528+-
2529+- _clear_dict(in_dict)
2530+-
2531+- try:
2532+- in_dict.update(original)
2533+- except AttributeError:
2534+- for key in original:
2535+- in_dict[key] = original[key]
2536+-
2537+-
2538+- def __exit__(self, *args):
2539+- """Unpatch the dict."""
2540+- self._unpatch_dict()
2541+- return False
2542+-
2543+- start = __enter__
2544+- stop = __exit__
2545+-
2546+-
2547+-def _clear_dict(in_dict):
2548+- try:
2549+- in_dict.clear()
2550+- except AttributeError:
2551+- keys = list(in_dict)
2552+- for key in keys:
2553+- del in_dict[key]
2554+-
2555+-
2556+-def _patch_stopall():
2557+- """Stop all active patches."""
2558+- for patch in list(_patch._active_patches):
2559+- patch.stop()
2560+-
2561+-
2562+-patch.object = _patch_object
2563+-patch.dict = _patch_dict
2564+-patch.multiple = _patch_multiple
2565+-patch.stopall = _patch_stopall
2566+-patch.TEST_PREFIX = 'test'
2567+-
2568+-magic_methods = (
2569+- "lt le gt ge eq ne "
2570+- "getitem setitem delitem "
2571+- "len contains iter "
2572+- "hash str sizeof "
2573+- "enter exit "
2574+- "divmod neg pos abs invert "
2575+- "complex int float index "
2576+- "trunc floor ceil "
2577+-)
2578+-
2579+-numerics = "add sub mul div floordiv mod lshift rshift and xor or pow "
2580+-inplace = ' '.join('i%s' % n for n in numerics.split())
2581+-right = ' '.join('r%s' % n for n in numerics.split())
2582+-extra = ''
2583+-if inPy3k:
2584+- extra = 'bool next '
2585+-else:
2586+- extra = 'unicode long nonzero oct hex truediv rtruediv '
2587+-
2588+-# not including __prepare__, __instancecheck__, __subclasscheck__
2589+-# (as they are metaclass methods)
2590+-# __del__ is not supported at all as it causes problems if it exists
2591+-
2592+-_non_defaults = set('__%s__' % method for method in [
2593+- 'cmp', 'getslice', 'setslice', 'coerce', 'subclasses',
2594+- 'format', 'get', 'set', 'delete', 'reversed',
2595+- 'missing', 'reduce', 'reduce_ex', 'getinitargs',
2596+- 'getnewargs', 'getstate', 'setstate', 'getformat',
2597+- 'setformat', 'repr', 'dir'
2598+-])
2599+-
2600+-
2601+-def _get_method(name, func):
2602+- "Turns a callable object (like a mock) into a real function"
2603+- def method(self, *args, **kw):
2604+- return func(self, *args, **kw)
2605+- method.__name__ = name
2606+- return method
2607+-
2608+-
2609+-_magics = set(
2610+- '__%s__' % method for method in
2611+- ' '.join([magic_methods, numerics, inplace, right, extra]).split()
2612+-)
2613+-
2614+-_all_magics = _magics | _non_defaults
2615+-
2616+-_unsupported_magics = set([
2617+- '__getattr__', '__setattr__',
2618+- '__init__', '__new__', '__prepare__'
2619+- '__instancecheck__', '__subclasscheck__',
2620+- '__del__'
2621+-])
2622+-
2623+-_calculate_return_value = {
2624+- '__hash__': lambda self: object.__hash__(self),
2625+- '__str__': lambda self: object.__str__(self),
2626+- '__sizeof__': lambda self: object.__sizeof__(self),
2627+- '__unicode__': lambda self: unicode(object.__str__(self)),
2628+-}
2629+-
2630+-_return_values = {
2631+- '__lt__': NotImplemented,
2632+- '__gt__': NotImplemented,
2633+- '__le__': NotImplemented,
2634+- '__ge__': NotImplemented,
2635+- '__int__': 1,
2636+- '__contains__': False,
2637+- '__len__': 0,
2638+- '__exit__': False,
2639+- '__complex__': 1j,
2640+- '__float__': 1.0,
2641+- '__bool__': True,
2642+- '__nonzero__': True,
2643+- '__oct__': '1',
2644+- '__hex__': '0x1',
2645+- '__long__': long(1),
2646+- '__index__': 1,
2647+-}
2648+-
2649+-
2650+-def _get_eq(self):
2651+- def __eq__(other):
2652+- ret_val = self.__eq__._mock_return_value
2653+- if ret_val is not DEFAULT:
2654+- return ret_val
2655+- return self is other
2656+- return __eq__
2657+-
2658+-def _get_ne(self):
2659+- def __ne__(other):
2660+- if self.__ne__._mock_return_value is not DEFAULT:
2661+- return DEFAULT
2662+- return self is not other
2663+- return __ne__
2664+-
2665+-def _get_iter(self):
2666+- def __iter__():
2667+- ret_val = self.__iter__._mock_return_value
2668+- if ret_val is DEFAULT:
2669+- return iter([])
2670+- # if ret_val was already an iterator, then calling iter on it should
2671+- # return the iterator unchanged
2672+- return iter(ret_val)
2673+- return __iter__
2674+-
2675+-_side_effect_methods = {
2676+- '__eq__': _get_eq,
2677+- '__ne__': _get_ne,
2678+- '__iter__': _get_iter,
2679+-}
2680+-
2681+-
2682+-
2683+-def _set_return_value(mock, method, name):
2684+- fixed = _return_values.get(name, DEFAULT)
2685+- if fixed is not DEFAULT:
2686+- method.return_value = fixed
2687+- return
2688+-
2689+- return_calulator = _calculate_return_value.get(name)
2690+- if return_calulator is not None:
2691+- try:
2692+- return_value = return_calulator(mock)
2693+- except AttributeError:
2694+- # XXXX why do we return AttributeError here?
2695+- # set it as a side_effect instead?
2696+- return_value = AttributeError(name)
2697+- method.return_value = return_value
2698+- return
2699+-
2700+- side_effector = _side_effect_methods.get(name)
2701+- if side_effector is not None:
2702+- method.side_effect = side_effector(mock)
2703+-
2704+-
2705+-
2706+-class MagicMixin(object):
2707+- def __init__(self, *args, **kw):
2708+- _super(MagicMixin, self).__init__(*args, **kw)
2709+- self._mock_set_magics()
2710+-
2711+-
2712+- def _mock_set_magics(self):
2713+- these_magics = _magics
2714+-
2715+- if self._mock_methods is not None:
2716+- these_magics = _magics.intersection(self._mock_methods)
2717+-
2718+- remove_magics = set()
2719+- remove_magics = _magics - these_magics
2720+-
2721+- for entry in remove_magics:
2722+- if entry in type(self).__dict__:
2723+- # remove unneeded magic methods
2724+- delattr(self, entry)
2725+-
2726+- # don't overwrite existing attributes if called a second time
2727+- these_magics = these_magics - set(type(self).__dict__)
2728+-
2729+- _type = type(self)
2730+- for entry in these_magics:
2731+- setattr(_type, entry, MagicProxy(entry, self))
2732+-
2733+-
2734+-
2735+-class NonCallableMagicMock(MagicMixin, NonCallableMock):
2736+- """A version of `MagicMock` that isn't callable."""
2737+- def mock_add_spec(self, spec, spec_set=False):
2738+- """Add a spec to a mock. `spec` can either be an object or a
2739+- list of strings. Only attributes on the `spec` can be fetched as
2740+- attributes from the mock.
2741+-
2742+- If `spec_set` is True then only attributes on the spec can be set."""
2743+- self._mock_add_spec(spec, spec_set)
2744+- self._mock_set_magics()
2745+-
2746+-
2747+-
2748+-class MagicMock(MagicMixin, Mock):
2749+- """
2750+- MagicMock is a subclass of Mock with default implementations
2751+- of most of the magic methods. You can use MagicMock without having to
2752+- configure the magic methods yourself.
2753+-
2754+- If you use the `spec` or `spec_set` arguments then *only* magic
2755+- methods that exist in the spec will be created.
2756+-
2757+- Attributes and the return value of a `MagicMock` will also be `MagicMocks`.
2758+- """
2759+- def mock_add_spec(self, spec, spec_set=False):
2760+- """Add a spec to a mock. `spec` can either be an object or a
2761+- list of strings. Only attributes on the `spec` can be fetched as
2762+- attributes from the mock.
2763+-
2764+- If `spec_set` is True then only attributes on the spec can be set."""
2765+- self._mock_add_spec(spec, spec_set)
2766+- self._mock_set_magics()
2767+-
2768+-
2769+-
2770+-class MagicProxy(object):
2771+- def __init__(self, name, parent):
2772+- self.name = name
2773+- self.parent = parent
2774+-
2775+- def __call__(self, *args, **kwargs):
2776+- m = self.create_mock()
2777+- return m(*args, **kwargs)
2778+-
2779+- def create_mock(self):
2780+- entry = self.name
2781+- parent = self.parent
2782+- m = parent._get_child_mock(name=entry, _new_name=entry,
2783+- _new_parent=parent)
2784+- setattr(parent, entry, m)
2785+- _set_return_value(parent, m, entry)
2786+- return m
2787+-
2788+- def __get__(self, obj, _type=None):
2789+- return self.create_mock()
2790+-
2791+-
2792+-
2793+-class _ANY(object):
2794+- "A helper object that compares equal to everything."
2795+-
2796+- def __eq__(self, other):
2797+- return True
2798+-
2799+- def __ne__(self, other):
2800+- return False
2801+-
2802+- def __repr__(self):
2803+- return '<ANY>'
2804+-
2805+-ANY = _ANY()
2806+-
2807+-
2808+-
2809+-def _format_call_signature(name, args, kwargs):
2810+- message = '%s(%%s)' % name
2811+- formatted_args = ''
2812+- args_string = ', '.join([repr(arg) for arg in args])
2813+- kwargs_string = ', '.join([
2814+- '%s=%r' % (key, value) for key, value in kwargs.items()
2815+- ])
2816+- if args_string:
2817+- formatted_args = args_string
2818+- if kwargs_string:
2819+- if formatted_args:
2820+- formatted_args += ', '
2821+- formatted_args += kwargs_string
2822+-
2823+- return message % formatted_args
2824+-
2825+-
2826+-
2827+-class _Call(tuple):
2828+- """
2829+- A tuple for holding the results of a call to a mock, either in the form
2830+- `(args, kwargs)` or `(name, args, kwargs)`.
2831+-
2832+- If args or kwargs are empty then a call tuple will compare equal to
2833+- a tuple without those values. This makes comparisons less verbose::
2834+-
2835+- _Call(('name', (), {})) == ('name',)
2836+- _Call(('name', (1,), {})) == ('name', (1,))
2837+- _Call(((), {'a': 'b'})) == ({'a': 'b'},)
2838+-
2839+- The `_Call` object provides a useful shortcut for comparing with call::
2840+-
2841+- _Call(((1, 2), {'a': 3})) == call(1, 2, a=3)
2842+- _Call(('foo', (1, 2), {'a': 3})) == call.foo(1, 2, a=3)
2843+-
2844+- If the _Call has no name then it will match any name.
2845+- """
2846+- def __new__(cls, value=(), name=None, parent=None, two=False,
2847+- from_kall=True):
2848+- name = ''
2849+- args = ()
2850+- kwargs = {}
2851+- _len = len(value)
2852+- if _len == 3:
2853+- name, args, kwargs = value
2854+- elif _len == 2:
2855+- first, second = value
2856+- if isinstance(first, basestring):
2857+- name = first
2858+- if isinstance(second, tuple):
2859+- args = second
2860+- else:
2861+- kwargs = second
2862+- else:
2863+- args, kwargs = first, second
2864+- elif _len == 1:
2865+- value, = value
2866+- if isinstance(value, basestring):
2867+- name = value
2868+- elif isinstance(value, tuple):
2869+- args = value
2870+- else:
2871+- kwargs = value
2872+-
2873+- if two:
2874+- return tuple.__new__(cls, (args, kwargs))
2875+-
2876+- return tuple.__new__(cls, (name, args, kwargs))
2877+-
2878+-
2879+- def __init__(self, value=(), name=None, parent=None, two=False,
2880+- from_kall=True):
2881+- self.name = name
2882+- self.parent = parent
2883+- self.from_kall = from_kall
2884+-
2885+-
2886+- def __eq__(self, other):
2887+- if other is ANY:
2888+- return True
2889+- try:
2890+- len_other = len(other)
2891+- except TypeError:
2892+- return False
2893+-
2894+- self_name = ''
2895+- if len(self) == 2:
2896+- self_args, self_kwargs = self
2897+- else:
2898+- self_name, self_args, self_kwargs = self
2899+-
2900+- other_name = ''
2901+- if len_other == 0:
2902+- other_args, other_kwargs = (), {}
2903+- elif len_other == 3:
2904+- other_name, other_args, other_kwargs = other
2905+- elif len_other == 1:
2906+- value, = other
2907+- if isinstance(value, tuple):
2908+- other_args = value
2909+- other_kwargs = {}
2910+- elif isinstance(value, basestring):
2911+- other_name = value
2912+- other_args, other_kwargs = (), {}
2913+- else:
2914+- other_args = ()
2915+- other_kwargs = value
2916+- else:
2917+- # len 2
2918+- # could be (name, args) or (name, kwargs) or (args, kwargs)
2919+- first, second = other
2920+- if isinstance(first, basestring):
2921+- other_name = first
2922+- if isinstance(second, tuple):
2923+- other_args, other_kwargs = second, {}
2924+- else:
2925+- other_args, other_kwargs = (), second
2926+- else:
2927+- other_args, other_kwargs = first, second
2928+-
2929+- if self_name and other_name != self_name:
2930+- return False
2931+-
2932+- # this order is important for ANY to work!
2933+- return (other_args, other_kwargs) == (self_args, self_kwargs)
2934+-
2935+-
2936+- def __ne__(self, other):
2937+- return not self.__eq__(other)
2938+-
2939+-
2940+- def __call__(self, *args, **kwargs):
2941+- if self.name is None:
2942+- return _Call(('', args, kwargs), name='()')
2943+-
2944+- name = self.name + '()'
2945+- return _Call((self.name, args, kwargs), name=name, parent=self)
2946+-
2947+-
2948+- def __getattr__(self, attr):
2949+- if self.name is None:
2950+- return _Call(name=attr, from_kall=False)
2951+- name = '%s.%s' % (self.name, attr)
2952+- return _Call(name=name, parent=self, from_kall=False)
2953+-
2954+-
2955+- def __repr__(self):
2956+- if not self.from_kall:
2957+- name = self.name or 'call'
2958+- if name.startswith('()'):
2959+- name = 'call%s' % name
2960+- return name
2961+-
2962+- if len(self) == 2:
2963+- name = 'call'
2964+- args, kwargs = self
2965+- else:
2966+- name, args, kwargs = self
2967+- if not name:
2968+- name = 'call'
2969+- elif not name.startswith('()'):
2970+- name = 'call.%s' % name
2971+- else:
2972+- name = 'call%s' % name
2973+- return _format_call_signature(name, args, kwargs)
2974+-
2975+-
2976+- def call_list(self):
2977+- """For a call object that represents multiple calls, `call_list`
2978+- returns a list of all the intermediate calls as well as the
2979+- final call."""
2980+- vals = []
2981+- thing = self
2982+- while thing is not None:
2983+- if thing.from_kall:
2984+- vals.append(thing)
2985+- thing = thing.parent
2986+- return _CallList(reversed(vals))
2987+-
2988+-
2989+-call = _Call(from_kall=False)
2990+-
2991+-
2992+-
2993+-def create_autospec(spec, spec_set=False, instance=False, _parent=None,
2994+- _name=None, **kwargs):
2995+- """Create a mock object using another object as a spec. Attributes on the
2996+- mock will use the corresponding attribute on the `spec` object as their
2997+- spec.
2998+-
2999+- Functions or methods being mocked will have their arguments checked
3000+- to check that they are called with the correct signature.
3001+-
3002+- If `spec_set` is True then attempting to set attributes that don't exist
3003+- on the spec object will raise an `AttributeError`.
3004+-
3005+- If a class is used as a spec then the return value of the mock (the
3006+- instance of the class) will have the same spec. You can use a class as the
3007+- spec for an instance object by passing `instance=True`. The returned mock
3008+- will only be callable if instances of the mock are callable.
3009+-
3010+- `create_autospec` also takes arbitrary keyword arguments that are passed to
3011+- the constructor of the created mock."""
3012+- if _is_list(spec):
3013+- # can't pass a list instance to the mock constructor as it will be
3014+- # interpreted as a list of strings
3015+- spec = type(spec)
3016+-
3017+- is_type = isinstance(spec, ClassTypes)
3018+-
3019+- _kwargs = {'spec': spec}
3020+- if spec_set:
3021+- _kwargs = {'spec_set': spec}
3022+- elif spec is None:
3023+- # None we mock with a normal mock without a spec
3024+- _kwargs = {}
3025+-
3026+- _kwargs.update(kwargs)
3027+-
3028+- Klass = MagicMock
3029+- if type(spec) in DescriptorTypes:
3030+- # descriptors don't have a spec
3031+- # because we don't know what type they return
3032+- _kwargs = {}
3033+- elif not _callable(spec):
3034+- Klass = NonCallableMagicMock
3035+- elif is_type and instance and not _instance_callable(spec):
3036+- Klass = NonCallableMagicMock
3037+-
3038+- _new_name = _name
3039+- if _parent is None:
3040+- # for a top level object no _new_name should be set
3041+- _new_name = ''
3042+-
3043+- mock = Klass(parent=_parent, _new_parent=_parent, _new_name=_new_name,
3044+- name=_name, **_kwargs)
3045+-
3046+- if isinstance(spec, FunctionTypes):
3047+- # should only happen at the top level because we don't
3048+- # recurse for functions
3049+- mock = _set_signature(mock, spec)
3050+- else:
3051+- _check_signature(spec, mock, is_type, instance)
3052+-
3053+- if _parent is not None and not instance:
3054+- _parent._mock_children[_name] = mock
3055+-
3056+- if is_type and not instance and 'return_value' not in kwargs:
3057+- mock.return_value = create_autospec(spec, spec_set, instance=True,
3058+- _name='()', _parent=mock)
3059+-
3060+- for entry in dir(spec):
3061+- if _is_magic(entry):
3062+- # MagicMock already does the useful magic methods for us
3063+- continue
3064+-
3065+- if isinstance(spec, FunctionTypes) and entry in FunctionAttributes:
3066+- # allow a mock to actually be a function
3067+- continue
3068+-
3069+- # XXXX do we need a better way of getting attributes without
3070+- # triggering code execution (?) Probably not - we need the actual
3071+- # object to mock it so we would rather trigger a property than mock
3072+- # the property descriptor. Likewise we want to mock out dynamically
3073+- # provided attributes.
3074+- # XXXX what about attributes that raise exceptions other than
3075+- # AttributeError on being fetched?
3076+- # we could be resilient against it, or catch and propagate the
3077+- # exception when the attribute is fetched from the mock
3078+- try:
3079+- original = getattr(spec, entry)
3080+- except AttributeError:
3081+- continue
3082+-
3083+- kwargs = {'spec': original}
3084+- if spec_set:
3085+- kwargs = {'spec_set': original}
3086+-
3087+- if not isinstance(original, FunctionTypes):
3088+- new = _SpecState(original, spec_set, mock, entry, instance)
3089+- mock._mock_children[entry] = new
3090+- else:
3091+- parent = mock
3092+- if isinstance(spec, FunctionTypes):
3093+- parent = mock.mock
3094+-
3095+- new = MagicMock(parent=parent, name=entry, _new_name=entry,
3096+- _new_parent=parent, **kwargs)
3097+- mock._mock_children[entry] = new
3098+- skipfirst = _must_skip(spec, entry, is_type)
3099+- _check_signature(original, new, skipfirst=skipfirst)
3100+-
3101+- # so functions created with _set_signature become instance attributes,
3102+- # *plus* their underlying mock exists in _mock_children of the parent
3103+- # mock. Adding to _mock_children may be unnecessary where we are also
3104+- # setting as an instance attribute?
3105+- if isinstance(new, FunctionTypes):
3106+- setattr(mock, entry, new)
3107+-
3108+- return mock
3109+-
3110+-
3111+-def _must_skip(spec, entry, is_type):
3112+- if not isinstance(spec, ClassTypes):
3113+- if entry in getattr(spec, '__dict__', {}):
3114+- # instance attribute - shouldn't skip
3115+- return False
3116+- spec = spec.__class__
3117+- if not hasattr(spec, '__mro__'):
3118+- # old style class: can't have descriptors anyway
3119+- return is_type
3120+-
3121+- for klass in spec.__mro__:
3122+- result = klass.__dict__.get(entry, DEFAULT)
3123+- if result is DEFAULT:
3124+- continue
3125+- if isinstance(result, (staticmethod, classmethod)):
3126+- return False
3127+- return is_type
3128+-
3129+- # shouldn't get here unless function is a dynamically provided attribute
3130+- # XXXX untested behaviour
3131+- return is_type
3132+-
3133+-
3134+-def _get_class(obj):
3135+- try:
3136+- return obj.__class__
3137+- except AttributeError:
3138+- # in Python 2, _sre.SRE_Pattern objects have no __class__
3139+- return type(obj)
3140+-
3141+-
3142+-class _SpecState(object):
3143+-
3144+- def __init__(self, spec, spec_set=False, parent=None,
3145+- name=None, ids=None, instance=False):
3146+- self.spec = spec
3147+- self.ids = ids
3148+- self.spec_set = spec_set
3149+- self.parent = parent
3150+- self.instance = instance
3151+- self.name = name
3152+-
3153+-
3154+-FunctionTypes = (
3155+- # python function
3156+- type(create_autospec),
3157+- # instance method
3158+- type(ANY.__eq__),
3159+- # unbound method
3160+- type(_ANY.__eq__),
3161+-)
3162+-
3163+-FunctionAttributes = set([
3164+- 'func_closure',
3165+- 'func_code',
3166+- 'func_defaults',
3167+- 'func_dict',
3168+- 'func_doc',
3169+- 'func_globals',
3170+- 'func_name',
3171+-])
3172+-
3173+-
3174+-file_spec = None
3175+-
3176+-
3177+-def mock_open(mock=None, read_data=''):
3178+- """
3179+- A helper function to create a mock to replace the use of `open`. It works
3180+- for `open` called directly or used as a context manager.
3181+-
3182+- The `mock` argument is the mock object to configure. If `None` (the
3183+- default) then a `MagicMock` will be created for you, with the API limited
3184+- to methods or attributes available on standard file handles.
3185+-
3186+- `read_data` is a string for the `read` method of the file handle to return.
3187+- This is an empty string by default.
3188+- """
3189+- global file_spec
3190+- if file_spec is None:
3191+- # set on first use
3192+- if inPy3k:
3193+- import _io
3194+- file_spec = list(set(dir(_io.TextIOWrapper)).union(set(dir(_io.BytesIO))))
3195+- else:
3196+- file_spec = file
3197+-
3198+- if mock is None:
3199+- mock = MagicMock(name='open', spec=open)
3200+-
3201+- handle = MagicMock(spec=file_spec)
3202+- handle.write.return_value = None
3203+- handle.__enter__.return_value = handle
3204+- handle.read.return_value = read_data
3205+-
3206+- mock.return_value = handle
3207+- return mock
3208+-
3209+-
3210+-class PropertyMock(Mock):
3211+- """
3212+- A mock intended to be used as a property, or other descriptor, on a class.
3213+- `PropertyMock` provides `__get__` and `__set__` methods so you can specify
3214+- a return value when it is fetched.
3215+-
3216+- Fetching a `PropertyMock` instance from an object calls the mock, with
3217+- no args. Setting it calls the mock with the value being set.
3218+- """
3219+- def _get_child_mock(self, **kwargs):
3220+- return MagicMock(**kwargs)
3221+-
3222+- def __get__(self, obj, obj_type):
3223+- return self()
3224+- def __set__(self, obj, val):
3225+- self(val)
3226++# This file is part of Checkbox.
3227++#
3228++# Copyright 2013 Canonical Ltd.
3229++# Written by:
3230++# Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
3231++#
3232++# Checkbox is free software: you can redistribute it and/or modify
3233++# it under the terms of the GNU General Public License as published by
3234++# the Free Software Foundation, either version 3 of the License, or
3235++# (at your option) any later version.
3236++#
3237++# Checkbox is distributed in the hope that it will be useful,
3238++# but WITHOUT ANY WARRANTY; without even the implied warranty of
3239++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3240++# GNU General Public License for more details.
3241++#
3242++# You should have received a copy of the GNU General Public License
3243++# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
3244++
3245++"""
3246++:mod:`plainbox.vendor.mock` -- vendorized mock module
3247++=====================================================
3248++
3249++This file has been patched-away by the Debian package as compared to the
3250++upstream version, not to ship a copy of a the 'mock' module that is now
3251++integrated into the upstream python3.3 release.
3252++"""
3253++
3254++from unittest.mock import *
3255diff --git a/debian/plainbox.manpages b/debian/plainbox.manpages
3256new file mode 100644
3257index 0000000..5c9ed39
3258--- /dev/null
3259+++ b/debian/plainbox.manpages
3260@@ -0,0 +1,32 @@
3261+build/sphinx/man/CHECKBOX_DATA.7
3262+build/sphinx/man/CHECKBOX_SHARE.7
3263+build/sphinx/man/PLAINBOX_PROVIDER_DATA.7
3264+build/sphinx/man/PLAINBOX_SESSION_SHARE.7
3265+build/sphinx/man/manage.py.1
3266+build/sphinx/man/plainbox-category-units.7
3267+build/sphinx/man/plainbox-check-config.1
3268+build/sphinx/man/plainbox-dev-analyze.1
3269+build/sphinx/man/plainbox-dev-crash.1
3270+build/sphinx/man/plainbox-dev-list.1
3271+build/sphinx/man/plainbox-dev-logtest.1
3272+build/sphinx/man/plainbox-dev-parse.1
3273+build/sphinx/man/plainbox-dev-script.1
3274+build/sphinx/man/plainbox-dev-special.1
3275+build/sphinx/man/plainbox-dev.1
3276+build/sphinx/man/plainbox-device.1
3277+build/sphinx/man/plainbox-file-units.7
3278+build/sphinx/man/plainbox-job-units.7
3279+build/sphinx/man/plainbox-run.1
3280+build/sphinx/man/plainbox-self-test.1
3281+build/sphinx/man/plainbox-session-archive.1
3282+build/sphinx/man/plainbox-session-export.1
3283+build/sphinx/man/plainbox-session-list.1
3284+build/sphinx/man/plainbox-session-remove.1
3285+build/sphinx/man/plainbox-session-show.1
3286+build/sphinx/man/plainbox-session-structure.7
3287+build/sphinx/man/plainbox-session.1
3288+build/sphinx/man/plainbox-startprovider.1
3289+build/sphinx/man/plainbox-template-units.7
3290+build/sphinx/man/plainbox-test-plan-units.7
3291+build/sphinx/man/plainbox.1
3292+build/sphinx/man/plainbox.conf.5
3293diff --git a/debian/python3-plainbox-doc.doc-base b/debian/python3-plainbox-doc.doc-base
3294new file mode 100644
3295index 0000000..2be3de8
3296--- /dev/null
3297+++ b/debian/python3-plainbox-doc.doc-base
3298@@ -0,0 +1,9 @@
3299+Document: plainbox
3300+Title: Plainbox Manual
3301+Author: Canonical Ltd.
3302+Abstract: This manual describes what Plainbox is, and how it can be used.
3303+Section: Programming/Python
3304+
3305+Format: HTML
3306+Index: /usr/share/doc/python3-plainbox-doc/html/index.html
3307+Files: /usr/share/doc/python3-plainbox-doc/html/*.html
3308\ No newline at end of file
3309diff --git a/debian/python3-plainbox-doc.docs b/debian/python3-plainbox-doc.docs
3310new file mode 100644
3311index 0000000..6f7511e
3312--- /dev/null
3313+++ b/debian/python3-plainbox-doc.docs
3314@@ -0,0 +1 @@
3315+build/sphinx/html
3316diff --git a/debian/python3-plainbox.install b/debian/python3-plainbox.install
3317new file mode 100644
3318index 0000000..a829b2d
3319--- /dev/null
3320+++ b/debian/python3-plainbox.install
3321@@ -0,0 +1,2 @@
3322+build/mo/* usr/share/locale
3323+plainbox/impl/providers/stubbox/build/mo/* usr/share/locale
3324diff --git a/debian/python3-plainbox.links b/debian/python3-plainbox.links
3325new file mode 100644
3326index 0000000..9297a04
3327--- /dev/null
3328+++ b/debian/python3-plainbox.links
3329@@ -0,0 +1,2 @@
3330+usr/share/python3-plainbox/data /usr/lib/python3/dist-packages/plainbox/data
3331+usr/share/python3-plainbox/test-data /usr/lib/python3/dist-packages/plainbox/test-data
3332diff --git a/debian/python3-plainbox.manpages b/debian/python3-plainbox.manpages
3333new file mode 100644
3334index 0000000..a7372fb
3335--- /dev/null
3336+++ b/debian/python3-plainbox.manpages
3337@@ -0,0 +1,2 @@
3338+build/sphinx/man/plainbox-trusted-launcher-1.1
3339+build/sphinx/man/plainbox-qml-shell.1
3340diff --git a/debian/python3-plainbox.preinst b/debian/python3-plainbox.preinst
3341new file mode 100644
3342index 0000000..8e73be6
3343--- /dev/null
3344+++ b/debian/python3-plainbox.preinst
3345@@ -0,0 +1,44 @@
3346+#! /bin/sh
3347+# Pre-install script for ‘python3-plainbox’.
3348+#
3349+# Manpage: ‘dh_installdeb(1)’
3350+
3351+set -e
3352+
3353+# Summary of ways this script can be called:
3354+# * <new-preinst> install
3355+# * <new-preinst> install <old-version>
3356+# * <new-preinst> upgrade <old-version>
3357+# * <old-preinst> abort-upgrade <new-version>
3358+# For details, see the Debian Policy §6.5 in the ‘debian-policy’ package
3359+# or on the web at <URL:http://www.debian.org/doc/debian-policy/>.
3360+
3361+action="$1"
3362+
3363+case "$action" in
3364+ upgrade)
3365+ data_dir="/usr/lib/python3/dist-packages/plainbox/data"
3366+ if [ -d "$data_dir" ] && [ ! -L "$data_dir" ] ; then
3367+ # The ‘data’ location should be platform-independent.
3368+ # The new package will replace the directory with a symlink.
3369+ rm -rf "$data_dir"
3370+ fi
3371+ testdata_dir="/usr/lib/python3/dist-packages/plainbox/test-data"
3372+ if [ -d "$testdata_dir" ] && [ ! -L "$testdata_dir" ] ; then
3373+ # The ‘data’ location should be platform-independent.
3374+ # The new package will replace the directory with a symlink.
3375+ rm -rf "$testdata_dir"
3376+ fi
3377+ ;;
3378+
3379+ install|abort-upgrade)
3380+ ;;
3381+
3382+ *)
3383+ printf "preinst called with unknown action ‘%s’\n" "$action" >&2
3384+ exit 1
3385+ ;;
3386+
3387+esac
3388+
3389+#DEBHELPER#
3390diff --git a/debian/rules b/debian/rules
3391new file mode 100755
3392index 0000000..79ee81e
3393--- /dev/null
3394+++ b/debian/rules
3395@@ -0,0 +1,49 @@
3396+#!/usr/bin/make -f
3397+export PYBUILD_NAME=plainbox
3398+export LANG=
3399+export LANGUAGE=
3400+export NO_PNG_PKG_MANGLE=1
3401+
3402+%:
3403+ dh $@ --with=python3,sphinxdoc --buildsystem=pybuild
3404+
3405+override_dh_auto_build:
3406+ dh_auto_build --buildsystem=pybuild
3407+ # Build sphinx html documentation and man pages
3408+ # Use TEMP_HOME to work around https://bugs.launchpad.net/plainbox/+bug/1478906
3409+ TEMP_HOME=`mktemp -d`; HOME=$$TEMP_HOME python3 setup.py build_sphinx -b html; rm -rf $$TEMP_HOME;
3410+ TEMP_HOME=`mktemp -d`; HOME=$$TEMP_HOME python3 setup.py build_sphinx -b man; rm -rf $$TEMP_HOME;
3411+ # Build plainbox translations
3412+ python3 setup.py build_i18n --merge-po
3413+ # Build translations for the bundled provider
3414+ PYTHONPATH=. ./plainbox/impl/providers/stubbox/manage.py i18n --dont-update-pot --dont-merge-po
3415+ PYTHONPATH=. ./plainbox/impl/providers/categories/manage.py i18n --dont-update-pot --dont-merge-po
3416+ PYTHONPATH=. ./plainbox/impl/providers/manifest/manage.py i18n --dont-update-pot --dont-merge-po
3417+ PYTHONPATH=. ./plainbox/impl/providers/exporters/manage.py i18n --dont-update-pot --dont-merge-po
3418+
3419+# Override dh_install to ensure that /usr/bin/plainbox is in the plainbox
3420+# package and not in the python3-plainbox package. Also move the data and
3421+# test-data directories to usr/share and provide symlinks (via
3422+# python3-plainbox.links) for everything to work.
3423+override_dh_install:
3424+ dh_install
3425+ mkdir -p debian/plainbox/usr/bin
3426+ mkdir -p debian/python3-plainbox/usr/share/python3-plainbox/
3427+ mv debian/python3-plainbox/usr/bin/plainbox debian/plainbox/usr/bin/
3428+ cp -R plainbox/data debian/python3-plainbox/usr/share/python3-plainbox/
3429+ cp -R plainbox/test-data debian/python3-plainbox/usr/share/python3-plainbox/
3430+ rm -rf $(foreach version,$(shell py3versions -s), debian/python3-plainbox/usr/lib/$(version)/dist-packages/plainbox/data)
3431+ rm -rf $(foreach version,$(shell py3versions -s), debian/python3-plainbox/usr/lib/$(version)/dist-packages/plainbox/test-data)
3432+ rm -f debian/python3-plainbox/usr/bin/stubbox
3433+
3434+# Override dh_clean to remove provider build artefacts
3435+override_dh_clean:
3436+ dh_clean
3437+ rm -rf plainbox/impl/providers/stubbox/build
3438+ rm -rf plainbox/impl/providers/categories/build
3439+
3440+# Drop the empty python-3.4 directory
3441+# Taken from https://wiki.debian.org/Python/LibraryStyleGuide
3442+override_dh_python3:
3443+ dh_python3
3444+ rm -rf debian/python3-plainbox/usr/lib/python3.?
3445diff --git a/debian/source/format b/debian/source/format
3446new file mode 100644
3447index 0000000..163aaf8
3448--- /dev/null
3449+++ b/debian/source/format
3450@@ -0,0 +1 @@
3451+3.0 (quilt)
3452diff --git a/debian/source/options b/debian/source/options
3453new file mode 100644
3454index 0000000..cccadcc
3455--- /dev/null
3456+++ b/debian/source/options
3457@@ -0,0 +1 @@
3458+extend-diff-ignore = ".*\.po$"
3459diff --git a/debian/tests/control b/debian/tests/control
3460new file mode 100644
3461index 0000000..1079546
3462--- /dev/null
3463+++ b/debian/tests/control
3464@@ -0,0 +1,2 @@
3465+Tests: unit-tests
3466+Depends: plainbox
3467diff --git a/debian/tests/unit-tests b/debian/tests/unit-tests
3468new file mode 100755
3469index 0000000..615deb5
3470--- /dev/null
3471+++ b/debian/tests/unit-tests
3472@@ -0,0 +1,10 @@
3473+#!/bin/sh
3474+# autopkgtest check: run plainbox unit tests and ensure everything passes
3475+# (C) 2013 Canonical Ltd.
3476+# Author: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
3477+
3478+set -e
3479+
3480+cd $ADTTMP
3481+plainbox self-test -u -v 2>&1
3482+echo "unit-tests: OK"
3483diff --git a/debian/watch b/debian/watch
3484new file mode 100644
3485index 0000000..bd41b5e
3486--- /dev/null
3487+++ b/debian/watch
3488@@ -0,0 +1,3 @@
3489+version=3
3490+opts=uversionmangle=s/(rc|a|b|c)/~$1/ \
3491+http://pypi.debian.net/plainbox/plainbox-(.+)\.(?:zip|tgz|tbz|txz|(?:tar\.(?:gz|bz2|xz)))
3492diff --git a/docs/author/index.rst b/docs/author/index.rst
3493index b22bb46..6106b08 100644
3494--- a/docs/author/index.rst
3495+++ b/docs/author/index.rst
3496@@ -8,8 +8,15 @@ core.
3497
3498 .. toctree::
3499 intro.rst
3500+<<<<<<< docs/author/index.rst
3501 qml-job-tutorial.rst
3502 providers.rst
3503+=======
3504+ tutorial.rst
3505+ qml-job-tutorial.rst
3506+ providers.rst
3507+ whitelists.rst
3508+>>>>>>> docs/author/index.rst
3509 rfc822.rst
3510 faq.rst
3511
3512diff --git a/docs/author/intro.rst b/docs/author/intro.rst
3513index 2dae15d..93e9365 100644
3514--- a/docs/author/intro.rst
3515+++ b/docs/author/intro.rst
3516@@ -49,7 +49,11 @@ Terminology
3517 In developing or using Plainbox, you'll run into several unfamiliar terms.
3518 Check the :doc:`../glossary` to learn what they mean. In fact, you should
3519 probably check it now. Pay particular attention to the terms *Checkbox*,
3520+<<<<<<< docs/author/intro.rst
3521 *Plainbox*, *job* and *provider*.
3522+=======
3523+*Plainbox*, *job*, *provider*, and *whitelist*.
3524+>>>>>>> docs/author/intro.rst
3525
3526 Getting Started
3527 ---------------
3528@@ -73,7 +77,11 @@ tests. First up is a welcome screen:
3529 select tests.
3530
3531 When you press the Enter key, ``checkbox-cli`` lets you select which
3532+<<<<<<< docs/author/intro.rst
3533 test plan to use:
3534+=======
3535+whitelist to use:
3536+>>>>>>> docs/author/intro.rst
3537
3538 .. image:: cc2.png
3539 :height: 343
3540@@ -81,7 +89,11 @@ test plan to use:
3541 :scale: 100
3542 :alt: checkbox-cli enables you to select which test suite to run.
3543
3544+<<<<<<< docs/author/intro.rst
3545 With a test plan selected, you can choose the individual tests to run:
3546+=======
3547+With a whitelist selected, you can choose the individual tests to run:
3548+>>>>>>> docs/author/intro.rst
3549
3550 .. image:: cc3.png
3551 :height: 600
3552@@ -117,7 +129,11 @@ A provider is described in a configuration file (stored in
3553 ``/usr/share/plainbox-providers-1``). This file describes where to find all
3554 the files from the provider. This file is usually managed automatically
3555 (more on this later). A provider can ship jobs, binaries, data and
3556+<<<<<<< docs/author/intro.rst
3557 test plans.
3558+=======
3559+whitelists.
3560+>>>>>>> docs/author/intro.rst
3561
3562 A **job** or **test** is the smallest unit or description that Plainbox
3563 knows about. It describes a single test (historically they're called
3564@@ -140,6 +156,13 @@ types include (but are not limited to):
3565 * ``shell`` -- An automated test that requires no user interaction; the
3566 test is passed or failed on the basis of the return value of the script
3567 or command.
3568+<<<<<<< docs/author/intro.rst
3569+=======
3570+ * ``local`` -- This type of job is similar to a ``shell`` test, but it
3571+ supports creating multiple tests from a single definition (say, to test
3572+ all the Ethernet ports on a computer). Jobs using the ``local`` plugin
3573+ are run when Plainbox is initialized.
3574+>>>>>>> docs/author/intro.rst
3575 * ``user-interact`` -- A test that asks the user to perform some action
3576 *before* the test is performed. The test then passes or fails
3577 automatically based on the output of the test. An example is
3578@@ -158,9 +181,176 @@ types include (but are not limited to):
3579 which probes the system to determine the maximum supported resolution
3580 and then asks the user to confirm that the resolution is correct.
3581
3582+<<<<<<< docs/author/intro.rst
3583 Each provider has a ``bin`` directory and all binaries there are available
3584 in the path.
3585
3586+=======
3587+A fairly complex example definition is::
3588+
3589+ plugin: local
3590+ _summary: Automated test to walk multiple network cards and test each one in sequence.
3591+ id: ethernet/multi_nic
3592+ requires:
3593+ device.category == 'NETWORK'
3594+ _description: Automated test to walk multiple network cards and test each one in sequence.
3595+ command:
3596+ cat <<'EOF' | run_templates -s 'udev_resource | filter_templates -w "category=NETWORK" | awk "/path: / { print \$2 }" | xargs -n 1 sh -c "for i in \``ls /sys\$0/net 2>/dev/null\``; do echo \$0 \$i; done"'
3597+ plugin: shell
3598+ id: ethernet/multi_nic_$2
3599+ requires:
3600+ package.name == 'ethtool'
3601+ package.name == 'nmap'
3602+ device.path == "$1"
3603+ user: root
3604+ environ: TEST_TARGET_FTP TEST_TARGET_IPERF TEST_USER TEST_PASS
3605+ command: network test -i $2 -t iperf --fail-threshold 80
3606+ estimated_duration: 330.0
3607+ description:
3608+ Testing for NIC $2
3609+ EOF
3610+
3611+Key points to note include:
3612+
3613+ * If a field name begins with an underscore, its value can be localized.
3614+ * The values of fields can appear on the same line as their field names,
3615+ as in ``plugin: local``; or they can appear on a subsequent line, which
3616+ is indented, as in the preceding example's ``requires: device.category
3617+ == 'NETWORK'``.
3618+ * The ``requires`` field can be used to specify dependencies; if the
3619+ specified condition is not met, the test does not run.
3620+ * The ``command`` field specifies the command that's used to run the test.
3621+ This can be a standard Linux command (or even a set of commands) or a
3622+ Checkbox test script. In this example's ``local`` test definition, the
3623+ first ``command`` line generates a list of network devices that is fed
3624+ to an embedded test, which is defined beginning with the second
3625+ ``plugin`` line immediately following the first ``command`` line.
3626+ * In this example, the line that reads ``EOF`` ends the
3627+ ``ethernet/ethtool_multi_nic_$2`` test's command; it's matched to the
3628+ ``EOF`` that's part of ``cat << 'EOF'`` near the start of that command.
3629+
3630+Each provider has a ``bin`` directory and all binaries there are available
3631+in the path.
3632+
3633+Whitelists
3634+``````````
3635+
3636+In the job files we have a "universe" of known jobs. We don't normally want
3637+to run them all; rather we want to select a subset depending on what we're
3638+testing, and maybe give the user a way to fine-tune that selection. Also,
3639+we need a way to determine the order in which they will run, beyond what
3640+dependencies may provide. This is where the whitelist comes in; think of it
3641+as a mask or selection filter from the universe of jobs. Whitelists support
3642+regular expressions, and Plainbox will attempt to run tests in the order
3643+shown in the whitelist. Again, providers ship whitelists in a specific
3644+directory, and you can use ``plainbox`` to run a specific whitelist with
3645+the ``-w`` option.
3646+
3647+You can also use ``plainbox`` to run a test with the ``-i`` syntax. This is
3648+good for quickly running a job and ensuring it works well.
3649+
3650+Let's look at ``checkbox-cli`` for a moment. This is a "launcher"; it
3651+specifies a set of configuration options for a specific testing purpose.
3652+This enables us to create mini-clients for each testing purpose, without
3653+changing the core utility (``checkbox-launcher``). For instance, let's look
3654+at the launcher for ``canonical-certification-server``, which appears in
3655+``./providers/plainbox-provider-certification-server/launcher/canonical-certification-server``
3656+in the Checkbox source tree::
3657+
3658+ #!/usr/bin/env checkbox-launcher
3659+ [welcome]
3660+ text = Welcome to System Certification!
3661+ This application will gather information from your system. Then you will be
3662+ asked manual tests to confirm that the system is working properly. Finally,
3663+ you will be asked for the Secure ID of the computer to submit the
3664+ information to the certification.canonical.com database.
3665+ To learn how to create or locate the Secure ID, please see here:
3666+ https://certification.canonical.com/
3667+
3668+ [suite]
3669+ # Whitelist(s) displayed in the suite selection screen
3670+ whitelist_filter = ^((network|storage|usb|virtualization)-only)|(server-(full|functional)-14.04)$
3671+ # Whitelist(s) pre-selected in the suite selection screen, default whitelist(s)
3672+ whitelist_selection = ^server-full-14.04$
3673+
3674+ [transport]
3675+ submit_to = certification
3676+
3677+ [config]
3678+ config_filename = canonical-certification.conf
3679+
3680+A launcher such as this sets up an environment that includes introductory
3681+text to be shown to users, a filter to determine what whitelists to present
3682+as options, information on where to (optionally) submit results, and a
3683+configuration filename. This allows each provider to ship a launcher or
3684+binary with which to launch its relevant tests.
3685+
3686+Developing Tests
3687+````````````````
3688+
3689+One way to deliver tests via Plainbox is to start your own provider. To
3690+learn how to do that, see the :ref:`tutorial`.
3691+
3692+In other cases you want to add tests to the main Checkbox repository (which
3693+is also what we recommend to keep tests centralized, unless they're so
3694+purpose-specific that this makes no sense).
3695+
3696+This is a bit easier because the provider in question already exists. So
3697+let's get started by branching a copy of ``lp:checkbox``. In brief, you
3698+should change to your software development directory and type ``bzr branch
3699+lp:checkbox my-branch`` to create a copy of the ``checkbox`` Launchpad
3700+project in the ``my-branch`` subdirectory. You can then edit the files in
3701+that subdirectory, upload the results to your own Launchpad account, and
3702+request a merge.
3703+
3704+To begin, consider the files and subdirectories in the main Checkbox
3705+development directory (``my-branch`` if you used the preceding ``bzr``
3706+command without change):
3707+
3708+ * ``checkbox-gui`` -- Checkbox GUI components, used in desktop/laptop
3709+ testing
3710+ * ``checkbox-ng`` -- The Plainbox-based version of Checkbox
3711+ * ``checkbox-support`` -- Support code for many providers
3712+ * ``checkbox-touch`` -- A Checkbox frontend optimized for touch/tablet
3713+ devices
3714+ * ``mk-venv`` -- A symbolic link to a script used to set up an environment
3715+ for testing Checkbox
3716+ * ``plainbox`` -- A Python3 library and development tools at the heart of
3717+ Plainbox
3718+ * ``plainbox-client`` -- Unfinished Python3 interface for Checkbox
3719+ * ``providers`` -- Provider definitions, including test scripts
3720+ * ``README.md`` -- A file describing the contents of the subdirectory in
3721+ greater detail
3722+ * ``setup.py`` -- A setup script
3723+ * ``support`` -- Support code that's not released
3724+ * ``tarmac-verify`` -- A support script
3725+ * ``test-in-lxc.sh`` -- A support script for testing in an LXC
3726+ * ``test-in-vagrant.sh`` -- A support script for testing with Vagrant
3727+ * ``test-with-coverage`` -- A link to a support script for testing with
3728+ coverage
3729+ * ``Vagrantfile`` -- A Vagrant configuration file
3730+
3731+Let's say I want to write a test to ensure that the ubuntu user exists in
3732+``/etc/passwd``. You need to remove any existing Checkbox provider
3733+packages, lest they interfere with your new or modified tests. The
3734+``setup.py`` script will set up a Plainbox development environment for you.
3735+
3736+We can write a simple job here, then add a requirement, perhaps a
3737+dependency, then a script in the directory. Note that scripts can be
3738+anything that's executable, we usually prefer either shell or Python but
3739+anything goes.
3740+
3741+Plainbox will supply two environment variables, ``PLAINBOX_PROVIDER_DATA``
3742+and ``SHARE``, we usually try to use them in the job description only, not
3743+in the scripts, to keep the scripts Plainbox-agnostic if possible.
3744+
3745+Once the test is running correctly, we can create a whitelist with a few
3746+tests and name it.
3747+
3748+Once we get everything running correctly we can prepare and propose a merge
3749+request using ``bzr`` as usual.
3750+
3751+>>>>>>> docs/author/intro.rst
3752 Other Questions
3753 ---------------
3754
3755diff --git a/docs/author/provider-files.rst b/docs/author/provider-files.rst
3756index 34f21d4..d7ab8d1 100644
3757--- a/docs/author/provider-files.rst
3758+++ b/docs/author/provider-files.rst
3759@@ -53,6 +53,14 @@ jobs_dir
3760 Absolute pathname to a directory with :term:`job definitions <job>`
3761 as individual ``.txt`` files using the :doc:`job file format <jobs>`.
3762
3763+<<<<<<< docs/author/provider-files.rst
3764+=======
3765+whitelists_dir
3766+ Absolute pathname to a directory with :term:`whitelists <whitelist>`
3767+ as individual ``.whitelist`` files using the
3768+ :doc:`whitelist format <whitelists>`.
3769+
3770+>>>>>>> docs/author/provider-files.rst
3771 bin_dir
3772 Absolute pathname to a directory with additional executables required by
3773 any of the job definitions.
3774@@ -75,6 +83,10 @@ location
3775 Variable Default Value
3776 ================ =====================
3777 jobs_dir $location/jobs
3778+<<<<<<< docs/author/provider-files.rst
3779+=======
3780+ whitelists_dir $location/whitelists
3781+>>>>>>> docs/author/provider-files.rst
3782 bin_dir $location/bin
3783 data_dir $location/data
3784 locale_dir $location/locale
3785diff --git a/docs/author/provider-namespaces.rst b/docs/author/provider-namespaces.rst
3786index e25036b..c5e73b7 100644
3787--- a/docs/author/provider-namespaces.rst
3788+++ b/docs/author/provider-namespaces.rst
3789@@ -120,7 +120,11 @@ The part of the provide name before the colon is used as the name-space. The
3790 colon is *not* a part of the name-space.
3791
3792 The implicit name-space is used to construct non-partial job definition names
3793+<<<<<<< docs/author/provider-namespaces.rst
3794 as well as to implicitly prefix each pattern inside test plans.
3795+=======
3796+as well as to implicitly prefix each pattern inside :term:`whitelists <whitelist>`.
3797+>>>>>>> docs/author/provider-namespaces.rst
3798
3799 Using Explicit Name-Spaces
3800 --------------------------
3801@@ -133,15 +137,25 @@ Explicit name-spaces need to be used in two situations:
3802 This is required as any partial ID may silently change the job it resolves
3803 to and we didn't want to introduce that ambiguity.
3804
3805+<<<<<<< docs/author/provider-namespaces.rst
3806 2. When including a job from another name-space inside a test plan, e.g.::
3807
3808 ~/com.example.some:provider$ cat units/test-plan.pxu
3809+=======
3810+2. When including a job from another name-space inside a whitelist, e.g.::
3811+
3812+ ~/com.example.some:provider$ cat whitelists/cross.whitelist
3813+>>>>>>> docs/author/provider-namespaces.rst
3814 job-a
3815 job-b
3816 com\.example\.other::job-a
3817 ~com.example.some:provider$
3818
3819+<<<<<<< docs/author/provider-namespaces.rst
3820 Here the test plan names three jobs:
3821+=======
3822+ Here the whitelist names three jobs:
3823+>>>>>>> docs/author/provider-namespaces.rst
3824
3825 * com.example.some::job-a
3826 * com.example.some::job-b
3827diff --git a/docs/author/provider-template.rst b/docs/author/provider-template.rst
3828index ae5bb76..302bf7d 100644
3829--- a/docs/author/provider-template.rst
3830+++ b/docs/author/provider-template.rst
3831@@ -23,14 +23,27 @@ The following files and directories are generated::
3832 ├── data
3833 │   ├── example.dat
3834 │   └── README.md
3835+<<<<<<< docs/author/provider-template.rst
3836+=======
3837+ ├── jobs
3838+ │   ├── examples-intermediate.txt
3839+ │   ├── examples-normal.txt
3840+ │   └── examples-trivial.txt
3841+>>>>>>> docs/author/provider-template.rst
3842 ├── manage.py
3843 ├── po
3844 │   └── POTFILES.in
3845 ├── README.md
3846+<<<<<<< docs/author/provider-template.rst
3847 └── units
3848    ├── examples-intermediate.txt
3849    ├── examples-normal.txt
3850    └── examples-trivial.txt
3851+=======
3852+ └── whitelists
3853+ ├── normal.whitelist
3854+ └── trivial.whitelist
3855+>>>>>>> docs/author/provider-template.rst
3856
3857 Generated Content
3858 =================
3859@@ -56,8 +69,15 @@ README.md
3860 Plainbox parlance, is the smallest piece of executable test code. Each
3861 job has a name and a number of other attributes.
3862
3863+<<<<<<< docs/author/provider-template.rst
3864 Jobs can be arranged in lists, test plans if you will. You can create as
3865 many test plans as you need, referring to arbitrary subsets of your jobs.
3866+=======
3867+ Jobs can be arranged in lists, test plans if you will that are known
3868+ as "whitelists". Those are defined in the ``whitelists/`` directory,
3869+ this time one per file. You can create as many whitelists as you need,
3870+ referring to arbitrary subsets of your jobs.
3871+>>>>>>> docs/author/provider-template.rst
3872
3873 Then there are the ``bin/`` and ``data/`` directories. Those are
3874 entirely for custom content you may need. You can put arbitrary
3875@@ -335,7 +355,11 @@ jobs/examples-intermediate.txt
3876 estimated_duration: 30
3877
3878
3879+<<<<<<< docs/author/provider-template.rst
3880 po/POTFILES.in
3881+=======
3882+po/PORFILES.in
3883+>>>>>>> docs/author/provider-template.rst
3884 --------------
3885
3886 ::
3887@@ -345,3 +369,23 @@ po/POTFILES.in
3888 [type: gettext/rfc822deb] jobs/examples-normal.txt
3889 [type: gettext/rfc822deb] jobs/examples-intermediate.txt
3890 manage.py
3891+<<<<<<< docs/author/provider-template.rst
3892+=======
3893+
3894+whitelists/trivial.whitelist
3895+----------------------------
3896+
3897+::
3898+
3899+ # select two trivial jobs by directly selecting their names
3900+ examples/trivial/always-pass
3901+ examples/trivial/always-fail
3902+
3903+whitelists/normal.whitelist
3904+---------------------------
3905+
3906+::
3907+
3908+ # use regular expression to select all normal jobs
3909+ examples/normal/.*
3910+>>>>>>> docs/author/provider-template.rst
3911diff --git a/docs/author/providers.rst b/docs/author/providers.rst
3912index cc1bb6c..40d4dc5 100644
3913--- a/docs/author/providers.rst
3914+++ b/docs/author/providers.rst
3915@@ -5,7 +5,11 @@ Providers
3916 Providers are a new feature introduced in Plainbox 0.5. They allow third party
3917 developers to produce and maintain private and public test collections.
3918
3919+<<<<<<< docs/author/providers.rst
3920 All :term:`jobs <job>` and test plans are now loaded from a provider. This
3921+=======
3922+All :term:`jobs <job>` and :term:`whitelists <whitelist>` are now loaded from a provider. This
3923+>>>>>>> docs/author/providers.rst
3924 also affects the :term:`Checkbox` project that now produces a custom user
3925 interface and a number of providers for various purposes.
3926
3927diff --git a/docs/author/tutorial.rst b/docs/author/tutorial.rst
3928new file mode 100644
3929index 0000000..892cb19
3930--- /dev/null
3931+++ b/docs/author/tutorial.rst
3932@@ -0,0 +1,177 @@
3933+.. _tutorial:
3934+
3935+========
3936+Tutorial
3937+========
3938+
3939+To best illustrate how providers work, we will walk through creating one
3940+step-by-step. At the end of this tutorial you will have a provider which adds
3941+a new :term:`whitelist`, several new jobs and the scripts and test data
3942+supporting those jobs. Before starting this tutorial you will need to have a
3943+running version of :term:`Plainbox` installed. You can either install it from
3944+the repositories of Debian or its derivatives by running ``apt-get install
3945+plainbox``, or if you prefer to work with the source, see :doc:`Getting
3946+started with development <../dev/intro>`. There is also a Launchpad PPA with
3947+the very latest development build for Ubuntu, which is `ppa:checkbox-dev/ppa`.
3948+
3949+#. To get started we create an initial template for our provider by running
3950+ ``plainbox startprovider com.example:myprovider``.
3951+
3952+#. This will create a directory called ``com.example:myprovider``.
3953+ Change to this directory and you will see that it contains::
3954+
3955+ /bin
3956+ /data
3957+ /integration-tests
3958+ /jobs
3959+ manage.py
3960+ README.md
3961+ /whitelists
3962+
3963+ The ``manage.py`` script is a helper script for developing the provider.
3964+ It provides a set of commands which assist in validating the correctness
3965+ of the provider and making it ready for distribution.
3966+
3967+#. Let’s create some jobs first by changing to the jobs directory. It currently
3968+ contains a file called category.txt which serves as an example of how
3969+ jobs should look. Let’s delete it and instead create a file called
3970+ ``myjobs.txt``. This can contain the following simple jobs::
3971+
3972+ plugin: shell
3973+ name: myjobs/shell_command
3974+ command: true
3975+ _description:
3976+ An example job that uses a command provided by the shell.
3977+
3978+ plugin: shell
3979+ name: myjobs/provider_command
3980+ command: mycommand
3981+ _description:
3982+ An example job that uses a test command provided by this provider.
3983+
3984+ At this point we can check that everything looks okay by running the command
3985+ ``./manage.py info`` which displays some information about the provider. The
3986+ output should be something like::
3987+
3988+ [Provider MetaData]
3989+ name: com.example:myprovider
3990+ version: 1.0
3991+ [Job Definitions]
3992+ 'myjobs/builtin_command', from jobs/myjobs.txt:1-5
3993+ 'myjobs/provider_command', from jobs/myjobs.txt:7-11
3994+ [White Lists]
3995+ 'category', from whitelists/category.whitelist:1-1
3996+
3997+ This shows all three jobs from the job file we added - great!
3998+
3999+#. Next we need to change directory to ``bin`` to add the command used by the
4000+ job ``myjobs/this_provider_command``. We create a file there called
4001+ ``mycommand`` which contains the following text::
4002+
4003+ #!/bin/sh
4004+ test `cat $CHECKBOX_SHARE/data/testfile` = 'expected'
4005+
4006+ This needs to be executable to be used in the job command so we need to run
4007+ ``chmod a+x mycommand`` to make it executable.
4008+
4009+ You'll notice the command uses a file in ``$CHECKBOX_SHARE/data`` - we'll
4010+ add this file to our provider next.
4011+
4012+#. Because the command we’re using uses a file that we expect to be located in
4013+ ``$CHECKBOX_SHARE/data``, we need to add this file to our provider so that
4014+ after the provider is installed this file is available in that location.
4015+ First we need to change to the directory called ``data``, then as indicated
4016+ by the contents of the script we wrote in the previous step, we need to
4017+ create a file there called ``testfile`` with the contents::
4018+
4019+ expected
4020+
4021+ As simple as that!
4022+
4023+#. Lastly we need to add a :term:`whitelist` that utilizes the jobs we created
4024+ earlier. We need to change to the directory called ``whitelists``. As with
4025+ the ``jobs`` directory there is already an example file there called
4026+ ``category.whitelist``. We can delete that and add a file called
4027+ ``mywhitelist.whitelist``. The contents should be::
4028+
4029+ myjobs/shell_command
4030+ myjobs/provider_command
4031+
4032+ The ``miscellanea/submission_resources`` and ``graphics/glxgears`` jobs
4033+ are from the default provider that is part of Plainbox.
4034+
4035+ We can check that everything is correct with the whitelist by running the
4036+ ``./manage.py info`` command again. The output should be like::
4037+
4038+ [Provider MetaData]
4039+ name: com.example:myprovider
4040+ version: 1.0
4041+ [Job Definitions]
4042+ 'myjobs/builtin_command', from jobs/myjobs.txt:1-5
4043+ 'myjobs/provider_command', from jobs/myjobs.txt:7-11
4044+ [White Lists]
4045+ 'mywhitelist', from whitelists/mywhitelist.whitelist:1-2
4046+
4047+ Our new :term:`whitelist` is listed there.
4048+
4049+#. Now we have a provider we need to test it to make sure everything is
4050+ correct. The first thing to do is to install the provider so that it
4051+ it visible to Plainbox. Run ``./manage.py develop`` then run
4052+ ``plainbox dev list provider``. Your provider should be in the list
4053+ that is displayed.
4054+
4055+#. We should also make sure the whole provider works end-to-end by running
4056+ the :term:`whitelist` which it provides. Run the following command -
4057+ ``plainbox run -w whitelists/mywhitelist.whitelist``.
4058+
4059+#. Assuming everything works okay, we can now package the provider for
4060+ distribution. This involves creating a basic ``debian`` directory
4061+ containing all of the files needed for packaging your provider. Create
4062+ a directory called ``debian`` at the base of your provider, and then
4063+ create the following files within it.
4064+
4065+ ``compat``::
4066+
4067+ 9
4068+
4069+ ``control``::
4070+
4071+ Source: plainbox-myprovider
4072+ Section: utils
4073+ Priority: optional
4074+ Maintainer: Brendan Donegan <brendan.donegan@canonical.com>
4075+ Standards-Version: 3.9.3
4076+ X-Python3-Version: >= 3.2
4077+ Build-Depends: debhelper (>= 9.2),
4078+ lsb-release,
4079+ python3 (>= 3.2),
4080+ python3-plainbox
4081+
4082+ Package: plainbox-myprovider
4083+ Architecture: all
4084+ Depends: plainbox-provider-checkbox
4085+ Description: My whitelist provider
4086+ A provider for Plainbox.
4087+
4088+ ``rules``::
4089+
4090+ #!/usr/bin/make -f
4091+ %:
4092+ dh "$@"
4093+
4094+ override_dh_auto_build:
4095+ $(CURDIR)/manage.py install
4096+
4097+ Note that the ``rules`` file must be executable. Make it so with
4098+ ``chmod a+x rules``. Also, be careful with the indentation in the
4099+ file - all indents must be actual TAB characters, not four spaces
4100+ for example.
4101+
4102+ ``source/format``::
4103+
4104+ 3.0 (native)
4105+
4106+ Finally we should create a ``changelog`` file. The easiest way to do this
4107+ is to run the command ``dch --create 'Initial release.'``. You'll need to
4108+ edit the field ``PACKAGE`` to the name of your provider and the field
4109+ ``VERSION`` to something like ``0.1``.
4110diff --git a/docs/author/whitelists.rst b/docs/author/whitelists.rst
4111new file mode 100644
4112index 0000000..7b5f162
4113--- /dev/null
4114+++ b/docs/author/whitelists.rst
4115@@ -0,0 +1,120 @@
4116+========================
4117+Checkbox Whitelist Files
4118+========================
4119+
4120+When creating a test suite for a particular purpose, it will be necessary to
4121+specify which tests to run and which order they should run in. For this purpose
4122+Checkbox provides the concept of Whitelists.
4123+
4124+Whitelist Format
4125+================
4126+
4127+A whitelist is a text file containing a line-seperated sequence of patterns,
4128+each representing one or more 'jobs'. These patterns are in the Python regular
4129+expression syntax. Comments may be included in the file by starting the line
4130+with '#'.
4131+
4132+Minimal Whitelist File
4133+======================
4134+
4135+In order to be useful a whitelist file needs to include a particular subset of
4136+jobs which provide Checkbox with all of the information it needs to run tests
4137+properly. These include jobs which attach hardware information and resource
4138+jobs which provide other jobs with information of the environment they a
4139+re running in (available hardware, available packages etc). To make this easy
4140+to do a single job exists whose purpose is to execute all of these other jobs::
4141+
4142+ miscellanea/submission-resources
4143+
4144+This should be included as the first job in any whitelist.
4145+
4146+Job Categories
4147+==============
4148+
4149+In order to allow Checkbox to display jobs by category in the UI it is
4150+necessary to include a particular local job which itself generates jobs which
4151+belong to that category. This job will normally look like ``__<category>__``
4152+where <category> is the name of the job file which contains the job. This is
4153+indicated again by the prefix of the job (before the ``/`` in the job name).
4154+As a quick example, the job ``graphics/glxgears`` is contained in
4155+``graphics.txt``. Therefore we should include the ``__graphics__`` job so that
4156+the ``graphics/glxgears`` job shows correctly under the category. The
4157+``__graphics__`` job itself looks like::
4158+
4159+ name: __graphics__
4160+ plugin: local
4161+ _description: Graphics tests
4162+ command:
4163+ shopt -s extglob
4164+ cat $CHECKBOX_SHARE/jobs/graphics.txt?(.in)
4165+
4166+Checkbox will interpret this job as a request to display any job in
4167+``graphics.txt`` (or its untranslated version ``graphics.txt.in``) under the
4168+heading shown in the description of this job (in this case 'Graphics tests').
4169+
4170+Tutorial
4171+========
4172+
4173+To compound what we discussed before, below is a brief tutorial which walks
4174+through assembling a basic whitelist file.
4175+
4176+1. First we need to create a file, let's name it tutorial.whitelist.
4177+Whitelists don't have to end with the .whitelist suffix but this is the
4178+convention used to help identify them.
4179+2. We start by adding the one job that is required for all whitelists, as
4180+explained above in the section 'Minimal Whitelist File', so our whitelist file
4181+looks like::
4182+
4183+ miscellanea/submission-resources
4184+
4185+3. Next we should choose some jobs that we want to run. This all depends on
4186+your specific use-case of course, but I've selected a few jobs that will help
4187+clearly illustrate more of the concepts involved in whitelists. These jobs will
4188+give us a whitelist file that looks like::
4189+
4190+ miscellanea/submission-resources
4191+ cpu/clocktest
4192+ ethernet/multi_nic
4193+ ethernet/multi_nic_eth0
4194+ graphics/glxgears
4195+
4196+ If we run this whitelist now then all of these jobs will be executed and a
4197+ valid test submission will be created, but we can still improve it in a couple
4198+ of ways.
4199+
4200+4. The first way is by adding the necessary jobs to allow the Checkbox UI to
4201+group the jobs into specific categories. To do this we need to add a job with
4202+a name like ``__<category>__`` for each category. We have three categories in
4203+our whitelist file - cpu, ethernet and graphics. The category of the job is
4204+the prefix of the job name prior to the ``/``. So now our whitelist file looks
4205+like::
4206+
4207+ miscellanea/submission-resources
4208+ __cpu__
4209+ __ethernet__
4210+ __graphics__
4211+ cpu/clocktest
4212+ ethernet/multi_nic
4213+ ethernet/multi_nic_eth0
4214+ graphics/glxgears
4215+
4216+ Now the Checkbox UI will group the jobs into these categories.
4217+
4218+5. Although it's not immediately apparent there is another problem with this
4219+whitelist. The ``ethernet/multi_nic`` tests are only able to include one job
4220+for the ethernet port 'eth0'. It would be better if we included all of the
4221+jobs generated by 'ethernet/multi_nic', no matter how many ethernet ports are
4222+present on the system under test. The best way to do this is to write the
4223+pattern so that it matches all of the possible job names. We can take advantage
4224+of the Python regular expression syntax and use the ``\d`` special character
4225+to match any decimal number. After doing this the whitelist file will look
4226+like this::
4227+
4228+ miscellanea/submission-resources
4229+ __cpu__
4230+ __ethernet__
4231+ __graphics__
4232+ cpu/clocktest
4233+ ethernet/multi_nic
4234+ ethernet/multi_nic_eth\d
4235+ graphics/glxgears
4236diff --git a/docs/conf.py b/docs/conf.py
4237index 07bd76e..4ff2437 100644
4238--- a/docs/conf.py
4239+++ b/docs/conf.py
4240@@ -124,11 +124,16 @@ pygments_style = 'sphinx'
4241 # Use our custom theme. For now it only adds Disqus.com support but we may
4242 # customize it further later on. The theme is called 'plainbox' and has one
4243 # option which controls if disqus is active or not.
4244+<<<<<<< docs/conf.py
4245 html_theme = 'plainbox'
4246+=======
4247+html_theme = 'default'
4248+>>>>>>> docs/conf.py
4249
4250 # Theme options are theme-specific and customize the look and feel of a theme
4251 # further. For a list of options available for each theme, see the
4252 # documentation.
4253+<<<<<<< docs/conf.py
4254 #
4255 # Due to the way disqus works, it's only going to work on
4256 # plainbox.readthedocs.org so only use it if building for readthedocs.
4257@@ -137,6 +142,8 @@ html_theme_options = {
4258 'show_disqus': 'true' if os.environ.get(
4259 "READTHEDOCS", None) == 'True' else ''
4260 }
4261+=======
4262+>>>>>>> docs/conf.py
4263
4264 # Add any paths that contain custom themes here, relative to this directory.
4265 html_theme_path = ['_theme']
4266diff --git a/docs/dev/old.rst b/docs/dev/old.rst
4267index 7921f68..9584888 100644
4268--- a/docs/dev/old.rst
4269+++ b/docs/dev/old.rst
4270@@ -144,6 +144,11 @@ dependencies) being added to the repository.
4271 Implementation issues
4272 ---------------------
4273
4274+<<<<<<< docs/dev/old.rst
4275+=======
4276+There are two issues that are known at this time:
4277+
4278+>>>>>>> docs/dev/old.rst
4279 * There is too much checkbox-specific knowledge which really belongs
4280 elsewhere. We are working to remove that so that non-checkbox jobs
4281 can be introduced later. There is a branch in progress that entirely
4282@@ -153,6 +158,18 @@ Implementation issues
4283 that was previously internal (most notably a way to add new jobs and
4284 resources).
4285
4286+<<<<<<< docs/dev/old.rst
4287+=======
4288+* The way jobs are currently selected is unfortunate because of local jobs
4289+ that can add new jobs to the system. This causes considerable complexity
4290+ at the application level where the application must check if each
4291+ executed job is a 'local' job and re-compute the desired_job_list. This
4292+ should be replaced by a matcher function that can be passed to
4293+ SessionState once so that desired_job_list is re-evaluated internally
4294+ whenever job_list changes.
4295+
4296+
4297+>>>>>>> docs/dev/old.rst
4298 :class:`~plainbox.impl.job.JobDefinition`
4299 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4300
4301@@ -200,6 +217,52 @@ plugin == "manual"
4302 This value is used for fully manual jobs. It has no special handling in the core
4303 apart from requiring a human-provided outcome (pass/fail classification)
4304
4305+<<<<<<< docs/dev/old.rst
4306+=======
4307+.. _local:
4308+
4309+plugin == "local"
4310+#################
4311+
4312+This value is used for special job generator jobs. The output of such jobs is
4313+interpreted as additional jobs and is identical in effect to loading such jobs
4314+from a job definition file.
4315+
4316+There are two practical uses for such jobs:
4317+
4318+* Some local jobs are used to generate a number of jobs for each object.
4319+ This is needed where the tested machine may have a number of such objects
4320+ and each requires unique testing. A good example is a computer where all
4321+ network tests are explicitly "instantiated" for each network card
4322+ present.
4323+
4324+ This is a valid use case but is rather unfortunate for architecture of
4325+ Plainbox and there is a desire to replace it with equally-expressive
4326+ pattern jobs. The advantage is that unlike local jobs (which cannot be
4327+ "discovered" without enduring any potential side effects that may be
4328+ caused by the job script command) pattern jobs would allow the core to
4329+ determine the names of jobs that can be generated and, for example,
4330+ automatically determine that a pattern job needs to be executed as a
4331+ dependency of a phantom (yet undetermined) job with a given name.
4332+
4333+ The solution with "pattern" jobs may be executed in future phases of
4334+ Plainbox development. Currently there is no support for that at all.
4335+
4336+ Currently Plainbox cannot determine job dependencies across local jobs.
4337+ That is, unless a local job is explicitly requested (in the desired job
4338+ list) Plainbox will not be able to run a job that is generated by a local
4339+ job at all and will treat it as if that job never existed.
4340+
4341+* Some local jobs are used to create a form of informal "category".
4342+ Typically all such jobs have a leading and trailing double underscore,
4343+ for example '__audio__'. This is currently being used by Checkbox for
4344+ building a hierarchical tree of tests that the user may select.
4345+
4346+ Since this has the same flaws as described above (for pattern jobs) it
4347+ will likely be replaced by an explicit category field that can be
4348+ specified each job.
4349+
4350+>>>>>>> docs/dev/old.rst
4351 plugin == "resource"
4352 ####################
4353
4354diff --git a/docs/dev/trusted-launcher.rst b/docs/dev/trusted-launcher.rst
4355index a0cc565..6e5a6ec 100644
4356--- a/docs/dev/trusted-launcher.rst
4357+++ b/docs/dev/trusted-launcher.rst
4358@@ -145,7 +145,11 @@ Usage
4359 .. code-block:: text
4360
4361 plainbox-trusted-launcher-1 [-h] (--hash HASH | --warmup)
4362+<<<<<<< docs/dev/trusted-launcher.rst
4363 [--via GENERATOR-JOB-HASH]
4364+=======
4365+ [--via LOCAL-JOB-HASH]
4366+>>>>>>> docs/dev/trusted-launcher.rst
4367 [NAME=VALUE [NAME=VALUE ...]]
4368
4369 positional arguments:
4370@@ -156,7 +160,11 @@ Usage
4371 --hash HASH job hash to match
4372 --warmup Return immediately, only useful when used with
4373 pkexec(1)
4374+<<<<<<< docs/dev/trusted-launcher.rst
4375 --via GENERATOR-JOB-HASH Generator job hash to use to match the generated job
4376+=======
4377+ --via LOCAL-JOB-HASH Local job hash to use to match the generated job
4378+>>>>>>> docs/dev/trusted-launcher.rst
4379
4380 .. note::
4381
4382@@ -185,11 +193,25 @@ thanks to the installed policy file the authentication will be kept.
4383 Special case of jobs using the Checkbox local plugin
4384 ----------------------------------------------------
4385
4386+<<<<<<< docs/dev/trusted-launcher.rst
4387 For jobs generated from resources jobs (e.g.
4388 disk/read_performance.*) the trusted launcher is started with ``--via`` meaning
4389 that we have to first eval a generator job to find a hash match. Once a match is
4390+=======
4391+For jobs generated from :ref:`local <local>` jobs (e.g.
4392+disk/read_performance.*) the trusted launcher is started with ``--via`` meaning
4393+that we have to first eval a local job to find a hash match. Once a match is
4394+>>>>>>> docs/dev/trusted-launcher.rst
4395 found, the job command is executed.
4396
4397 .. code-block:: bash
4398
4399+<<<<<<< docs/dev/trusted-launcher.rst
4400 $ pkexec plainbox-trusted-launcher-1 --hash JOB-HASH --via GENERATOR-JOB-HASH
4401+=======
4402+ $ pkexec plainbox-trusted-launcher-1 --hash JOB-HASH --via LOCAL-JOB-HASH
4403+
4404+.. note::
4405+
4406+ it will obviously fail if any local job can ever generate another local job.
4407+>>>>>>> docs/dev/trusted-launcher.rst
4408diff --git a/docs/glossary.rst b/docs/glossary.rst
4409index 212d9a2..8d22fef 100644
4410--- a/docs/glossary.rst
4411+++ b/docs/glossary.rst
4412@@ -46,11 +46,20 @@ Glossary
4413 necessary for end-user work. ``plainbox`` is usually installed
4414 explicitly if needed.
4415
4416+<<<<<<< docs/glossary.rst
4417 test plan
4418
4419 Test plans are text files used by Checkbox to select jobs for
4420 execution. They can include simple regular expressions to match and
4421 pick many similar jobs at once.
4422+=======
4423+ whitelist
4424+
4425+ Whitelists are text files used by Checkbox to select jobs for
4426+ execution. They can include simple regular expressions to match and
4427+ pick many similar jobs at once. For more information see
4428+ :doc:`Checkbox Whitelist Files <author/whitelists>`
4429+>>>>>>> docs/glossary.rst
4430
4431 job
4432
4433@@ -62,7 +71,11 @@ Glossary
4434
4435 provider
4436
4437+<<<<<<< docs/glossary.rst
4438 A container for jobs, test plans, private executables and data.
4439+=======
4440+ A container for jobs, whitelists, private executables and data.
4441+>>>>>>> docs/glossary.rst
4442 Providers are the foundation of Plainbox as they *provide* all of the
4443 content. Providers can be created and managed by any entity, separately
4444 from the Checkbox project.
4445@@ -95,7 +108,11 @@ Glossary
4446 attachment
4447
4448 Attachments are a special type of a Job that can creates an attachment
4449+<<<<<<< docs/glossary.rst
4450 record in the submission reports. They are commonly used to include
4451+=======
4452+ record in the submission.xml file. They are commonly used to include
4453+>>>>>>> docs/glossary.rst
4454 basic system information files and output of certain commands which can
4455 aid in system certification.
4456
4457diff --git a/docs/manpages/plainbox-dev-analyze.rst b/docs/manpages/plainbox-dev-analyze.rst
4458index 23fc999..6bcc0c1 100644
4459--- a/docs/manpages/plainbox-dev-analyze.rst
4460+++ b/docs/manpages/plainbox-dev-analyze.rst
4461@@ -15,6 +15,16 @@ plainbox-dev-analyze (1)
4462 and the command prints nothing at all) to inspect certain aspects of the
4463 hypothetical session
4464
4465+<<<<<<< docs/manpages/plainbox-dev-analyze.rst
4466+=======
4467+ The only exception to the rule above is the ``--run-local`` option. With that
4468+ option all local jobs and their dependencies *are* started. This is
4469+ technically required to correctly emulate the behavior of ``plainbox run``
4470+ that does so unconditionally. Still, local jobs can cause harm so don't run
4471+ untrusted code this way (the author of this man page recalls one local job
4472+ that ran ``sudo reboot`` to measure bootchart data)
4473+
4474+>>>>>>> docs/manpages/plainbox-dev-analyze.rst
4475 Report Types
4476 ============
4477
4478@@ -67,11 +77,19 @@ plainbox-dev-analyze (1)
4479 always includes additional jobs (such as resource jobs and other
4480 dependencies)
4481
4482+<<<<<<< docs/manpages/plainbox-dev-analyze.rst
4483 The run list is of great importance. Most of the time the test operator
4484 will see tests in precisely this order. The only exception is that some
4485 test applications choose to pre-run generator jobs (resources). Still, if
4486 your job ordering is wrong in any way, inspecting the run list is the best
4487 way to debug the problem.
4488+=======
4489+ The run list is of great importance. Most of the time the test operator will
4490+ see tests in precisely this order. The only exception is that some test
4491+ applications choose to pre-run local jobs. Still, if your job ordering is
4492+ wrong in any way, inspecting the run list is the best way to debug the
4493+ problem.
4494+>>>>>>> docs/manpages/plainbox-dev-analyze.rst
4495
4496 See Also
4497 ========
4498diff --git a/docs/manpages/plainbox-exporter-units.rst b/docs/manpages/plainbox-exporter-units.rst
4499index df7172c..2b0791b 100644
4500--- a/docs/manpages/plainbox-exporter-units.rst
4501+++ b/docs/manpages/plainbox-exporter-units.rst
4502@@ -120,4 +120,40 @@ The provider shipping such unit can be as follow::
4503    └── exporters.pxu
4504
4505 Note that exporters.pxu is not strictly needed to store the exporter units, but
4506+<<<<<<< docs/manpages/plainbox-exporter-units.rst
4507 keeping them in a dedicated file is a good practice.
4508+=======
4509+keeping them in a dedidated file is a good practice.
4510+
4511+How to use exporter units?
4512+--------------------------
4513+
4514+In order to call an exporter unit from provider foo, you just need to add the
4515+unit id to the cli or the gui launcher in the exporter section:
4516+
4517+Example of a gui launcher:
4518+
4519+ #!/usr/bin/checkbox-gui
4520+
4521+ [welcome]
4522+ title = "Foo"
4523+ text = "bar"
4524+
4525+ [exporter]
4526+ HTML = "com.foo.bar::my_html"
4527+
4528+Example of a cli launcher:
4529+
4530+ #!/usr/bin/env checkbox-launcher
4531+ [welcome]
4532+ text = Foo
4533+
4534+ [suite]
4535+ whitelist_filter = ^.*$
4536+ whitelist_selection = ^default$
4537+
4538+ [exporter]
4539+ com.foo.bar::my_html
4540+ com.foo.bar::my_json
4541+ com.foo.baz::my_html
4542+>>>>>>> docs/manpages/plainbox-exporter-units.rst
4543diff --git a/docs/manpages/plainbox-file-units.rst b/docs/manpages/plainbox-file-units.rst
4544index 3c5ddbd..d8da24e 100644
4545--- a/docs/manpages/plainbox-file-units.rst
4546+++ b/docs/manpages/plainbox-file-units.rst
4547@@ -36,6 +36,12 @@ There are two fields that are used by the file unit:
4548 'unit-source':
4549 The file is a source of unit definitions. Currently this is the only
4550 actually implemented value.
4551+<<<<<<< docs/manpages/plainbox-file-units.rst
4552+=======
4553+
4554+ 'legacy-whitelist':
4555+ This file is a legacy whitelist.
4556+>>>>>>> docs/manpages/plainbox-file-units.rst
4557
4558 'script':
4559 This file is an architecture independent executable.
4560@@ -57,4 +63,8 @@ There are two fields that are used by the file unit:
4561 This file contains copyright and licensing information.
4562
4563 'docs':
4564+<<<<<<< docs/manpages/plainbox-file-units.rst
4565+ This file contains documentation.
4566+=======
4567 This file contains documentation.
4568+>>>>>>> docs/manpages/plainbox-file-units.rst
4569diff --git a/docs/manpages/plainbox-job-units.rst b/docs/manpages/plainbox-job-units.rst
4570index 08e8fd1..d33c2d8 100644
4571--- a/docs/manpages/plainbox-job-units.rst
4572+++ b/docs/manpages/plainbox-job-units.rst
4573@@ -56,6 +56,12 @@ Following fields may be used by the job unit:
4574 test's outcome. This is essentially a manual job with a command.
4575 :attachment: jobs whose command output will be attached to the
4576 test report or submission.
4577+<<<<<<< docs/manpages/plainbox-job-units.rst
4578+=======
4579+ :local: a job whose command output needs to be in Checkbox job
4580+ format. Jobs output by a local job will be added to the set of
4581+ available jobs to be run.
4582+>>>>>>> docs/manpages/plainbox-job-units.rst
4583 :resource: A job whose command output results in a set of rfc822
4584 records, containing key/value pairs, and that can be used in other
4585 jobs' ``requires`` expressions.
4586diff --git a/docs/manpages/plainbox-run.rst b/docs/manpages/plainbox-run.rst
4587index 3363aa8..b3a6432 100644
4588--- a/docs/manpages/plainbox-run.rst
4589+++ b/docs/manpages/plainbox-run.rst
4590@@ -74,6 +74,47 @@ plainbox-run (1)
4591
4592 plainbox run -i '.*::foo' -i '.*::bar'
4593
4594+<<<<<<< docs/manpages/plainbox-run.rst
4595+=======
4596+ Selecting jobs with whitelists
4597+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4598+
4599+ The second mechanism is the ``--whitelist WHITELIST`` command-line option.
4600+ WhiteLists (or test plans, which is somewhat easier to relate to).
4601+ Whitelists are simple text files composed of a list of regular expressions,
4602+ identical to those that may be passed with the ``-i`` option.
4603+
4604+ Unlike the ``-i`` option though, there are two kinds of whitelists.
4605+ Standalone whitelists are not associated with any Plainbox Provider. Such
4606+ whitelists can be distributed entirely separately from any other component
4607+ and thus have no association with any namespace.
4608+
4609+ Therefore, be fully qualified, each pattern must include both the namespace
4610+ and the partial identifier components. For example, this is a valid, fully
4611+ quallified whitelist::
4612+
4613+ com.canonical.plainbox::stub/.*
4614+
4615+ It will unambiguously select some of the jobs from the special, internal
4616+ StubBox provider that is built into Plainbox. It can be saved under any
4617+ filename and stored in any directory and it will always select the same set
4618+ of jobs.
4619+
4620+ In contrast, whitelists that are associated with a particular provider, by
4621+ being stored in the per-provider ``whitelists/`` directory, carry an
4622+ implicit namespace. Such whitelists are typically written without
4623+ mentioning the namespace component.
4624+
4625+ For example, the same "stub/.*" pattern can be abbreviated to::
4626+
4627+ stub/.*
4628+
4629+ Typically this syntax is used in all whitelists specific to a particular
4630+ provider unless the provider maintainer explicitly wants to include a job
4631+ from another namespace (for example, one of the well-known Checkbox job
4632+ definitions).
4633+
4634+>>>>>>> docs/manpages/plainbox-run.rst
4635 GENERATED JOBS
4636 ==============
4637
4638@@ -87,7 +128,32 @@ plainbox-run (1)
4639 storage devices) and then duplicate each of the store specific tests so
4640 that all devices are tested separately.
4641
4642+<<<<<<< docs/manpages/plainbox-run.rst
4643 One limitation is that jobs cannot override existing definitions.
4644+=======
4645+ At this time jobs can be generated only from jobs using the plugin type
4646+ `local`. Jobs of this kind are expected to print fully conforming job
4647+ definitions on stdout. Generated jobs cause a few complexities and one
4648+ limitation that is currently enforced is that generated jobs cannot
4649+ generate additional jobs if any of the affected jobs need to run as another
4650+ user.
4651+
4652+ Another limitation is that jobs cannot override existing definitions.
4653+
4654+ Creating Parent-Child Association
4655+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4656+
4657+ A relatively niche and legacy feature of generated jobs is to print a
4658+ verbatim copy of existing job definitions from a ``local`` job definition
4659+ named afer a generic testing theme or category. For example the Checkbox
4660+ job definition ``__wireless__`` prints, with the help of ``cat`` (1), all
4661+ of the job definitions defined in the file ``wireless.txt``.
4662+
4663+ This behavior is special-cased not to cause redefinition errors. Instead,
4664+ existing definitions gain the ``via`` attribute that links them to the
4665+ generator job. This feature is used by derivative application such as
4666+ Checkbox. Plainbox is not using it at this time.
4667+>>>>>>> docs/manpages/plainbox-run.rst
4668
4669 RESUMING
4670 ========
4671@@ -132,10 +198,17 @@ plainbox-run (1)
4672
4673 Some formats are more useful than others in that they are capable of
4674 transferring more of the internal state. Depending on your application you
4675+<<<<<<< docs/manpages/plainbox-run.rst
4676 may wish to choose the most generic format (tar.xz) and process it further
4677 with additional tools, choose the most basic format (text) just to get a
4678 simple summary of the results or lastly choose one of the two specialized
4679 formats (xlsx and html) that are specific to the Checkbox workflow.
4680+=======
4681+ may wish to choose the most generic format (json) and process it further
4682+ with additional tools, choose the most basic format (text) just to get a
4683+ simple summary of the results or lastly choose one of the two specialized
4684+ formats (xml and html) that are specific to the Checkbox workflow.
4685+>>>>>>> docs/manpages/plainbox-run.rst
4686
4687 Out of the box the following exporters are supported:
4688
4689@@ -171,7 +244,11 @@ plainbox-run (1)
4690 xlsx
4691 ----
4692
4693+<<<<<<< docs/manpages/plainbox-run.rst
4694 This exporter creates a standalone .xlsx (OOXML format for Microsoft Excel)
4695+=======
4696+ This exporter creates a standalone .xlsx (XML format for Microsoft Excel)
4697+>>>>>>> docs/manpages/plainbox-run.rst
4698 file that contains a human-readable test report. It is quit similar to the
4699 HTML report but it is easier to edit. It is useful for communicating with
4700 other humans and since it is entirely standalone and off-line it can be
4701@@ -179,6 +256,20 @@ plainbox-run (1)
4702
4703 It depends on python3-xlsxwriter package
4704
4705+<<<<<<< docs/manpages/plainbox-run.rst
4706+=======
4707+ hexr
4708+ ----
4709+
4710+ This exporter creates a rather confusingly named XML document only
4711+ applicable for internal Canonical Hardware Certification Team workflow.
4712+
4713+ It is not a generic XML representation of test results and instead it
4714+ carries quite a few legacy constructs that are only retained for
4715+ compatibility with other internal tools. If you want generic processing
4716+ look for JSON instead.
4717+
4718+>>>>>>> docs/manpages/plainbox-run.rst
4719 Selecting Exporter Options
4720 ^^^^^^^^^^^^^^^^^^^^^^^^^^
4721
4722@@ -243,24 +334,51 @@ plainbox-run (1)
4723 Exported data will include comments added by the test operator to each
4724 job result that has them.
4725
4726+<<<<<<< docs/manpages/plainbox-run.rst
4727 with-job-hash:
4728 Exported data will include the ``hash`` attribute alongside each job
4729 result. The hash attribute is the checksum of the job definition's
4730 data.
4731+=======
4732+ with-job-via:
4733+ Exported data will include the ``via`` attribute alongside each job
4734+ result. The via attribute contains the checksum of the job definition
4735+ that generated a particular job definition. This is useful for tracking
4736+ jobs generated by jobs with the plugin type `local`.
4737+
4738+ with-job-hash:
4739+ Exported data will include the ``hash`` attribute alongside each job
4740+ result. The hash attribute is the checksum of the job definition's
4741+ data. It can be useful alongside with `with-job-via`.
4742+>>>>>>> docs/manpages/plainbox-run.rst
4743
4744 machine-json:
4745 The generated JSON document will be minimal (devoid of any optional
4746 whitespace). This option is best to be used if the result is not
4747 intended to be read by humans as it saves some space.
4748
4749+<<<<<<< docs/manpages/plainbox-run.rst
4750 text
4751+=======
4752+ rfc822
4753+>>>>>>> docs/manpages/plainbox-run.rst
4754 ------
4755
4756 All of the options have the same meaning as for the `json` exporter:
4757 `with-io-log`, `squash-io-log`, `flatten-io-log`, `with-run-list`,
4758 `with-job-list`, `with-resource-map`, `with-job-defs`, `with-attachments`,
4759+<<<<<<< docs/manpages/plainbox-run.rst
4760 `with-comments`, `with-job-hash`. The only exception is the `machine-json`
4761 option which doesn't exist for this exporter.
4762+=======
4763+ `with-comments`, `with-job-via`, `with-job-hash`. The only exception is
4764+ the `machine-json` option which doesn't exist for this exporter.
4765+
4766+ text
4767+ ----
4768+
4769+ Same as with rfc822.
4770+>>>>>>> docs/manpages/plainbox-run.rst
4771
4772 xlsx
4773 ----
4774@@ -280,6 +398,18 @@ plainbox-run (1)
4775 with-text-attachments:
4776 Exported spreadsheet will include text attachments on a separate sheet
4777
4778+<<<<<<< docs/manpages/plainbox-run.rst
4779+=======
4780+ xml
4781+ ---
4782+
4783+ client-name:
4784+ This option allows clients to override the name of the application
4785+ generating the XML document. By default that name is `plainbox`. To
4786+ use this option pass ``--output-options client-name=other-name``
4787+ command-line option.
4788+
4789+>>>>>>> docs/manpages/plainbox-run.rst
4790 TRANSPORTING RESULTS
4791 ====================
4792
4793@@ -298,12 +428,32 @@ plainbox-run (1)
4794
4795 Plainbox comes equipped with the following transports:
4796
4797+<<<<<<< docs/manpages/plainbox-run.rst
4798 certification
4799 ^^^^^^^^^^^^^
4800
4801 This transport can send the results exported using the ``tar`` exporter to
4802 the Canonical Certification Website (https://certification.canonical.com).
4803
4804+=======
4805+ launchpad
4806+ ^^^^^^^^^
4807+
4808+ This transport can send the results exported using ``xml`` exporter to the
4809+ Launchpad Hardware Database. This is a little-known feature offered by the
4810+ https://launchpad.net/ website.
4811+
4812+ certification
4813+ ^^^^^^^^^^^^^
4814+
4815+ This transport can send the results exported using the ``xml`` exporter to
4816+ the Canonical Certification Website (https://certification.canonical.com).
4817+
4818+ This transport is of little use to anyone but the Canonical Hardware
4819+ Certification Team that also maintains Plainbox and Checkbox but it is
4820+ mentioned here for completeness.
4821+
4822+>>>>>>> docs/manpages/plainbox-run.rst
4823 See Also
4824 ========
4825
4826diff --git a/docs/manpages/plainbox-test-plan-units.rst b/docs/manpages/plainbox-test-plan-units.rst
4827index 6857100..b04b135 100644
4828--- a/docs/manpages/plainbox-test-plan-units.rst
4829+++ b/docs/manpages/plainbox-test-plan-units.rst
4830@@ -99,10 +99,18 @@ copy such constructs when working on a new test plan from scratch
4831 common and most test plans used by Checkbox actually look like that.
4832
4833 - You can use regular expressions to select many tests at the same time.
4834+<<<<<<< docs/manpages/plainbox-test-plan-units.rst
4835 This is the only way to select generated jobs (created by template
4836 units). Please remember that the dot character has a special meaning so
4837 unless you actually want to match *any character* escape the dot with
4838 the backslash character (\\).
4839+=======
4840+ This is the only way to select generated jobs (created either by
4841+ template units or by job definitions using the legacy 'local' plugin
4842+ type). Please remember that the dot character has a special meaning
4843+ so unless you actually want to match *any character* escape the dot
4844+ with the backslash character (\\).
4845+>>>>>>> docs/manpages/plainbox-test-plan-units.rst
4846
4847 Regardless of if you use patterns or literal job identifiers you can use
4848 their fully qualified name (the one that includes the namespace they reside
4849@@ -148,7 +156,11 @@ copy such constructs when working on a new test plan from scratch
4850
4851 Note that each entry in the bootstrap_include section must be a valid job
4852 identifier and cannot be a regular expression pattern.
4853+<<<<<<< docs/manpages/plainbox-test-plan-units.rst
4854 Also note that only resource jobs are allowed in this section.
4855+=======
4856+ Also note that only local and resource jobs are allowed in this section.
4857+>>>>>>> docs/manpages/plainbox-test-plan-units.rst
4858
4859 ``exclude``:
4860 A multi-line list of job identifiers or patterns matching such identifiers
4861diff --git a/docs/manpages/plainbox-trusted-launcher-1.rst b/docs/manpages/plainbox-trusted-launcher-1.rst
4862index 77cdfeb..e609736 100644
4863--- a/docs/manpages/plainbox-trusted-launcher-1.rst
4864+++ b/docs/manpages/plainbox-trusted-launcher-1.rst
4865@@ -77,8 +77,18 @@ The following environment variables *DO NOT* affect ``plainbox-trusted-launcher-
4866 Bugs
4867 ====
4868
4869+<<<<<<< docs/manpages/plainbox-trusted-launcher-1.rst
4870 The launcher is somewhat inefficient, in that it has to re-run all of the
4871 dependencies of the generator job over and over. Ideally those would be cached,
4872+=======
4873+Currently it is impossible to use ``plainbox-trusted-launcher-1`` with a
4874+``local`` job needs to run as root, that generates another ``local`` job that
4875+needs to run as root, to generate any additional jobs that also need to run as
4876+root. In other words, only one-level job generation is supported.
4877+
4878+The launcher is somewhat inefficient, in that it has to re-run all of the
4879+dependencies of the ``local`` job over and over. Ideally those would be cached,
4880+>>>>>>> docs/manpages/plainbox-trusted-launcher-1.rst
4881 per-session, but that would significantly increase the complexity of the code
4882 running as root.
4883
4884diff --git a/docs/usage.rst b/docs/usage.rst
4885index e2f2f0a..6f698b5 100644
4886--- a/docs/usage.rst
4887+++ b/docs/usage.rst
4888@@ -47,12 +47,31 @@ To list all known jobs run:
4889
4890 plainbox dev special --list-jobs
4891
4892+<<<<<<< docs/usage.rst
4893+=======
4894+Running a white list
4895+^^^^^^^^^^^^^^^^^^^^
4896+
4897+To run a :term:`whitelist` pass the ``--whitelist`` or ``-w`` option.
4898+
4899+For example, to run the default white list run:
4900+
4901+.. code-block:: bash
4902+
4903+ $ plainbox run -w /path/to/some/file.whitelist
4904+
4905+>>>>>>> docs/usage.rst
4906 Saving test results
4907 ^^^^^^^^^^^^^^^^^^^
4908
4909 Anything that Plainbox captures and stores during test execution can be
4910+<<<<<<< docs/usage.rst
4911 exported to a file using the exporter system. The three most commonly used
4912 exporters are tar.xz, html and xlsx.
4913+=======
4914+exported to a file using the exporter system. The two most commonly used
4915+exporters are JSON (versatile and general) and XML (for internal Canonical use).
4916+>>>>>>> docs/usage.rst
4917
4918 JSON Exporter
4919 -------------
4920@@ -61,7 +80,11 @@ To generate a JSON file with all of the internally available data (for storage,
4921 processing or other automation) you will need to pass three additional
4922 arguments to ``plainbox run``:
4923
4924+<<<<<<< docs/usage.rst
4925 #. ``--output-format=com.canonical.com.canonical.plainbox::json``
4926+=======
4927+#. ``--output-format=com.canonical.plainbox::json``
4928+>>>>>>> docs/usage.rst
4929 #. ``--output-options=OPTION1,OPTION2`` where *OPTIONx* are option names.
4930 #. ``--output-file=NAME`` where *NAME* is a file name.
4931
4932@@ -70,7 +93,27 @@ exporter options can be specified, separated with commas.
4933
4934 .. code-block:: bash
4935
4936+<<<<<<< docs/usage.rst
4937 $ plainbox run -i com.canonical.certification::foo --output-format=com.canonical.plainbox::json --output-file=results.json
4938+=======
4939+ $ plainbox run --whitelist=/path/to/some/file.whitelist --output-format=com.canonical.plainbox::json --output-file=results.json
4940+
4941+XML Exporter
4942+------------
4943+
4944+To generate an XML file that can be sent to the :term:`certification website`
4945+you need to pass two additional arguments to ``plainbox run``:
4946+
4947+#. ``--output-format=com.canonical.plainbox::hexr``
4948+#. ``--output-file=NAME`` where *NAME* is a file name
4949+
4950+For example, to get the default certification tests ready to be submitted
4951+run this command:
4952+
4953+.. code-block:: bash
4954+
4955+ $ plainbox run --whitelist=/path/to/some/file.whitelist --output-format=com.canonical.plainbox::hexr --output-file=submission.xml
4956+>>>>>>> docs/usage.rst
4957
4958 Other Exporters
4959 ---------------
4960diff --git a/plainbox.egg-info/PKG-INFO b/plainbox.egg-info/PKG-INFO
4961new file mode 100644
4962index 0000000..fafbf3f
4963--- /dev/null
4964+++ b/plainbox.egg-info/PKG-INFO
4965@@ -0,0 +1,62 @@
4966+Metadata-Version: 1.1
4967+Name: plainbox
4968+Version: 0.38.0
4969+Summary: Toolkit for software and hardware integration testing
4970+Home-page: https://launchpad.net/plainbox/
4971+Author: Zygmunt Krynicki
4972+Author-email: zygmunt.krynicki@canonical.com
4973+License: GPLv3
4974+Description: PlainBox
4975+ ========
4976+
4977+ PlainBox is a toolkit consisting of python3 library, development tools,
4978+ documentation and examples. It is targeted at developers working on testing or
4979+ certification applications and authors creating tests for such applications.
4980+
4981+ PlainBox can be used to both create simple and comprehensive test tools as well
4982+ as to develop and execute test jobs and test scenarios. It was created as a
4983+ refined and rewritten core of the CheckBox project. It has a well tested and
4984+ documented core, small but active development community and a collection of
4985+ associated projects that use it as a lower-level engine/back-end library.
4986+
4987+ PlainBox has a novel approach to discovering (and probing) hardware and
4988+ software that is extensible and not hardwired into the system. It allows test
4989+ developers to express association between a particular test and the hardware,
4990+ software and configuration constraints that must be met for the test to execute
4991+ meaningfully. This feature, along with pluggable test definitions, makes
4992+ PlainBox flexible and applicable to many diverse testing situations, ranging
4993+ from mobile phones, traditional desktop computers, servers and up to testing
4994+ "cloud" installations.
4995+
4996+ External Documentation Links
4997+ ============================
4998+
4999+ * `Using PlainBox <http://plainbox.readthedocs.org/en/latest/usage.html>`_
5000+ * `Hacking on PlainBox <http://plainbox.readthedocs.org/en/latest/dev/index.html>`_
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches