__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
-__version__ = "$Revision$"[11:-2]
+__revision__ = "$Revision$"[11:-2]
from wxPython.wx import *
-from crust import CrustFrame
+from PyCrust.crust import CrustFrame
class App(wxApp):
"""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.
if __name__ == '__main__':
main()
-
+
__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
-import filling
+from PyCrust import filling
# 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
if __name__ == '__main__':
main()
-
+
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.
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/
-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?
-----------------------------------------------
-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
-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?
__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
"""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', \
"""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, \
"""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__':
__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 *
"""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, \
"""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):
"""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', \
"""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, \
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
-__version__ = "$Revision$"[11:-2]
+__revision__ = "$Revision$"[11:-2]
import os
import sys
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):
sys.ps1 = ps1
sys.ps2 = ps2
-
\ No newline at end of file
+
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
-__version__ = "$Revision$"[11:-2]
+__revision__ = "$Revision$"[11:-2]
import inspect
import string
"""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:
- 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)
- 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 = {}
+ 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
- # 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
- attributes += dict.keys()
+ attributes = dict.keys()
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.
- attributes = [attribute for attribute in attributes if hasattr(object, attribute)]
+ attributes = [attribute for attribute in attributes \
+ if hasattr(object, attribute)]
return attributes
+def hasattrAlwaysReturnsTrue(object):
+ return hasattr(object, 'bogu5_123_aTTri8ute')
+
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.
"""
+ 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.
+ # !!! 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.
- attributes += dir(object)
+ attributes = dir(object)
+ attrdict[(key, 'dir', len(attributes))] = attributes
+ # Get attributes from the object's dictionary, if it has one.
try:
- keys = object.__dict__.keys()
- except:
+ attributes = object.__dict__.keys()
+ attributes.sort()
+ except: # Must catch all because object might have __getattr__.
pass
else:
- attributes += keys
+ attrdict[(key, '__dict__', len(attributes))] = attributes
# 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:
- attributes += getAllAttributeNames(object.__class__)
+ attrdict.update(getAllAttributeNames(klass))
# 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:
- 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:
- attributes += getAllAttributeNames(base)
- return attributes
+ attrdict.update(getAllAttributeNames(base))
+ return attrdict
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."""
-
- calltip = ('', '', '')
+ calltip = ('', '', '') # object name, argspec, tip text.
# 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 = ''
- 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__
+ except AttributeError:
+ pass
tip1 = ''
argspec = ''
if inspect.isbuiltin(object):
# 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.
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.
- 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.
- """
+ 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
- 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 = ''
- elif command in ("''", '""', '""""""', '[]', '()', '{}'):
+ elif command in emptyTypes and terminator in ('.', '', None):
# Let empty type delimiter pairs go through.
root = command
else:
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 = ''
- 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
+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
+
__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.
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)
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
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
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
-
\ No newline at end of file
+
__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 *
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."""
"""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 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__
- from pseudo import PseudoKeyword
__builtin__.close = __builtin__.exit = __builtin__.quit = \
'Click on the close button to leave the application.'
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)
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', \
- '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', \
- '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', \
- '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', \
- '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, \
"""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, \
"""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__':
__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'