4343import string
4444import socket
4545import pydoc
46- import types
4746import unicodedata
4847import textwrap
4948from cStringIO import StringIO
6160from bpython .formatter import BPythonFormatter , Parenthesis
6261
6362# This for completion
63+ from bpython import inspection
6464from bpython import importcompletion
6565from glob import glob
6666
@@ -97,71 +97,6 @@ def calculate_screen_lines(tokens, width, cursor=0):
9797 return lines
9898
9999
100- def parsekeywordpairs (signature ):
101- tokens = PythonLexer ().get_tokens (signature )
102- stack = []
103- substack = []
104- parendepth = 0
105- begin = False
106- for token , value in tokens :
107- if not begin :
108- if token is Token .Punctuation and value == u'(' :
109- begin = True
110- continue
111-
112- if token is Token .Punctuation :
113- if value == u'(' :
114- parendepth += 1
115- elif value == u')' :
116- parendepth -= 1
117- elif value == ':' and parendepth == - 1 :
118- # End of signature reached
119- break
120-
121- if parendepth > 0 :
122- substack .append (value )
123- continue
124-
125- if (token is Token .Punctuation and
126- (value == ',' or (value == ')' and parendepth == - 1 ))):
127- stack .append (substack [:])
128- del substack [:]
129- continue
130-
131- if value and value .strip ():
132- substack .append (value )
133-
134- d = {}
135- for item in stack :
136- if len (item ) >= 3 :
137- d [item [0 ]] = '' .join (item [2 :])
138- return d
139-
140- def fixlongargs (f , argspec ):
141- """Functions taking default arguments that are references to other objects
142- whose str() is too big will cause breakage, so we swap out the object
143- itself with the name it was referenced with in the source by parsing the
144- source itself !"""
145- if argspec [3 ] is None :
146- # No keyword args, no need to do anything
147- return
148- values = list (argspec [3 ])
149- if not values :
150- return
151- keys = argspec [0 ][- len (values ):]
152- try :
153- src = inspect .getsourcelines (f )
154- except IOError :
155- return
156- signature = '' .join (src [0 ])
157- kwparsed = parsekeywordpairs (signature )
158-
159- for i , (key , value ) in enumerate (zip (keys , values )):
160- if len (str (value )) != len (kwparsed [key ]):
161- values [i ] = kwparsed [key ]
162-
163- argspec [3 ] = values
164-
165100class FakeStdin (object ):
166101 """Provide a fake stdin type for things like raw_input() etc."""
167102
@@ -414,54 +349,6 @@ def writetb(self, l):
414349 fancy."""
415350 map (self .write , ["\x01 %s\x03 %s" % (OPTS .color_scheme ['error' ], i ) for i in l ])
416351
417- class AttrCleaner (object ):
418- """A context manager that tries to make an object not exhibit side-effects
419- on attribute lookup."""
420- def __init__ (self , obj ):
421- self .obj = obj
422-
423- def __enter__ (self ):
424- """Try to make an object not exhibit side-effects on attribute
425- lookup."""
426- type_ = type (self .obj )
427- __getattribute__ = None
428- __getattr__ = None
429- # Dark magic:
430- # If __getattribute__ doesn't exist on the class and __getattr__ does
431- # then __getattr__ will be called when doing
432- # getattr(type_, '__getattribute__', None)
433- # so we need to first remove the __getattr__, then the
434- # __getattribute__, then look up the attributes and then restore the
435- # original methods. :-(
436- # The upshot being that introspecting on an object to display its
437- # attributes will avoid unwanted side-effects.
438- if py3 or type_ != types .InstanceType :
439- __getattr__ = getattr (type_ , '__getattr__' , None )
440- if __getattr__ is not None :
441- try :
442- setattr (type_ , '__getattr__' , (lambda _ : None ))
443- except TypeError :
444- __getattr__ = None
445- __getattribute__ = getattr (type_ , '__getattribute__' , None )
446- if __getattribute__ is not None :
447- try :
448- setattr (type_ , '__getattribute__' , object .__getattribute__ )
449- except TypeError :
450- # XXX: This happens for e.g. built-in types
451- __getattribute__ = None
452- self .attribs = (__getattribute__ , __getattr__ )
453- # /Dark magic
454-
455- def __exit__ (self , exc_type , exc_val , exc_tb ):
456- """Restore an object's magic methods."""
457- type_ = type (self .obj )
458- __getattribute__ , __getattr__ = self .attribs
459- # Dark magic:
460- if __getattribute__ is not None :
461- setattr (type_ , '__getattribute__' , __getattribute__ )
462- if __getattr__ is not None :
463- setattr (type_ , '__getattr__' , __getattr__ )
464- # /Dark magic
465352
466353class Repl (object ):
467354 """Implements the necessary guff for a Python-repl-alike interface
@@ -569,7 +456,7 @@ def attr_matches(self, text):
569456 # a SyntaxError
570457 return []
571458 obj = eval (expr , self .interp .locals )
572- with AttrCleaner (obj ):
459+ with inspection . AttrCleaner (obj ):
573460 matches = self .attr_lookup (obj , expr , attr )
574461 return matches
575462
@@ -591,7 +478,7 @@ def attr_lookup(self, obj, expr, attr):
591478
592479 def _callable_postfix (self , value , word ):
593480 """rlcompleter's _callable_postfix done right."""
594- with AttrCleaner (value ):
481+ with inspection . AttrCleaner (value ):
595482 if hasattr (value , '__call__' ):
596483 word += '('
597484 return word
@@ -643,98 +530,10 @@ def get_args(self):
643530
644531 self .current_func = None
645532
646- def getpydocspec (f , func ):
647- try :
648- argspec = pydoc .getdoc (f )
649- except NameError :
650- return None
651-
652- rx = re .compile (r'([a-zA-Z_][a-zA-Z0-9_]*?)\((.*?)\)' )
653- s = rx .search (argspec )
654- if s is None :
655- return None
656-
657- if not hasattr (f , '__name__' ) or s .groups ()[0 ] != f .__name__ :
658- return None
659-
660- args = list ()
661- defaults = list ()
662- varargs = varkwargs = None
663- kwonly_args = list ()
664- kwonly_defaults = dict ()
665- for arg in s .group (2 ).split (',' ):
666- arg = arg .strip ()
667- if arg .startswith ('**' ):
668- varkwargs = arg [2 :]
669- elif arg .startswith ('*' ):
670- varargs = arg [1 :]
671- else :
672- arg , _ , default = arg .partition ('=' )
673- if varargs is not None :
674- kwonly_args .append (arg )
675- if default :
676- kwonly_defaults [arg ] = default
677- else :
678- args .append (arg )
679- if default :
680- defaults .append (default )
681-
682- return [func , (args , varargs , varkwargs , defaults ,
683- kwonly_args , kwonly_defaults )]
684-
685- def getargspec (func ):
686- try :
687- if func in self .interp .locals :
688- f = self .interp .locals [func ]
689- except TypeError :
690- return None
691- else :
692- try :
693- f = eval (func , self .interp .locals )
694- except Exception :
695- # Same deal with the exceptions :(
696- return None
697- else :
698- self .current_func = f
699-
700- is_bound_method = inspect .ismethod (f ) and f .im_self is not None
701- try :
702- if inspect .isclass (f ):
703- self .current_func = f
704- if py3 :
705- argspec = inspect .getfullargspec (f .__init__ )
706- else :
707- argspec = inspect .getargspec (f .__init__ )
708- self .current_func = f .__init__
709- is_bound_method = True
710- else :
711- if py3 :
712- argspec = inspect .getfullargspec (f )
713- else :
714- argspec = inspect .getargspec (f )
715- self .current_func = f
716- argspec = list (argspec )
717- fixlongargs (f , argspec )
718- self .argspec = [func , argspec , is_bound_method ]
719- return True
720-
721- except (NameError , TypeError , KeyError ):
722- with AttrCleaner (f ):
723- t = getpydocspec (f , func )
724- if t is None :
725- return None
726- self .argspec = t
727- if inspect .ismethoddescriptor (f ):
728- self .argspec [1 ][0 ].insert (0 , 'obj' )
729- self .argspec .append (is_bound_method )
730- return True
731- except AttributeError :
732- # This happens if no __init__ is found
733- return None
734-
735533 if not OPTS .arg_spec :
736534 return False
737535
536+ # Find the name of the current function
738537 stack = [['' , 0 , '' ]]
739538 try :
740539 for (token , value ) in PythonLexer ().get_tokens (self .s ):
@@ -762,7 +561,27 @@ def getargspec(func):
762561 except IndexError :
763562 return False
764563
765- if getargspec (func ):
564+ # We found a name, now get a function object
565+ try :
566+ if func in self .interp .locals :
567+ f = self .interp .locals [func ]
568+ except TypeError :
569+ return None
570+ else :
571+ try :
572+ f = eval (func , self .interp .locals )
573+ except Exception :
574+ # Same deal with the exceptions :(
575+ return None
576+ if inspect .isclass (f ):
577+ try :
578+ f = f .__init__
579+ except AttributeError :
580+ return None
581+ self .current_func = f
582+
583+ self .argspec = inspection .getargspec (func , f )
584+ if self .argspec :
766585 self .argspec .append (arg_number )
767586 return True
768587 return False
0 commit comments