Show More
@@ -76,6 +76,7 b' import os' | |||
|
76 | 76 | import re |
|
77 | 77 | import shlex |
|
78 | 78 | import sys |
|
79 | import StringIO | |
|
79 | 80 | |
|
80 | 81 | from IPython.config.configurable import Configurable |
|
81 | 82 | from IPython.core.error import TryNext |
@@ -664,29 +665,64 b' class IPCompleter(Completer):' | |||
|
664 | 665 | |
|
665 | 666 | return matches |
|
666 | 667 | |
|
668 | def _default_arguments_from_docstring(self,doc): | |
|
669 | doc = doc.lstrip() | |
|
670 | sio = StringIO.StringIO(doc) | |
|
671 | #care only the firstline | |
|
672 | #docstring can be long | |
|
673 | line = sio.readline() | |
|
674 | p = re.compile(r'^[\w]+\(([^)]*)\).*') | |
|
675 | #'min(iterable[, key=func])\n' -> 'iterable[, key=func]' | |
|
676 | sig = p.search(line) | |
|
677 | if sig is None: return [] | |
|
678 | # iterable[, key=func]' -> ['iterable[' ,' key=func]'] | |
|
679 | sig = sig.groups()[0].split(',') | |
|
680 | #use this if you want iterable to show up too | |
|
681 | #q = re.compile('[\s|\[]*(\w+)(?:\s*=?\s*.*)') | |
|
682 | q = re.compile('[\s|\[]*(\w+)(?:\s*=\s*.*)') | |
|
683 | ret = [] | |
|
684 | for s in sig: | |
|
685 | tmp = q.match(s) | |
|
686 | if tmp is not None: | |
|
687 | ret.append(tmp.groups()[0]) | |
|
688 | return ret | |
|
689 | ||
|
667 | 690 | def _default_arguments(self, obj): |
|
668 | 691 | """Return the list of default arguments of obj if it is callable, |
|
669 | 692 | or empty list otherwise.""" |
|
670 | ||
|
671 | if not (inspect.isfunction(obj) or inspect.ismethod(obj)): | |
|
693 | call_obj = obj | |
|
694 | ret = [] | |
|
695 | if inspect.isbuiltin(obj): | |
|
696 | #parse builtin docstring for signature | |
|
697 | ret+=self._default_arguments_from_docstring( | |
|
698 | getattr(obj,'__doc__','')) | |
|
699 | elif not (inspect.isfunction(obj) or inspect.ismethod(obj)): | |
|
672 | 700 | # for classes, check for __init__,__new__ |
|
673 | 701 | if inspect.isclass(obj): |
|
674 | obj = (getattr(obj,'__init__',None) or | |
|
702 | #for cython embded signature it puts | |
|
703 | #__init__ signature in class docstring not __init__'s one | |
|
704 | ret = self._default_arguments_from_docstring( | |
|
705 | getattr(obj,'__doc__','')) | |
|
706 | call_obj = (getattr(obj,'__init__',None) or | |
|
675 | 707 | getattr(obj,'__new__',None)) |
|
708 | ret += self._default_arguments_from_docstring( | |
|
709 | getattr(all_obj,'__doc__','')) | |
|
676 | 710 | # for all others, check if they are __call__able |
|
677 | 711 | elif hasattr(obj, '__call__'): |
|
678 | obj = obj.__call__ | |
|
679 | # XXX: is there a way to handle the builtins ? | |
|
712 | call_obj = obj.__call__ | |
|
713 | ||
|
680 | 714 | try: |
|
681 | args,_,_1,defaults = inspect.getargspec(obj) | |
|
715 | args,_,_1,defaults = inspect.getargspec(call_obj) | |
|
682 | 716 | if defaults: |
|
683 |
ret |
|
|
684 |
except TypeError: |
|
|
685 | return [] | |
|
717 | ret+=args[-len(defaults):] | |
|
718 | except TypeError: | |
|
719 | pass | |
|
720 | ||
|
721 | return list(set(ret)) | |
|
686 | 722 | |
|
687 | 723 | def python_func_kw_matches(self,text): |
|
688 | 724 | """Match named parameters (kwargs) of the last open function""" |
|
689 | ||
|
725 | ||
|
690 | 726 | if "." in text: # a parameter cannot be dotted |
|
691 | 727 | return [] |
|
692 | 728 | try: regexp = self.__funcParamsRegex |
@@ -703,6 +739,7 b' class IPCompleter(Completer):' | |||
|
703 | 739 | tokens = regexp.findall(self.text_until_cursor) |
|
704 | 740 | tokens.reverse() |
|
705 | 741 | iterTokens = iter(tokens); openPar = 0 |
|
742 | ||
|
706 | 743 | for token in iterTokens: |
|
707 | 744 | if token == ')': |
|
708 | 745 | openPar -= 1 |
@@ -716,6 +753,7 b' class IPCompleter(Completer):' | |||
|
716 | 753 | # 2. Concatenate dotted names ("foo.bar" for "foo.bar(x, pa" ) |
|
717 | 754 | ids = [] |
|
718 | 755 | isId = re.compile(r'\w+$').match |
|
756 | ||
|
719 | 757 | while True: |
|
720 | 758 | try: |
|
721 | 759 | ids.append(next(iterTokens)) |
@@ -735,9 +773,10 b' class IPCompleter(Completer):' | |||
|
735 | 773 | for callableMatch in callableMatches: |
|
736 | 774 | try: |
|
737 | 775 | namedArgs = self._default_arguments(eval(callableMatch, |
|
738 |
|
|
|
776 | self.namespace)) | |
|
739 | 777 | except: |
|
740 | 778 | continue |
|
779 | ||
|
741 | 780 | for namedArg in namedArgs: |
|
742 | 781 | if namedArg.startswith(text): |
|
743 | 782 | argMatches.append("%s=" %namedArg) |
@@ -288,10 +288,13 b' def test_func_kw_completions():' | |||
|
288 | 288 | s, matches = c.complete(None, 'myfunc(1,b') |
|
289 | 289 | nt.assert_in('b=', matches) |
|
290 | 290 | # Simulate completing with cursor right after b (pos==10): |
|
291 | s, matches = c.complete(None,'myfunc(1,b)', 10) | |
|
291 | s, matches = c.complete(None, 'myfunc(1,b)', 10) | |
|
292 | 292 | nt.assert_in('b=', matches) |
|
293 | s, matches = c.complete(None,'myfunc(a="escaped\\")string",b') | |
|
293 | s, matches = c.complete(None, 'myfunc(a="escaped\\")string",b') | |
|
294 | 294 | nt.assert_in('b=', matches) |
|
295 | #builtin function | |
|
296 | s, matches = c.complete(None, 'min(k, k') | |
|
297 | nt.assert_in('key=', matches) | |
|
295 | 298 | |
|
296 | 299 | |
|
297 | 300 | def test_line_magics(): |
General Comments 0
You need to be logged in to leave comments.
Login now