##// END OF EJS Templates
- Small dir. completion fix, problem reported by Stefan.
fperez -
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,650 +1,657 b''
1 1 """Word completion for IPython.
2 2
3 3 This module is a fork of the rlcompleter module in the Python standard
4 4 library. The original enhancements made to rlcompleter have been sent
5 5 upstream and were accepted as of Python 2.3, but we need a lot more
6 6 functionality specific to IPython, so this module will continue to live as an
7 7 IPython-specific utility.
8 8
9 9 ---------------------------------------------------------------------------
10 10 Original rlcompleter documentation:
11 11
12 12 This requires the latest extension to the readline module (the
13 13 completes keywords, built-ins and globals in __main__; when completing
14 14 NAME.NAME..., it evaluates (!) the expression up to the last dot and
15 15 completes its attributes.
16 16
17 17 It's very cool to do "import string" type "string.", hit the
18 18 completion key (twice), and see the list of names defined by the
19 19 string module!
20 20
21 21 Tip: to use the tab key as the completion key, call
22 22
23 23 readline.parse_and_bind("tab: complete")
24 24
25 25 Notes:
26 26
27 27 - Exceptions raised by the completer function are *ignored* (and
28 28 generally cause the completion to fail). This is a feature -- since
29 29 readline sets the tty device in raw (or cbreak) mode, printing a
30 30 traceback wouldn't work well without some complicated hoopla to save,
31 31 reset and restore the tty state.
32 32
33 33 - The evaluation of the NAME.NAME... form may cause arbitrary
34 34 application defined code to be executed if an object with a
35 35 __getattr__ hook is found. Since it is the responsibility of the
36 36 application (or the user) to enable this feature, I consider this an
37 37 acceptable risk. More complicated expressions (e.g. function calls or
38 38 indexing operations) are *not* evaluated.
39 39
40 40 - GNU readline is also used by the built-in functions input() and
41 41 raw_input(), and thus these also benefit/suffer from the completer
42 42 features. Clearly an interactive application can benefit by
43 43 specifying its own completer function and using raw_input() for all
44 44 its input.
45 45
46 46 - When the original stdin is not a tty device, GNU readline is never
47 47 used, and this module (and the readline module) are silently inactive.
48 48
49 49 """
50 50
51 51 #*****************************************************************************
52 52 #
53 53 # Since this file is essentially a minimally modified copy of the rlcompleter
54 54 # module which is part of the standard Python distribution, I assume that the
55 55 # proper procedure is to maintain its copyright as belonging to the Python
56 56 # Software Foundation (in addition to my own, for all new code).
57 57 #
58 58 # Copyright (C) 2001 Python Software Foundation, www.python.org
59 59 # Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
60 60 #
61 61 # Distributed under the terms of the BSD License. The full license is in
62 62 # the file COPYING, distributed as part of this software.
63 63 #
64 64 #*****************************************************************************
65 65
66 66 import __builtin__
67 67 import __main__
68 68 import glob
69 69 import keyword
70 70 import os
71 71 import re
72 72 import shlex
73 73 import sys
74 74 import IPython.rlineimpl as readline
75 75 import itertools
76 76 from IPython.ipstruct import Struct
77 77 from IPython import ipapi
78 78
79 79 import types
80 80
81 81 # Python 2.4 offers sets as a builtin
82 82 try:
83 83 set([1,2])
84 84 except NameError:
85 85 from sets import Set as set
86 86
87 87 from IPython.genutils import debugx
88 88
89 89 __all__ = ['Completer','IPCompleter']
90 90
91 91 def get_class_members(cls):
92 92 ret = dir(cls)
93 93 if hasattr(cls,'__bases__'):
94 94 for base in cls.__bases__:
95 95 ret.extend(get_class_members(base))
96 96 return ret
97 97
98 98 class Completer:
99 99 def __init__(self,namespace=None,global_namespace=None):
100 100 """Create a new completer for the command line.
101 101
102 102 Completer([namespace,global_namespace]) -> completer instance.
103 103
104 104 If unspecified, the default namespace where completions are performed
105 105 is __main__ (technically, __main__.__dict__). Namespaces should be
106 106 given as dictionaries.
107 107
108 108 An optional second namespace can be given. This allows the completer
109 109 to handle cases where both the local and global scopes need to be
110 110 distinguished.
111 111
112 112 Completer instances should be used as the completion mechanism of
113 113 readline via the set_completer() call:
114 114
115 115 readline.set_completer(Completer(my_namespace).complete)
116 116 """
117 117
118 118 # some minimal strict typechecks. For some core data structures, I
119 119 # want actual basic python types, not just anything that looks like
120 120 # one. This is especially true for namespaces.
121 121 for ns in (namespace,global_namespace):
122 122 if ns is not None and type(ns) != types.DictType:
123 123 raise TypeError,'namespace must be a dictionary'
124 124
125 125 # Don't bind to namespace quite yet, but flag whether the user wants a
126 126 # specific namespace or to use __main__.__dict__. This will allow us
127 127 # to bind to __main__.__dict__ at completion time, not now.
128 128 if namespace is None:
129 129 self.use_main_ns = 1
130 130 else:
131 131 self.use_main_ns = 0
132 132 self.namespace = namespace
133 133
134 134 # The global namespace, if given, can be bound directly
135 135 if global_namespace is None:
136 136 self.global_namespace = {}
137 137 else:
138 138 self.global_namespace = global_namespace
139 139
140 140 def complete(self, text, state):
141 141 """Return the next possible completion for 'text'.
142 142
143 143 This is called successively with state == 0, 1, 2, ... until it
144 144 returns None. The completion should begin with 'text'.
145 145
146 146 """
147 147 if self.use_main_ns:
148 148 self.namespace = __main__.__dict__
149 149
150 150 if state == 0:
151 151 if "." in text:
152 152 self.matches = self.attr_matches(text)
153 153 else:
154 154 self.matches = self.global_matches(text)
155 155 try:
156 156 return self.matches[state]
157 157 except IndexError:
158 158 return None
159 159
160 160 def global_matches(self, text):
161 161 """Compute matches when text is a simple name.
162 162
163 163 Return a list of all keywords, built-in functions and names currently
164 164 defined in self.namespace or self.global_namespace that match.
165 165
166 166 """
167 167 matches = []
168 168 match_append = matches.append
169 169 n = len(text)
170 170 for lst in [keyword.kwlist,
171 171 __builtin__.__dict__.keys(),
172 172 self.namespace.keys(),
173 173 self.global_namespace.keys()]:
174 174 for word in lst:
175 175 if word[:n] == text and word != "__builtins__":
176 176 match_append(word)
177 177 return matches
178 178
179 179 def attr_matches(self, text):
180 180 """Compute matches when text contains a dot.
181 181
182 182 Assuming the text is of the form NAME.NAME....[NAME], and is
183 183 evaluatable in self.namespace or self.global_namespace, it will be
184 184 evaluated and its attributes (as revealed by dir()) are used as
185 185 possible completions. (For class instances, class members are are
186 186 also considered.)
187 187
188 188 WARNING: this can still invoke arbitrary C code, if an object
189 189 with a __getattr__ hook is evaluated.
190 190
191 191 """
192 192 import re
193 193
194 194 # Another option, seems to work great. Catches things like ''.<tab>
195 195 m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text)
196 196
197 197 if not m:
198 198 return []
199 199
200 200 expr, attr = m.group(1, 3)
201 201 try:
202 202 object = eval(expr, self.namespace)
203 203 except:
204 204 try:
205 205 object = eval(expr, self.global_namespace)
206 206 except:
207 207 return []
208 208
209 209
210 210 # Start building the attribute list via dir(), and then complete it
211 211 # with a few extra special-purpose calls.
212 212 words = dir(object)
213 213
214 214 if hasattr(object,'__class__'):
215 215 words.append('__class__')
216 216 words.extend(get_class_members(object.__class__))
217 217
218 218 # Some libraries (such as traits) may introduce duplicates, we want to
219 219 # track and clean this up if it happens
220 220 may_have_dupes = False
221 221
222 222 # this is the 'dir' function for objects with Enthought's traits
223 223 if hasattr(object, 'trait_names'):
224 224 try:
225 225 words.extend(object.trait_names())
226 226 may_have_dupes = True
227 227 except TypeError:
228 228 # This will happen if `object` is a class and not an instance.
229 229 pass
230 230
231 231 # Support for PyCrust-style _getAttributeNames magic method.
232 232 if hasattr(object, '_getAttributeNames'):
233 233 try:
234 234 words.extend(object._getAttributeNames())
235 235 may_have_dupes = True
236 236 except TypeError:
237 237 # `object` is a class and not an instance. Ignore
238 238 # this error.
239 239 pass
240 240
241 241 if may_have_dupes:
242 242 # eliminate possible duplicates, as some traits may also
243 243 # appear as normal attributes in the dir() call.
244 244 words = set(words)
245 245
246 246 # filter out non-string attributes which may be stuffed by dir() calls
247 247 # and poor coding in third-party modules
248 248 words = [w for w in words
249 249 if isinstance(w, basestring) and w != "__builtins__"]
250 250 # Build match list to return
251 251 n = len(attr)
252 252 return ["%s.%s" % (expr, w) for w in words if w[:n] == attr ]
253 253
254 254 class IPCompleter(Completer):
255 255 """Extension of the completer class with IPython-specific features"""
256 256
257 257 def __init__(self,shell,namespace=None,global_namespace=None,
258 258 omit__names=0,alias_table=None):
259 259 """IPCompleter() -> completer
260 260
261 261 Return a completer object suitable for use by the readline library
262 262 via readline.set_completer().
263 263
264 264 Inputs:
265 265
266 266 - shell: a pointer to the ipython shell itself. This is needed
267 267 because this completer knows about magic functions, and those can
268 268 only be accessed via the ipython instance.
269 269
270 270 - namespace: an optional dict where completions are performed.
271 271
272 272 - global_namespace: secondary optional dict for completions, to
273 273 handle cases (such as IPython embedded inside functions) where
274 274 both Python scopes are visible.
275 275
276 276 - The optional omit__names parameter sets the completer to omit the
277 277 'magic' names (__magicname__) for python objects unless the text
278 278 to be completed explicitly starts with one or more underscores.
279 279
280 280 - If alias_table is supplied, it should be a dictionary of aliases
281 281 to complete. """
282 282
283 283 Completer.__init__(self,namespace,global_namespace)
284 284 self.magic_prefix = shell.name+'.magic_'
285 285 self.magic_escape = shell.ESC_MAGIC
286 286 self.readline = readline
287 287 delims = self.readline.get_completer_delims()
288 288 delims = delims.replace(self.magic_escape,'')
289 289 self.readline.set_completer_delims(delims)
290 290 self.get_line_buffer = self.readline.get_line_buffer
291 291 self.omit__names = omit__names
292 292 self.merge_completions = shell.rc.readline_merge_completions
293 293
294 294 if alias_table is None:
295 295 alias_table = {}
296 296 self.alias_table = alias_table
297 297 # Regexp to split filenames with spaces in them
298 298 self.space_name_re = re.compile(r'([^\\] )')
299 299 # Hold a local ref. to glob.glob for speed
300 300 self.glob = glob.glob
301 301
302 302 # Determine if we are running on 'dumb' terminals, like (X)Emacs
303 303 # buffers, to avoid completion problems.
304 304 term = os.environ.get('TERM','xterm')
305 305 self.dumb_terminal = term in ['dumb','emacs']
306 306
307 307 # Special handling of backslashes needed in win32 platforms
308 308 if sys.platform == "win32":
309 309 self.clean_glob = self._clean_glob_win32
310 310 else:
311 311 self.clean_glob = self._clean_glob
312 312 self.matchers = [self.python_matches,
313 313 self.file_matches,
314 314 self.alias_matches,
315 315 self.python_func_kw_matches]
316 316
317 317 # Code contributed by Alex Schmolck, for ipython/emacs integration
318 318 def all_completions(self, text):
319 319 """Return all possible completions for the benefit of emacs."""
320 320
321 321 completions = []
322 322 comp_append = completions.append
323 323 try:
324 324 for i in xrange(sys.maxint):
325 325 res = self.complete(text, i)
326 326
327 327 if not res: break
328 328
329 329 comp_append(res)
330 330 #XXX workaround for ``notDefined.<tab>``
331 331 except NameError:
332 332 pass
333 333 return completions
334 334 # /end Alex Schmolck code.
335 335
336 336 def _clean_glob(self,text):
337 337 return self.glob("%s*" % text)
338 338
339 339 def _clean_glob_win32(self,text):
340 340 return [f.replace("\\","/")
341 341 for f in self.glob("%s*" % text)]
342 342
343 343 def file_matches(self, text):
344 344 """Match filenames, expanding ~USER type strings.
345 345
346 346 Most of the seemingly convoluted logic in this completer is an
347 347 attempt to handle filenames with spaces in them. And yet it's not
348 348 quite perfect, because Python's readline doesn't expose all of the
349 349 GNU readline details needed for this to be done correctly.
350 350
351 351 For a filename with a space in it, the printed completions will be
352 352 only the parts after what's already been typed (instead of the
353 353 full completions, as is normally done). I don't think with the
354 354 current (as of Python 2.3) Python readline it's possible to do
355 355 better."""
356 356
357 357 #print 'Completer->file_matches: <%s>' % text # dbg
358 358
359 359 # chars that require escaping with backslash - i.e. chars
360 360 # that readline treats incorrectly as delimiters, but we
361 361 # don't want to treat as delimiters in filename matching
362 362 # when escaped with backslash
363 363
364 364 protectables = ' ()[]{}'
365 365
366 366 if text.startswith('!'):
367 367 text = text[1:]
368 368 text_prefix = '!'
369 369 else:
370 370 text_prefix = ''
371 371
372 372 def protect_filename(s):
373 373 return "".join([(ch in protectables and '\\' + ch or ch)
374 374 for ch in s])
375
376 def single_dir_expand(matches):
377 "Recursively expand match lists containing a single dir."
378
379 if len(matches) == 1 and os.path.isdir(matches[0]):
380 # Takes care of links to directories also. Use '/'
381 # explicitly, even under Windows, so that name completions
382 # don't end up escaped.
383 d = matches[0]
384 if d[-1] in ['/','\\']:
385 d = d[:-1]
386
387 matches = [ (d + '/' + p) for p in os.listdir(d) ]
388 return single_dir_expand(matches)
389 else:
390 return matches
375 391
376 392 lbuf = self.lbuf
377 393 open_quotes = 0 # track strings with open quotes
378 394 try:
379 395 lsplit = shlex.split(lbuf)[-1]
380 396 except ValueError:
381 397 # typically an unmatched ", or backslash without escaped char.
382 398 if lbuf.count('"')==1:
383 399 open_quotes = 1
384 400 lsplit = lbuf.split('"')[-1]
385 401 elif lbuf.count("'")==1:
386 402 open_quotes = 1
387 403 lsplit = lbuf.split("'")[-1]
388 404 else:
389 405 return []
390 406 except IndexError:
391 407 # tab pressed on empty line
392 408 lsplit = ""
393 409
394 410 if lsplit != protect_filename(lsplit):
395 411 # if protectables are found, do matching on the whole escaped
396 412 # name
397 413 has_protectables = 1
398 414 text0,text = text,lsplit
399 415 else:
400 416 has_protectables = 0
401 417 text = os.path.expanduser(text)
402 418
403 419 if text == "":
404 420 return [text_prefix + protect_filename(f) for f in self.glob("*")]
405 421
406 422 m0 = self.clean_glob(text.replace('\\',''))
407 423 if has_protectables:
408 424 # If we had protectables, we need to revert our changes to the
409 425 # beginning of filename so that we don't double-write the part
410 426 # of the filename we have so far
411 427 len_lsplit = len(lsplit)
412 428 matches = [text_prefix + text0 +
413 429 protect_filename(f[len_lsplit:]) for f in m0]
414 430 else:
415 431 if open_quotes:
416 432 # if we have a string with an open quote, we don't need to
417 433 # protect the names at all (and we _shouldn't_, as it
418 434 # would cause bugs when the filesystem call is made).
419 435 matches = m0
420 436 else:
421 437 matches = [text_prefix +
422 438 protect_filename(f) for f in m0]
423 if len(matches) == 1 and os.path.isdir(matches[0]):
424 # Takes care of links to directories also. Use '/'
425 # explicitly, even under Windows, so that name completions
426 # don't end up escaped.
427 d = matches[0]
428 if d[-1] in ['/','\\']:
429 d = d[:-1]
430
431 matches = [ (d + '/' + p) for p in os.listdir(d) ]
432
433 return matches
439
440 return single_dir_expand(matches)
434 441
435 442 def alias_matches(self, text):
436 443 """Match internal system aliases"""
437 444 #print 'Completer->alias_matches:',text,'lb',self.lbuf # dbg
438 445
439 446 # if we are not in the first 'item', alias matching
440 447 # doesn't make sense
441 448 if ' ' in self.lbuf:
442 449 return []
443 450 text = os.path.expanduser(text)
444 451 aliases = self.alias_table.keys()
445 452 if text == "":
446 453 return aliases
447 454 else:
448 455 return [alias for alias in aliases if alias.startswith(text)]
449 456
450 457 def python_matches(self,text):
451 458 """Match attributes or global python names"""
452 459
453 460 #print 'Completer->python_matches, txt=<%s>' % text # dbg
454 461 if "." in text:
455 462 try:
456 463 matches = self.attr_matches(text)
457 464 if text.endswith('.') and self.omit__names:
458 465 if self.omit__names == 1:
459 466 # true if txt is _not_ a __ name, false otherwise:
460 467 no__name = (lambda txt:
461 468 re.match(r'.*\.__.*?__',txt) is None)
462 469 else:
463 470 # true if txt is _not_ a _ name, false otherwise:
464 471 no__name = (lambda txt:
465 472 re.match(r'.*\._.*?',txt) is None)
466 473 matches = filter(no__name, matches)
467 474 except NameError:
468 475 # catches <undefined attributes>.<tab>
469 476 matches = []
470 477 else:
471 478 matches = self.global_matches(text)
472 479 # this is so completion finds magics when automagic is on:
473 480 if (matches == [] and
474 481 not text.startswith(os.sep) and
475 482 not ' ' in self.lbuf):
476 483 matches = self.attr_matches(self.magic_prefix+text)
477 484 return matches
478 485
479 486 def _default_arguments(self, obj):
480 487 """Return the list of default arguments of obj if it is callable,
481 488 or empty list otherwise."""
482 489
483 490 if not (inspect.isfunction(obj) or inspect.ismethod(obj)):
484 491 # for classes, check for __init__,__new__
485 492 if inspect.isclass(obj):
486 493 obj = (getattr(obj,'__init__',None) or
487 494 getattr(obj,'__new__',None))
488 495 # for all others, check if they are __call__able
489 496 elif hasattr(obj, '__call__'):
490 497 obj = obj.__call__
491 498 # XXX: is there a way to handle the builtins ?
492 499 try:
493 500 args,_,_1,defaults = inspect.getargspec(obj)
494 501 if defaults:
495 502 return args[-len(defaults):]
496 503 except TypeError: pass
497 504 return []
498 505
499 506 def python_func_kw_matches(self,text):
500 507 """Match named parameters (kwargs) of the last open function"""
501 508
502 509 if "." in text: # a parameter cannot be dotted
503 510 return []
504 511 try: regexp = self.__funcParamsRegex
505 512 except AttributeError:
506 513 regexp = self.__funcParamsRegex = re.compile(r'''
507 514 '.*?' | # single quoted strings or
508 515 ".*?" | # double quoted strings or
509 516 \w+ | # identifier
510 517 \S # other characters
511 518 ''', re.VERBOSE | re.DOTALL)
512 519 # 1. find the nearest identifier that comes before an unclosed
513 520 # parenthesis e.g. for "foo (1+bar(x), pa", the candidate is "foo"
514 521 tokens = regexp.findall(self.get_line_buffer())
515 522 tokens.reverse()
516 523 iterTokens = iter(tokens); openPar = 0
517 524 for token in iterTokens:
518 525 if token == ')':
519 526 openPar -= 1
520 527 elif token == '(':
521 528 openPar += 1
522 529 if openPar > 0:
523 530 # found the last unclosed parenthesis
524 531 break
525 532 else:
526 533 return []
527 534 # 2. Concatenate dotted names ("foo.bar" for "foo.bar(x, pa" )
528 535 ids = []
529 536 isId = re.compile(r'\w+$').match
530 537 while True:
531 538 try:
532 539 ids.append(iterTokens.next())
533 540 if not isId(ids[-1]):
534 541 ids.pop(); break
535 542 if not iterTokens.next() == '.':
536 543 break
537 544 except StopIteration:
538 545 break
539 546 # lookup the candidate callable matches either using global_matches
540 547 # or attr_matches for dotted names
541 548 if len(ids) == 1:
542 549 callableMatches = self.global_matches(ids[0])
543 550 else:
544 551 callableMatches = self.attr_matches('.'.join(ids[::-1]))
545 552 argMatches = []
546 553 for callableMatch in callableMatches:
547 554 try: namedArgs = self._default_arguments(eval(callableMatch,
548 555 self.namespace))
549 556 except: continue
550 557 for namedArg in namedArgs:
551 558 if namedArg.startswith(text):
552 559 argMatches.append("%s=" %namedArg)
553 560 return argMatches
554 561
555 562 def dispatch_custom_completer(self,text):
556 563 # print "Custom! '%s' %s" % (text, self.custom_completers) # dbg
557 564 line = self.full_lbuf
558 565 if not line.strip():
559 566 return None
560 567
561 568 event = Struct()
562 569 event.line = line
563 570 event.symbol = text
564 571 cmd = line.split(None,1)[0]
565 572 event.command = cmd
566 573 #print "\ncustom:{%s]\n" % event # dbg
567 574
568 575 # for foo etc, try also to find completer for %foo
569 576 if not cmd.startswith(self.magic_escape):
570 577 try_magic = self.custom_completers.s_matches(
571 578 self.magic_escape + cmd)
572 579 else:
573 580 try_magic = []
574 581
575 582
576 583 for c in itertools.chain(
577 584 self.custom_completers.s_matches(cmd),
578 585 try_magic,
579 586 self.custom_completers.flat_matches(self.lbuf)):
580 587 # print "try",c # dbg
581 588 try:
582 589 res = c(event)
583 590 return [r for r in res if r.lower().startswith(text.lower())]
584 591 except ipapi.TryNext:
585 592 pass
586 593
587 594 return None
588 595
589 596
590 597
591 598 def complete(self, text, state):
592 599 """Return the next possible completion for 'text'.
593 600
594 601 This is called successively with state == 0, 1, 2, ... until it
595 602 returns None. The completion should begin with 'text'. """
596 603
597 604 #print '\n*** COMPLETE: <%s> (%s)' % (text,state) # dbg
598 605
599 606 # if there is only a tab on a line with only whitespace, instead
600 607 # of the mostly useless 'do you want to see all million
601 608 # completions' message, just do the right thing and give the user
602 609 # his tab! Incidentally, this enables pasting of tabbed text from
603 610 # an editor (as long as autoindent is off).
604 611
605 612 # don't apply this on 'dumb' terminals, such as emacs buffers, so we
606 613 # don't interfere with their own tab-completion mechanism.
607 614 self.full_lbuf = self.get_line_buffer()
608 615 self.lbuf = self.full_lbuf[:self.readline.get_endidx()]
609 616 if not (self.dumb_terminal or self.get_line_buffer().strip()):
610 617 self.readline.insert_text('\t')
611 618 return None
612 619
613 620
614 621 magic_escape = self.magic_escape
615 622 magic_prefix = self.magic_prefix
616 623
617 624 try:
618 625 if text.startswith(magic_escape):
619 626 text = text.replace(magic_escape,magic_prefix)
620 627 elif text.startswith('~'):
621 628 text = os.path.expanduser(text)
622 629 if state == 0:
623 630 custom_res = self.dispatch_custom_completer(text)
624 631 if custom_res is not None:
625 632 # did custom completers produce something?
626 633 self.matches = custom_res
627 634 else:
628 635 # Extend the list of completions with the results of each
629 636 # matcher, so we return results to the user from all
630 637 # namespaces.
631 638 if self.merge_completions:
632 639 self.matches = []
633 640 for matcher in self.matchers:
634 641 self.matches.extend(matcher(text))
635 642 else:
636 643 for matcher in self.matchers:
637 644 self.matches = matcher(text)
638 645 if self.matches:
639 646 break
640 647
641 648 try:
642 649 return self.matches[state].replace(magic_prefix,magic_escape)
643 650 except IndexError:
644 651 return None
645 652 except:
646 653 from IPython.ultraTB import AutoFormattedTB; # dbg
647 654 tb=AutoFormattedTB('Verbose');tb() #dbg
648 655
649 656 # If completion fails, don't annoy the user.
650 657 return None
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now