Merge lp:~gz/bzr/support_OO_flag into lp:bzr

Proposed by Martin Packman
Status: Merged
Approved by: Vincent Ladeuil
Approved revision: no longer in the source branch.
Merged at revision: not available
Proposed branch: lp:~gz/bzr/support_OO_flag
Merge into: lp:bzr
Diff against target: 1507 lines (+199/-168) (has conflicts)
24 files modified
NEWS (+13/-0)
bzr (+0/-3)
bzrlib/builtins.py (+85/-85)
bzrlib/bundle/commands.py (+1/-1)
bzrlib/cmd_version_info.py (+1/-1)
bzrlib/config.py (+1/-1)
bzrlib/conflicts.py (+2/-2)
bzrlib/foreign.py (+1/-1)
bzrlib/mail_client.py (+12/-12)
bzrlib/plugins/launchpad/__init__.py (+5/-5)
bzrlib/plugins/netrc_credential_store/__init__.py (+1/-1)
bzrlib/plugins/news_merge/__init__.py (+1/-1)
bzrlib/sign_my_commits.py (+1/-1)
bzrlib/tests/__init__.py (+13/-1)
bzrlib/tests/test_commands.py (+16/-19)
bzrlib/tests/test_decorators.py (+11/-11)
bzrlib/tests/test_errors.py (+1/-1)
bzrlib/tests/test_help.py (+9/-9)
bzrlib/tests/test_plugins.py (+5/-5)
bzrlib/tests/test_selftest.py (+11/-2)
bzrlib/tests/test_symbol_versioning.py (+3/-0)
bzrlib/tests/test_workingtree.py (+2/-2)
doc/developers/HACKING.txt (+2/-1)
doc/developers/plugin-api.txt (+2/-3)
Text conflict in NEWS
To merge this branch: bzr merge lp:~gz/bzr/support_OO_flag
Reviewer Review Type Date Requested Status
Vincent Ladeuil Approve
Martin Pool Approve
Andrew Bennetts Abstain
Review via email: mp+22725@code.launchpad.net

Commit message

Manually assign docstrings to command objects, so that they work with python -OO.

Description of the change

This is semi-automated change prepending `__doc__ = ` to the start of all docstrings that should be user, rather than just developer, visible. Therefore it's safe to run `python -OO bzr` which leads (with caveats) to smaller .pyo files on disk.

Bazaar is one of the few python projects that could actually benefit from stripping docstrings, it has lots, and startup time is very important. It's hard to measure cold startup on windows, but seems like a couple of tenths of a second win, though less than a tenth of a second for warm startup:

 C:\bzr\bzr\support_OO_flag>timeit \Python24\python.exe bzr version > nul

 Version Number: Windows NT 5.1 (Build 2600)
 Exit Time: 5:51 pm, Wednesday, March 31 2010
 Elapsed Time: 0:00:00.593
 Process Time: 0:00:00.546
 System Calls: 19835
 Context Switches: 4983
 Page Faults: 6681
 Bytes Read: 4436702
 Bytes Written: 2058
 Bytes Other: 124834

 C:\bzr\bzr\support_OO_flag>timeit \Python24\python.exe -OO bzr version > nul

 Version Number: Windows NT 5.1 (Build 2600)
 Exit Time: 5:51 pm, Wednesday, March 31 2010
 Elapsed Time: 0:00:00.562
 Process Time: 0:00:00.515
 System Calls: 18016
 Context Switches: 4862
 Page Faults: 6012
 Bytes Read: 3492931
 Bytes Written: 2058
 Bytes Other: 124268

The numbers vary a lot, but bytes read and page faults are that order of improvement.

Whether this is a useful change for improving startup time is another question. Distros don't install packages with docstring-stripped .pyo files, so likely only pre-built windows binary could benefit - and as that bundles plugins, only if those are modified too. Perhaps a worthy change even if don't want to distribute a docstring-less bzr, as it defends against someone else importing bzrlib when -OO and those files breaking help for normal usage.

If there's interest in landing this, there are a couple of things left. Needs NEWS, and probably a note in HACKING to say "add `__doc__ = ` to the start of docstrings you want the user to see". Later could look at doing the same thing to commands in plugins, then perhaps at creating the all-in-one installer without docstrings.

Some notes on the contents of the patch, as it's pretty big despite being trivial. It creates some long lines, but the help texts already have these anyway. I'm using the expression `__doc__ is None` as a backwards compatible version of `sys.flags.optimize == 2` in a few places, which is safe as the Bazaar code is quite consistent in supplying module docstrings. There are some mostly-obvious changes to tests. I had written a new blackbox test specifically to run with -OO, but better off just running selftest like that. When reinvoking python in bzrlib.tests.TestCase.start_bzr_subprocess should really propagate opt-ness, but doesn't matter much.

To post a comment you must log in.
Revision history for this message
Andrew Bennetts (spiv) wrote :

I'm ambivalent. The benefit is pretty small, and likely to be even smaller as we improve the lazy loading of commands. On the other hand, the change is fairly small too, although superficially ugly.

Also, as you point out, the benefit cannot be realised until all the bundled plugins are updated like this as well. It would be nice to interoperate better with -OO code that uses bzrlib as a library... but I don't recall anyone ever complaining about that either.

As far as the implementation goes, this looks fine to me. The question is simply do we want to implement this?

Thanks very much for running the experiment, though! I had wondered what the benefit would be. How much size difference does it make, do you know?

review: Abstain
Revision history for this message
John A Meinel (jameinel) wrote :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Andrew Bennetts wrote:
> Review: Abstain
> I'm ambivalent. The benefit is pretty small, and likely to be even smaller as we improve the lazy loading of commands. On the other hand, the change is fairly small too, although superficially ugly.
>
> Also, as you point out, the benefit cannot be realised until all the bundled plugins are updated like this as well. It would be nice to interoperate better with -OO code that uses bzrlib as a library... but I don't recall anyone ever complaining about that either.
>
> As far as the implementation goes, this looks fine to me. The question is simply do we want to implement this?
>
> Thanks very much for running the experiment, though! I had wondered what the benefit would be. How much size difference does it make, do you know?

Well, we went this way for errors, though we did it using a new
attribute _fmt. Which I think actually went pretty well. We could even
do it compatibly with getattr(obj, '_fmt', None) else
deprecated(getattr(obj, '__doc__', None)), etc.

I think moving this way would be good. I think using something like _fmt
would be better than __doc__, if only to eliminate confusion. (And that
you can easily find out what bits aren't doing it the right way.)

John
=:->
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAku9QGcACgkQJdeBCYSNAAPPFACdGzxbNFzNOV5x/WdKXJvqLczF
fiAAnAgae2UQZao1XWHUelXKtrDJqYFL
=zzLa
-----END PGP SIGNATURE-----

Revision history for this message
Robert Collins (lifeless) wrote :

On Thu, 2010-04-08 at 02:36 +0000, John A Meinel wrote:
>
> I think moving this way would be good. I think using something like
> _fmt
> would be better than __doc__, if only to eliminate confusion. (And
> that
> you can easily find out what bits aren't doing it the right way.)

Well, you can find out easily with python -O0 too, so I don't think
thats really significant.

I love that pydoc shows the help at the moment, so I'd really rather not
see us use _fmt or something. It makes more sense with exceptions where
the API guide for the object doesn't correlate all that well with the
output we want from it.

-Rob

Revision history for this message
Martin Packman (gz) wrote :

> I'm ambivalent. The benefit is pretty small, and likely to be even smaller as
> we improve the lazy loading of commands. On the other hand, the change is
> fairly small too, although superficially ugly.

Yes, this and the lazy loading changes are orthogonal. Better laziness means less gain here, but likewise this will always be a win.

> Thanks very much for running the experiment, though! I had wondered what the
> benefit would be. How much size difference does it make, do you know?

Well, going on for a megabyte less read from disk in the `bzr version` example above. Overall:

 C:\bzr\bzr\dev>setup.py build_ext --allow-python-fallback install_lib -d %TEMP% -O2 2>nul>nul

 C:\bzr\bzr\dev>dir /S %TEMP%\bzrlib\*.py | grep -C1 Total

      Total Files Listed:
              719 File(s) 11,998,932 bytes

 C:\bzr\bzr\dev>dir /S %TEMP%\bzrlib\*.pyc | grep -C1 Total

      Total Files Listed:
              719 File(s) 10,010,178 bytes

 C:\bzr\bzr\dev>dir /S %TEMP%\bzrlib\*.pyo | grep -C1 Total

      Total Files Listed:
              719 File(s) 8,537,527 bytes

Most of the docstrings are in the lib not the tests which is why a lot of that saving is seen when running a command. Both kinds of compiled file compress to about 35% in a standard zip - bytecode compresses worse than text, but bytecode-and-text compresses no better than just bytecode.

> Well, we went this way for errors, though we did it using a new
> attribute _fmt. Which I think actually went pretty well. We could even
> do it compatibly with getattr(obj, '_fmt', None) else
> deprecated(getattr(obj, '__doc__', None)), etc.
>
> I think moving this way would be good. I think using something like _fmt
> would be better than __doc__, if only to eliminate confusion. (And that
> you can easily find out what bits aren't doing it the right way.)

Personally, I don't mind this kind of overloading of docstring function. Unlike with error format strings, the help text is still documentation. Sticking the __doc__ label at the front is ugly as Andrew says in some ways, but it also serves as a kind of @user_needs_to_see_this decorator. Reminder of the dual purpose and maybe the need to avoid "this command sucks and needs rewriting" notes.

Revision history for this message
Martin Pool (mbp) wrote :

I think that's kind of cool; given the pydoc point explicitly
assigning to __doc__ is probably the best tradeoff.

If we merge this, we should add a note to the developer guide about
why it is done this way, and ideally also add a test run to Babune
with -OO.
--
Martin <http://launchpad.net/~mbp/>

Revision history for this message
Martin Packman (gz) wrote :

Documentation added, put the news entry under 'Internals', move it to 'API Changes' or whatever on merge if that'd deemed more appropriate. The remaining step is to look at the installer creation stuff, see if there's a feasible benefit to be had. Can perhaps just strip bzrlib only to start, maybe Ian or someone can give me a hand working it out.

Revision history for this message
Martin Pool (mbp) wrote :

Ok, the documentation looks reasonable and I'm glad you thought of the case of plugins. Let's do it.

Ubuntu does have a small number of pyo files under /usr so perhaps it is possible to arrange for bzr to run with -OO and to then load precompiled stripped files.

review: Approve
Revision history for this message
Robert Collins (lifeless) wrote :

This looks good to go, except NEWS needs a fixup

Revision history for this message
Martin Packman (gz) wrote :

Is the fixup something I need to do prior to the normal merge?

I have a followup experimenting with using this in the windows packaging without messing with plugins that I'd like to see someone try. Interested to see how much it'll shrink the 17.2MB library.zip bundled currently.

Revision history for this message
Robert Collins (lifeless) wrote :

Someone needs to do it before it can be sent to PQM; in the
very-limited-awkward PQM access we had previously, it would go something
like this (and the person would be e.g. me/vila/poolie etc):

cd integration
bzr pull --overwrite [your branch]
bzr merge bzr.dev
fix-up-to-be-ready
bzr commit; bzr push; bzr pqm-submit -m ....

Now however, we can nearly push-button submit your branch, if you fix it up
and push; or we can do a similar but slightly more involved dance:

cd integration
bzr pull --overwrite [your branch]
bzr merge bzr.dev
fixup
bzr commit; bzr push; bzr lp-open; propose a new merge, copy your
description in, copy your commit message in, approve it;
$ feed-pqm bzr
m [set the commit message]
s [queues it]

We'll probably want a hydrazine command to clone a merge proposal and
update, for doing integration like this.

Easiest by far is if you update your branch to be ready-to-land.

Revision history for this message
Martin Packman (gz) wrote :

Thanks for the rundown, have merged trunk and updated.

Revision history for this message
Robert Collins (lifeless) wrote :

Sorry to be a pain, but are you aware that we keep each stanza of NEWS alphabetically sorted to ease merging? It looks like its not in alpha-order.

Revision history for this message
Martin Packman (gz) wrote :

Hgrf, no, either missed for forgotten about that edict. NEWS changed, will remember for the future.

Revision history for this message
Robert Collins (lifeless) wrote :

Thank you for that. There is one more thing you could start doing on new
proposals - fill in the 'comit message' field. We haven't been using it
previously, and we're not fully migrated yet, but I'll be adding it to the
general developers docs shortly.

Revision history for this message
Martin Packman (gz) wrote :

I messed up some logic that was causing failures that got blamed on <lp:~parthm/bzr/no-chown-if-bzrlog-exists> the last revision should resolve it.

Revision history for this message
Vincent Ladeuil (vila) wrote :
Download full text (12.5 KiB)

Unfortunately python -OO bzr selftest fails (see below), which is a bit weird.

bzr selftest: /home/vila/src/bzr/reviews/support_OO_flag/bzr
   /home/vila/src/bzr/reviews/support_OO_flag/bzrlib
   bzr-2.2.0dev1 python-2.6.4 Linux-2.6.31-20-generic-x86_64-with-Ubuntu-9.10-karmic

/home/vila/src/bzr/reviews/support_OO_flag/bzrlib/lazy_import.py:125: UserWarning: No help message set for <bzrlib.tests.test_commands.cmd_foo object at 0x93a8c10>
  return obj(*args, **kwargs)
/home/vila/src/bzr/reviews/support_OO_flag/bzrlib/commands.py:411: UserWarning: No help message set for <bzrlib.tests.test_commands.cmd_foo object at 0x939e450>
  warn("No help message set for %r" % self)
/home/vila/src/bzr/reviews/support_OO_flag/bzrlib/commands.py:411: UserWarning: No help message set for <bzrlib.tests.test_commands.cmd_test_extend_command_hook object at 0x9d1ba90>
  warn("No help message set for %r" % self)
/home/vila/src/bzr/reviews/support_OO_flag/bzrlib/commands.py:411: UserWarning: No help message set for <bzrlib.tests.test_commands.ACommand object at 0x938eb50>
  warn("No help message set for %r" % self)
/home/vila/src/bzr/reviews/support_OO_flag/bzrlib/commands.py:411: UserWarning: No help message set for <bzrlib.tests.test_commands.ACommand object at 0x9afdd10>
  warn("No help message set for %r" % self)
/home/vila/src/bzr/reviews/support_OO_flag/bzrlib/commands.py:411: UserWarning: No help message set for <bzrlib.tests.test_commands.ACommand object at 0x9afd6d0>
  warn("No help message set for %r" % self)
/home/vila/src/bzr/reviews/support_OO_flag/bzrlib/commands.py:411: UserWarning: No help message set for <bzrlib.tests.test_commands.ACommand object at 0x9afd290>
  warn("No help message set for %r" % self)
/home/vila/src/bzr/reviews/support_OO_flag/bzrlib/commands.py:411: UserWarning: No help message set for <bzrlib.tests.test_commands.ACommand object at 0x93a8d90>
  warn("No help message set for %r" % self)
/home/vila/src/bzr/reviews/support_OO_flag/bzrlib/commands.py:411: UserWarning: No help message set for <bzrlib.tests.test_commands.ACommand object at 0x93a8550>
  warn("No help message set for %r" % self)
/home/vila/src/bzr/reviews/support_OO_flag/bzrlib/commands.py:411: UserWarning: No help message set for <bzrlib.tests.test_commands.ACommand object at 0x93a8ad0>
  warn("No help message set for %r" % self)
/home/vila/src/bzr/reviews/support_OO_flag/bzrlib/commands.py:411: UserWarning: No help message set for <bzrlib.tests.test_commands.ACommand object at 0x9d4d150>
  warn("No help message set for %r" % self)
/home/vila/src/bzr/reviews/support_OO_flag/bzrlib/commands.py:411: UserWarning: No help message set for <bzrlib.tests.test_commands.ACommand object at 0x93a8450>
  warn("No help message set for %r" % self)
/home/vila/src/bzr/reviews/support_OO_flag/bzrlib/commands.py:411: UserWarning: No help message set for <bzrlib.tests.test_commands.ACommand object at 0x9d41210>
  warn("No help message set for %r" % self)
ERROR: test_commands.TestCommands.test_help_hidden
    Text attachment: log
------------

------------
Text attachment: traceback
------------
Traceback (most recent call last):
  File "/home/vila/lib/python/testtools/runtest.py", line...

review: Needs Fixing
Revision history for this message
Martin Packman (gz) wrote :

Urk, sorry Vincent, thanks for the report. These failures and the previous issue were due to poor workflow on my part. As selftest takes so long to run and has lots of spurious error output, I've been tending to only test a limited set of modules I know to have problems. Clearly this means I miss thing when it's a more involved changeset like this, apologies.

Anyway, I've fixed the failures you've identified and would be grateful if you tried again.

Revision history for this message
Vincent Ladeuil (vila) wrote :

>>>>> Martin [gz] writes:

    > Urk, sorry Vincent, thanks for the report.

No worries.

    > These failures and the previous issue were due to poor workflow on
    > my part. As selftest takes so long to run and has lots of spurious
    > error output, I've been tending to only test a limited set of
    > modules I know to have problems.

We all fall into this trap, repeatedly.

    > Clearly this means I miss thing when it's a more involved
    > changeset like this, apologies.

No need for that, really, that's why we have reviews and pqm (but in
that case, pqm would have failed to detect it though).

    > Anyway, I've fixed the failures you've identified and would be
    > grateful if you tried again.

Done. Works.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'NEWS'
2--- NEWS 2010-04-22 13:32:23 +0000
3+++ NEWS 2010-04-22 18:59:24 +0000
4@@ -165,6 +165,19 @@
5 Command is now transient and only exists for the duration of ``run()``.
6 (Robert Collins)
7
8+<<<<<<< TREE
9+=======
10+* Permit bzr to run under ``python -OO`` which reduces the size of bytecode
11+ files loaded from disk. To ensure docstrings needed for help are never
12+ stripped, the prefix ``__doc__ =`` should now be used.
13+ (Martin <gzlist@googlemail.com>)
14+
15+Testing
16+*******
17+
18+* ``bzr selftest --parallel=subprocess`` now works correctly on win32.
19+ (Gordon Tyler, #551332)
20+>>>>>>> MERGE-SOURCE
21
22 bzr 2.2.0b1
23 ###########
24
25=== modified file 'bzr'
26--- bzr 2010-04-16 07:56:51 +0000
27+++ bzr 2010-04-22 18:59:24 +0000
28@@ -25,9 +25,6 @@
29 # update this on each release
30 _script_version = (2, 2, 0)
31
32-if __doc__ is None:
33- print "bzr does not support python -OO."
34- sys.exit(2)
35 try:
36 version_info = sys.version_info
37 except AttributeError:
38
39=== modified file 'bzrlib/builtins.py'
40--- bzrlib/builtins.py 2010-04-22 15:44:21 +0000
41+++ bzrlib/builtins.py 2010-04-22 18:59:24 +0000
42@@ -239,7 +239,7 @@
43 # opens the branch?)
44
45 class cmd_status(Command):
46- """Display status summary.
47+ __doc__ = """Display status summary.
48
49 This reports on versioned and unknown files, reporting them
50 grouped by state. Possible states are:
51@@ -332,7 +332,7 @@
52
53
54 class cmd_cat_revision(Command):
55- """Write out metadata for a revision.
56+ __doc__ = """Write out metadata for a revision.
57
58 The revision to print can either be specified by a specific
59 revision identifier, or you can use --revision.
60@@ -390,7 +390,7 @@
61
62
63 class cmd_dump_btree(Command):
64- """Dump the contents of a btree index file to stdout.
65+ __doc__ = """Dump the contents of a btree index file to stdout.
66
67 PATH is a btree index file, it can be any URL. This includes things like
68 .bzr/repository/pack-names, or .bzr/repository/indices/a34b3a...ca4a4.iix
69@@ -471,7 +471,7 @@
70
71
72 class cmd_remove_tree(Command):
73- """Remove the working tree from a given branch/checkout.
74+ __doc__ = """Remove the working tree from a given branch/checkout.
75
76 Since a lightweight checkout is little more than a working tree
77 this will refuse to run against one.
78@@ -514,7 +514,7 @@
79
80
81 class cmd_revno(Command):
82- """Show current revision number.
83+ __doc__ = """Show current revision number.
84
85 This is equal to the number of revisions on this branch.
86 """
87@@ -550,7 +550,7 @@
88
89
90 class cmd_revision_info(Command):
91- """Show revision number and revision id for a given revision identifier.
92+ __doc__ = """Show revision number and revision id for a given revision identifier.
93 """
94 hidden = True
95 takes_args = ['revision_info*']
96@@ -612,7 +612,7 @@
97
98
99 class cmd_add(Command):
100- """Add specified files or directories.
101+ __doc__ = """Add specified files or directories.
102
103 In non-recursive mode, all the named items are added, regardless
104 of whether they were previously ignored. A warning is given if
105@@ -698,7 +698,7 @@
106
107
108 class cmd_mkdir(Command):
109- """Create a new versioned directory.
110+ __doc__ = """Create a new versioned directory.
111
112 This is equivalent to creating the directory and then adding it.
113 """
114@@ -720,7 +720,7 @@
115
116
117 class cmd_relpath(Command):
118- """Show path of a file relative to root"""
119+ __doc__ = """Show path of a file relative to root"""
120
121 takes_args = ['filename']
122 hidden = True
123@@ -735,7 +735,7 @@
124
125
126 class cmd_inventory(Command):
127- """Show inventory of the current working copy or a revision.
128+ __doc__ = """Show inventory of the current working copy or a revision.
129
130 It is possible to limit the output to a particular entry
131 type using the --kind option. For example: --kind file.
132@@ -796,7 +796,7 @@
133
134
135 class cmd_mv(Command):
136- """Move or rename a file.
137+ __doc__ = """Move or rename a file.
138
139 :Usage:
140 bzr mv OLDNAME NEWNAME
141@@ -933,7 +933,7 @@
142
143
144 class cmd_pull(Command):
145- """Turn this branch into a mirror of another branch.
146+ __doc__ = """Turn this branch into a mirror of another branch.
147
148 By default, this command only works on branches that have not diverged.
149 Branches are considered diverged if the destination branch's most recent
150@@ -1060,7 +1060,7 @@
151
152
153 class cmd_push(Command):
154- """Update a mirror of this branch.
155+ __doc__ = """Update a mirror of this branch.
156
157 The target branch will not have its working tree populated because this
158 is both expensive, and is not supported on remote file systems.
159@@ -1173,7 +1173,7 @@
160
161
162 class cmd_branch(Command):
163- """Create a new branch that is a copy of an existing branch.
164+ __doc__ = """Create a new branch that is a copy of an existing branch.
165
166 If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
167 be used. In other words, "branch ../foo/bar" will attempt to create ./bar.
168@@ -1286,7 +1286,7 @@
169
170
171 class cmd_checkout(Command):
172- """Create a new checkout of an existing branch.
173+ __doc__ = """Create a new checkout of an existing branch.
174
175 If BRANCH_LOCATION is omitted, checkout will reconstitute a working tree for
176 the branch found in '.'. This is useful if you have removed the working tree
177@@ -1355,7 +1355,7 @@
178
179
180 class cmd_renames(Command):
181- """Show list of renamed files.
182+ __doc__ = """Show list of renamed files.
183 """
184 # TODO: Option to show renames between two historical versions.
185
186@@ -1387,7 +1387,7 @@
187
188
189 class cmd_update(Command):
190- """Update a tree to have the latest code committed to its branch.
191+ __doc__ = """Update a tree to have the latest code committed to its branch.
192
193 This will perform a merge into the working tree, and may generate
194 conflicts. If you have any local changes, you will still
195@@ -1473,7 +1473,7 @@
196
197
198 class cmd_info(Command):
199- """Show information about a working tree, branch or repository.
200+ __doc__ = """Show information about a working tree, branch or repository.
201
202 This command will show all known locations and formats associated to the
203 tree, branch or repository.
204@@ -1517,7 +1517,7 @@
205
206
207 class cmd_remove(Command):
208- """Remove files or directories.
209+ __doc__ = """Remove files or directories.
210
211 This makes bzr stop tracking changes to the specified files. bzr will delete
212 them if they can easily be recovered using revert. If no options or
213@@ -1571,7 +1571,7 @@
214
215
216 class cmd_file_id(Command):
217- """Print file_id of a particular file or directory.
218+ __doc__ = """Print file_id of a particular file or directory.
219
220 The file_id is assigned when the file is first added and remains the
221 same through all revisions where the file exists, even when it is
222@@ -1593,7 +1593,7 @@
223
224
225 class cmd_file_path(Command):
226- """Print path of file_ids to a file or directory.
227+ __doc__ = """Print path of file_ids to a file or directory.
228
229 This prints one line for each directory down to the target,
230 starting at the branch root.
231@@ -1615,7 +1615,7 @@
232
233
234 class cmd_reconcile(Command):
235- """Reconcile bzr metadata in a branch.
236+ __doc__ = """Reconcile bzr metadata in a branch.
237
238 This can correct data mismatches that may have been caused by
239 previous ghost operations or bzr upgrades. You should only
240@@ -1643,7 +1643,7 @@
241
242
243 class cmd_revision_history(Command):
244- """Display the list of revision ids on a branch."""
245+ __doc__ = """Display the list of revision ids on a branch."""
246
247 _see_also = ['log']
248 takes_args = ['location?']
249@@ -1659,7 +1659,7 @@
250
251
252 class cmd_ancestry(Command):
253- """List all revisions merged into this branch."""
254+ __doc__ = """List all revisions merged into this branch."""
255
256 _see_also = ['log', 'revision-history']
257 takes_args = ['location?']
258@@ -1684,7 +1684,7 @@
259
260
261 class cmd_init(Command):
262- """Make a directory into a versioned branch.
263+ __doc__ = """Make a directory into a versioned branch.
264
265 Use this to create an empty branch, or before importing an
266 existing project.
267@@ -1793,7 +1793,7 @@
268
269
270 class cmd_init_repository(Command):
271- """Create a shared repository for branches to share storage space.
272+ __doc__ = """Create a shared repository for branches to share storage space.
273
274 New branches created under the repository directory will store their
275 revisions in the repository, not in the branch directory. For branches
276@@ -1853,7 +1853,7 @@
277
278
279 class cmd_diff(Command):
280- """Show differences in the working tree, between revisions or branches.
281+ __doc__ = """Show differences in the working tree, between revisions or branches.
282
283 If no arguments are given, all changes for the current tree are listed.
284 If files are given, only the changes in those files are listed.
285@@ -1994,7 +1994,7 @@
286
287
288 class cmd_deleted(Command):
289- """List files deleted in the working tree.
290+ __doc__ = """List files deleted in the working tree.
291 """
292 # TODO: Show files deleted since a previous revision, or
293 # between two revisions.
294@@ -2023,7 +2023,7 @@
295
296
297 class cmd_modified(Command):
298- """List files modified in working tree.
299+ __doc__ = """List files modified in working tree.
300 """
301
302 hidden = True
303@@ -2046,7 +2046,7 @@
304
305
306 class cmd_added(Command):
307- """List files added in working tree.
308+ __doc__ = """List files added in working tree.
309 """
310
311 hidden = True
312@@ -2082,7 +2082,7 @@
313
314
315 class cmd_root(Command):
316- """Show the tree root directory.
317+ __doc__ = """Show the tree root directory.
318
319 The root is the nearest enclosing directory with a .bzr control
320 directory."""
321@@ -2112,7 +2112,7 @@
322
323
324 class cmd_log(Command):
325- """Show historical log for a branch or subset of a branch.
326+ __doc__ = """Show historical log for a branch or subset of a branch.
327
328 log is bzr's default tool for exploring the history of a branch.
329 The branch to use is taken from the first parameter. If no parameters
330@@ -2483,7 +2483,7 @@
331
332
333 class cmd_touching_revisions(Command):
334- """Return revision-ids which affected a particular file.
335+ __doc__ = """Return revision-ids which affected a particular file.
336
337 A more user-friendly interface is "bzr log FILE".
338 """
339@@ -2504,7 +2504,7 @@
340
341
342 class cmd_ls(Command):
343- """List files in a tree.
344+ __doc__ = """List files in a tree.
345 """
346
347 _see_also = ['status', 'cat']
348@@ -2621,7 +2621,7 @@
349
350
351 class cmd_unknowns(Command):
352- """List unknown files.
353+ __doc__ = """List unknown files.
354 """
355
356 hidden = True
357@@ -2634,7 +2634,7 @@
358
359
360 class cmd_ignore(Command):
361- """Ignore specified files or patterns.
362+ __doc__ = """Ignore specified files or patterns.
363
364 See ``bzr help patterns`` for details on the syntax of patterns.
365
366@@ -2736,7 +2736,7 @@
367
368
369 class cmd_ignored(Command):
370- """List ignored files and the patterns that matched them.
371+ __doc__ = """List ignored files and the patterns that matched them.
372
373 List all the ignored files and the ignore pattern that caused the file to
374 be ignored.
375@@ -2763,7 +2763,7 @@
376
377
378 class cmd_lookup_revision(Command):
379- """Lookup the revision-id from a revision-number
380+ __doc__ = """Lookup the revision-id from a revision-number
381
382 :Examples:
383 bzr lookup-revision 33
384@@ -2783,7 +2783,7 @@
385
386
387 class cmd_export(Command):
388- """Export current or past revision to a destination directory or archive.
389+ __doc__ = """Export current or past revision to a destination directory or archive.
390
391 If no revision is specified this exports the last committed revision.
392
393@@ -2846,7 +2846,7 @@
394
395
396 class cmd_cat(Command):
397- """Write the contents of a file as of a given revision to standard output.
398+ __doc__ = """Write the contents of a file as of a given revision to standard output.
399
400 If no revision is nominated, the last revision is used.
401
402@@ -2932,7 +2932,7 @@
403
404
405 class cmd_local_time_offset(Command):
406- """Show the offset in seconds from GMT to local time."""
407+ __doc__ = """Show the offset in seconds from GMT to local time."""
408 hidden = True
409 @display_command
410 def run(self):
411@@ -2941,7 +2941,7 @@
412
413
414 class cmd_commit(Command):
415- """Commit changes into a new revision.
416+ __doc__ = """Commit changes into a new revision.
417
418 An explanatory message needs to be given for each commit. This is
419 often done by using the --message option (getting the message from the
420@@ -3207,7 +3207,7 @@
421
422
423 class cmd_check(Command):
424- """Validate working tree structure, branch consistency and repository history.
425+ __doc__ = """Validate working tree structure, branch consistency and repository history.
426
427 This command checks various invariants about branch and repository storage
428 to detect data corruption or bzr bugs.
429@@ -3277,7 +3277,7 @@
430
431
432 class cmd_upgrade(Command):
433- """Upgrade branch storage to current format.
434+ __doc__ = """Upgrade branch storage to current format.
435
436 The check command or bzr developers may sometimes advise you to run
437 this command. When the default format has changed you may also be warned
438@@ -3301,7 +3301,7 @@
439
440
441 class cmd_whoami(Command):
442- """Show or set bzr user id.
443+ __doc__ = """Show or set bzr user id.
444
445 :Examples:
446 Show the email of the current user::
447@@ -3351,7 +3351,7 @@
448
449
450 class cmd_nick(Command):
451- """Print or set the branch nickname.
452+ __doc__ = """Print or set the branch nickname.
453
454 If unset, the tree root directory name is used as the nickname.
455 To print the current nickname, execute with no argument.
456@@ -3375,7 +3375,7 @@
457
458
459 class cmd_alias(Command):
460- """Set/unset and display aliases.
461+ __doc__ = """Set/unset and display aliases.
462
463 :Examples:
464 Show the current aliases::
465@@ -3445,7 +3445,7 @@
466
467
468 class cmd_selftest(Command):
469- """Run internal test suite.
470+ __doc__ = """Run internal test suite.
471
472 If arguments are given, they are regular expressions that say which tests
473 should run. Tests matching any expression are run, and other tests are
474@@ -3633,7 +3633,7 @@
475
476
477 class cmd_version(Command):
478- """Show version of bzr."""
479+ __doc__ = """Show version of bzr."""
480
481 encoding_type = 'replace'
482 takes_options = [
483@@ -3650,7 +3650,7 @@
484
485
486 class cmd_rocks(Command):
487- """Statement of optimism."""
488+ __doc__ = """Statement of optimism."""
489
490 hidden = True
491
492@@ -3660,7 +3660,7 @@
493
494
495 class cmd_find_merge_base(Command):
496- """Find and print a base revision for merging two branches."""
497+ __doc__ = """Find and print a base revision for merging two branches."""
498 # TODO: Options to specify revisions on either side, as if
499 # merging only part of the history.
500 takes_args = ['branch', 'other']
501@@ -3686,7 +3686,7 @@
502
503
504 class cmd_merge(Command):
505- """Perform a three-way merge.
506+ __doc__ = """Perform a three-way merge.
507
508 The source of the merge can be specified either in the form of a branch,
509 or in the form of a path to a file containing a merge directive generated
510@@ -4047,7 +4047,7 @@
511
512
513 class cmd_remerge(Command):
514- """Redo a merge.
515+ __doc__ = """Redo a merge.
516
517 Use this if you want to try a different merge technique while resolving
518 conflicts. Some merge techniques are better than others, and remerge
519@@ -4142,7 +4142,7 @@
520
521
522 class cmd_revert(Command):
523- """Revert files to a previous revision.
524+ __doc__ = """Revert files to a previous revision.
525
526 Giving a list of files will revert only those files. Otherwise, all files
527 will be reverted. If the revision is not specified with '--revision', the
528@@ -4214,7 +4214,7 @@
529
530
531 class cmd_assert_fail(Command):
532- """Test reporting of assertion failures"""
533+ __doc__ = """Test reporting of assertion failures"""
534 # intended just for use in testing
535
536 hidden = True
537@@ -4224,7 +4224,7 @@
538
539
540 class cmd_help(Command):
541- """Show help on a command or other topic.
542+ __doc__ = """Show help on a command or other topic.
543 """
544
545 _see_also = ['topics']
546@@ -4243,7 +4243,7 @@
547
548
549 class cmd_shell_complete(Command):
550- """Show appropriate completions for context.
551+ __doc__ = """Show appropriate completions for context.
552
553 For a list of all available commands, say 'bzr shell-complete'.
554 """
555@@ -4258,7 +4258,7 @@
556
557
558 class cmd_missing(Command):
559- """Show unmerged/unpulled revisions between two branches.
560+ __doc__ = """Show unmerged/unpulled revisions between two branches.
561
562 OTHER_BRANCH may be local or remote.
563
564@@ -4431,7 +4431,7 @@
565
566
567 class cmd_pack(Command):
568- """Compress the data within a repository.
569+ __doc__ = """Compress the data within a repository.
570
571 This operation compresses the data within a bazaar repository. As
572 bazaar supports automatic packing of repository, this operation is
573@@ -4466,7 +4466,7 @@
574
575
576 class cmd_plugins(Command):
577- """List the installed plugins.
578+ __doc__ = """List the installed plugins.
579
580 This command displays the list of installed plugins including
581 version of plugin and a short description of each.
582@@ -4511,7 +4511,7 @@
583
584
585 class cmd_testament(Command):
586- """Show testament (signing-form) of a revision."""
587+ __doc__ = """Show testament (signing-form) of a revision."""
588 takes_options = [
589 'revision',
590 Option('long', help='Produce long-format testament.'),
591@@ -4543,7 +4543,7 @@
592
593
594 class cmd_annotate(Command):
595- """Show the origin of each line in a file.
596+ __doc__ = """Show the origin of each line in a file.
597
598 This prints out the given file with an annotation on the left side
599 indicating which revision, author and date introduced the change.
600@@ -4596,7 +4596,7 @@
601
602
603 class cmd_re_sign(Command):
604- """Create a digital signature for an existing revision."""
605+ __doc__ = """Create a digital signature for an existing revision."""
606 # TODO be able to replace existing ones.
607
608 hidden = True # is this right ?
609@@ -4662,7 +4662,7 @@
610
611
612 class cmd_bind(Command):
613- """Convert the current branch into a checkout of the supplied branch.
614+ __doc__ = """Convert the current branch into a checkout of the supplied branch.
615
616 Once converted into a checkout, commits must succeed on the master branch
617 before they will be applied to the local branch.
618@@ -4702,7 +4702,7 @@
619
620
621 class cmd_unbind(Command):
622- """Convert the current checkout into a regular branch.
623+ __doc__ = """Convert the current checkout into a regular branch.
624
625 After unbinding, the local branch is considered independent and subsequent
626 commits will be local only.
627@@ -4719,7 +4719,7 @@
628
629
630 class cmd_uncommit(Command):
631- """Remove the last committed revision.
632+ __doc__ = """Remove the last committed revision.
633
634 --verbose will print out what is being removed.
635 --dry-run will go through all the motions, but not actually
636@@ -4827,7 +4827,7 @@
637
638
639 class cmd_break_lock(Command):
640- """Break a dead lock on a repository, branch or working directory.
641+ __doc__ = """Break a dead lock on a repository, branch or working directory.
642
643 CAUTION: Locks should only be broken when you are sure that the process
644 holding the lock has been stopped.
645@@ -4852,7 +4852,7 @@
646
647
648 class cmd_wait_until_signalled(Command):
649- """Test helper for test_start_and_stop_bzr_subprocess_send_signal.
650+ __doc__ = """Test helper for test_start_and_stop_bzr_subprocess_send_signal.
651
652 This just prints a line to signal when it is ready, then blocks on stdin.
653 """
654@@ -4866,7 +4866,7 @@
655
656
657 class cmd_serve(Command):
658- """Run the bzr server."""
659+ __doc__ = """Run the bzr server."""
660
661 aliases = ['server']
662
663@@ -4932,7 +4932,7 @@
664
665
666 class cmd_join(Command):
667- """Combine a tree into its containing tree.
668+ __doc__ = """Combine a tree into its containing tree.
669
670 This command requires the target tree to be in a rich-root format.
671
672@@ -4978,7 +4978,7 @@
673
674
675 class cmd_split(Command):
676- """Split a subdirectory of a tree into a separate tree.
677+ __doc__ = """Split a subdirectory of a tree into a separate tree.
678
679 This command will produce a target tree in a format that supports
680 rich roots, like 'rich-root' or 'rich-root-pack'. These formats cannot be
681@@ -5004,7 +5004,7 @@
682
683
684 class cmd_merge_directive(Command):
685- """Generate a merge directive for auto-merge tools.
686+ __doc__ = """Generate a merge directive for auto-merge tools.
687
688 A directive requests a merge to be performed, and also provides all the
689 information necessary to do so. This means it must either include a
690@@ -5103,7 +5103,7 @@
691
692
693 class cmd_send(Command):
694- """Mail or create a merge-directive for submitting changes.
695+ __doc__ = """Mail or create a merge-directive for submitting changes.
696
697 A merge directive provides many things needed for requesting merges:
698
699@@ -5220,7 +5220,7 @@
700
701
702 class cmd_bundle_revisions(cmd_send):
703- """Create a merge-directive for submitting changes.
704+ __doc__ = """Create a merge-directive for submitting changes.
705
706 A merge directive provides many things needed for requesting merges:
707
708@@ -5293,7 +5293,7 @@
709
710
711 class cmd_tag(Command):
712- """Create, remove or modify a tag naming a revision.
713+ __doc__ = """Create, remove or modify a tag naming a revision.
714
715 Tags give human-meaningful names to revisions. Commands that take a -r
716 (--revision) option can be given -rtag:X, where X is any previously
717@@ -5366,7 +5366,7 @@
718
719
720 class cmd_tags(Command):
721- """List tags.
722+ __doc__ = """List tags.
723
724 This command shows a table of tag names and the revisions they reference.
725 """
726@@ -5440,7 +5440,7 @@
727
728
729 class cmd_reconfigure(Command):
730- """Reconfigure the type of a bzr directory.
731+ __doc__ = """Reconfigure the type of a bzr directory.
732
733 A target configuration must be specified.
734
735@@ -5531,7 +5531,7 @@
736
737
738 class cmd_switch(Command):
739- """Set the branch of a checkout and update.
740+ __doc__ = """Set the branch of a checkout and update.
741
742 For lightweight checkouts, this changes the branch being referenced.
743 For heavyweight checkouts, this checks that there are no local commits
744@@ -5627,7 +5627,7 @@
745
746
747 class cmd_view(Command):
748- """Manage filtered views.
749+ __doc__ = """Manage filtered views.
750
751 Views provide a mask over the tree so that users can focus on
752 a subset of a tree when doing their work. After creating a view,
753@@ -5781,7 +5781,7 @@
754
755
756 class cmd_hooks(Command):
757- """Show hooks."""
758+ __doc__ = """Show hooks."""
759
760 hidden = True
761
762@@ -5801,7 +5801,7 @@
763
764
765 class cmd_remove_branch(Command):
766- """Remove a branch.
767+ __doc__ = """Remove a branch.
768
769 This will remove the branch from the specified location but
770 will keep any working tree or repository in place.
771@@ -5826,7 +5826,7 @@
772
773
774 class cmd_shelve(Command):
775- """Temporarily set aside some changes from the current tree.
776+ __doc__ = """Temporarily set aside some changes from the current tree.
777
778 Shelve allows you to temporarily put changes you've made "on the shelf",
779 ie. out of the way, until a later time when you can bring them back from
780@@ -5901,7 +5901,7 @@
781
782
783 class cmd_unshelve(Command):
784- """Restore shelved changes.
785+ __doc__ = """Restore shelved changes.
786
787 By default, the most recently shelved changes are restored. However if you
788 specify a shelf by id those changes will be restored instead. This works
789@@ -5933,7 +5933,7 @@
790
791
792 class cmd_clean_tree(Command):
793- """Remove unwanted files from working tree.
794+ __doc__ = """Remove unwanted files from working tree.
795
796 By default, only unknown files, not ignored files, are deleted. Versioned
797 files are never deleted.
798@@ -5967,7 +5967,7 @@
799
800
801 class cmd_reference(Command):
802- """list, view and set branch locations for nested trees.
803+ __doc__ = """list, view and set branch locations for nested trees.
804
805 If no arguments are provided, lists the branch locations for nested trees.
806 If one argument is provided, display the branch location for that tree.
807
808=== modified file 'bzrlib/bundle/commands.py'
809--- bzrlib/bundle/commands.py 2010-03-25 09:39:03 +0000
810+++ bzrlib/bundle/commands.py 2010-04-22 18:59:24 +0000
811@@ -41,7 +41,7 @@
812
813
814 class cmd_bundle_info(Command):
815- """Output interesting stats about a bundle"""
816+ __doc__ = """Output interesting stats about a bundle"""
817
818 hidden = True
819 takes_args = ['location']
820
821=== modified file 'bzrlib/cmd_version_info.py'
822--- bzrlib/cmd_version_info.py 2010-02-17 17:11:16 +0000
823+++ bzrlib/cmd_version_info.py 2010-04-22 18:59:24 +0000
824@@ -48,7 +48,7 @@
825
826
827 class cmd_version_info(Command):
828- """Show version information about this tree.
829+ __doc__ = """Show version information about this tree.
830
831 You can use this command to add information about version into
832 source code of an application. The output can be in one of the
833
834=== modified file 'bzrlib/config.py'
835--- bzrlib/config.py 2010-03-06 05:28:17 +0000
836+++ bzrlib/config.py 2010-04-22 18:59:24 +0000
837@@ -1407,7 +1407,7 @@
838
839
840 class PlainTextCredentialStore(CredentialStore):
841- """Plain text credential store for the authentication.conf file."""
842+ __doc__ = """Plain text credential store for the authentication.conf file"""
843
844 def decode_password(self, credentials):
845 """See CredentialStore.decode_password."""
846
847=== modified file 'bzrlib/conflicts.py'
848--- bzrlib/conflicts.py 2010-03-25 09:09:31 +0000
849+++ bzrlib/conflicts.py 2010-04-22 18:59:24 +0000
850@@ -46,7 +46,7 @@
851
852
853 class cmd_conflicts(commands.Command):
854- """List files with conflicts.
855+ __doc__ = """List files with conflicts.
856
857 Merge will do its best to combine the changes in two branches, but there
858 are some kinds of problems only a human can fix. When it encounters those,
859@@ -99,7 +99,7 @@
860
861
862 class cmd_resolve(commands.Command):
863- """Mark a conflict as resolved.
864+ __doc__ = """Mark a conflict as resolved.
865
866 Merge will do its best to combine the changes in two branches, but there
867 are some kinds of problems only a human can fix. When it encounters those,
868
869=== modified file 'bzrlib/foreign.py'
870--- bzrlib/foreign.py 2010-04-12 16:54:35 +0000
871+++ bzrlib/foreign.py 2010-04-22 18:59:24 +0000
872@@ -259,7 +259,7 @@
873
874
875 class cmd_dpush(Command):
876- """Push into a different VCS without any custom bzr metadata.
877+ __doc__ = """Push into a different VCS without any custom bzr metadata.
878
879 This will afterwards rebase the local branch on the remote
880 branch unless the --no-rebase option is used, in which case
881
882=== modified file 'bzrlib/mail_client.py'
883--- bzrlib/mail_client.py 2009-09-24 19:51:37 +0000
884+++ bzrlib/mail_client.py 2010-04-22 18:59:24 +0000
885@@ -89,7 +89,7 @@
886
887
888 class Editor(MailClient):
889- """DIY mail client that uses commit message editor"""
890+ __doc__ = """DIY mail client that uses commit message editor"""
891
892 supports_body = True
893
894@@ -230,13 +230,13 @@
895
896
897 class ExternalMailClient(BodyExternalMailClient):
898- """An external mail client."""
899+ __doc__ = """An external mail client."""
900
901 supports_body = False
902
903
904 class Evolution(BodyExternalMailClient):
905- """Evolution mail client."""
906+ __doc__ = """Evolution mail client."""
907
908 _client_commands = ['evolution']
909
910@@ -258,7 +258,7 @@
911
912
913 class Mutt(BodyExternalMailClient):
914- """Mutt mail client."""
915+ __doc__ = """Mutt mail client."""
916
917 _client_commands = ['mutt']
918
919@@ -286,7 +286,7 @@
920
921
922 class Thunderbird(BodyExternalMailClient):
923- """Mozilla Thunderbird (or Icedove)
924+ __doc__ = """Mozilla Thunderbird (or Icedove)
925
926 Note that Thunderbird 1.5 is buggy and does not support setting
927 "to" simultaneously with including a attachment.
928@@ -321,7 +321,7 @@
929
930
931 class KMail(ExternalMailClient):
932- """KDE mail client."""
933+ __doc__ = """KDE mail client."""
934
935 _client_commands = ['kmail']
936
937@@ -341,7 +341,7 @@
938
939
940 class Claws(ExternalMailClient):
941- """Claws mail client."""
942+ __doc__ = """Claws mail client."""
943
944 supports_body = True
945
946@@ -387,7 +387,7 @@
947
948
949 class XDGEmail(BodyExternalMailClient):
950- """xdg-email attempts to invoke the user's preferred mail client"""
951+ __doc__ = """xdg-email attempts to invoke the user's preferred mail client"""
952
953 _client_commands = ['xdg-email']
954
955@@ -409,7 +409,7 @@
956
957
958 class EmacsMail(ExternalMailClient):
959- """Call emacsclient to have a mail buffer.
960+ __doc__ = """Call emacsclient to have a mail buffer.
961
962 This only work for emacs >= 22.1 due to recent -e/--eval support.
963
964@@ -519,7 +519,7 @@
965
966
967 class MAPIClient(BodyExternalMailClient):
968- """Default Windows mail client launched using MAPI."""
969+ __doc__ = """Default Windows mail client launched using MAPI."""
970
971 def _compose(self, prompt, to, subject, attach_path, mime_subtype,
972 extension, body=None):
973@@ -540,7 +540,7 @@
974
975
976 class MailApp(BodyExternalMailClient):
977- """Use MacOS X's Mail.app for sending email messages.
978+ __doc__ = """Use MacOS X's Mail.app for sending email messages.
979
980 Although it would be nice to use appscript, it's not installed
981 with the shipped Python installations. We instead build an
982@@ -599,7 +599,7 @@
983
984
985 class DefaultMail(MailClient):
986- """Default mail handling. Tries XDGEmail (or MAPIClient on Windows),
987+ __doc__ = """Default mail handling. Tries XDGEmail (or MAPIClient on Windows),
988 falls back to Editor"""
989
990 supports_body = True
991
992=== modified file 'bzrlib/plugins/launchpad/__init__.py'
993--- bzrlib/plugins/launchpad/__init__.py 2010-02-23 07:43:11 +0000
994+++ bzrlib/plugins/launchpad/__init__.py 2010-04-22 18:59:24 +0000
995@@ -53,7 +53,7 @@
996
997
998 class cmd_register_branch(Command):
999- """Register a branch with launchpad.net.
1000+ __doc__ = """Register a branch with launchpad.net.
1001
1002 This command lists a bzr branch in the directory of branches on
1003 launchpad.net. Registration allows the branch to be associated with
1004@@ -161,7 +161,7 @@
1005
1006
1007 class cmd_launchpad_open(Command):
1008- """Open a Launchpad branch page in your web browser."""
1009+ __doc__ = """Open a Launchpad branch page in your web browser."""
1010
1011 aliases = ['lp-open']
1012 takes_options = [
1013@@ -211,7 +211,7 @@
1014
1015
1016 class cmd_launchpad_login(Command):
1017- """Show or set the Launchpad user ID.
1018+ __doc__ = """Show or set the Launchpad user ID.
1019
1020 When communicating with Launchpad, some commands need to know your
1021 Launchpad user ID. This command can be used to set or show the
1022@@ -267,7 +267,7 @@
1023
1024 # XXX: cmd_launchpad_mirror is untested
1025 class cmd_launchpad_mirror(Command):
1026- """Ask Launchpad to mirror a branch now."""
1027+ __doc__ = """Ask Launchpad to mirror a branch now."""
1028
1029 aliases = ['lp-mirror']
1030 takes_args = ['location?']
1031@@ -286,7 +286,7 @@
1032
1033
1034 class cmd_lp_propose_merge(Command):
1035- """Propose merging a branch on Launchpad.
1036+ __doc__ = """Propose merging a branch on Launchpad.
1037
1038 This will open your usual editor to provide the initial comment. When it
1039 has created the proposal, it will open it in your default web browser.
1040
1041=== modified file 'bzrlib/plugins/netrc_credential_store/__init__.py'
1042--- bzrlib/plugins/netrc_credential_store/__init__.py 2009-04-10 18:56:00 +0000
1043+++ bzrlib/plugins/netrc_credential_store/__init__.py 2010-04-22 18:59:24 +0000
1044@@ -14,7 +14,7 @@
1045 # along with this program; if not, write to the Free Software
1046 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1047
1048-"""Use ~/.netrc as a credential store for authentication.conf."""
1049+__doc__ = """Use ~/.netrc as a credential store for authentication.conf."""
1050
1051 # Since we are a built-in plugin we share the bzrlib version
1052 from bzrlib import version_info
1053
1054=== modified file 'bzrlib/plugins/news_merge/__init__.py'
1055--- bzrlib/plugins/news_merge/__init__.py 2010-01-28 17:27:16 +0000
1056+++ bzrlib/plugins/news_merge/__init__.py 2010-04-22 18:59:24 +0000
1057@@ -14,7 +14,7 @@
1058 # along with this program; if not, write to the Free Software
1059 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1060
1061-"""Merge hook for bzr's NEWS file.
1062+__doc__ = """Merge hook for bzr's NEWS file.
1063
1064 To enable this plugin, add a section to your branch.conf or location.conf
1065 like::
1066
1067=== modified file 'bzrlib/sign_my_commits.py'
1068--- bzrlib/sign_my_commits.py 2009-03-23 14:59:43 +0000
1069+++ bzrlib/sign_my_commits.py 2010-04-22 18:59:24 +0000
1070@@ -30,7 +30,7 @@
1071
1072
1073 class cmd_sign_my_commits(Command):
1074- """Sign all commits by a given committer.
1075+ __doc__ = """Sign all commits by a given committer.
1076
1077 If location is not specified the local tree is used.
1078 If committer is not specified the default committer is used.
1079
1080=== modified file 'bzrlib/tests/__init__.py'
1081--- bzrlib/tests/__init__.py 2010-04-22 15:44:21 +0000
1082+++ bzrlib/tests/__init__.py 2010-04-22 18:59:24 +0000
1083@@ -14,6 +14,7 @@
1084 # along with this program; if not, write to the Free Software
1085 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1086
1087+"""Testing framework extensions"""
1088
1089 # TODO: Perhaps there should be an API to find out if bzr running under the
1090 # test suite -- some plugins might want to avoid making intrusive changes if
1091@@ -1312,6 +1313,14 @@
1092 f.close()
1093 self.assertEqualDiff(content, s)
1094
1095+ def assertDocstring(self, expected_docstring, obj):
1096+ """Fail if obj does not have expected_docstring"""
1097+ if __doc__ is None:
1098+ # With -OO the docstring should be None instead
1099+ self.assertIs(obj.__doc__, None)
1100+ else:
1101+ self.assertEqual(expected_docstring, obj.__doc__)
1102+
1103 def failUnlessExists(self, path):
1104 """Fail unless path or paths, which may be abs or relative, exist."""
1105 if not isinstance(path, basestring):
1106@@ -3796,7 +3805,10 @@
1107
1108
1109 def _test_suite_modules_to_doctest():
1110- """Return the list of modules to doctest."""
1111+ """Return the list of modules to doctest."""
1112+ if __doc__ is None:
1113+ # GZ 2009-03-31: No docstrings with -OO so there's nothing to doctest
1114+ return []
1115 return [
1116 'bzrlib',
1117 'bzrlib.branchbuilder',
1118
1119=== modified file 'bzrlib/tests/test_commands.py'
1120--- bzrlib/tests/test_commands.py 2010-03-25 09:39:03 +0000
1121+++ bzrlib/tests/test_commands.py 2010-04-22 18:59:24 +0000
1122@@ -65,7 +65,7 @@
1123 @staticmethod
1124 def get_command(options):
1125 class cmd_foo(commands.Command):
1126- 'Bar'
1127+ __doc__ = 'Bar'
1128
1129 takes_options = options
1130
1131@@ -120,38 +120,35 @@
1132 class TestSeeAlso(tests.TestCase):
1133 """Tests for the see also functional of Command."""
1134
1135+ @staticmethod
1136+ def _get_command_with_see_also(see_also):
1137+ class ACommand(commands.Command):
1138+ __doc__ = """A sample command."""
1139+ _see_also = see_also
1140+ return ACommand()
1141+
1142 def test_default_subclass_no_see_also(self):
1143- class ACommand(commands.Command):
1144- """A sample command."""
1145- command = ACommand()
1146+ command = self._get_command_with_see_also([])
1147 self.assertEqual([], command.get_see_also())
1148
1149 def test__see_also(self):
1150 """When _see_also is defined, it sets the result of get_see_also()."""
1151- class ACommand(commands.Command):
1152- _see_also = ['bar', 'foo']
1153- command = ACommand()
1154+ command = self._get_command_with_see_also(['bar', 'foo'])
1155 self.assertEqual(['bar', 'foo'], command.get_see_also())
1156
1157 def test_deduplication(self):
1158 """Duplicates in _see_also are stripped out."""
1159- class ACommand(commands.Command):
1160- _see_also = ['foo', 'foo']
1161- command = ACommand()
1162+ command = self._get_command_with_see_also(['foo', 'foo'])
1163 self.assertEqual(['foo'], command.get_see_also())
1164
1165 def test_sorted(self):
1166 """_see_also is sorted by get_see_also."""
1167- class ACommand(commands.Command):
1168- _see_also = ['foo', 'bar']
1169- command = ACommand()
1170+ command = self._get_command_with_see_also(['foo', 'bar'])
1171 self.assertEqual(['bar', 'foo'], command.get_see_also())
1172
1173 def test_additional_terms(self):
1174 """Additional terms can be supplied and are deduped and sorted."""
1175- class ACommand(commands.Command):
1176- _see_also = ['foo', 'bar']
1177- command = ACommand()
1178+ command = self._get_command_with_see_also(['foo', 'bar'])
1179 self.assertEqual(['bar', 'foo', 'gam'],
1180 command.get_see_also(['gam', 'bar', 'gam']))
1181
1182@@ -212,7 +209,7 @@
1183 "extend_command", hook_calls.append, None)
1184 # create a command, should not fire
1185 class cmd_test_extend_command_hook(commands.Command):
1186- """A sample command."""
1187+ __doc__ = """A sample command."""
1188 self.assertEqual([], hook_calls)
1189 # -- as a builtin
1190 # register the command class, should not fire
1191@@ -249,7 +246,7 @@
1192 commands.install_bzr_command_hooks()
1193 hook_calls = []
1194 class ACommand(commands.Command):
1195- """A sample command."""
1196+ __doc__ = """A sample command."""
1197 def get_cmd(cmd_or_None, cmd_name):
1198 hook_calls.append(('called', cmd_or_None, cmd_name))
1199 if cmd_name in ('foo', 'info'):
1200@@ -280,7 +277,7 @@
1201 """Hook get_missing_command for testing."""
1202 self.hook_calls = []
1203 class ACommand(commands.Command):
1204- """A sample command."""
1205+ __doc__ = """A sample command."""
1206 def get_missing_cmd(cmd_name):
1207 self.hook_calls.append(('called', cmd_name))
1208 if cmd_name in ('foo', 'info'):
1209
1210=== modified file 'bzrlib/tests/test_decorators.py'
1211--- bzrlib/tests/test_decorators.py 2009-10-02 06:12:20 +0000
1212+++ bzrlib/tests/test_decorators.py 2010-04-22 18:59:24 +0000
1213@@ -167,14 +167,14 @@
1214 """@needs_read_lock exposes underlying name and doc."""
1215 sam = create_decorator_sample(None)
1216 self.assertEqual('frob', sam.frob.__name__)
1217- self.assertEqual('Frob the sample object', sam.frob.__doc__)
1218+ self.assertDocstring('Frob the sample object', sam.frob)
1219
1220 def test_write_lock_passthrough(self):
1221 """@needs_write_lock exposes underlying name and doc."""
1222 sam = create_decorator_sample(None)
1223 self.assertEqual('bank', sam.bank.__name__)
1224- self.assertEqual('Bank the sample, but using bar and biz.',
1225- sam.bank.__doc__)
1226+ self.assertDocstring('Bank the sample, but using bar and biz.',
1227+ sam.bank)
1228
1229 def test_argument_passthrough(self):
1230 """Test that arguments get passed around properly."""
1231@@ -208,8 +208,8 @@
1232 my_function.func_code.co_name)
1233 self.assertEqual('(foo, bar, baz=None, biz=1)',
1234 self.get_formatted_args(my_function))
1235- self.assertEqual('Just a function that supplies several arguments.',
1236- inspect.getdoc(my_function))
1237+ self.assertDocstring(
1238+ 'Just a function that supplies several arguments.', my_function)
1239
1240 def test__fast_needs_read_lock(self):
1241 """Test the output of _fast_needs_read_lock."""
1242@@ -222,8 +222,8 @@
1243 self.assertEqual('read_locked', my_function.func_code.co_name)
1244 self.assertEqual('(self, *args, **kwargs)',
1245 self.get_formatted_args(my_function))
1246- self.assertEqual('Just a function that supplies several arguments.',
1247- inspect.getdoc(my_function))
1248+ self.assertDocstring(
1249+ 'Just a function that supplies several arguments.', my_function)
1250
1251 def test__pretty_needs_write_lock(self):
1252 """Test that _pretty_needs_write_lock generates a nice wrapper."""
1253@@ -237,8 +237,8 @@
1254 my_function.func_code.co_name)
1255 self.assertEqual('(foo, bar, baz=None, biz=1)',
1256 self.get_formatted_args(my_function))
1257- self.assertEqual('Just a function that supplies several arguments.',
1258- inspect.getdoc(my_function))
1259+ self.assertDocstring(
1260+ 'Just a function that supplies several arguments.', my_function)
1261
1262 def test__fast_needs_write_lock(self):
1263 """Test the output of _fast_needs_write_lock."""
1264@@ -251,8 +251,8 @@
1265 self.assertEqual('write_locked', my_function.func_code.co_name)
1266 self.assertEqual('(self, *args, **kwargs)',
1267 self.get_formatted_args(my_function))
1268- self.assertEqual('Just a function that supplies several arguments.',
1269- inspect.getdoc(my_function))
1270+ self.assertDocstring(
1271+ 'Just a function that supplies several arguments.', my_function)
1272
1273 def test_use_decorators(self):
1274 """Test that you can switch the type of the decorators."""
1275
1276=== modified file 'bzrlib/tests/test_errors.py'
1277--- bzrlib/tests/test_errors.py 2010-02-17 17:11:16 +0000
1278+++ bzrlib/tests/test_errors.py 2010-04-22 18:59:24 +0000
1279@@ -670,7 +670,7 @@
1280
1281
1282 class ErrorWithNoFormat(errors.BzrError):
1283- """This class has a docstring but no format string."""
1284+ __doc__ = """This class has a docstring but no format string."""
1285
1286
1287 class TestErrorFormatting(TestCase):
1288
1289=== modified file 'bzrlib/tests/test_help.py'
1290--- bzrlib/tests/test_help.py 2009-06-15 10:22:08 +0000
1291+++ bzrlib/tests/test_help.py 2010-04-22 18:59:24 +0000
1292@@ -41,7 +41,7 @@
1293
1294 def test_command_help_includes_see_also(self):
1295 class cmd_WithSeeAlso(commands.Command):
1296- """A sample command."""
1297+ __doc__ = """A sample command."""
1298 _see_also = ['foo', 'bar']
1299 cmd = cmd_WithSeeAlso()
1300 helptext = cmd.get_help_text()
1301@@ -56,7 +56,7 @@
1302 def test_get_help_text(self):
1303 """Commands have a get_help_text method which returns their help."""
1304 class cmd_Demo(commands.Command):
1305- """A sample command."""
1306+ __doc__ = """A sample command."""
1307 cmd = cmd_Demo()
1308 helptext = cmd.get_help_text()
1309 self.assertStartsWith(helptext,
1310@@ -67,7 +67,7 @@
1311
1312 def test_command_with_additional_see_also(self):
1313 class cmd_WithSeeAlso(commands.Command):
1314- """A sample command."""
1315+ __doc__ = """A sample command."""
1316 _see_also = ['foo', 'bar']
1317 cmd = cmd_WithSeeAlso()
1318 helptext = cmd.get_help_text(['gam'])
1319@@ -81,7 +81,7 @@
1320
1321 def test_command_only_additional_see_also(self):
1322 class cmd_WithSeeAlso(commands.Command):
1323- """A sample command."""
1324+ __doc__ = """A sample command."""
1325 cmd = cmd_WithSeeAlso()
1326 helptext = cmd.get_help_text(['gam'])
1327 self.assertEndsWith(
1328@@ -95,14 +95,14 @@
1329 def test_get_help_topic(self):
1330 """The help topic for a Command is its name()."""
1331 class cmd_foo_bar(commands.Command):
1332- """A sample command."""
1333+ __doc__ = """A sample command."""
1334 cmd = cmd_foo_bar()
1335 self.assertEqual(cmd.name(), cmd.get_help_topic())
1336
1337 def test_formatted_help_text(self):
1338 """Help text should be plain text by default."""
1339 class cmd_Demo(commands.Command):
1340- """A sample command.
1341+ __doc__ = """A sample command.
1342
1343 :Examples:
1344 Example 1::
1345@@ -159,7 +159,7 @@
1346 def test_concise_help_text(self):
1347 """Concise help text excludes the descriptive sections."""
1348 class cmd_Demo(commands.Command):
1349- """A sample command.
1350+ __doc__ = """A sample command.
1351
1352 Blah blah blah.
1353
1354@@ -206,7 +206,7 @@
1355 def test_help_custom_section_ordering(self):
1356 """Custom descriptive sections should remain in the order given."""
1357 class cmd_Demo(commands.Command):
1358- """A sample command.
1359+ __doc__ = """A sample command.
1360
1361 Blah blah blah.
1362
1363@@ -252,7 +252,7 @@
1364 def test_help_text_custom_usage(self):
1365 """Help text may contain a custom usage section."""
1366 class cmd_Demo(commands.Command):
1367- """A sample command.
1368+ __doc__ = """A sample command.
1369
1370 :Usage:
1371 cmd Demo [opts] args
1372
1373=== modified file 'bzrlib/tests/test_plugins.py'
1374--- bzrlib/tests/test_plugins.py 2010-04-06 07:22:31 +0000
1375+++ bzrlib/tests/test_plugins.py 2010-04-22 18:59:24 +0000
1376@@ -473,7 +473,7 @@
1377 f.write("""\
1378 from bzrlib import commands
1379 class cmd_myplug(commands.Command):
1380- '''Just a simple test plugin.'''
1381+ __doc__ = '''Just a simple test plugin.'''
1382 aliases = ['mplg']
1383 def run(self):
1384 print 'Hello from my plugin'
1385@@ -780,8 +780,8 @@
1386 self.overrideAttr(plugin, '_loaded', False)
1387 plugin.load_plugins(['.'])
1388 self.assertPluginKnown('test_foo')
1389- self.assertEqual("This is the doc for test_foo",
1390- bzrlib.plugins.test_foo.__doc__)
1391+ self.assertDocstring("This is the doc for test_foo",
1392+ bzrlib.plugins.test_foo)
1393
1394 def test_not_loaded(self):
1395 self.warnings = []
1396@@ -816,8 +816,8 @@
1397
1398 def assertTestFooLoadedFrom(self, path):
1399 self.assertPluginKnown('test_foo')
1400- self.assertEqual('This is the doc for test_foo',
1401- bzrlib.plugins.test_foo.__doc__)
1402+ self.assertDocstring('This is the doc for test_foo',
1403+ bzrlib.plugins.test_foo)
1404 self.assertEqual(path, bzrlib.plugins.test_foo.dir_source)
1405
1406 def test_regular_load(self):
1407
1408=== modified file 'bzrlib/tests/test_selftest.py'
1409--- bzrlib/tests/test_selftest.py 2010-04-18 08:51:37 +0000
1410+++ bzrlib/tests/test_selftest.py 2010-04-22 18:59:24 +0000
1411@@ -2773,6 +2773,10 @@
1412 # Test that a plausible list of modules to doctest is returned
1413 # by _test_suite_modules_to_doctest.
1414 test_list = tests._test_suite_modules_to_doctest()
1415+ if __doc__ is None:
1416+ # When docstrings are stripped, there are no modules to doctest
1417+ self.assertEqual([], test_list)
1418+ return
1419 self.assertSubset([
1420 'bzrlib.timestamp',
1421 ],
1422@@ -2795,6 +2799,8 @@
1423 self.overrideAttr(tests, '_test_suite_testmod_names', testmod_names)
1424 def doctests():
1425 calls.append("modules_to_doctest")
1426+ if __doc__ is None:
1427+ return []
1428 return ['bzrlib.timestamp']
1429 self.overrideAttr(tests, '_test_suite_modules_to_doctest', doctests)
1430 expected_test_list = [
1431@@ -2803,11 +2809,14 @@
1432 ('bzrlib.tests.per_transport.TransportTests'
1433 '.test_abspath(LocalTransport,LocalURLServer)'),
1434 'bzrlib.tests.test_selftest.TestTestSuite.test_test_suite',
1435- # modules_to_doctest
1436- 'bzrlib.timestamp.format_highres_date',
1437 # plugins can't be tested that way since selftest may be run with
1438 # --no-plugins
1439 ]
1440+ if __doc__ is not None:
1441+ expected_test_list.extend([
1442+ # modules_to_doctest
1443+ 'bzrlib.timestamp.format_highres_date',
1444+ ])
1445 suite = tests.test_suite()
1446 self.assertEqual(set(["testmod_names", "modules_to_doctest"]),
1447 set(calls))
1448
1449=== modified file 'bzrlib/tests/test_symbol_versioning.py'
1450--- bzrlib/tests/test_symbol_versioning.py 2010-01-25 17:48:22 +0000
1451+++ bzrlib/tests/test_symbol_versioning.py 2010-04-22 18:59:24 +0000
1452@@ -179,6 +179,9 @@
1453 def check_deprecated_callable(self, expected_warning, expected_docstring,
1454 expected_name, expected_module,
1455 deprecated_callable):
1456+ if __doc__ is None:
1457+ # With -OO the docstring should just be the deprecated version
1458+ expected_docstring = expected_docstring.split('\n')[-2].lstrip()
1459 old_warning_method = symbol_versioning.warn
1460 try:
1461 symbol_versioning.set_warning_method(self.capture_warning)
1462
1463=== modified file 'bzrlib/tests/test_workingtree.py'
1464--- bzrlib/tests/test_workingtree.py 2009-03-23 14:59:43 +0000
1465+++ bzrlib/tests/test_workingtree.py 2010-04-22 18:59:24 +0000
1466@@ -303,9 +303,9 @@
1467 self.assertEqual(
1468 'method_with_tree_write_lock',
1469 tree.method_with_tree_write_lock.__name__)
1470- self.assertEqual(
1471+ self.assertDocstring(
1472 "A lock_tree_write decorated method that returns its arguments.",
1473- tree.method_with_tree_write_lock.__doc__)
1474+ tree.method_with_tree_write_lock)
1475 args = (1, 2, 3)
1476 kwargs = {'a':'b'}
1477 result = tree.method_with_tree_write_lock(1,2,3, a='b')
1478
1479=== modified file 'doc/developers/HACKING.txt'
1480--- doc/developers/HACKING.txt 2010-03-30 07:29:56 +0000
1481+++ doc/developers/HACKING.txt 2010-04-22 18:59:24 +0000
1482@@ -1053,7 +1053,8 @@
1483 and on other help topics. (See ``help_topics.py``.)
1484
1485 As for python docstrings, the first paragraph should be a single-sentence
1486-synopsis of the command.
1487+synopsis of the command. These are user-visible and should be prefixed with
1488+``__doc__ =`` so help works under ``python -OO`` with docstrings stripped.
1489
1490 The help for options should be one or more proper sentences, starting with
1491 a capital letter and finishing with a full stop (period).
1492
1493=== modified file 'doc/developers/plugin-api.txt'
1494--- doc/developers/plugin-api.txt 2010-02-23 03:18:56 +0000
1495+++ doc/developers/plugin-api.txt 2010-04-22 18:59:24 +0000
1496@@ -186,9 +186,8 @@
1497 short complete sentence summarizing the plugin. The full docstring is
1498 shown by ``bzr help PLUGIN_NAME``.
1499
1500-Remember that to be effective, the module docstring must be the first
1501-statement in the file. It may come after comments but it must be before
1502-any import statements.
1503+This is a user-visible docstring so should be prefixed with ``__doc__ =``
1504+to ensure help works under ``python -OO`` with docstrings stripped.
1505
1506 API version
1507 -----------