Signed-off-by: Khem Raj <raj.k...@gmail.com> --- .../ipython/001-completer-across-raw-types.patch | 562 ++++++++++++++++++++ .../ipython3/001-completer-across-raw-types.patch | 562 ++++++++++++++++++++ meta/recipes-devtools/python/ipython3_0.13.1.bb | 71 +++ meta/recipes-devtools/python/ipython_0.13.1.bb | 48 ++ 4 files changed, 1243 insertions(+) create mode 100644 meta/recipes-devtools/python/ipython/001-completer-across-raw-types.patch create mode 100644 meta/recipes-devtools/python/ipython3/001-completer-across-raw-types.patch create mode 100644 meta/recipes-devtools/python/ipython3_0.13.1.bb create mode 100644 meta/recipes-devtools/python/ipython_0.13.1.bb
diff --git a/meta/recipes-devtools/python/ipython/001-completer-across-raw-types.patch b/meta/recipes-devtools/python/ipython/001-completer-across-raw-types.patch new file mode 100644 index 0000000..d753ca3 --- /dev/null +++ b/meta/recipes-devtools/python/ipython/001-completer-across-raw-types.patch @@ -0,0 +1,562 @@ +diff --git a/IPython/core/completer.py b/IPython/core/completer.py +index 8cb2345..076e2fa 100644 +--- a/IPython/core/completer.py ++++ b/IPython/core/completer.py +@@ -76,14 +76,18 @@ import os + import re + import shlex + import sys ++import types + + from IPython.config.configurable import Configurable + from IPython.core.error import TryNext + from IPython.core.inputsplitter import ESC_MAGIC ++from IPython.core.oinspect import getargspec + from IPython.utils import generics + from IPython.utils import io ++from IPython.utils import py3compat + from IPython.utils.dir2 import dir2 + from IPython.utils.process import arg_split ++from IPython.utils.py3compat import cast_unicode + from IPython.utils.traitlets import CBool, Enum + + #----------------------------------------------------------------------------- +@@ -181,6 +185,26 @@ def compress_user(path, tilde_expand, tilde_val): + class Bunch(object): pass + + ++class PostFix(object): ++ """ ++ Effectively a static class which encapsulates a bunch of postfix defs. ++ ++ """ ++ ++ ## delimiters which support the type completers ++ DELIMS = ' \t\n`!@#$^&*=+\\|;:",<>?' ++ ++ ## postfix strings for types ++ LIST = '[' ++ DICT = "['" ++ CALL = '(' ++ OBJ = '.' ++ ++ ## basic callable types ++ CALLABLES = [ types.FunctionType, types.LambdaType, types.MethodType, \ ++ types.BuiltinFunctionType, types.BuiltinMethodType ] ++ ++ + DELIMS = ' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?' + GREEDY_DELIMS = ' \r\n' + +@@ -200,6 +224,11 @@ class CompletionSplitter(object): + + # Private interface + ++ # These are the default-defaults. They get updated when the postfix ++ # engine is engaged. ++ _preferred_delims = DELIMS ++ _preferred_greedy_delims = GREEDY_DELIMS ++ + # A string of delimiter characters. The default value makes sense for + # IPython's most typical usage patterns. + _delims = DELIMS +@@ -246,6 +275,34 @@ class Completer(Configurable): + """ + ) + ++ use_postfix = CBool(False, config=True, ++ help="""Activate postfix indicator ++ ++ This will enable the feature to append syntactic notation to matches ++ providing indication as to what type they are. ++ ++ Append: ++ ( - any callable item ++ [ - any list ++ [' - any dictionary ++ """ ++ ) ++ ++ postfix_verbose = Enum((0,1,2), default_value=1, config=True, ++ help="""Provide verbose postfix suggestions. ++ ++ This is only valid if use_postfix=True. Verbosity is as follows: ++ ++ 0 - No postfix notations will be appended until you've isolate a ++ single attribute name. ++ 1 - In multiple-completion cases, types deriving from list, dict and ++ functions will have "[", "['" or "(" appended respectively. Detailed ++ operations are made available once a single attribute is determined. ++ 2 - Multiple-completion cases will have duplicate or triplicate entries ++ differing only by the "interface" character at the end. This can ++ make the tab completion lists pretty long. ++ """ ++ ) + + def __init__(self, namespace=None, global_namespace=None, config=None, **kwargs): + """Create a new completer for the command line. +@@ -303,6 +360,289 @@ class Completer(Configurable): + except IndexError: + return None + ++ def __dict_completions(self, expr, token, cruft, obj): ++ """Provide completion support for keys in a dictionary. ++ """ ++ #print("Completer->__dict_completions: t=%s" % (token)) ++ ++ # merge the token and cruft ++ token += cruft ++ ++ # handle the basic case ++ if (cruft == ""): ++ return ["%s['%s']" % (expr, k) for k in obj.keys()] ++ ++ # support the situation where the user started to type '] ++ if cruft.endswith("'"): ++ return [expr + token + cruft + "]"] ++ if cruft.endswith("']"): ++ return [expr + token + cruft] ++ ++ # for valid data, match any keys... ++ return ["%s['%s']" % (expr, k) for k in obj.keys() if k.startswith(cruft)] ++ ++ def __list_completions(self, expr, token, cruft, obj): ++ """Provide completion support for lists. ++ """ ++ entries = len(obj) - 1 ++ ++ #print("Completer->__list_completions: t=%s l=%d" % (token, entries)) ++ ++ # if it is already complete, leave it ++ if cruft.endswith("]"): ++ return [expr + token] ++ ++ # handle basic case or trash ++ if (cruft == "") or (not cruft.isdigit()): ++ return ["%s[0]" % (expr), "%s[%d]" % (expr, entries)] ++ ++ # main algorithm works only if val != 0 ++ if int(cruft) == 0: ++ return ["%s[0]" % (expr)] ++ ++ # generate a list of indicies whose first printed chars match ++ sim = [] ++ n = 1 ++ val = int(cruft) ++ while val*n <= entries: ++ # setup default end points ++ start = val*n ++ end = (val+1) * n ++ ++ # account for the possibility that we don't go all the way through ++ if end > entries: ++ end = entries+1; ++ ++ # append the next set of data ++ sim += range(start, end) ++ ++ # present based on base-10 ++ n *= 10 ++ ++ # create the option list ++ return ["%s[%d]" % (expr, s) for s in sim ] ++ ++ def __call_completions(self, expr, token, cruft, obj): ++ """Provide completion support for function calls. ++ """ ++ #print("Completer->__call_completions: FIX-ME") ++ matches = [] ++ if inspect.isclass(obj): ++ obj = obj.__init__ ++ elif (not py3compat.PY3) and type(obj) is types.InstanceType: ++ obj = obj.__call__ ++ ++ try: ++ hdef = inspect.formatargspec(*getargspec(obj)) ++ return cast_unicode(hdef).strip('(').strip(')').split(', ') ++ except: ++ return [] ++ ++ def __object_completions(self, expr, token, cruft, obj): ++ """Provide completion support for function calls. ++ """ ++ #print("Completer->__object_completions:") ++ if token is None: ++ token = '' ++ ++ # handle global items ++ if '.' not in expr+token: ++ #print(" global") ++ # provide options for incomplete text ++ subset = dict() ++ n = len(expr) ++ for lst in [keyword.kwlist, ++ builtins.__dict__.keys(), ++ self.namespace.keys(), ++ self.global_namespace.keys()]: ++ for word in lst: ++ if word[:n] == expr and word != "__builtins__": ++ obj = self._global_lookup(word) ++ #subset.append( (obj, word) ) ++ subset[word] = obj ++ ++ # manage the ones we actually care about ++ matches = [] ++ for k in subset.keys(): ++ ss = (subset[k], k) ++ if ss[0] != None: ++ apl = self._append_postfix(ss[0], ss[1], len(subset.keys())) ++ for ap in apl: ++ matches.append(ap) ++ else: ++ matches.append(ss[1]) ++ ++ # true matches updated accordingly ++ return matches ++ ++ else: ++ #print(" local") ++ # support overridding with __all__ attribute ++ if self.limit_to__all__ and hasattr(obj, '__all__'): ++ words = get__all__entries(obj) ++ else: ++ words = dir2(obj) ++ ++ try: ++ words = generics.complete_object(obj, words) ++ except TryNext: ++ pass ++ except Exception: ++ # Silence errors from completion function ++ #raise # dbg ++ pass ++ ++ # Build match list to return ++ n = len(cruft) ++ res = [] ++ subset = [] ++ ++ # first create a subset -- the ones we care about ++ for w in words: ++ if w[:n] == cruft and hasattr(obj, w): ++ val = getattr(obj, w) ++ subset.append( (w, val) ) ++ ++ # now, setup tha matches ++ for ss in subset: ++ apl = self._append_postfix(ss[1], ++ "%s.%s" % (expr, ss[0]), ++ len(subset)) ++ for ap in apl: ++ res.append(ap) ++ return res ++ ++ def _append_postfix(self, val, text, total_completions=0): ++ """Figure out what postfix symbol to append. ++ """ ++ #print("_append_postfix") ++ ++ # observer the request ++ if not self.use_postfix: ++ #print(" no-post-fix") ++ return [ text ] ++ ++ # ignore the postfix additions as preferred ++ if total_completions > 1: ++ ++ if self.postfix_verbose == 0: ++ #print(" omit-postfix (%d)" % total_completions) ++ return [ text ] ++ ++ elif self.postfix_verbose == 1: ++ if isinstance( val, dict ): ++ return [ text + PostFix.DICT ] ++ elif isinstance( val, list ): ++ return [ text + PostFix.LIST ] ++ elif type(val) in PostFix.CALLABLES: ++ return [ text + PostFix.CALL ] ++ else: ++ return [ text ] ++ ++ else: ++ # fall through and decode EVERYTHING ++ pass ++ ++ ++ # prepare multiple results ++ items = [] ++ ++ # handle scalars ++ if isinstance( val, int ) or isinstance( val, float ): ++ items.append( text ) # scalar itself ++ items.append( text + PostFix.OBJ ) # object completion ++ ++ # handle strings ++ elif isinstance( val, str ): ++ items.append( text ) # scalar itself ++ items.append( text + PostFix.OBJ ) # object completion ++ items.append( text + PostFix.LIST ) # list completion ++ ++ # handle lists ++ elif isinstance( val, list ): ++ items.append( text + PostFix.OBJ ) # object completion ++ items.append( text + PostFix.LIST ) # list completion ++ ++ # handle dicts ++ elif isinstance( val, dict ): ++ items.append( text + PostFix.OBJ ) # object completion ++ items.append( text + PostFix.DICT ) # dict completion ++ ++ # handle common callables ++ elif type(val) in PostFix.CALLABLES: ++ # skip object completion ++ items.append( text + PostFix.CALL ) # callable completion ++ ++ # handle general objects ++ else: ++ # always add its "object" completion ++ items.append( text + PostFix.OBJ ) ++ ++ # if it is callable, then provide the functional notation ++ if callable(val): ++ items.append( text + PostFix.CALL ) ++ ++ # is it iterable? ++ if hasattr(val, '__getitem__'): ++ try: ++ v = val[0] ++ items.append( text + PostFix.LIST ) # yup, some sort of list ++ except TypeError: ++ # wrong key type -- must be a general dictionary ++ items.append( text + PostFix.DICT ) ++ except KeyError: ++ # invalid key -- likely a dictionary ++ items.append( text + PostFix.DICT ) ++ except IndexError: ++ pass # empty list -- the object notation will handle it ++ ++ return items ++ ++ def _global_lookup(self, text): ++ """This routine searches the global namespace to find the object. ++ """ ++ try: ++ obj = eval(text, self.namespace) ++ except: ++ try: ++ obj = eval(text, self.global_namespace) ++ except: ++ obj = None ++ return obj ++ ++ def _postfix_completer(self, expr, token, cruft, ns_lookup_fn): ++ """Identify object-type completions. ++ """ ++ #print("Completer->_postfix_completer") ++ #print(" e=%s t=%s c=%s" % (expr, token, cruft)) ++ ++ # the token can be none as a result of the parent RE. ++ if token is None: ++ token = '' ++ ++ # get the object ++ # -- this may not be possible if it is part of a global ++ obj = ns_lookup_fn(expr+token+cruft) ++ if obj: ++ # odjust the params to reflect the new object ++ expr = expr + token + cruft ++ token = '' ++ cruft = '' ++ else: ++ # look up the base item ++ obj = ns_lookup_fn(expr) ++ ++ # sort them out ++ if token == PostFix.CALL: ++ return self.__call_completions(expr, token, cruft, obj) ++ elif token == PostFix.DICT: ++ return self.__dict_completions(expr, token, cruft, obj) ++ elif token == PostFix.LIST: ++ return self.__list_completions(expr, token, cruft, obj) ++ ++ # treat it as a plain object ++ return self.__object_completions(expr, token, cruft, obj) ++ + def global_matches(self, text): + """Compute matches when text is a simple name. + +@@ -310,18 +650,19 @@ class Completer(Configurable): + defined in self.namespace or self.global_namespace that match. + + """ +- #print 'Completer->global_matches, txt=%r' % text # dbg +- matches = [] +- match_append = matches.append +- n = len(text) +- for lst in [keyword.kwlist, +- __builtin__.__dict__.keys(), +- self.namespace.keys(), +- self.global_namespace.keys()]: +- for word in lst: +- if word[:n] == text and word != "__builtins__": +- match_append(word) +- return matches ++ #print('Completer->global_matches, txt=%r' % text) # dbg ++ ++ # sort out the components ++ m = re.match(r"(\w+)(\[\'|\[|\()?(\S*)$", text) ++ expr = m.group(1) ++ token = m.group(2) ++ cruft = m.group(3) ++ ++ # catch the completions across object types ++ matches = self._postfix_completer(expr, token, cruft, self._global_lookup) ++ if matches is not None: ++ return matches ++ return [] + + def attr_matches(self, text): + """Compute matches when text contains a dot. +@@ -338,44 +679,27 @@ class Completer(Configurable): + """ + + #io.rprint('Completer->attr_matches, txt=%r' % text) # dbg +- # Another option, seems to work great. Catches things like ''.<tab> +- m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text) +- +- if m: +- expr, attr = m.group(1, 3) +- elif self.greedy: +- m2 = re.match(r"(.+)\.(\w*)$", self.line_buffer) +- if not m2: +- return [] +- expr, attr = m2.group(1,2) +- else: ++ ++ pat = r"(\S+(\.\w+)*)(\.|\[\'|\[|\()(\S*)$" ++ m = re.match(pat, text) ++ ++ if not m: ++ io.rprint("Failed to match ...") + return [] +- +- try: +- obj = eval(expr, self.namespace) +- except: +- try: +- obj = eval(expr, self.global_namespace) +- except: +- return [] + +- if self.limit_to__all__ and hasattr(obj, '__all__'): +- words = get__all__entries(obj) +- else: +- words = dir2(obj) ++ # group(0) is the whole string ++ expr = m.group(1) ++ # group(2) is always 'None' ++ token = m.group(3) ++ cruft = m.group(4) ++ #expr, attr = m.group(1, 3) + +- try: +- words = generics.complete_object(obj, words) +- except TryNext: +- pass +- except Exception: +- # Silence errors from completion function +- #raise # dbg +- pass +- # Build match list to return +- n = len(attr) +- res = ["%s.%s" % (expr, w) for w in words if w[:n] == attr ] +- return res ++ ++ # catch the completions across object types ++ foo = self._postfix_completer(expr, token, cruft, self._global_lookup) ++ if foo is not None: ++ return foo ++ return [] + + + def get__all__entries(obj): +@@ -393,13 +717,34 @@ class IPCompleter(Completer): + + def _greedy_changed(self, name, old, new): + """update the splitter and readline delims when greedy is changed""" ++ #io.rprint("_greedy_changed: name=%s o=%d n%d" % (name, old, new)) + if new: +- self.splitter.delims = GREEDY_DELIMS ++ self.splitter.delims = self.splitter._preferred_greedy_delims + else: +- self.splitter.delims = DELIMS ++ self.splitter.delims = self.splitter._preferred_delims + + if self.readline: + self.readline.set_completer_delims(self.splitter.delims) ++ ++ # ++ # This is the implicit callback for applying changes to the 'use_postfix' ++ # configuration parameter. ++ # ++ def _use_postfix_changed(self, name, old, new): ++ """engage the correct delims ++ """ ++ #io.rprint("_use_postfix_changed: name=%s o=%d n%d" % (name, old, new)) ++ if new: ++ self.splitter._preferred_delims = PostFix.DELIMS ++ else: ++ self.splitter._preferred_delims = DELIMS ++ ++ # update the parser ++ self.splitter.delims = self.splitter._preferred_delims ++ ++ # update readline ++ if self.readline: ++ self.readline.set_completer_delims(self.splitter.delims) + + merge_completions = CBool(True, config=True, + help="""Whether to merge completion results into a single list +@@ -643,24 +988,24 @@ class IPCompleter(Completer): + """Match attributes or global python names""" + + #io.rprint('Completer->python_matches, txt=%r' % text) # dbg +- if "." in text: +- try: +- matches = self.attr_matches(text) +- if text.endswith('.') and self.omit__names: +- if self.omit__names == 1: +- # true if txt is _not_ a __ name, false otherwise: +- no__name = (lambda txt: +- re.match(r'.*\.__.*?__',txt) is None) +- else: +- # true if txt is _not_ a _ name, false otherwise: +- no__name = (lambda txt: +- re.match(r'.*\._.*?',txt) is None) +- matches = filter(no__name, matches) +- except NameError: +- # catches <undefined attributes>.<tab> +- matches = [] +- else: +- matches = self.global_matches(text) ++ if "." not in text: ++ return self.global_matches(text) ++ ++ try: ++ matches = self.attr_matches(text) ++ if text.endswith('.') and self.omit__names: ++ if self.omit__names == 1: ++ # true if txt is _not_ a __ name, false otherwise: ++ no__name = (lambda txt: ++ re.match(r'.*\.__.*?__',txt) is None) ++ else: ++ # true if txt is _not_ a _ name, false otherwise: ++ no__name = (lambda txt: ++ re.match(r'.*\._.*?',txt) is None) ++ matches = filter(no__name, matches) ++ except NameError: ++ # catches <undefined attributes>.<tab> ++ matches = [] + + return matches + diff --git a/meta/recipes-devtools/python/ipython3/001-completer-across-raw-types.patch b/meta/recipes-devtools/python/ipython3/001-completer-across-raw-types.patch new file mode 100644 index 0000000..d753ca3 --- /dev/null +++ b/meta/recipes-devtools/python/ipython3/001-completer-across-raw-types.patch @@ -0,0 +1,562 @@ +diff --git a/IPython/core/completer.py b/IPython/core/completer.py +index 8cb2345..076e2fa 100644 +--- a/IPython/core/completer.py ++++ b/IPython/core/completer.py +@@ -76,14 +76,18 @@ import os + import re + import shlex + import sys ++import types + + from IPython.config.configurable import Configurable + from IPython.core.error import TryNext + from IPython.core.inputsplitter import ESC_MAGIC ++from IPython.core.oinspect import getargspec + from IPython.utils import generics + from IPython.utils import io ++from IPython.utils import py3compat + from IPython.utils.dir2 import dir2 + from IPython.utils.process import arg_split ++from IPython.utils.py3compat import cast_unicode + from IPython.utils.traitlets import CBool, Enum + + #----------------------------------------------------------------------------- +@@ -181,6 +185,26 @@ def compress_user(path, tilde_expand, tilde_val): + class Bunch(object): pass + + ++class PostFix(object): ++ """ ++ Effectively a static class which encapsulates a bunch of postfix defs. ++ ++ """ ++ ++ ## delimiters which support the type completers ++ DELIMS = ' \t\n`!@#$^&*=+\\|;:",<>?' ++ ++ ## postfix strings for types ++ LIST = '[' ++ DICT = "['" ++ CALL = '(' ++ OBJ = '.' ++ ++ ## basic callable types ++ CALLABLES = [ types.FunctionType, types.LambdaType, types.MethodType, \ ++ types.BuiltinFunctionType, types.BuiltinMethodType ] ++ ++ + DELIMS = ' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?' + GREEDY_DELIMS = ' \r\n' + +@@ -200,6 +224,11 @@ class CompletionSplitter(object): + + # Private interface + ++ # These are the default-defaults. They get updated when the postfix ++ # engine is engaged. ++ _preferred_delims = DELIMS ++ _preferred_greedy_delims = GREEDY_DELIMS ++ + # A string of delimiter characters. The default value makes sense for + # IPython's most typical usage patterns. + _delims = DELIMS +@@ -246,6 +275,34 @@ class Completer(Configurable): + """ + ) + ++ use_postfix = CBool(False, config=True, ++ help="""Activate postfix indicator ++ ++ This will enable the feature to append syntactic notation to matches ++ providing indication as to what type they are. ++ ++ Append: ++ ( - any callable item ++ [ - any list ++ [' - any dictionary ++ """ ++ ) ++ ++ postfix_verbose = Enum((0,1,2), default_value=1, config=True, ++ help="""Provide verbose postfix suggestions. ++ ++ This is only valid if use_postfix=True. Verbosity is as follows: ++ ++ 0 - No postfix notations will be appended until you've isolate a ++ single attribute name. ++ 1 - In multiple-completion cases, types deriving from list, dict and ++ functions will have "[", "['" or "(" appended respectively. Detailed ++ operations are made available once a single attribute is determined. ++ 2 - Multiple-completion cases will have duplicate or triplicate entries ++ differing only by the "interface" character at the end. This can ++ make the tab completion lists pretty long. ++ """ ++ ) + + def __init__(self, namespace=None, global_namespace=None, config=None, **kwargs): + """Create a new completer for the command line. +@@ -303,6 +360,289 @@ class Completer(Configurable): + except IndexError: + return None + ++ def __dict_completions(self, expr, token, cruft, obj): ++ """Provide completion support for keys in a dictionary. ++ """ ++ #print("Completer->__dict_completions: t=%s" % (token)) ++ ++ # merge the token and cruft ++ token += cruft ++ ++ # handle the basic case ++ if (cruft == ""): ++ return ["%s['%s']" % (expr, k) for k in obj.keys()] ++ ++ # support the situation where the user started to type '] ++ if cruft.endswith("'"): ++ return [expr + token + cruft + "]"] ++ if cruft.endswith("']"): ++ return [expr + token + cruft] ++ ++ # for valid data, match any keys... ++ return ["%s['%s']" % (expr, k) for k in obj.keys() if k.startswith(cruft)] ++ ++ def __list_completions(self, expr, token, cruft, obj): ++ """Provide completion support for lists. ++ """ ++ entries = len(obj) - 1 ++ ++ #print("Completer->__list_completions: t=%s l=%d" % (token, entries)) ++ ++ # if it is already complete, leave it ++ if cruft.endswith("]"): ++ return [expr + token] ++ ++ # handle basic case or trash ++ if (cruft == "") or (not cruft.isdigit()): ++ return ["%s[0]" % (expr), "%s[%d]" % (expr, entries)] ++ ++ # main algorithm works only if val != 0 ++ if int(cruft) == 0: ++ return ["%s[0]" % (expr)] ++ ++ # generate a list of indicies whose first printed chars match ++ sim = [] ++ n = 1 ++ val = int(cruft) ++ while val*n <= entries: ++ # setup default end points ++ start = val*n ++ end = (val+1) * n ++ ++ # account for the possibility that we don't go all the way through ++ if end > entries: ++ end = entries+1; ++ ++ # append the next set of data ++ sim += range(start, end) ++ ++ # present based on base-10 ++ n *= 10 ++ ++ # create the option list ++ return ["%s[%d]" % (expr, s) for s in sim ] ++ ++ def __call_completions(self, expr, token, cruft, obj): ++ """Provide completion support for function calls. ++ """ ++ #print("Completer->__call_completions: FIX-ME") ++ matches = [] ++ if inspect.isclass(obj): ++ obj = obj.__init__ ++ elif (not py3compat.PY3) and type(obj) is types.InstanceType: ++ obj = obj.__call__ ++ ++ try: ++ hdef = inspect.formatargspec(*getargspec(obj)) ++ return cast_unicode(hdef).strip('(').strip(')').split(', ') ++ except: ++ return [] ++ ++ def __object_completions(self, expr, token, cruft, obj): ++ """Provide completion support for function calls. ++ """ ++ #print("Completer->__object_completions:") ++ if token is None: ++ token = '' ++ ++ # handle global items ++ if '.' not in expr+token: ++ #print(" global") ++ # provide options for incomplete text ++ subset = dict() ++ n = len(expr) ++ for lst in [keyword.kwlist, ++ builtins.__dict__.keys(), ++ self.namespace.keys(), ++ self.global_namespace.keys()]: ++ for word in lst: ++ if word[:n] == expr and word != "__builtins__": ++ obj = self._global_lookup(word) ++ #subset.append( (obj, word) ) ++ subset[word] = obj ++ ++ # manage the ones we actually care about ++ matches = [] ++ for k in subset.keys(): ++ ss = (subset[k], k) ++ if ss[0] != None: ++ apl = self._append_postfix(ss[0], ss[1], len(subset.keys())) ++ for ap in apl: ++ matches.append(ap) ++ else: ++ matches.append(ss[1]) ++ ++ # true matches updated accordingly ++ return matches ++ ++ else: ++ #print(" local") ++ # support overridding with __all__ attribute ++ if self.limit_to__all__ and hasattr(obj, '__all__'): ++ words = get__all__entries(obj) ++ else: ++ words = dir2(obj) ++ ++ try: ++ words = generics.complete_object(obj, words) ++ except TryNext: ++ pass ++ except Exception: ++ # Silence errors from completion function ++ #raise # dbg ++ pass ++ ++ # Build match list to return ++ n = len(cruft) ++ res = [] ++ subset = [] ++ ++ # first create a subset -- the ones we care about ++ for w in words: ++ if w[:n] == cruft and hasattr(obj, w): ++ val = getattr(obj, w) ++ subset.append( (w, val) ) ++ ++ # now, setup tha matches ++ for ss in subset: ++ apl = self._append_postfix(ss[1], ++ "%s.%s" % (expr, ss[0]), ++ len(subset)) ++ for ap in apl: ++ res.append(ap) ++ return res ++ ++ def _append_postfix(self, val, text, total_completions=0): ++ """Figure out what postfix symbol to append. ++ """ ++ #print("_append_postfix") ++ ++ # observer the request ++ if not self.use_postfix: ++ #print(" no-post-fix") ++ return [ text ] ++ ++ # ignore the postfix additions as preferred ++ if total_completions > 1: ++ ++ if self.postfix_verbose == 0: ++ #print(" omit-postfix (%d)" % total_completions) ++ return [ text ] ++ ++ elif self.postfix_verbose == 1: ++ if isinstance( val, dict ): ++ return [ text + PostFix.DICT ] ++ elif isinstance( val, list ): ++ return [ text + PostFix.LIST ] ++ elif type(val) in PostFix.CALLABLES: ++ return [ text + PostFix.CALL ] ++ else: ++ return [ text ] ++ ++ else: ++ # fall through and decode EVERYTHING ++ pass ++ ++ ++ # prepare multiple results ++ items = [] ++ ++ # handle scalars ++ if isinstance( val, int ) or isinstance( val, float ): ++ items.append( text ) # scalar itself ++ items.append( text + PostFix.OBJ ) # object completion ++ ++ # handle strings ++ elif isinstance( val, str ): ++ items.append( text ) # scalar itself ++ items.append( text + PostFix.OBJ ) # object completion ++ items.append( text + PostFix.LIST ) # list completion ++ ++ # handle lists ++ elif isinstance( val, list ): ++ items.append( text + PostFix.OBJ ) # object completion ++ items.append( text + PostFix.LIST ) # list completion ++ ++ # handle dicts ++ elif isinstance( val, dict ): ++ items.append( text + PostFix.OBJ ) # object completion ++ items.append( text + PostFix.DICT ) # dict completion ++ ++ # handle common callables ++ elif type(val) in PostFix.CALLABLES: ++ # skip object completion ++ items.append( text + PostFix.CALL ) # callable completion ++ ++ # handle general objects ++ else: ++ # always add its "object" completion ++ items.append( text + PostFix.OBJ ) ++ ++ # if it is callable, then provide the functional notation ++ if callable(val): ++ items.append( text + PostFix.CALL ) ++ ++ # is it iterable? ++ if hasattr(val, '__getitem__'): ++ try: ++ v = val[0] ++ items.append( text + PostFix.LIST ) # yup, some sort of list ++ except TypeError: ++ # wrong key type -- must be a general dictionary ++ items.append( text + PostFix.DICT ) ++ except KeyError: ++ # invalid key -- likely a dictionary ++ items.append( text + PostFix.DICT ) ++ except IndexError: ++ pass # empty list -- the object notation will handle it ++ ++ return items ++ ++ def _global_lookup(self, text): ++ """This routine searches the global namespace to find the object. ++ """ ++ try: ++ obj = eval(text, self.namespace) ++ except: ++ try: ++ obj = eval(text, self.global_namespace) ++ except: ++ obj = None ++ return obj ++ ++ def _postfix_completer(self, expr, token, cruft, ns_lookup_fn): ++ """Identify object-type completions. ++ """ ++ #print("Completer->_postfix_completer") ++ #print(" e=%s t=%s c=%s" % (expr, token, cruft)) ++ ++ # the token can be none as a result of the parent RE. ++ if token is None: ++ token = '' ++ ++ # get the object ++ # -- this may not be possible if it is part of a global ++ obj = ns_lookup_fn(expr+token+cruft) ++ if obj: ++ # odjust the params to reflect the new object ++ expr = expr + token + cruft ++ token = '' ++ cruft = '' ++ else: ++ # look up the base item ++ obj = ns_lookup_fn(expr) ++ ++ # sort them out ++ if token == PostFix.CALL: ++ return self.__call_completions(expr, token, cruft, obj) ++ elif token == PostFix.DICT: ++ return self.__dict_completions(expr, token, cruft, obj) ++ elif token == PostFix.LIST: ++ return self.__list_completions(expr, token, cruft, obj) ++ ++ # treat it as a plain object ++ return self.__object_completions(expr, token, cruft, obj) ++ + def global_matches(self, text): + """Compute matches when text is a simple name. + +@@ -310,18 +650,19 @@ class Completer(Configurable): + defined in self.namespace or self.global_namespace that match. + + """ +- #print 'Completer->global_matches, txt=%r' % text # dbg +- matches = [] +- match_append = matches.append +- n = len(text) +- for lst in [keyword.kwlist, +- __builtin__.__dict__.keys(), +- self.namespace.keys(), +- self.global_namespace.keys()]: +- for word in lst: +- if word[:n] == text and word != "__builtins__": +- match_append(word) +- return matches ++ #print('Completer->global_matches, txt=%r' % text) # dbg ++ ++ # sort out the components ++ m = re.match(r"(\w+)(\[\'|\[|\()?(\S*)$", text) ++ expr = m.group(1) ++ token = m.group(2) ++ cruft = m.group(3) ++ ++ # catch the completions across object types ++ matches = self._postfix_completer(expr, token, cruft, self._global_lookup) ++ if matches is not None: ++ return matches ++ return [] + + def attr_matches(self, text): + """Compute matches when text contains a dot. +@@ -338,44 +679,27 @@ class Completer(Configurable): + """ + + #io.rprint('Completer->attr_matches, txt=%r' % text) # dbg +- # Another option, seems to work great. Catches things like ''.<tab> +- m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text) +- +- if m: +- expr, attr = m.group(1, 3) +- elif self.greedy: +- m2 = re.match(r"(.+)\.(\w*)$", self.line_buffer) +- if not m2: +- return [] +- expr, attr = m2.group(1,2) +- else: ++ ++ pat = r"(\S+(\.\w+)*)(\.|\[\'|\[|\()(\S*)$" ++ m = re.match(pat, text) ++ ++ if not m: ++ io.rprint("Failed to match ...") + return [] +- +- try: +- obj = eval(expr, self.namespace) +- except: +- try: +- obj = eval(expr, self.global_namespace) +- except: +- return [] + +- if self.limit_to__all__ and hasattr(obj, '__all__'): +- words = get__all__entries(obj) +- else: +- words = dir2(obj) ++ # group(0) is the whole string ++ expr = m.group(1) ++ # group(2) is always 'None' ++ token = m.group(3) ++ cruft = m.group(4) ++ #expr, attr = m.group(1, 3) + +- try: +- words = generics.complete_object(obj, words) +- except TryNext: +- pass +- except Exception: +- # Silence errors from completion function +- #raise # dbg +- pass +- # Build match list to return +- n = len(attr) +- res = ["%s.%s" % (expr, w) for w in words if w[:n] == attr ] +- return res ++ ++ # catch the completions across object types ++ foo = self._postfix_completer(expr, token, cruft, self._global_lookup) ++ if foo is not None: ++ return foo ++ return [] + + + def get__all__entries(obj): +@@ -393,13 +717,34 @@ class IPCompleter(Completer): + + def _greedy_changed(self, name, old, new): + """update the splitter and readline delims when greedy is changed""" ++ #io.rprint("_greedy_changed: name=%s o=%d n%d" % (name, old, new)) + if new: +- self.splitter.delims = GREEDY_DELIMS ++ self.splitter.delims = self.splitter._preferred_greedy_delims + else: +- self.splitter.delims = DELIMS ++ self.splitter.delims = self.splitter._preferred_delims + + if self.readline: + self.readline.set_completer_delims(self.splitter.delims) ++ ++ # ++ # This is the implicit callback for applying changes to the 'use_postfix' ++ # configuration parameter. ++ # ++ def _use_postfix_changed(self, name, old, new): ++ """engage the correct delims ++ """ ++ #io.rprint("_use_postfix_changed: name=%s o=%d n%d" % (name, old, new)) ++ if new: ++ self.splitter._preferred_delims = PostFix.DELIMS ++ else: ++ self.splitter._preferred_delims = DELIMS ++ ++ # update the parser ++ self.splitter.delims = self.splitter._preferred_delims ++ ++ # update readline ++ if self.readline: ++ self.readline.set_completer_delims(self.splitter.delims) + + merge_completions = CBool(True, config=True, + help="""Whether to merge completion results into a single list +@@ -643,24 +988,24 @@ class IPCompleter(Completer): + """Match attributes or global python names""" + + #io.rprint('Completer->python_matches, txt=%r' % text) # dbg +- if "." in text: +- try: +- matches = self.attr_matches(text) +- if text.endswith('.') and self.omit__names: +- if self.omit__names == 1: +- # true if txt is _not_ a __ name, false otherwise: +- no__name = (lambda txt: +- re.match(r'.*\.__.*?__',txt) is None) +- else: +- # true if txt is _not_ a _ name, false otherwise: +- no__name = (lambda txt: +- re.match(r'.*\._.*?',txt) is None) +- matches = filter(no__name, matches) +- except NameError: +- # catches <undefined attributes>.<tab> +- matches = [] +- else: +- matches = self.global_matches(text) ++ if "." not in text: ++ return self.global_matches(text) ++ ++ try: ++ matches = self.attr_matches(text) ++ if text.endswith('.') and self.omit__names: ++ if self.omit__names == 1: ++ # true if txt is _not_ a __ name, false otherwise: ++ no__name = (lambda txt: ++ re.match(r'.*\.__.*?__',txt) is None) ++ else: ++ # true if txt is _not_ a _ name, false otherwise: ++ no__name = (lambda txt: ++ re.match(r'.*\._.*?',txt) is None) ++ matches = filter(no__name, matches) ++ except NameError: ++ # catches <undefined attributes>.<tab> ++ matches = [] + + return matches + diff --git a/meta/recipes-devtools/python/ipython3_0.13.1.bb b/meta/recipes-devtools/python/ipython3_0.13.1.bb new file mode 100644 index 0000000..33b1461 --- /dev/null +++ b/meta/recipes-devtools/python/ipython3_0.13.1.bb @@ -0,0 +1,71 @@ +SUMMARY = "Enhanced Python Shell - Python3" +DESCRIPTION = "Enhanced Python3 Shell -- A really great shell." +HOMEPAGE = "http://ipython.org/" +SECTION = "devel/python" + +LICENSE = "BSD" +LIC_FILES_CHKSUM = "file://docs/source/about/license_and_copyright.txt;md5=3311a509e946df2ddf84507563e7b504" + +SRCNAME = "ipython" +RPROVIDES_${PN} = "ipython3" +DEPENDS = "less" +RDEPENDS_${PN} = " \ + python3-compression \ + python3-core \ + python3-codecs \ + python3-ctypes \ + python3-crypt \ + python3-datetime \ + python3-debugger \ + python3-distribute \ + python3-distutils \ + python3-doctest \ + python3-io \ + python3-json \ + python3-lang \ + python3-logging \ + python3-math \ + python3-misc \ + python3-modules \ + python3-netclient \ + python3-pickle \ + python3-pkgutil \ + python3-pprint \ + python3-pydoc \ + python3-re \ + python3-readline \ + python3-resource \ + python3-shell \ + python3-stringold \ + python3-subprocess \ + python3-terminal \ + python3-textutils \ + python3-threading \ + python3-unittest \ + python3-unixadmin \ + " +RRECOMMENDS_${PN} = " \ + python3-nose \ + python3-pyzmq \ + " + +SRC_URI = "http://archive.ipython.org/release/${PV}/ipython-${PV}.tar.gz \ + file://001-completer-across-raw-types.patch \ + " + +# pick up the v3 toolset +inherit setuptools3 + +FILES_${PN} = "/" + +SRC_URI[md5sum] = "ca7e75f7c802afc6aaa0a1ea59846420" +SRC_URI[sha256sum] = "3bbf1095c4fd1fbf0a0871d9e26571a1ce3c4113d83ee3b688fa58e7e917f8c0" + +S = "${WORKDIR}/${SRCNAME}-${PV}" + +#do_unpackpost() { +# echo "PYTHON_BASEVERSION is " ${PYTHON_BASEVERSION} +# mv ${S}/../ipython-${PV}/* ${S} +#} + +#addtask unpackpost after do_unpack before do_patch diff --git a/meta/recipes-devtools/python/ipython_0.13.1.bb b/meta/recipes-devtools/python/ipython_0.13.1.bb new file mode 100644 index 0000000..7ee8862 --- /dev/null +++ b/meta/recipes-devtools/python/ipython_0.13.1.bb @@ -0,0 +1,48 @@ +SUMMARY = "Enhanced Python Shell" +DESCRIPTION = "Enhanced Python Shell -- A really great shell." +HOMEPAGE = "http://ipython.org/" +SECTION = "devel/python" + +LICENSE = "BSD" +LIC_FILES_CHKSUM = "file://docs/source/about/license_and_copyright.txt;md5=3311a509e946df2ddf84507563e7b504" + +RPROVIDES_${PN} = "ipython" +DEPENDS = "less" +RDEPENDS_${PN} = " \ + python-core \ + python-codecs \ + python-crypt \ + python-datetime \ + python-debugger \ + python-distribute \ + python-distutils \ + python-io \ + python-json \ + python-lang \ + python-misc \ + python-modules \ + python-netclient \ + python-pickle \ + python-pkgutil \ + python-pprint \ + python-pydoc \ + python-resource \ + python-shell \ + python-stringold \ + python-subprocess \ + python-terminal \ + python-textutils \ + python-threading \ + python-unixadmin \ + " + +SRC_URI = "http://archive.ipython.org/release/${PV}/ipython-${PV}.tar.gz \ + file://001-completer-across-raw-types.patch \ + " + +inherit setuptools + +FILES_${PN} = "/" + +SRC_URI[md5sum] = "ca7e75f7c802afc6aaa0a1ea59846420" +SRC_URI[sha256sum] = "3bbf1095c4fd1fbf0a0871d9e26571a1ce3c4113d83ee3b688fa58e7e917f8c0" -- 1.7.9.5 _______________________________________________ Openembedded-core mailing list Openembedded-core@lists.openembedded.org http://lists.openembedded.org/mailman/listinfo/openembedded-core