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 |
""" |
|
|
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 |
""" |
|
|
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() |
|
|
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 |
""" |
|
|
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() |
|
|
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 | |
|
256 | for p in wrap_paragraphs(self.keyvalue_description): | |
|
257 | print p | |
|
258 | ||
|
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 |
|
|
|
255 | ||
|
269 | for p in wrap_paragraphs(self.description): | |
|
270 | print p | |
|
271 | ||
|
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 |
""" |
|
|
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