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