Commits

Jonathan Eunice committed 431cfe2

Improved ability of show to not freak out if cannot determine name of variable it's showing. In that case, show the value with '?' as name. Esp. helpful for interactive use.

Comments (0)

Files changed (5)

     Returns each non-blank line in text enclosed in a list.
     """
     return [ l.strip() for l in text.strip().splitlines() if l.strip() ]
-    
+
     # The double-mention of l.strip() is yet another fine example of why
     # Python needs en passant aliasing.
 
 system = str(sys.platform).lower()
 impl = platform.python_implementation()
 
-install_requires = ['six', 'options>=0.5', 'say>=0.969', 'stuf>=0.9.12',
+install_requires = ['six', 'options', 'say>=0.969', 'stuf>=0.9.12',
                     'mementos>=0.506', 'codegen' ]
 
 if 'darwin' in system:
     if impl != 'PyPy':
         install_requires += ['readline']
-        
+
         # if iPython ran under PyPy, it'd require readline too
         # but on my system, readline fails to install under PyPy
         # thus this spot omission
-        
+
 elif 'win32' in system:
     install_requires += ['pyreadline']
 
         self.say = Say(retvalue=self.options.retvalue)
         self.opts = None  # per call options, set on each call to reflect transient state
         self._watching = {} # remembers last value of variables for given frames
-    
+
     def call_location(self, caller):
         """
         Create a call location string indicating where a show() was called.
                 filepath = caller.f_locals.get('__file__', caller.f_globals.get('__file__', 'UNKNOWN'))
                 filename = os.path.basename(filepath)
                 module_name = re.sub(r'.py', '', filename)
-            
+
             lineno = caller.f_lineno
             co_name = caller.f_code.co_name
             if co_name == '<module>':
         Return a list of argument name, value tuples with the given values.
         """
         filename, lineno = frame_to_source_info(caller)
-        argnames = CallArgs(filename, lineno).args
+        try:
+            argnames = CallArgs(filename, lineno).args
+        except ArgsUnavailable:
+            argnames = '?' * len(values)
         argtuples = list(zip(list(argnames), list(values)))
         return argtuples
 
 
     def __gt__(self, other):
         """
-        Simple, non-functional call. Experimental.  
+        Simple, non-functional call. Experimental.
         """
 
         opts = self.options.push({})
 
     def __rshift__(self, other):
         """
-        Simple, non-functional call. Experimental.  
+        Simple, non-functional call. Experimental.
         """
 
         opts = self.options.push({})
                                 not isinstance(v, FUNKY) and \
                                 not getattr(v, '__module__', '').startswith( ('IPython', 'site', 'show')) and \
                                 not (isInteractive and (k == 'In' or k == 'Out'))
-                            ]        
+                            ]
         if args:
             # self.say("args = {args!r}")
             argtuples = self.get_arg_tuples(caller, args)
     # TODO: Give this decorator standard show kwargs
     # TODO: Unifiy inout and retval function argument/return value decorators
     # TODO: Figure out why test not working (correct answer, but output caputure fails)
-    
+
     # Promote delegated formatting functions
     def blank_lines(self, *args, **kwargs):
         self.say.blank_lines(*args, **kwargs)
 # creation of other show objects. Currently disabled while working on it.
 
 # TODO: add easier decorator for function tracing (just @show?)
-

show/introspect.py

 class ClassProps(with_metaclass(MementoMetaclass)):
 
     """
-    Memoized finder of class props. 
+    Memoized finder of class props.
     """
 
     def __init__(self, cls):
     @property
     def prefixed(self):
         return [ self.prefixes[p] + p for p in self.props ]
-    
+
     # TODO: finish code to do class-based discovery of props along the MRO
     # NOT sure what the prefixing is
 
     # prop_prefix = cprops.prefixes.copy()
     # prop_prefix.update({ k: prefix.normal for k in dictkeys })
     # prop_prefix.update({ k: prefix.slot for k in slotkeys })
-    
+
     allprops = sorted(set(proxykeys + dictkeys + slotkeys + classkeys))
 
     if DEBUGGING:
     """
 
     TARGET_FUNCS = set()  # function names we care about
-    
+
     @classmethod
     def add_target_func(cls, name):
         suffixes = [ '', '.items', '.props', '.changed', '.dir', '.chars' ]
         names = [ name + s for s in suffixes ]
         cls.TARGET_FUNCS.update(names)
-    
+
     def __init__(self, filepath, lineno):
         ast.NodeVisitor.__init__(self)
         self.filepath = filepath
         """
         src = ""
         for lastlineno in range(self.lineno, self.lineno+10):
-            src += getline(self.filepath, lastlineno)
+            line = getline(self.filepath, lastlineno)
+            if line is None:
+                raise ArgsUnavailable('getline returns None at {0}'.format(lastlineno))
+            src += line
             try:
                 srcleft = textwrap.dedent(src)
                 self.ast = ast.parse(srcleft)
             except SyntaxError:
                 pass
         raise RuntimeError('Failed to parse:\n{}\n'.format(src))
-        
+
     def visit_Call(self, node):
         """
         Called for all ``ast.Call`` nodes. Collects source of each argument.
                 return n.func.id
             elif isinstance(n.func, ast.Attribute):
                 a = n.func
-                if isinstance(a.value, ast.Name): 
+                if isinstance(a.value, ast.Name):
                     return '.'.join([a.value.id, a.attr])
                 else:
                     return None # could be an attribute of a call, but for those, we don't much care
             if isinstance(n, ast.Name):
                 return n.id
             elif isinstance(n, ast.Attribute):
-                if isinstance(n.value, ast.Name): 
+                if isinstance(n.value, ast.Name):
                     return '.'.join([n.value.id, n.attr])
                 else:
                     return None # could be an attribute of a call, but for those, we don't much care
             if isinstance(n, ast.Name):
                 return n.id
             elif isinstance(n, ast.Attribute):
-                if isinstance(n.value, ast.Name): 
+                if isinstance(n.value, ast.Name):
                     return '.'.join([n.value.id, n.attr])
                 else:
                     return None # could be an attribute of a call, but for those, we don't much care

show/linecacher.py

 import sys
 import linecache
 
+class ArgsUnavailable(ValueError): pass
+
 isInteractive = hasattr(sys, 'ps1') or hasattr(sys, 'ipcompleter')
 # http://stackoverflow.com/questions/967369/python-find-out-if-running-in-shell-or-not-e-g-sun-grid-engine-queue
 
             self._lines.append(rl.get_history_item(rl.get_current_history_length()))
             rl.clear_history()
             self._lastseen = rl.get_current_history_length()  # have we seen it all?
-            
+
         @property
         def lines(self):
             """
             self._lines  = [ None ] # first item is None to compensate: 0-based arrays
                                     # but 1-based line numbers
             self._lines.append(rl.get_history_item(rl.get_current_history_length()))
-        
+
         #def show(self):
         #    """
         #    Show last items.
         if filename == '<stdin>':
             index = -1 if lineno == 1 else lineno - 1
             # for interactive Python, lineno == 1 a lot
-            return history.lines[index]
+            try:
+                return history.lines[index]
+            except IndexError:
+                raise ArgsUnavailable('Cannot retrieve hisotry line {0}'.format(index))
         else:
             return linecache.getline(filename, lineno)
 
 
 def omitnames(names, patterns, sort=True):
     """
-    Given a collection (list, set) of ``names``, remove any that match the glob
+    Given a collection (list, set) of ``names``, remove any that do NOT match the glob
     sub-patterns found in ``patterns`` (separated by whitespace). If ``sort``,
     returns a sorted list (the default); else return the remaining names in
     their original order. If patterns is false-y, just return names.
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.