##// END OF EJS Templates
wrap helpstring output to 80 cols
MinRK -
Show More
@@ -33,7 +33,11 b' from IPython.utils.traitlets import ('
33 33 Unicode, List, Int, Enum, Dict, Instance
34 34 )
35 35 from IPython.utils.importstring import import_item
36 from IPython.utils.text import indent
36 from IPython.utils.text import indent, wrap_paragraphs, dedent
37
38 #-----------------------------------------------------------------------------
39 # function for re-wrapping a helpstring
40 #-----------------------------------------------------------------------------
37 41
38 42 #-----------------------------------------------------------------------------
39 43 # Descriptions for the various sections
@@ -44,6 +48,8 b" Flags are command-line arguments passed as '--<flag>'."
44 48 These take no parameters, unlike regular key-value arguments.
45 49 They are typically used for setting boolean flags, or enabling
46 50 modes that involve setting multiple options together.
51
52 Flags *always* begin with '--', never just one '-'.
47 53 """.strip() # trim newlines of front and back
48 54
49 55 alias_description = """
@@ -104,10 +110,18 b' class Application(SingletonConfigurable):'
104 110 # this must be a dict of two-tuples, the first element being the Config/dict
105 111 # and the second being the help string for the flag
106 112 flags = Dict()
113 def _flags_changed(self, name, old, new):
114 """ensure flags dict is valid"""
115 for key,value in new.iteritems():
116 assert len(value) == 2, "Bad flag: %r:%s"%(key,value)
117 assert isinstance(value[0], (dict, Config)), "Bad flag: %r:%s"%(key,value)
118 assert isinstance(value[1], basestring), "Bad flag: %r:%s"%(key,value)
119
107 120
108 121 # subcommands for launching other applications
109 122 # if this is not empty, this will be a parent Application
110 # this must be a dict of two-tuples, the first element being the application class/import string
123 # this must be a dict of two-tuples,
124 # the first element being the application class/import string
111 125 # and the second being the help string for the subcommand
112 126 subcommands = Dict()
113 127 # parse_command_line will initialize a subapp, if requested
@@ -123,11 +137,6 b' class Application(SingletonConfigurable):'
123 137 # options.
124 138 self.classes.insert(0, self.__class__)
125 139
126 # ensure self.flags dict is valid
127 for key,value in self.flags.iteritems():
128 assert len(value) == 2, "Bad flag: %r:%s"%(key,value)
129 assert isinstance(value[0], (dict, Config)), "Bad flag: %r:%s"%(key,value)
130 assert isinstance(value[1], basestring), "Bad flag: %r:%s"%(key,value)
131 140 self.init_logging()
132 141
133 142 def _config_changed(self, name, old, new):
@@ -170,14 +179,16 b' class Application(SingletonConfigurable):'
170 179 self.log.setLevel(new)
171 180
172 181 def print_alias_help(self):
173 """print the alias part of the help"""
182 """Print the alias part of the help."""
174 183 if not self.aliases:
175 184 return
176 185
177 186 lines = ['Aliases']
178 187 lines.append('-'*len(lines[0]))
179 lines.append(self.alias_description)
180 188 lines.append('')
189 for p in wrap_paragraphs(self.alias_description):
190 lines.append(p)
191 lines.append('')
181 192
182 193 classdict = {}
183 194 for cls in self.classes:
@@ -197,23 +208,25 b' class Application(SingletonConfigurable):'
197 208 print '\n'.join(lines)
198 209
199 210 def print_flag_help(self):
200 """print the flag part of the help"""
211 """Print the flag part of the help."""
201 212 if not self.flags:
202 213 return
203 214
204 215 lines = ['Flags']
205 216 lines.append('-'*len(lines[0]))
206 lines.append(self.flag_description)
207 217 lines.append('')
218 for p in wrap_paragraphs(self.flag_description):
219 lines.append(p)
220 lines.append('')
208 221
209 222 for m, (cfg,help) in self.flags.iteritems():
210 223 lines.append('--'+m)
211 lines.append(indent(help.strip(), flatten=True))
224 lines.append(indent(dedent(help.strip())))
212 225 lines.append('')
213 226 print '\n'.join(lines)
214 227
215 228 def print_subcommands(self):
216 """print the subcommand part of the help"""
229 """Print the subcommand part of the help."""
217 230 if not self.subcommands:
218 231 return
219 232
@@ -222,14 +235,14 b' class Application(SingletonConfigurable):'
222 235 for subc, (cls,help) in self.subcommands.iteritems():
223 236 lines.append("%s : %s"%(subc, cls))
224 237 if help:
225 lines.append(indent(help.strip(), flatten=True))
238 lines.append(indent(dedent(help.strip())))
226 239 lines.append('')
227 240 print '\n'.join(lines)
228 241
229 242 def print_help(self, classes=False):
230 243 """Print the help for each Configurable class in self.classes.
231 244
232 If classes=False (the default), only flags and aliases are printed
245 If classes=False (the default), only flags and aliases are printed.
233 246 """
234 247 self.print_subcommands()
235 248 self.print_flag_help()
@@ -239,8 +252,10 b' class Application(SingletonConfigurable):'
239 252 if self.classes:
240 253 print "Class parameters"
241 254 print "----------------"
242 print self.keyvalue_description
243 255 print
256 for p in wrap_paragraphs(self.keyvalue_description):
257 print p
258 print
244 259
245 260 for cls in self.classes:
246 261 cls.class_print_help()
@@ -251,8 +266,9 b' class Application(SingletonConfigurable):'
251 266
252 267 def print_description(self):
253 268 """Print the application description."""
254 print self.description
255 print
269 for p in wrap_paragraphs(self.description):
270 print p
271 print
256 272
257 273 def print_version(self):
258 274 """Print the version string."""
@@ -269,7 +285,7 b' class Application(SingletonConfigurable):'
269 285 self.config = newconfig
270 286
271 287 def initialize_subcommand(self, subc, argv=None):
272 """Initialize a subcommand with argv"""
288 """Initialize a subcommand with argv."""
273 289 subapp,help = self.subcommands.get(subc)
274 290
275 291 if isinstance(subapp, basestring):
@@ -330,7 +346,7 b' class Application(SingletonConfigurable):'
330 346 #-----------------------------------------------------------------------------
331 347
332 348 def boolean_flag(name, configurable, set_help='', unset_help=''):
333 """helper for building basic --trait, --no-trait flags
349 """Helper for building basic --trait, --no-trait flags.
334 350
335 351 Parameters
336 352 ----------
@@ -360,3 +376,4 b" def boolean_flag(name, configurable, set_help='', unset_help=''):"
360 376 setter = {cls : {trait : True}}
361 377 unsetter = {cls : {trait : False}}
362 378 return {name : (setter, set_help), 'no-'+name : (unsetter, unset_help)}
379
@@ -21,12 +21,12 b' Authors:'
21 21 # Imports
22 22 #-----------------------------------------------------------------------------
23 23
24 from copy import deepcopy
25 24 import datetime
25 from copy import deepcopy
26 26
27 27 from loader import Config
28 28 from IPython.utils.traitlets import HasTraits, Instance
29 from IPython.utils.text import indent
29 from IPython.utils.text import indent, wrap_paragraphs
30 30
31 31
32 32 #-----------------------------------------------------------------------------
@@ -51,7 +51,7 b' class Configurable(HasTraits):'
51 51 created = None
52 52
53 53 def __init__(self, **kwargs):
54 """Create a conigurable given a config config.
54 """Create a configurable given a config config.
55 55
56 56 Parameters
57 57 ----------
@@ -153,27 +153,31 b' class Configurable(HasTraits):'
153 153
154 154 @classmethod
155 155 def class_get_trait_help(cls, trait):
156 """Get the help string for a single """
156 """Get the help string for a single trait."""
157 157 lines = []
158 158 header = "%s.%s : %s" % (cls.__name__, trait.name, trait.__class__.__name__)
159 lines.append(header)
159 160 try:
160 161 dvr = repr(trait.get_default_value())
161 162 except Exception:
162 163 dvr = None # ignore defaults we can't construct
163 164 if dvr is not None:
164 header += ' [default: %s]'%dvr
165 lines.append(header)
165 if len(dvr) > 64:
166 dvr = dvr[:61]+'...'
167 lines.append(indent('Default: %s'%dvr, 4))
168 if 'Enum' in trait.__class__.__name__:
169 # include Enum choices
170 lines.append(indent('Choices: %r'%(trait.values,)))
166 171
167 172 help = trait.get_metadata('help')
168 173 if help is not None:
169 lines.append(indent(help.strip(), flatten=True))
170 if 'Enum' in trait.__class__.__name__:
171 # include Enum choices
172 lines.append(indent('Choices: %r'%(trait.values,), flatten=True))
174 help = '\n'.join(wrap_paragraphs(help, 76))
175 lines.append(indent(help, 4))
173 176 return '\n'.join(lines)
174 177
175 178 @classmethod
176 179 def class_print_help(cls):
180 """Get the help string for a single trait and print it."""
177 181 print cls.class_get_help()
178 182
179 183
@@ -19,6 +19,7 b' import __main__'
19 19 import os
20 20 import re
21 21 import shutil
22 import textwrap
22 23 from string import Formatter
23 24
24 25 from IPython.external.path import path
@@ -520,6 +521,58 b' def format_screen(strng):'
520 521 strng = par_re.sub('',strng)
521 522 return strng
522 523
524 def dedent(text):
525 """Equivalent of textwrap.dedent that ignores unindented first line.
526
527 This means it will still dedent strings like:
528 '''foo
529 is a bar
530 '''
531
532 For use in wrap_paragraphs.
533 """
534
535 if text.startswith('\n'):
536 # text starts with blank line, don't ignore the first line
537 return textwrap.dedent(text)
538
539 # split first line
540 splits = text.split('\n',1)
541 if len(splits) == 1:
542 # only one line
543 return textwrap.dedent(text)
544
545 first, rest = splits
546 # dedent everything but the first line
547 rest = textwrap.dedent(rest)
548 return '\n'.join([first, rest])
549
550 def wrap_paragraphs(text, ncols=80):
551 """Wrap multiple paragraphs to fit a specified width.
552
553 This is equivalent to textwrap.wrap, but with support for multiple
554 paragraphs, as separated by empty lines.
555
556 Returns
557 -------
558
559 list of complete paragraphs, wrapped to fill `ncols` columns.
560 """
561 paragraph_re = re.compile(r'\n(\s*\n)+', re.MULTILINE)
562 text = dedent(text).strip()
563 paragraphs = paragraph_re.split(text)[::2] # every other entry is space
564 out_ps = []
565 indent_re = re.compile(r'\n\s+', re.MULTILINE)
566 for p in paragraphs:
567 # presume indentation that survives dedent is meaningful formatting,
568 # so don't fill unless text is flush.
569 if indent_re.search(p) is None:
570 # wrap paragraph
571 p = textwrap.fill(p, ncols)
572 out_ps.append(p)
573 return out_ps
574
575
523 576
524 577 class EvalFormatter(Formatter):
525 578 """A String Formatter that allows evaluation of simple expressions.
General Comments 0
You need to be logged in to leave comments. Login now