]> git.saurik.com Git - wxWidgets.git/commitdiff
New PyCrust from Patrick O'Brien
authorRobin Dunn <robin@alldunn.com>
Tue, 9 Apr 2002 21:57:35 +0000 (21:57 +0000)
committerRobin Dunn <robin@alldunn.com>
Tue, 9 Apr 2002 21:57:35 +0000 (21:57 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@15058 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

wxPython/wxPython/lib/PyCrust/PyCrustApp.py
wxPython/wxPython/lib/PyCrust/PyFillingApp.py
wxPython/wxPython/lib/PyCrust/README.txt
wxPython/wxPython/lib/PyCrust/crust.py
wxPython/wxPython/lib/PyCrust/filling.py
wxPython/wxPython/lib/PyCrust/interpreter.py
wxPython/wxPython/lib/PyCrust/introspect.py
wxPython/wxPython/lib/PyCrust/pseudo.py
wxPython/wxPython/lib/PyCrust/shell.py
wxPython/wxPython/lib/PyCrust/version.py

index 1dcb1a668cb71f5c43fb9ccc743f369f57ffe439..fef1c40ee21ecb5512342d4b72860b718232c7e2 100755 (executable)
@@ -3,18 +3,18 @@
 
 __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
 __cvsid__ = "$Id$"
 
 __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
 __cvsid__ = "$Id$"
-__version__ = "$Revision$"[11:-2]
+__revision__ = "$Revision$"[11:-2]
 
 from wxPython.wx import *
 
 from wxPython.wx import *
-from crust import CrustFrame
+from PyCrust.crust import CrustFrame
 
 
 class App(wxApp):
     """PyCrust standalone application."""
 
 
 class App(wxApp):
     """PyCrust standalone application."""
-
+    
     def OnInit(self):
         locals = {'__app__': 'PyCrust Standalone Application'}
     def OnInit(self):
         locals = {'__app__': 'PyCrust Standalone Application'}
-        self.crustFrame = CrustFrame(locals=locals, size=(800,600))
+        self.crustFrame = CrustFrame(locals=locals)
         self.crustFrame.Show(true)
         self.SetTopWindow(self.crustFrame)
         # Add the application object to the sys module's namespace.
         self.crustFrame.Show(true)
         self.SetTopWindow(self.crustFrame)
         # Add the application object to the sys module's namespace.
@@ -33,4 +33,4 @@ def main():
 if __name__ == '__main__':
     main()
 
 if __name__ == '__main__':
     main()
 
-
index 61d3db5cb0978554fa08eef64cade5729bf87519..efdcd6a6de4acbc8aee35c0887e30b3ad38910f2 100755 (executable)
@@ -3,19 +3,19 @@
 
 __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
 __cvsid__ = "$Id$"
 
 __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
 __cvsid__ = "$Id$"
-__version__ = "$Revision$"[11:-2]
+__revision__ = "$Revision$"[11:-2]
 
 # We use this object to get more introspection when run standalone.
 application = None
 
 
 # We use this object to get more introspection when run standalone.
 application = None
 
-import filling
+from PyCrust import filling
 
 # These are imported just to have something interesting to inspect.
 
 # These are imported just to have something interesting to inspect.
-import crust
-import interpreter
-import introspect
-import pseudo
-import shell
+from PyCrust import crust
+from PyCrust import interpreter
+from PyCrust import introspect
+from PyCrust import pseudo
+from PyCrust import shell
 import sys
 from wxPython import wx
 
 import sys
 from wxPython import wx
 
@@ -32,4 +32,4 @@ def main():
 if __name__ == '__main__':
     main()
 
 if __name__ == '__main__':
     main()
 
-
index 828b99a46b4b105d3674f7bedea353730d8486d5..b5c4d8ad9bdea5d39640c5a9cc3696fecc72a9e6 100644 (file)
@@ -23,12 +23,6 @@ Have you ever tried to bake a pie without one? Well, you
 shouldn't build a Python program without a PyCrust either.
 
 
 shouldn't build a Python program without a PyCrust either.
 
 
-Where can I get the latest release of PyCrust?
-----------------------------------------------
-The latest PyCrust releases are available at:
-http://sourceforge.net/project/showfiles.php?group_id=31263
-
-
 What else do I need to use PyCrust?
 -----------------------------------
 PyCrust requires Python 2.1 or later, and wxPython 2.3.1 or later.
 What else do I need to use PyCrust?
 -----------------------------------
 PyCrust requires Python 2.1 or later, and wxPython 2.3.1 or later.
@@ -37,30 +31,34 @@ Python is available at http://www.python.org/.
 wxPython is available at http://www.wxpython.org/.
 
 
 wxPython is available at http://www.wxpython.org/.
 
 
+Where can I get the latest version of PyCrust?
+----------------------------------------------
+The latest production version ships with wxPython.
+The latest developer version is available in CVS at:
+http://sourceforge.net/cvs/?group_id=31263
+
+
 Where is the PyCrust project hosted?
 ------------------------------------
 At SourceForge, of course. The SourceForge summary page:
 http://sourceforge.net/projects/pycrust/
 
 
 Where is the PyCrust project hosted?
 ------------------------------------
 At SourceForge, of course. The SourceForge summary page:
 http://sourceforge.net/projects/pycrust/
 
 
-Does PyCrust have a mailing list full of wonderful people?
-----------------------------------------------------------
-As a matter of fact, we do. Join the PyCrust mailing lists at:
-http://sourceforge.net/mail/?group_id=31263
-
-
 I found a bug in PyCrust, what do I do with it?
 -----------------------------------------------
 I found a bug in PyCrust, what do I do with it?
 -----------------------------------------------
-You can send it to me at pobrien@orbtech.com, or, preferably,
-submit a bug report on our bug tracker at SourceForge:
-http://sourceforge.net/tracker/?group_id=31263
+You can send it to me at pobrien@orbtech.com.
 
 
 I want a new feature added to PyCrust. Will you do it?
 ------------------------------------------------------
 Flattery and money will get you anything. Short of that, you
 
 
 I want a new feature added to PyCrust. Will you do it?
 ------------------------------------------------------
 Flattery and money will get you anything. Short of that, you
-can try posting a request on our feature tracker at SourceForge:
-http://sourceforge.net/tracker/?group_id=31263
+can send me a request and I'll see what I can do.
+
+
+Does PyCrust have a mailing list full of wonderful people?
+----------------------------------------------------------
+As a matter of fact, we do. Join the PyCrust mailing lists at:
+http://sourceforge.net/mail/?group_id=31263
 
 
 What is the CVS information for this README file?
 
 
 What is the CVS information for this README file?
index 128ce54cd2eddded444bc8f9a2b8c9f111adaf43..59175c58fa1a87b5990a17ccc73954d9503a27ac 100644 (file)
@@ -2,7 +2,7 @@
 
 __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
 __cvsid__ = "$Id$"
 
 __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
 __cvsid__ = "$Id$"
-__version__ = "$Revision$"[11:-2]
+__revision__ = "$Revision$"[11:-2]
 
 from wxPython.wx import *
 from shell import Shell
 
 from wxPython.wx import *
 from shell import Shell
@@ -14,7 +14,7 @@ class Crust(wxSplitterWindow):
     """PyCrust Crust based on wxSplitterWindow."""
     
     name = 'PyCrust Crust'
     """PyCrust Crust based on wxSplitterWindow."""
     
     name = 'PyCrust Crust'
-    revision = __version__
+    revision = __revision__
     
     def __init__(self, parent, id=-1, pos=wxDefaultPosition, \
                  size=wxDefaultSize, style=wxSP_3D, name='Crust Window', \
     
     def __init__(self, parent, id=-1, pos=wxDefaultPosition, \
                  size=wxDefaultSize, style=wxSP_3D, name='Crust Window', \
@@ -42,7 +42,7 @@ class CrustFrame(wxFrame, ShellMenu):
     """Frame containing all the PyCrust components."""
     
     name = 'PyCrust Frame'
     """Frame containing all the PyCrust components."""
     
     name = 'PyCrust Frame'
-    revision = __version__
+    revision = __revision__
     
     def __init__(self, parent=None, id=-1, title='PyCrust', \
                  pos=wxDefaultPosition, size=wxDefaultSize, \
     
     def __init__(self, parent=None, id=-1, title='PyCrust', \
                  pos=wxDefaultPosition, size=wxDefaultSize, \
@@ -52,7 +52,7 @@ class CrustFrame(wxFrame, ShellMenu):
         """Create a PyCrust CrustFrame instance."""
         wxFrame.__init__(self, parent, id, title, pos, size, style)
         intro = 'Welcome To PyCrust %s - The Flakiest Python Shell' % VERSION
         """Create a PyCrust CrustFrame instance."""
         wxFrame.__init__(self, parent, id, title, pos, size, style)
         intro = 'Welcome To PyCrust %s - The Flakiest Python Shell' % VERSION
-        intro += '\nSponsored by Orbtech - Your Source For Python Development Services'
+        intro += '\nSponsored by Orbtech - Specializing in Python Application Development'
         self.CreateStatusBar()
         self.SetStatusText(intro.replace('\n', ', '))
         if wxPlatform == '__WXMSW__':
         self.CreateStatusBar()
         self.SetStatusText(intro.replace('\n', ', '))
         if wxPlatform == '__WXMSW__':
index 4cb15af1d0fe70db55eca95b7cad18c8ae16392f..15c627ce6072e8ac7242cfa4150e57b958d95d08 100644 (file)
@@ -3,7 +3,7 @@ the local namespace or any object."""
 
 __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
 __cvsid__ = "$Id$"
 
 __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
 __cvsid__ = "$Id$"
-__version__ = "$Revision$"[11:-2]
+__revision__ = "$Revision$"[11:-2]
 
 from wxPython.wx import *
 from wxPython.stc import *
 
 from wxPython.wx import *
 from wxPython.stc import *
@@ -19,7 +19,7 @@ class FillingTree(wxTreeCtrl):
     """PyCrust FillingTree based on wxTreeCtrl."""
     
     name = 'PyCrust Filling Tree'
     """PyCrust FillingTree based on wxTreeCtrl."""
     
     name = 'PyCrust Filling Tree'
-    revision = __version__
+    revision = __revision__
 
     def __init__(self, parent, id=-1, pos=wxDefaultPosition, \
                  size=wxDefaultSize, style=wxTR_HAS_BUTTONS, \
 
     def __init__(self, parent, id=-1, pos=wxDefaultPosition, \
                  size=wxDefaultSize, style=wxTR_HAS_BUTTONS, \
@@ -203,7 +203,7 @@ class FillingText(wxStyledTextCtrl):
     """PyCrust FillingText based on wxStyledTextCtrl."""
     
     name = 'PyCrust Filling Text'
     """PyCrust FillingText based on wxStyledTextCtrl."""
     
     name = 'PyCrust Filling Text'
-    revision = __version__
+    revision = __revision__
 
     def __init__(self, parent, id=-1, pos=wxDefaultPosition, \
                  size=wxDefaultSize, style=wxCLIP_CHILDREN):
 
     def __init__(self, parent, id=-1, pos=wxDefaultPosition, \
                  size=wxDefaultSize, style=wxCLIP_CHILDREN):
@@ -265,7 +265,7 @@ class Filling(wxSplitterWindow):
     """PyCrust Filling based on wxSplitterWindow."""
     
     name = 'PyCrust Filling'
     """PyCrust Filling based on wxSplitterWindow."""
     
     name = 'PyCrust Filling'
-    revision = __version__
+    revision = __revision__
     
     def __init__(self, parent, id=-1, pos=wxDefaultPosition, \
                  size=wxDefaultSize, style=wxSP_3D, name='Filling Window', \
     
     def __init__(self, parent, id=-1, pos=wxDefaultPosition, \
                  size=wxDefaultSize, style=wxSP_3D, name='Filling Window', \
@@ -288,7 +288,7 @@ class FillingFrame(wxFrame):
     """Frame containing the PyCrust filling, or namespace tree component."""
     
     name = 'PyCrust Filling Frame'
     """Frame containing the PyCrust filling, or namespace tree component."""
     
     name = 'PyCrust Filling Frame'
-    revision = __version__
+    revision = __revision__
     
     def __init__(self, parent=None, id=-1, title='PyFilling', \
                  pos=wxDefaultPosition, size=wxDefaultSize, \
     
     def __init__(self, parent=None, id=-1, title='PyFilling', \
                  pos=wxDefaultPosition, size=wxDefaultSize, \
index 8274e35ed14b97165c4c1073ea9018940d5a0bea..f669a5d122194fd490ec65e1a508d6e614f4f22b 100644 (file)
@@ -2,7 +2,7 @@
 
 __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
 __cvsid__ = "$Id$"
 
 __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
 __cvsid__ = "$Id$"
-__version__ = "$Revision$"[11:-2]
+__revision__ = "$Revision$"[11:-2]
 
 import os
 import sys
 
 import os
 import sys
@@ -13,7 +13,7 @@ import introspect
 class Interpreter(InteractiveInterpreter):
     """PyCrust Interpreter based on code.InteractiveInterpreter."""
     
 class Interpreter(InteractiveInterpreter):
     """PyCrust Interpreter based on code.InteractiveInterpreter."""
     
-    revision = __version__
+    revision = __revision__
     
     def __init__(self, locals=None, rawin=None, \
                  stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr):
     
     def __init__(self, locals=None, rawin=None, \
                  stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr):
@@ -102,4 +102,4 @@ class InterpreterAlaCarte(Interpreter):
         sys.ps1 = ps1
         sys.ps2 = ps2
 
         sys.ps1 = ps1
         sys.ps2 = ps2
 
-   
\ No newline at end of file
+   
index 7f4efb64c12f2646487daff4ae6cbfdef4fe1fac..39561ade2c7f904683c38c0166a8d4d63833801c 100644 (file)
@@ -3,7 +3,7 @@ like call tips and command auto completion."""
 
 __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
 __cvsid__ = "$Id$"
 
 __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
 __cvsid__ = "$Id$"
-__version__ = "$Revision$"[11:-2]
+__revision__ = "$Revision$"[11:-2]
 
 import inspect
 import string
 
 import inspect
 import string
@@ -14,117 +14,128 @@ def getAutoCompleteList(command='', locals=None, includeMagic=1, \
     """Return list of auto-completion options for command.
     
     The list of options will be based on the locals namespace."""
     """Return list of auto-completion options for command.
     
     The list of options will be based on the locals namespace."""
-
+    attributes = []
     # Get the proper chunk of code from the command.
     root = getRoot(command, terminator='.')
     try:
     # Get the proper chunk of code from the command.
     root = getRoot(command, terminator='.')
     try:
-        object = eval(root, locals)
+        if locals is not None:
+            object = eval(root, locals)
+        else:
+            object = eval(root)
+    except:
+        pass
+    else:
         attributes = getAttributeNames(object, includeMagic, \
                                        includeSingle, includeDouble)
         attributes = getAttributeNames(object, includeMagic, \
                                        includeSingle, includeDouble)
-        return attributes
-    except:
-        return []
+    return attributes
     
 def getAttributeNames(object, includeMagic=1, includeSingle=1, includeDouble=1):
     """Return list of unique attributes, including inherited, for an object."""
     attributes = []
     dict = {}
     
 def getAttributeNames(object, includeMagic=1, includeSingle=1, includeDouble=1):
     """Return list of unique attributes, including inherited, for an object."""
     attributes = []
     dict = {}
+    if not hasattrAlwaysReturnsTrue(object):
+        # Add some attributes that don't always get picked up.
+        # If they don't apply, they'll get filtered out at the end.
+        attributes += ['__bases__', '__class__', '__dict__', '__name__', \
+                       'func_closure', 'func_code', 'func_defaults', \
+                       'func_dict', 'func_doc', 'func_globals', 'func_name']
     if includeMagic:
         try: attributes += object._getAttributeNames()
         except: pass
     if includeMagic:
         try: attributes += object._getAttributeNames()
         except: pass
-    # Get all attribute names, removing duplicates from the attribute list.
-    for item in getAllAttributeNames(object):
+    # Get all attribute names.
+    attrdict = getAllAttributeNames(object)
+    for attrlist in attrdict.values():
+        attributes += attrlist
+    # Remove duplicates from the attribute list.
+    for item in attributes:
         dict[item] = None
         dict[item] = None
-    attributes += dict.keys()
+    attributes = dict.keys()
     attributes.sort(lambda x, y: cmp(x.upper(), y.upper()))
     if not includeSingle:
     attributes.sort(lambda x, y: cmp(x.upper(), y.upper()))
     if not includeSingle:
-        attributes = filter(lambda item: item[0]!='_' or item[1]=='_', attributes)
+        attributes = filter(lambda item: item[0]!='_' \
+                            or item[1]=='_', attributes)
     if not includeDouble:
         attributes = filter(lambda item: item[:2]!='__', attributes)
     # Make sure we haven't picked up any bogus attributes somehow.
     if not includeDouble:
         attributes = filter(lambda item: item[:2]!='__', attributes)
     # Make sure we haven't picked up any bogus attributes somehow.
-    attributes = [attribute for attribute in attributes if hasattr(object, attribute)]
+    attributes = [attribute for attribute in attributes \
+                  if hasattr(object, attribute)]
     return attributes
 
     return attributes
 
+def hasattrAlwaysReturnsTrue(object):
+    return hasattr(object, 'bogu5_123_aTTri8ute')
+
 def getAllAttributeNames(object):
 def getAllAttributeNames(object):
-    """Return list of all attributes, including inherited, for an object.
+    """Return mapping of all attributes, including inherited, for an object.
     
     Recursively walk through a class and all base classes.
     """
     
     Recursively walk through a class and all base classes.
     """
+    attrdict = {}  # (object, technique, count): [list of attributes]
     # !!!
     # !!! Do Not use hasattr() as a test anywhere in this function,
     # !!! because it is unreliable with remote objects - xmlrpc, soap, etc.
     # !!!
     # !!! Do Not use hasattr() as a test anywhere in this function,
     # !!! because it is unreliable with remote objects - xmlrpc, soap, etc.
+    # !!! They always return true for hasattr().
     # !!! 
     # !!! 
-    attributes = []
+    key = str(object)
     # Wake up sleepy objects - a hack for ZODB objects in "ghost" state.
     wakeupcall = dir(object)
     del wakeupcall
     # Get attributes available through the normal convention.
     # Wake up sleepy objects - a hack for ZODB objects in "ghost" state.
     wakeupcall = dir(object)
     del wakeupcall
     # Get attributes available through the normal convention.
-    attributes += dir(object)
+    attributes = dir(object)
+    attrdict[(key, 'dir', len(attributes))] = attributes
+    # Get attributes from the object's dictionary, if it has one.
     try:
     try:
-        keys = object.__dict__.keys()
-    except:
+        attributes = object.__dict__.keys()
+        attributes.sort()
+    except:  # Must catch all because object might have __getattr__.
         pass
     else:
         pass
     else:
-        attributes += keys
+        attrdict[(key, '__dict__', len(attributes))] = attributes
     # For a class instance, get the attributes for the class.
     # For a class instance, get the attributes for the class.
-    if hasattr(object, '__class__'):
-        # Break a circular reference. This happens with extension classes.
-        if object.__class__ is object:
+    try:
+        klass = object.__class__
+    except:  # Must catch all because object might have __getattr__.
+        pass
+    else:
+        if klass is object:
+            # Break a circular reference. This happens with extension classes.
             pass
         else:
             pass
         else:
-            attributes += getAllAttributeNames(object.__class__)
+            attrdict.update(getAllAttributeNames(klass))
     # Also get attributes from any and all parent classes.
     try:
         bases = object.__bases__
     # Also get attributes from any and all parent classes.
     try:
         bases = object.__bases__
-    except:
+    except:  # Must catch all because object might have __getattr__.
         pass
     else:
         pass
     else:
-        if isinstance(bases, type(())):
+        if isinstance(bases, types.TupleType):
             for base in bases:
                 if type(base) is types.TypeType:
                     # Break a circular reference. Happens in Python 2.2.
                     pass
                 else:
             for base in bases:
                 if type(base) is types.TypeType:
                     # Break a circular reference. Happens in Python 2.2.
                     pass
                 else:
-                    attributes += getAllAttributeNames(base)
-    return attributes
+                    attrdict.update(getAllAttributeNames(base))
+    return attrdict
 
 def getCallTip(command='', locals=None):
 
 def getCallTip(command='', locals=None):
-    """Return call tip text for a command.
+    """For a command, return a tuple of object name, argspec, tip text.
     
     The call tip information will be based on the locals namespace."""
     
     The call tip information will be based on the locals namespace."""
-
-    calltip = ('', '', '')
+    calltip = ('', '', '')  # object name, argspec, tip text.
     # Get the proper chunk of code from the command.
     root = getRoot(command, terminator='(')
     try:
     # Get the proper chunk of code from the command.
     root = getRoot(command, terminator='(')
     try:
-        object = eval(root, locals)
+        if locals is not None:
+            object = eval(root, locals)
+        else:
+            object = eval(root)
     except:
         return calltip
     name = ''
     except:
         return calltip
     name = ''
-    dropSelf = 1
-    # Switch to the object that has the information we need.
-    if inspect.isbuiltin(object):
-        # Builtin functions don't have an argspec that we can get.
-        pass
-    elif inspect.ismethod(object) or hasattr(object, 'im_func'):
-        # Get the function from the object otherwise inspect.getargspec()
-        # complains that the object isn't a Python function.
-        object = object.im_func
-    elif inspect.isclass(object):
-        # Get the __init__ method function for the class.
-        constructor = getConstructor(object)
-        if constructor is not None:
-            object = constructor
-    elif callable(object):
-        # Get the __call__ method instead.
-        try:
-            object = object.__call__.im_func
-        except:
-            dropSelf = 0
-    else:
-        dropSelf = 0
-    if hasattr(object, '__name__'):
+    object, dropSelf = getBaseObject(object)
+    try:
         name = object.__name__
         name = object.__name__
+    except AttributeError:
+        pass
     tip1 = ''
     argspec = ''
     if inspect.isbuiltin(object):
     tip1 = ''
     argspec = ''
     if inspect.isbuiltin(object):
@@ -134,8 +145,8 @@ def getCallTip(command='', locals=None):
         # tip1 is a string like: "getCallTip(command='', locals=None)"
         argspec = apply(inspect.formatargspec, inspect.getargspec(object))
         if dropSelf:
         # tip1 is a string like: "getCallTip(command='', locals=None)"
         argspec = apply(inspect.formatargspec, inspect.getargspec(object))
         if dropSelf:
-            # The first parameter to a method is a reference to the
-            # instance, usually coded as "self", and is passed
+            # The first parameter to a method is a reference to an
+            # instance, usually coded as "self", and is usually passed
             # automatically by Python and therefore we want to drop it.
             temp = argspec.split(',')
             if len(temp) == 1:  # No other arguments.
             # automatically by Python and therefore we want to drop it.
             temp = argspec.split(',')
             if len(temp) == 1:  # No other arguments.
@@ -158,34 +169,21 @@ def getCallTip(command='', locals=None):
     calltip = (name, argspec[1:-1], tip.strip())
     return calltip
 
     calltip = (name, argspec[1:-1], tip.strip())
     return calltip
 
-def getConstructor(object):
-    """Return constructor for class object, or None if there isn't one."""
-    try:
-        return object.__init__.im_func
-    except AttributeError:
-        for base in object.__bases__:
-            constructor = getConstructor(base)
-            if constructor is not None:
-                return constructor
-    return None
-
 def getRoot(command, terminator=None):
     """Return the rightmost root portion of an arbitrary Python command.
     
 def getRoot(command, terminator=None):
     """Return the rightmost root portion of an arbitrary Python command.
     
-    The command would normally terminate with a "(" or ".". Anything after 
-    the terminator will be dropped, allowing you to get back to the root.
     Return only the root portion that can be eval()'d without side effects.
     Return only the root portion that can be eval()'d without side effects.
-    """
+    The command would normally terminate with a "(" or ".". The terminator
+    and anything after the terminator will be dropped."""
     root = ''
     validChars = "._" + string.uppercase + string.lowercase + string.digits
     root = ''
     validChars = "._" + string.uppercase + string.lowercase + string.digits
-    if terminator:
-        # Drop the final terminator and anything that follows.
-        pieces = command.split(terminator)
-        if len(pieces) > 1:
-            command = terminator.join(pieces[:-1])
+    emptyTypes = ("''", '""', '""""""', "''''''", '[]', '()', '{}')
+    validSeparators = string.whitespace + ',+-*/=%<>&|^~:([{'
+    # Drop the final terminator and anything that follows.
+    command = rtrimTerminus(command, terminator)
     if len(command) == 0:
         root = ''
     if len(command) == 0:
         root = ''
-    elif command in ("''", '""', '""""""', '[]', '()', '{}'):
+    elif command in emptyTypes and terminator in ('.', '', None):
         # Let empty type delimiter pairs go through.
         root = command
     else:
         # Let empty type delimiter pairs go through.
         root = command
     else:
@@ -193,16 +191,77 @@ def getRoot(command, terminator=None):
         i = len(command)
         while i and command[i-1] in validChars:
             i -= 1
         i = len(command)
         while i and command[i-1] in validChars:
             i -= 1
-        # Detect situations where we are in the middle of a string.
-        # This code catches the simplest case, but needs to catch others.
-        if command[i-1] in ("'", '"'):
-            # We're in the middle of a string so we aren't dealing with an
-            # object and it would be misleading to return anything here.
+        # Default to everything from the "invalid" character to the end.
+        root = command[i:]
+        # Override certain exceptions.
+        if i > 0 and command[i-1] in ("'", '"'):
+            # Detect situations where we are in the middle of a string.
+            # This code catches the simplest case, but needs to catch others.
             root = ''
             root = ''
-        else:
-            # Grab everything from the "invalid" character to the end.
-            root = command[i:]
+        elif ((2 <= i < len(command) and command[i] == '.') \
+           or (2 <= i <= len(command) and terminator in ('.', '', None))) \
+        and command[i-2:i] in emptyTypes:
+            # Allow empty types to get through.
+            # Don't confuse an empty tupple with an argumentless callable.
+            if i == 2 or (i >= 3 and command[i-3] in validSeparators):
+                root = command[i-2:]
     return root
 
     return root
 
+def rtrimTerminus(command, terminator=None):
+    """Return command minus the final terminator and anything that follows."""
+    if terminator:
+        pieces = command.split(terminator)
+        if len(pieces) > 1:
+            command = terminator.join(pieces[:-1])
+    return command
+
+def getBaseObject(object):
+    """Return base object and dropSelf indicator for an object."""
+    if inspect.isbuiltin(object):
+        # Builtin functions don't have an argspec that we can get.
+        dropSelf = 0
+    elif inspect.ismethod(object):
+        # Get the function from the object otherwise inspect.getargspec()
+        # complains that the object isn't a Python function.
+        try:
+            if object.im_self is None:
+                # This is an unbound method so we do not drop self from the
+                # argspec, since an instance must be passed as the first arg.
+                dropSelf = 0
+            else:
+                dropSelf = 1
+            object = object.im_func
+        except AttributeError:
+            dropSelf = 0
+    elif inspect.isclass(object):
+        # Get the __init__ method function for the class.
+        constructor = getConstructor(object)
+        if constructor is not None:
+            object = constructor
+            dropSelf = 1
+        else:
+            dropSelf = 0
+    elif callable(object):
+        # Get the __call__ method instead.
+        try:
+            object = object.__call__.im_func
+            dropSelf = 1
+        except AttributeError:
+            dropSelf = 0
+    else:
+        dropSelf = 0
+    return object, dropSelf
+
+def getConstructor(object):
+    """Return constructor for class object, or None if there isn't one."""
+    try:
+        return object.__init__.im_func
+    except AttributeError:
+        for base in object.__bases__:
+            constructor = getConstructor(base)
+            if constructor is not None:
+                return constructor
+    return None
+
      
  
      
  
index d231dc26474c1eac18163d28fd32aae2a5c7c70f..0483388f69b8c365b79fc3f5b85ee09e7c99c9c5 100644 (file)
@@ -2,7 +2,7 @@
 
 __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
 __cvsid__ = "$Id$"
 
 __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
 __cvsid__ = "$Id$"
-__version__ = "$Revision$"[11:-2]
+__revision__ = "$Revision$"[11:-2]
 
 class PseudoKeyword:
     """A callable class that calls a method passed as a parameter.
 
 class PseudoKeyword:
     """A callable class that calls a method passed as a parameter.
@@ -27,8 +27,10 @@ class PseudoKeyword:
     def __init__(self, method):
         """Create a callable object that executes method when called."""
         
     def __init__(self, method):
         """Create a callable object that executes method when called."""
         
-        # XXX Should probably check that this is a callable object.
-        self.method = method
+        if callable(method):
+            self.method = method
+        else:
+            raise ValueError, 'method must be callable'
         
     def __call__(self, *args, **kwds):
         self.method(*args, **kwds)
         
     def __call__(self, *args, **kwds):
         self.method(*args, **kwds)
@@ -63,7 +65,10 @@ class PseudoFile:
 class PseudoFileIn(PseudoFile):
     
     def __init__(self, readline):
 class PseudoFileIn(PseudoFile):
     
     def __init__(self, readline):
-        self.readline = readline
+        if callable(readline):
+            self.readline = readline
+        else:
+            raise ValueError, 'readline must be callable'
     
     def isatty(self):
         return 1
     
     def isatty(self):
         return 1
@@ -72,7 +77,10 @@ class PseudoFileIn(PseudoFile):
 class PseudoFileOut(PseudoFile):
     
     def __init__(self, write):
 class PseudoFileOut(PseudoFile):
     
     def __init__(self, write):
-        self.write = write
+        if callable(write):
+            self.write = write
+        else:
+            raise ValueError, 'write must be callable'
     
     def isatty(self):
         return 1
     
     def isatty(self):
         return 1
@@ -81,10 +89,13 @@ class PseudoFileOut(PseudoFile):
 class PseudoFileErr(PseudoFile):
 
     def __init__(self, write):
 class PseudoFileErr(PseudoFile):
 
     def __init__(self, write):
-        self.write = write
+        if callable(write):
+            self.write = write
+        else:
+            raise ValueError, 'write must be callable'
         
     def isatty(self):
         return 1
         
         
         
     def isatty(self):
         return 1
         
         
\ No newline at end of file
index 5927c0723b76c307dc3f2594b7d102d8f62aa7b6..3c14698bb82918865f45d28c8a1d7e5eabac12a5 100644 (file)
@@ -6,7 +6,7 @@ Sponsored by Orbtech - Your Source For Python Development Services"""
 
 __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
 __cvsid__ = "$Id$"
 
 __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
 __cvsid__ = "$Id$"
-__version__ = "$Revision$"[11:-2]
+__revision__ = "$Revision$"[11:-2]
 
 from wxPython.wx import *
 from wxPython.stc import *
 
 from wxPython.wx import *
 from wxPython.stc import *
@@ -52,7 +52,7 @@ class ShellFacade:
     still accessible, even though only some are visible to the user."""
 
     name = 'PyCrust Shell Interface'
     still accessible, even though only some are visible to the user."""
 
     name = 'PyCrust Shell Interface'
-    revision = __version__
+    revision = __revision__
 
     def __init__(self, other):
         """Create a ShellFacade instance."""
 
     def __init__(self, other):
         """Create a ShellFacade instance."""
@@ -128,7 +128,7 @@ class Shell(wxStyledTextCtrl):
     """PyCrust Shell based on wxStyledTextCtrl."""
 
     name = 'PyCrust Shell'
     """PyCrust Shell based on wxStyledTextCtrl."""
 
     name = 'PyCrust Shell'
-    revision = __version__
+    revision = __revision__
 
     def __init__(self, parent, id=-1, pos=wxDefaultPosition, \
                  size=wxDefaultSize, style=wxCLIP_CHILDREN, introText='', \
 
     def __init__(self, parent, id=-1, pos=wxDefaultPosition, \
                  size=wxDefaultSize, style=wxCLIP_CHILDREN, introText='', \
@@ -231,18 +231,9 @@ class Shell(wxStyledTextCtrl):
     def setBuiltinKeywords(self):
         """Create pseudo keywords as part of builtins.
 
     def setBuiltinKeywords(self):
         """Create pseudo keywords as part of builtins.
 
-        This is a rather clever hack that sets "close", "exit" and "quit"
-        to a PseudoKeyword object so that we can make them do what we want.
-        In this case what we want is to call our self.quit() method.
-        The user can type "close", "exit" or "quit" without the final parens.
+        This simply sets "close", "exit" and "quit" to a helpful string.
         """
         """
-## POB: This is having some weird side-effects so I'm taking it out.
-##        import __builtin__
-##        from pseudo import PseudoKeyword
-##        __builtin__.close = __builtin__.exit = __builtin__.quit = \
-##            PseudoKeyword(self.quit)
         import __builtin__
         import __builtin__
-        from pseudo import PseudoKeyword
         __builtin__.close = __builtin__.exit = __builtin__.quit = \
             'Click on the close button to leave the application.'
 
         __builtin__.close = __builtin__.exit = __builtin__.quit = \
             'Click on the close button to leave the application.'
 
@@ -322,6 +313,7 @@ class Shell(wxStyledTextCtrl):
             if self.AutoCompActive(): self.AutoCompCancel()
             # Get the command between the prompt and the cursor.
             # Add the '(' to the end of the command.
             if self.AutoCompActive(): self.AutoCompCancel()
             # Get the command between the prompt and the cursor.
             # Add the '(' to the end of the command.
+            self.ReplaceSelection('')
             command = self.GetTextRange(stoppos, currpos) + '('
             self.write('(')
             if self.autoCallTip: self.autoCallTipShow(command)
             command = self.GetTextRange(stoppos, currpos) + '('
             self.write('(')
             if self.autoCallTip: self.autoCallTipShow(command)
@@ -939,21 +931,17 @@ class ShellMenu:
 
         m = self.autocompMenu = wxMenu()
         m.Append(ID_AUTOCOMP_SHOW, 'Show Auto Completion', \
 
         m = self.autocompMenu = wxMenu()
         m.Append(ID_AUTOCOMP_SHOW, 'Show Auto Completion', \
-                 'Show auto completion during dot syntax', \
-                 kind=wxITEM_CHECK)
+                 'Show auto completion during dot syntax', 1)
         m.Append(ID_AUTOCOMP_INCLUDE_MAGIC, 'Include Magic Attributes', \
         m.Append(ID_AUTOCOMP_INCLUDE_MAGIC, 'Include Magic Attributes', \
-                 'Include attributes visible to __getattr__ and __setattr__', \
-                 kind=wxITEM_CHECK)
+                 'Include attributes visible to __getattr__ and __setattr__', 1)
         m.Append(ID_AUTOCOMP_INCLUDE_SINGLE, 'Include Single Underscores', \
         m.Append(ID_AUTOCOMP_INCLUDE_SINGLE, 'Include Single Underscores', \
-                 'Include attibutes prefixed by a single underscore', \
-                 kind=wxITEM_CHECK)
+                 'Include attibutes prefixed by a single underscore', 1)
         m.Append(ID_AUTOCOMP_INCLUDE_DOUBLE, 'Include Double Underscores', \
         m.Append(ID_AUTOCOMP_INCLUDE_DOUBLE, 'Include Double Underscores', \
-                 'Include attibutes prefixed by a double underscore', \
-                 kind=wxITEM_CHECK)
+                 'Include attibutes prefixed by a double underscore', 1)
 
         m = self.calltipsMenu = wxMenu()
         m.Append(ID_CALLTIPS_SHOW, 'Show Call Tips', \
 
         m = self.calltipsMenu = wxMenu()
         m.Append(ID_CALLTIPS_SHOW, 'Show Call Tips', \
-                 'Show call tips with argument specifications', kind=wxITEM_CHECK)
+                 'Show call tips with argument specifications', 1)
 
         m = self.optionsMenu = wxMenu()
         m.AppendMenu(ID_AUTOCOMP, '&Auto Completion', self.autocompMenu, \
 
         m = self.optionsMenu = wxMenu()
         m.AppendMenu(ID_AUTOCOMP, '&Auto Completion', self.autocompMenu, \
@@ -1091,7 +1079,7 @@ class ShellFrame(wxFrame, ShellMenu):
     """Frame containing the PyCrust shell component."""
 
     name = 'PyCrust Shell Frame'
     """Frame containing the PyCrust shell component."""
 
     name = 'PyCrust Shell Frame'
-    revision = __version__
+    revision = __revision__
 
     def __init__(self, parent=None, id=-1, title='PyShell', \
                  pos=wxDefaultPosition, size=wxDefaultSize, \
 
     def __init__(self, parent=None, id=-1, title='PyShell', \
                  pos=wxDefaultPosition, size=wxDefaultSize, \
@@ -1100,7 +1088,7 @@ class ShellFrame(wxFrame, ShellMenu):
         """Create a PyCrust ShellFrame instance."""
         wxFrame.__init__(self, parent, id, title, pos, size, style)
         intro = 'Welcome To PyCrust %s - The Flakiest Python Shell' % VERSION
         """Create a PyCrust ShellFrame instance."""
         wxFrame.__init__(self, parent, id, title, pos, size, style)
         intro = 'Welcome To PyCrust %s - The Flakiest Python Shell' % VERSION
-        intro += '\nSponsored by Orbtech - Your Source For Python Development Services'
+        intro += '\nSponsored by Orbtech - Specializing in Python Application Development'
         self.CreateStatusBar()
         self.SetStatusText(intro.replace('\n', ', '))
         if wxPlatform == '__WXMSW__':
         self.CreateStatusBar()
         self.SetStatusText(intro.replace('\n', ', '))
         if wxPlatform == '__WXMSW__':
index adce0561034677269a874c93adf952762c475fea..ef2b9d7b80d950b75c66de2d2b21142b3f314497 100644 (file)
@@ -4,7 +4,7 @@ interpreter, each have a revision property based on the CVS Revision."""
 
 __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
 __cvsid__ = "$Id$"
 
 __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
 __cvsid__ = "$Id$"
-__version__ = "$Revision$"[11:-2]
+__revision__ = "$Revision$"[11:-2]
 
 
-VERSION = '0.7.1'
+VERSION = '0.7.2'