Compare commits

..

1 Commits

Author SHA1 Message Date
Bryan Petty
0b2c8aadbb This commit was manufactured by cvs2svn to create tag
'b4_big_updates'.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/tags/b4_big_updates@33056 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2005-03-25 20:34:52 +00:00
34 changed files with 6297 additions and 80 deletions

View File

@@ -1,80 +0,0 @@
dnl
dnl AM_PATH_CPPUNIT(MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
dnl
AC_DEFUN(AM_PATH_CPPUNIT,
[
AC_ARG_WITH(cppunit-prefix,[ --with-cppunit-prefix=PFX Prefix where CppUnit is installed (optional)],
cppunit_config_prefix="$withval", cppunit_config_prefix="")
AC_ARG_WITH(cppunit-exec-prefix,[ --with-cppunit-exec-prefix=PFX Exec prefix where CppUnit is installed (optional)],
cppunit_config_exec_prefix="$withval", cppunit_config_exec_prefix="")
if test x$cppunit_config_exec_prefix != x ; then
cppunit_config_args="$cppunit_config_args --exec-prefix=$cppunit_config_exec_prefix"
if test x${CPPUNIT_CONFIG+set} != xset ; then
CPPUNIT_CONFIG=$cppunit_config_exec_prefix/bin/cppunit-config
fi
fi
if test x$cppunit_config_prefix != x ; then
cppunit_config_args="$cppunit_config_args --prefix=$cppunit_config_prefix"
if test x${CPPUNIT_CONFIG+set} != xset ; then
CPPUNIT_CONFIG=$cppunit_config_prefix/bin/cppunit-config
fi
fi
AC_PATH_PROG(CPPUNIT_CONFIG, cppunit-config, no)
cppunit_version_min=$1
AC_MSG_CHECKING(for Cppunit - version >= $cppunit_version_min)
no_cppunit=""
if test "$CPPUNIT_CONFIG" = "no" ; then
no_cppunit=yes
else
CPPUNIT_CFLAGS=`$CPPUNIT_CONFIG --cflags`
CPPUNIT_LIBS=`$CPPUNIT_CONFIG --libs`
cppunit_version=`$CPPUNIT_CONFIG --version`
cppunit_major_version=`echo $cppunit_version | \
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
cppunit_minor_version=`echo $cppunit_version | \
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
cppunit_micro_version=`echo $cppunit_version | \
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
cppunit_major_min=`echo $cppunit_version_min | \
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
cppunit_minor_min=`echo $cppunit_version_min | \
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
cppunit_micro_min=`echo $cppunit_version_min | \
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
cppunit_version_proper=`expr \
$cppunit_major_version \> $cppunit_major_min \| \
$cppunit_major_version \= $cppunit_major_min \& \
$cppunit_minor_version \> $cppunit_minor_min \| \
$cppunit_major_version \= $cppunit_major_min \& \
$cppunit_minor_version \= $cppunit_minor_min \& \
$cppunit_micro_version \>= $cppunit_micro_min `
if test "$cppunit_version_proper" = "1" ; then
AC_MSG_RESULT([$cppunit_major_version.$cppunit_minor_version.$cppunit_micro_version])
else
AC_MSG_RESULT(no)
no_cppunit=yes
fi
fi
if test "x$no_cppunit" = x ; then
ifelse([$2], , :, [$2])
else
CPPUNIT_CFLAGS=""
CPPUNIT_LIBS=""
ifelse([$3], , :, [$3])
fi
AC_SUBST(CPPUNIT_CFLAGS)
AC_SUBST(CPPUNIT_LIBS)
])

617
wxPython/wx/py/CHANGES.txt Normal file
View File

@@ -0,0 +1,617 @@
0.9.4 (1/25/2004 to //2004)
------------------------------
Removed wxd decorators in favor of new SWIG-generated docstrings.
Removed docs tabs from crust interface:
* wxPython Docs
* wxSTC Docs
Fixed Calltip tab refresh problem on Windows.
shell.autoCompleteAutoHide added with default of False.
Changed default namespace of Shell to __main__.__dict__, instead of an
empty dictionary.
0.9.3 (9/25/2003 to 1/24/2004)
------------------------------
Fun and games with dynamic renaming. Details of any other changes
were lost in the confusion. I'll try to do better in the future.
0.9.2 (5/3/2003 to 9/25/2003)
-----------------------------
Changed to the new prefix-less "wx" package::
import wx
instead of::
from wxPython import wx
Fixed typo in ``PyWrap.py``::
if __name__ == '__main__':
main(sys.argv)
should have been::
if __name__ == '__main__':
main()
Added pretty-print Display tab to Crust, based on suggestion from
Jason Whitlark.
Improved ``Can*`` checks in ``EditWindow``, since STC is too lenient,
particularly when it is set to read-only but returns True for
CanPaste() (seems like an STC bug to me)::
def CanCopy(self):
"""Return True if text is selected and can be copied."""
return self.GetSelectionStart() != self.GetSelectionEnd()
def CanCut(self):
"""Return True if text is selected and can be cut."""
return self.CanCopy() and self.CanEdit()
def CanEdit(self):
"""Return True if editing should succeed."""
return not self.GetReadOnly()
def CanPaste(self):
"""Return True if pasting should succeed."""
return stc.StyledTextCtrl.CanPaste(self) and self.CanEdit()
0.9.1 (3/21/2003 to 5/2/2003)
-----------------------------
PyCrust is dead! Long live Py!
* Renamed ``PyCrust`` package to ``py``.
* Moved code to wxPython's CVS repository.
Fixed bug in ``introspect.py`` on introspecting objects occurring
immediately after a secondary prompt, like this::
>>> l = [1, 2, 3]
>>> for n in range(3):
... l. <-- failed to popup autocomplete list
Added documentation files:
* PyManual.txt
* wxPythonManual.txt
* wxPythonPackage.txt
* wxPythonExamples.txt
Added PyAlaMode and PyAlaCarte code editors.
Major refactoring to support ``editor`` and ``shell`` from the same
base.
Renamed program files:
* ``PyCrustApp.py`` to ``PyCrust.py``
* ``PyFillingApp.py`` to ``PyFilling.py``
* ``PyShellApp.py`` to ``PyShell.py``
* ``wrap.py`` to ``PyWrap.py``
Removed disabling of autocomplete for lists of 2000 items or more.
The current implementation of wxSTC can now handle lists this big.
Improved handling of ``sys.path`` to mimic the standard Python shell.
0.9 (2/27/2003 to 3/20/2003)
----------------------------
Added fontIncrease, fontDecrease, fontDefault signals, receivers and
keybindings::
Ctrl+] Increase font size.
Ctrl+[ Decrease font size.
Ctrl+= Default font size.
Continued enhancement of the decorator capability to provide better
documentation and docstrings for wxPython classes and functions.
Introduced new tabbed interface:
* Namespace
* Calltip
* Session
* Dispatcher
* wxPython Docs
* wxSTC Docs
``Filling.tree`` now expands tuples as well as lists. (It should have
done this all along, I just never noticed this omission before.)
Added this True/False test to all modules::
try:
True
except NameError:
True = 1==1
False = 1==0
Added ``wxd`` directory with decoration classes.
0.8.2 (1/5/2003 to 2/26/2003)
-----------------------------
Wrapped ``sys.ps1``, ``sys.ps2``, and ``sys.ps3`` in ``str()``.
(Thanks, Kieran Holland.)
Fixed minor things found by PyChecker.
Changed locals to use ``__main__.__dict__`` and added code to clean up
the namespace, making it as close to the regular Python environment as
possible. This solves the problem of pickling and unpickling
instances of classes defined in the shell.
Made ``shell.PasteAndRun()`` a little more forgiving when it finds a
ps2 prompt line with no trailing space, such when you copy code from a
web page.
Improved autocomplete behavior by adding these to shell::
self.AutoCompSetAutoHide(False)
self.AutoCompStops(' .,;:([)]}\'"\\<>%^&+-=*/|`')
Added ``decor`` directory, ``decorator.py``, ``stcDecor.py``, and
``stcConstants.py``. These all serve the purpose of adding docstrings
to existing wxPython classes, in particular the ``wxStyledTextCtrl``.
Added ``wrap.py``, a command line utility for running a wxPython app
with additional runtime-tools loaded, such as PyCrust (the only tool
at this point).
Flushed the clipboard Cut/Copy operations so that selections will
exist in the clipboard even after PyCrust has been closed.
Improved the suppression of docstrings for simple data types appearing
in the namespace viewer.
Better handling of autocompletion with numeric types; no
autocompletion when typing a dot after an integer. If the
autocompletion is desired, type a space before the dot::
func = 3 .
More Filling!!! The namespace tree is now dynamically updated.
0.8.1 (12/20/2002 to 12/25/2002)
--------------------------------
Improved keyboard handling with Autocomplete active. You can now use
Enter as well as Tab to select an item from the list.
Disabled autocomplete for lists of 2000 items or more. The current
implementation of wxSTC can't handle lists this big.
Changed ``filling`` to always display docstrings for objects. This is
useful for objects whose docstrings have been decorated, rather than
coming directly from the source code. (Hmmm. Sounds like someone is
doing some decorating. I wonder where that would be helpful? <wink>)
Fixed handling of icon. Added ``images.py`` file.
0.8 (10/29/2002 to 12/16/2002)
------------------------------
Added "help" to startup banner info.
Made all ``wx`` and ``stc`` imports explicit. No more ``import *``.
Replaced use of the ``wx`` module's ``true`` and ``false`` with
Python's ``True`` and ``False``.
Changed ``introspect.getRoot()`` to use ``tokenize`` module. This
does a slightly better job than the previous parsing routine and the
code is clearer.
Improved handling of whitespace and empty types during introspection.
Fixed cut/copy clipboard problem under Linux. (Robin Dunn rocks!!!)
Added shell.about() which works like this::
>>> shell.about()
PyCrust Version: 0.8
Shell Revision: 1.80
Interpreter Revision: 1.15
Python Version: 2.2.2
wxPython Version: 2.3.3.1
Platform: linux2
Added copy plus and paste plus to shell menu.
Moved shell menu from ``shell.py`` to ``shellmenu.py``.
Added ``sys.stdin.readlines()`` support.
Added ``time.sleep()`` in ``readline()`` and ``OnIdle()`` event
handler to free up the CPU.
0.7.2 (2/22/2002 to 8/27/2002)
------------------------------
Tweaked ``getAttributeNames()`` to pick up a few more attributes::
'__bases__', '__class__', '__dict__', '__name__', 'func_closure',
'func_code', 'func_defaults', 'func_dict', 'func_doc',
'func_globals', 'func_name'
Added a tests directory and unit tests.
Improved support for empty types in the shell: ``[]``, ``()`` and
``{}`` as far as when call tips and autocompletion are available.
Added support for the other triple string - ``''''''``.
Refactored ``introspect.py`` to improve testability.
Improved call tips for unbound methods by leaving the "self"
parameter, since unbound methods require an instance be passed.
Fixed call tip bug where a tip was displayed when a "(" was typed
after an object that wasn't callable.
Fixed ``getAllAttributeNames`` when ``str(object)`` fails.
Added brace highlighting. (Thank you, Kevin Altis.)
Fixed problem displaying unicode objects in ``PyFilling``.
Changed how ``filling.py`` checks for expandable objects. Lists are
now expandable objects.
Made the key handling more robust when there is an active text
selection that includes text prior to the last primary prompt. Thanks
to Raul Cota for pointing this out.
Fixed wxSTC problem with brace highlighting and non-us keyboards.
(Thank you for the patch, Jean-Michel Fauth.)
Added ``busy = wxBusyCursor()`` to key points in ``shell`` and
``filling``.
Added ``OnCloseWindow`` handler to ``ShellFrame`` and ``CrustFrame``.
Default to ``SetWrapMode(1)`` for shell and namespace viewer.
Added ``shell.wrap()`` and ``shell.zoom()``.
Added autoCompleteKeys hooks for Raul Cota.
Cleaned up various little key handling bugs.
Changed input methods to get values from shell, rather than dialog
boxes. Renamed ``readIn`` to ``readline`` and ``readRaw`` to
``raw_input``.
0.7.1 (12/12/2001 to 2/21/2002)
-------------------------------
Fixed ``OnChar()`` issues effecting European keyboards, as reported by
Jean-Michel Fauth.
Fixed ``introspect.py`` issue with xmlrpc objects reported by Kevin
Altis.
Fixed some introspect/PyFilling issues with regard to Python 2.2.
Fixed font background color as reported by Keith J. Farmer. (Thanks)
Fixed problem with call tips and autocompletion inside multiline
commands as report by Kevin Altis.
Improved ``OnKeyDown`` handling of cut/copy/paste operations based on
feedback from Syver Enstad. (Thanks)
Added a ``shell.help()`` method to display some help info.
Changed sort of items in the namespace viewer to case insensitive.
Changed ``attributes.sort(lambda x, y: cmp(x.upper(), y.upper()))`` in
advance of an upcoming fix to an autocompletion matching bug in wxSTC.
Improved support for ZODB by allowing namespace drilldown into BTrees.
Added ``shell.PasteAndRun()`` to support pasting multiple commands into
the shell from the clipboard. Ctrl+Shift+V or v.
Enter now always processes a command (or copies down a previous one.)
To insert a line break, press Ctrl+Enter.
Escape key clears the current, unexecuted command.
History retrieval changed to replace current command. Added new keys
to insert from history - Shift+Up and Shift+Down.
Better call tips on objects with ``__call__`` methods.
Improved call tip positioning calculation.
0.7 (10/15/2001 to 12/11/2001)
------------------------------
Changed how command history retrieval functions work. Added Alt-P,
Alt-N as keybindings for Retrieve-Previous, Retrieve-Next.
Added full support for multi-line commands, similar to IDLE.
Changed ``introspect.getAttributeNames()`` to do a case insensitive
sort.
Changed Cut/Copy/Paste to deal with prompts intelligently. Cut and
Copy remove all prompts. Paste can handle prompted or not-prompted
text.
Added ``CopyWithPrompts()`` method attached to Ctrl-Shift-C for those
times when you really do want all the prompts left intact.
Improved handling of the shell's read-only zone.
Changed ``CrustFrame.__init__`` parameter spec to include all
parameters allowed by a ``wxFrame``.
Changed ``FillingText`` to be read-only.
Renamed ``PyCrust.py`` to ``PyCrustApp.py`` to eliminate
package/module name conflicts that kept you from doing ``from PyCrust
import shell`` inside files located in the ``PyCrust`` directory.
Renamed ``PyFilling.py`` to ``PyFillingApp.py`` and ``PyShell.py`` to
``PyShellApp.py`` to maintain consistency.
Removed the ``__date__`` property from all modules.
Fixed bug in ``introspect.getCallTip()``, reported by Kevin Altis.
0.6.1 (9/19/2001 to 10/12/2001)
-------------------------------
Changed ``Shell.run()`` to always position to the end of existing
text, as suggested by Raul Cota.
Changed ``introspect.getAllAttributeNames()`` to break circular
references in ``object.__class__``, which occurs in Zope/ZODB
extension classes.
Changed ``filling.FillingTree.getChildren()`` to introspect extension
classes.
Fixed minor bugs in ``introspect.getCallTip()`` that were interfering
with call tips for Zope/ZODB extension class methods.
In preparation for wxPython 2.3.2, added code to fix a font sizing
problem. Versions of wxPython prior to 2.3.2 had a sizing bug on Win
platform where the font was 2 points larger than what was specified.
Added a hack to ``introspect.getAllAttributeNames()`` to "wake up"
ZODB objects that are asleep - in a "ghost" state. Otherwise it
returns incomplete info.
0.6 (8/21/2001 to 9/12/2001)
----------------------------
Added ``PyFilling.py`` and ``filling.py``.
``PyShell.py`` and ``PyFilling.py`` can now be run standalone, as well
as ``PyCrust.py``.
Added ``crust.py`` and moved some code from ``PyCrust.py`` to it.
Added command history retrieval features submitted by Richie Hindle.
Changed ``shell.write()`` to replace line endings with OS-specific
endings. Changed ``shell.py`` and ``interpreter.py`` to use
``os.linesep`` in strings having hardcoded line endings.
Added ``shell.redirectStdin()``, ``shell.redirectStdout()`` and
``shell.redirectStderr()`` to allow the surrounding app to toggle
requests that the specified ``sys.std*`` be redirected to the shell.
These can also be run from within the shell itself, of course.
The shell now adds the current working directory "." to the search
path::
sys.path.insert(0, os.curdir)
Added support for distutils installations.
0.5.4 (8/17/2001 to 8/20/2001)
------------------------------
Changed default font size under Linux to::
'size' : 12,
'lnsize' : 10,
Changed ``Shell`` to expect a parameter referencing an Interpreter
class, rather than an intepreter instance, to facilitate subclassing
of Interpreter, which effectively broke when the Editor class was
eliminated.
Fixed ``PyCrustAlaCarte.py``, which had been broken by previous
changes.
Created ``InterpreterAlaCarte`` class as an example for use in the
demo.
Split ``PyCrust.py`` into ``PyCrust.py`` and ``PyShell.py`` in
anticipation of ``PyFilling.py``.
0.5.3 (8/16/2001)
-----------------
Added patch to ``PyCrust.py`` to fix wxPython bug::
wxID_SELECTALL = NewId() # This *should* be defined by wxPython.
0.5.2 (8/14/2001 to 8/15/2001)
------------------------------
Shortened module names by dropping "PyCrust" as a prefix.
Changed ``version`` to ``VERSION`` in ``version`` module.
Added Options menu to PyCrust application.
Eliminated the Editor class (and editor module) by merging with Shell.
This means that Shell "is a" wxStyledTextCtrl rather than "has a".
There just wasn't enough non-gui code to justify the separation.
Plus, Shell will be much easier for gui toolkits/designers to deal
with now.
0.5.1 (8/10/2001 to 8/14/2001)
------------------------------
Added ``introspect`` module.
Moved some functionality from ``PyCrustInterp`` to ``introspect``.
Changed ``introspect.getRoot()`` to no longer remove whitespace from
the command. This was a remnant of a previous approach that, when
left as part of the current approach, turned out to be a really bad
thing.
Changed ``introspect.getRoot()`` to allow commands of ``''``, ``""``,
``""""""``, ``[]``, ``()``, and ``{}`` to pass through. This allows
you to type them, followed by a dot, and get autocomplete options on
them.
Changed ``introspect.getRoot()`` to identify some situations where
strings shouldn't be considered roots. For example::
>>> import PyCrust # To illustrate the potential problem.
>>> len('PyCrust.py')
Typing the dot at the end of "PyCrust" in the second line above should
NOT result in an autocompletion list because "PyCrust" is part of a
string in this context, not a reference to the PyCrust module object.
Similar reasoning applies to call tips. For example::
>>> len('dir(')
Typing the left paren at the end of "dir" should NOT result in a call
tip.
Both features now behave properly in the examples given. However,
there is still the case where whitespace precedes the potential root
and that is NOT handled properly. For example::
>>> len('this is a dir(')
and::
>>> len('This is PyCrust.py')
More code needs to be written to handle more complex situations.
Added ``locals=None`` parameter to ``Shell.__init__()``.
Added support for magic attribute retrieval. Users can change this
with::
>>> shell.editor.autoCompleteIncludeMagic = 0
Added the ability to set filters on auto completion to exclude
attributes prefixed with a single or double underscore. Users can
exclude one or the other or both with::
>>> shell.editor.autoCompleteExcludeSingle = 1
>>> shell.editor.autoCompleteExcludeDouble = 1
0.5 (8/8/2001)
--------------
Mostly just a final version change before creating a release.
0.4 (8/4/2001 to 8/7/2001)
--------------------------
Changed version/revision handling.
Fixed bugs.
0.3 (8/2/2001 to 8/3/2001)
--------------------------
Removed lots of cruft.
Added lots of docstrings.
Imported to CVS repository at SourceForge.
Added call tips.
0.2 (7/30/2001 to 8/2/2001)
---------------------------
Renamed several files.
Added command autocompletion.
Added menus to PyCrust.py: File, Edit and Help.
Added sample applications: ``PyCrustAlaCarte.py``,
``PyCrustAlaMode.py``, and ``PyCrustMinimus.py``.
0.1 (7/1/2001 to 7/19/2001)
---------------------------
Added basic syntax coloring much like Boa.
Added read-only logging much like IDLE.
Can retrieve a previous command by putting the cursor back on that
line and hitting enter.
Stdin and raw_input operate properly so you can now do ``help()`` and
``license()`` without hanging.
Redefined "quit", "exit", and "close" to display a better-than-nothing
response.
Home key honors the prompt.
Created SourceForge account, but nothing was posted.
In the beginning, there was pie... (7/1/2001)
---------------------------------------------
Blame it all on IDLE, Boa and PythonWin. I was using all three, got
frustrated with their dissimilarities, and began to let everyone know
how I felt. At the same time, Scintilla looked like an interesting
tool to build a shell around. And while I didn't receive much in the
way of positive feedback, let alone encouragement, I just couldn't let
go of the idea of a Scintilla-based Python shell. Then the PythonCard
project got to the point where they were talking about including a
shell in their development environment. That was all the incentive I
needed. PyCrust had to happen...

BIN
wxPython/wx/py/Py.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@@ -0,0 +1,36 @@
"""PyAlaCarte is a simple programmer's editor."""
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
import wx
from wx import py
import os
import sys
class App(wx.App):
"""PyAlaCarte standalone application."""
def __init__(self, filename=None):
self.filename = filename
wx.App.__init__(self, redirect=False)
def OnInit(self):
wx.InitAllImageHandlers()
self.frame = py.editor.EditorFrame(filename=self.filename)
self.frame.Show()
self.SetTopWindow(self.frame)
return True
def main(filename=None):
if not filename and len(sys.argv) > 1:
filename = sys.argv[1]
if filename:
filename = os.path.realpath(filename)
app = App(filename)
app.MainLoop()
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,36 @@
"""PyAlaMode is a programmer's editor."""
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
import wx
from wx import py
import os
import sys
class App(wx.App):
"""PyAlaMode standalone application."""
def __init__(self, filename=None):
self.filename = filename
wx.App.__init__(self, redirect=False)
def OnInit(self):
wx.InitAllImageHandlers()
self.frame = py.editor.EditorNotebookFrame(filename=self.filename)
self.frame.Show()
self.SetTopWindow(self.frame)
return True
def main(filename=None):
if not filename and len(sys.argv) > 1:
filename = sys.argv[1]
if filename:
filename = os.path.realpath(filename)
app = App(filename)
app.MainLoop()
if __name__ == '__main__':
main()

35
wxPython/wx/py/PyAlaModeTest.py Executable file
View File

@@ -0,0 +1,35 @@
"""PyAlaModeTest is a programmer's editor."""
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
import wx
from wx import py
import os
import sys
class App(wx.App):
"""PyAlaModeTest standalone application."""
def __init__(self, filename=None):
self.filename = filename
wx.App.__init__(self, redirect=False)
def OnInit(self):
wx.InitAllImageHandlers()
self.frame = py.editor.EditorShellNotebookFrame(filename=self.filename)
self.frame.Show()
self.SetTopWindow(self.frame)
return True
def main(filename=None):
app = App(filename)
app.MainLoop()
if __name__ == '__main__':
filename = None
if len(sys.argv) > 1:
filename = os.path.realpath(sys.argv[1])
main(filename)

BIN
wxPython/wx/py/PyCrust.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

70
wxPython/wx/py/PyCrust.py Normal file
View File

@@ -0,0 +1,70 @@
"""PyCrust is a python shell and namespace browser application."""
# The next two lines, and the other code below that makes use of
# ``__main__`` and ``original``, serve the purpose of cleaning up the
# main namespace to look as much as possible like the regular Python
# shell environment.
import __main__
original = __main__.__dict__.keys()
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
import wx
class App(wx.App):
"""PyCrust standalone application."""
def OnInit(self):
import wx
from wx import py
wx.InitAllImageHandlers()
self.frame = py.crust.CrustFrame()
self.frame.SetSize((800, 600))
self.frame.Show()
self.SetTopWindow(self.frame)
return True
'''
The main() function needs to handle being imported, such as with the
pycrust script that wxPython installs:
#!/usr/bin/env python
from wx.py.PyCrust import main
main()
'''
def main():
"""The main function for the PyCrust program."""
# Cleanup the main namespace, leaving the App class.
import __main__
md = __main__.__dict__
keepers = original
keepers.append('App')
for key in md.keys():
if key not in keepers:
del md[key]
# Create an application instance.
app = App(0)
# Mimic the contents of the standard Python shell's sys.path.
import sys
if sys.path[0]:
sys.path[0] = ''
# Add the application object to the sys module's namespace.
# This allows a shell user to do:
# >>> import sys
# >>> sys.app.whatever
sys.app = app
del sys
# Cleanup the main namespace some more.
if md.has_key('App') and md['App'] is App:
del md['App']
if md.has_key('__main__') and md['__main__'] is __main__:
del md['__main__']
# Start the wxPython event loop.
app.MainLoop()
if __name__ == '__main__':
main()

Binary file not shown.

After

Width:  |  Height:  |  Size: 706 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,35 @@
"""PyFilling is a python namespace inspection application."""
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
# We use this object to get more introspection when run standalone.
app = None
import filling
# These are imported just to have something interesting to inspect.
import crust
import interpreter
import introspect
import pseudo
import shell
import sys
import wx
class App(filling.App):
def OnInit(self):
filling.App.OnInit(self)
self.root = self.fillingFrame.filling.tree.root
return True
def main():
"""Create and run the application."""
global app
app = App(0)
app.fillingFrame.filling.tree.Expand(app.root)
app.MainLoop()
if __name__ == '__main__':
main()

71
wxPython/wx/py/PyShell.py Normal file
View File

@@ -0,0 +1,71 @@
"""PyShell is a python shell application."""
# The next two lines, and the other code below that makes use of
# ``__main__`` and ``original``, serve the purpose of cleaning up the
# main namespace to look as much as possible like the regular Python
# shell environment.
import __main__
original = __main__.__dict__.keys()
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
import wx
class App(wx.App):
"""PyShell standalone application."""
def OnInit(self):
import wx
from wx import py
wx.InitAllImageHandlers()
self.frame = py.shell.ShellFrame()
self.frame.SetSize((750, 525))
self.frame.Show()
self.SetTopWindow(self.frame)
self.frame.shell.SetFocus()
return True
'''
The main() function needs to handle being imported, such as with the
pyshell script that wxPython installs:
#!/usr/bin/env python
from wx.py.PyShell import main
main()
'''
def main():
"""The main function for the PyShell program."""
# Cleanup the main namespace, leaving the App class.
import __main__
md = __main__.__dict__
keepers = original
keepers.append('App')
for key in md.keys():
if key not in keepers:
del md[key]
# Create an application instance.
app = App(0)
# Cleanup the main namespace some more.
if md.has_key('App') and md['App'] is App:
del md['App']
if md.has_key('__main__') and md['__main__'] is __main__:
del md['__main__']
# Mimic the contents of the standard Python shell's sys.path.
import sys
if sys.path[0]:
sys.path[0] = ''
# Add the application object to the sys module's namespace.
# This allows a shell user to do:
# >>> import sys
# >>> sys.app.whatever
sys.app = app
del sys
# Start the wxPython event loop.
app.MainLoop()
if __name__ == '__main__':
main()

48
wxPython/wx/py/PyWrap.py Normal file
View File

@@ -0,0 +1,48 @@
"""PyWrap is a command line utility that runs a wxPython program with
additional runtime-tools, such as PyCrust."""
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
import wx
from wx import py
import os
import sys
def wrap(app):
wx.InitAllImageHandlers()
frame = py.crust.CrustFrame()
frame.SetSize((750, 525))
frame.Show(True)
frame.shell.interp.locals['app'] = app
app.MainLoop()
def main(modulename=None):
sys.path.insert(0, os.curdir)
if not modulename:
if len(sys.argv) < 2:
print "Please specify a module name."
raise SystemExit
modulename = sys.argv[1]
if modulename.endswith('.py'):
modulename = modulename[:-3]
module = __import__(modulename)
# Find the App class.
App = None
d = module.__dict__
for item in d.keys():
try:
if issubclass(d[item], wx.App):
App = d[item]
except (NameError, TypeError):
pass
if App is None:
print "No App class was found."
raise SystemExit
app = App()
wrap(app)
if __name__ == '__main__':
main()

83
wxPython/wx/py/README.txt Normal file
View File

@@ -0,0 +1,83 @@
=====================================
PyCrust - The Flakiest Python Shell
=====================================
Half-baked by Patrick K. O'Brien (pobrien@orbtech.com)
Orbtech - "Your source for Python programming expertise."
Sample all our half-baked Python goods at www.orbtech.com.
What is PyCrust?
----------------
PyCrust is an interactive Python environment written in Python.
PyCrust components can run standalone or be integrated into other
development environments and/or other Python applications.
PyCrust comes with an interactive Python shell (PyShell), an
interactive namespace/object tree control (PyFilling) and an
integrated, split-window combination of the two (PyCrust).
What is PyCrust good for?
-------------------------
Have you ever tried to bake a pie without one? Well, you shouldn't
build a Python program without a PyCrust either.
What else do I need to use PyCrust?
-----------------------------------
PyCrust requires Python 2.2 or later, and wxPython 2.4 or later.
PyCrust uses wxPython and the Scintilla wrapper (wxStyledTextCtrl).
Python is available at http://www.python.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 the wxWindows CVS at:
http://cvs.wxwindows.org/viewcvs.cgi/
Where is the PyCrust project hosted?
------------------------------------
The old answer was "At SourceForge, of course." The SourceForge
summary page is still available at:
http://sourceforge.net/projects/pycrust/
The new answer is that there is no longer a need for a separate
project. Simply install wxPython and you'll have everything you need.
I found a bug in PyCrust, what do I do with it?
-----------------------------------------------
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 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?
-------------------------------------------------
$Date$
$Revision$
$Id$

View File

@@ -0,0 +1,20 @@
"""The py package, formerly the PyCrust package."""
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
import buffer
import crust
import dispatcher
import document
import editor
import editwindow
import filling
import frame
import images
import interpreter
import introspect
import pseudo
import shell
import version

138
wxPython/wx/py/buffer.py Normal file
View File

@@ -0,0 +1,138 @@
"""Buffer class."""
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
from interpreter import Interpreter
import imp
import os
import sys
import document
class Buffer:
"""Buffer class."""
id = 0
def __init__(self, filename=None):
"""Create a Buffer instance."""
Buffer.id += 1
self.id = Buffer.id
self.interp = Interpreter(locals={})
self.name = ''
self.editors = {}
self.editor = None
self.modules = sys.modules.keys()
self.syspath = sys.path[:]
while True:
try:
self.syspath.remove('')
except ValueError:
break
while True:
try:
self.syspath.remove('.')
except ValueError:
break
self.open(filename)
def addEditor(self, editor):
"""Add an editor."""
self.editor = editor
self.editors[editor.id] = editor
def hasChanged(self):
"""Return True if text in editor has changed since last save."""
if self.editor:
return self.editor.hasChanged()
else:
return False
def new(self, filepath):
"""New empty buffer."""
if not filepath:
return
if os.path.exists(filepath):
self.confirmed = self.overwriteConfirm(filepath)
else:
self.confirmed = True
def open(self, filename):
"""Open file into buffer."""
self.doc = document.Document(filename)
self.name = self.doc.filename or ('Untitled:' + str(self.id))
self.modulename = self.doc.filebase
# XXX This should really make sure filedir is first item in syspath.
# XXX Or maybe this should be moved to the update namespace method.
if self.doc.filedir and self.doc.filedir not in self.syspath:
# To create the proper context for updateNamespace.
self.syspath.insert(0, self.doc.filedir)
if self.doc.filepath and os.path.exists(self.doc.filepath):
self.confirmed = True
if self.editor:
text = self.doc.read()
self.editor._setBuffer(buffer=self, text=text)
def overwriteConfirm(filepath):
"""Confirm overwriting an existing file."""
return False
def save(self):
"""Save buffer."""
filepath = self.doc.filepath
if not filepath:
return # XXX Get filename
if not os.path.exists(filepath):
self.confirmed = True
if not self.confirmed:
self.confirmed = self.overwriteConfirm(filepath)
if self.confirmed:
self.doc.write(self.editor.getText())
if self.editor:
self.editor.setSavePoint()
def saveAs(self, filename):
"""Save buffer."""
self.doc = document.Document(filename)
self.name = self.doc.filename
self.modulename = self.doc.filebase
self.save()
def updateNamespace(self):
"""Update the namespace for autocompletion and calltips.
Return True if updated, False if there was an error."""
if not self.interp or not hasattr(self.editor, 'getText'):
return False
syspath = sys.path
sys.path = self.syspath
text = self.editor.getText()
text = text.replace('\r\n', '\n')
text = text.replace('\r', '\n')
name = self.modulename or self.name
module = imp.new_module(name)
newspace = module.__dict__.copy()
try:
try:
code = compile(text, name, 'exec')
except:
raise
# return False
try:
exec code in newspace
except:
raise
# return False
else:
# No problems, so update the namespace.
self.interp.locals.clear()
self.interp.locals.update(newspace)
return True
finally:
sys.path = syspath
for m in sys.modules.keys():
if m not in self.modules:
del sys.modules[m]

218
wxPython/wx/py/crust.py Normal file
View File

@@ -0,0 +1,218 @@
"""Crust combines the shell and filling into one control."""
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
import wx
import os
import pprint
import sys
import dispatcher
import editwindow
from filling import Filling
import frame
from shell import Shell
from version import VERSION
class Crust(wx.SplitterWindow):
"""Crust based on SplitterWindow."""
name = 'Crust'
revision = __revision__
def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.SP_3D,
name='Crust Window', rootObject=None, rootLabel=None,
rootIsNamespace=True, intro='', locals=None,
InterpClass=None, *args, **kwds):
"""Create Crust instance."""
wx.SplitterWindow.__init__(self, parent, id, pos, size, style, name)
self.shell = Shell(parent=self, introText=intro,
locals=locals, InterpClass=InterpClass,
*args, **kwds)
self.editor = self.shell
if rootObject is None:
rootObject = self.shell.interp.locals
self.notebook = wx.Notebook(parent=self, id=-1)
self.shell.interp.locals['notebook'] = self.notebook
self.filling = Filling(parent=self.notebook,
rootObject=rootObject,
rootLabel=rootLabel,
rootIsNamespace=rootIsNamespace)
# Add 'filling' to the interpreter's locals.
self.shell.interp.locals['filling'] = self.filling
self.notebook.AddPage(page=self.filling, text='Namespace', select=True)
self.display = Display(parent=self.notebook)
self.notebook.AddPage(page=self.display, text='Display')
# Add 'pp' (pretty print) to the interpreter's locals.
self.shell.interp.locals['pp'] = self.display.setItem
self.calltip = Calltip(parent=self.notebook)
self.notebook.AddPage(page=self.calltip, text='Calltip')
self.sessionlisting = SessionListing(parent=self.notebook)
self.notebook.AddPage(page=self.sessionlisting, text='Session')
self.dispatcherlisting = DispatcherListing(parent=self.notebook)
self.notebook.AddPage(page=self.dispatcherlisting, text='Dispatcher')
## from wxd import wx_
## self.wxdocs = Filling(parent=self.notebook,
## rootObject=wx_,
## rootLabel='wx',
## rootIsNamespace=False,
## static=True)
## self.notebook.AddPage(page=self.wxdocs, text='wxPython Docs')
## from wxd import stc_
## self.stcdocs = Filling(parent=self.notebook,
## rootObject=stc_.StyledTextCtrl,
## rootLabel='StyledTextCtrl',
## rootIsNamespace=False,
## static=True)
## self.notebook.AddPage(page=self.stcdocs, text='StyledTextCtrl Docs')
self.SplitHorizontally(self.shell, self.notebook, 300)
self.SetMinimumPaneSize(1)
class Display(editwindow.EditWindow):
"""STC used to display an object using Pretty Print."""
def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
size=wx.DefaultSize,
style=wx.CLIP_CHILDREN | wx.SUNKEN_BORDER,
static=False):
"""Create Display instance."""
editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
# Configure various defaults and user preferences.
self.SetReadOnly(True)
self.SetWrapMode(False)
if not static:
dispatcher.connect(receiver=self.push, signal='Interpreter.push')
def push(self, command, more):
"""Receiver for Interpreter.push signal."""
self.Refresh()
def Refresh(self):
if not hasattr(self, "item"):
return
self.SetReadOnly(False)
text = pprint.pformat(self.item)
self.SetText(text)
self.SetReadOnly(True)
def setItem(self, item):
"""Set item to pretty print in the notebook Display tab."""
self.item = item
self.Refresh()
class Calltip(wx.TextCtrl):
"""Text control containing the most recent shell calltip."""
def __init__(self, parent=None, id=-1):
style = (wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_RICH2)
wx.TextCtrl.__init__(self, parent, id, style=style)
self.SetBackgroundColour(wx.Colour(255, 255, 232))
dispatcher.connect(receiver=self.display, signal='Shell.calltip')
def display(self, calltip):
"""Receiver for Shell.calltip signal."""
## self.SetValue(calltip) # Caused refresh problem on Windows.
self.Clear()
self.AppendText(calltip)
class SessionListing(wx.TextCtrl):
"""Text control containing all commands for session."""
def __init__(self, parent=None, id=-1):
style = (wx.TE_MULTILINE | wx.TE_READONLY |
wx.TE_RICH2 | wx.TE_DONTWRAP)
wx.TextCtrl.__init__(self, parent, id, style=style)
dispatcher.connect(receiver=self.push, signal='Interpreter.push')
def push(self, command, more):
"""Receiver for Interpreter.push signal."""
if command and not more:
self.SetInsertionPointEnd()
start, end = self.GetSelection()
if start != end:
self.SetSelection(0, 0)
self.AppendText(command + '\n')
class DispatcherListing(wx.TextCtrl):
"""Text control containing all dispatches for session."""
def __init__(self, parent=None, id=-1):
style = (wx.TE_MULTILINE | wx.TE_READONLY |
wx.TE_RICH2 | wx.TE_DONTWRAP)
wx.TextCtrl.__init__(self, parent, id, style=style)
dispatcher.connect(receiver=self.spy)
def spy(self, signal, sender):
"""Receiver for Any signal from Any sender."""
text = '%r from %s' % (signal, sender)
self.SetInsertionPointEnd()
start, end = self.GetSelection()
if start != end:
self.SetSelection(0, 0)
self.AppendText(text + '\n')
class CrustFrame(frame.Frame):
"""Frame containing all the PyCrust components."""
name = 'CrustFrame'
revision = __revision__
def __init__(self, parent=None, id=-1, title='PyCrust',
pos=wx.DefaultPosition, size=wx.DefaultSize,
style=wx.DEFAULT_FRAME_STYLE,
rootObject=None, rootLabel=None, rootIsNamespace=True,
locals=None, InterpClass=None, *args, **kwds):
"""Create CrustFrame instance."""
frame.Frame.__init__(self, parent, id, title, pos, size, style)
intro = 'PyCrust %s - The Flakiest Python Shell' % VERSION
intro += '\nSponsored by Orbtech - '
intro += 'Your source for Python programming expertise.'
self.SetStatusText(intro.replace('\n', ', '))
self.crust = Crust(parent=self, intro=intro,
rootObject=rootObject,
rootLabel=rootLabel,
rootIsNamespace=rootIsNamespace,
locals=locals,
InterpClass=InterpClass, *args, **kwds)
self.shell = self.crust.shell
# Override the filling so that status messages go to the status bar.
self.crust.filling.tree.setStatusText = self.SetStatusText
# Override the shell so that status messages go to the status bar.
self.shell.setStatusText = self.SetStatusText
# Fix a problem with the sash shrinking to nothing.
self.crust.filling.SetSashPosition(200)
# Set focus to the shell editor.
self.shell.SetFocus()
def OnClose(self, event):
"""Event handler for closing."""
self.crust.shell.destroy()
self.Destroy()
def OnAbout(self, event):
"""Display an About window."""
title = 'About PyCrust'
text = 'PyCrust %s\n\n' % VERSION + \
'Yet another Python shell, only flakier.\n\n' + \
'Half-baked by Patrick K. O\'Brien,\n' + \
'the other half is still in the oven.\n\n' + \
'Shell Revision: %s\n' % self.shell.revision + \
'Interpreter Revision: %s\n\n' % self.shell.interp.revision + \
'Platform: %s\n' % sys.platform + \
'Python Version: %s\n' % sys.version.split()[0] + \
'wxPython Version: %s\n' % wx.VERSION_STRING + \
('\t(%s)\n' % ", ".join(wx.PlatformInfo[1:]))
dialog = wx.MessageDialog(self, text, title,
wx.OK | wx.ICON_INFORMATION)
dialog.ShowModal()
dialog.Destroy()

View File

@@ -0,0 +1,260 @@
"""Provides global signal dispatching services."""
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
import exceptions
import types
import weakref
class DispatcherError(exceptions.Exception):
def __init__(self, args=None):
self.args = args
class Parameter:
"""Used to represent default parameter values."""
def __repr__(self):
return self.__class__.__name__
class Any(Parameter): pass
Any = Any()
class Anonymous(Parameter): pass
Anonymous = Anonymous()
connections = {}
senders = {}
_boundMethods = weakref.WeakKeyDictionary()
def connect(receiver, signal=Any, sender=Any, weak=True):
"""Connect receiver to sender for signal.
If sender is Any, receiver will receive signal from any sender.
If signal is Any, receiver will receive any signal from sender.
If sender is None, receiver will receive signal from Anonymous.
If signal is Any and sender is None, receiver will receive any
signal from Anonymous.
If signal is Any and sender is Any, receiver will receive any
signal from any sender.
If weak is true, weak references will be used."""
if signal is None:
raise DispatcherError, 'signal cannot be None'
if weak:
receiver = safeRef(receiver)
senderkey = id(sender)
signals = {}
if connections.has_key(senderkey):
signals = connections[senderkey]
else:
connections[senderkey] = signals
# Keep track of senders for cleanup.
if sender not in (None, Any):
def remove(object, senderkey=senderkey):
_removeSender(senderkey=senderkey)
# Skip objects that can not be weakly referenced, which means
# they won't be automatically cleaned up, but that's too bad.
try:
weakSender = weakref.ref(sender, remove)
senders[senderkey] = weakSender
except:
pass
receivers = []
if signals.has_key(signal):
receivers = signals[signal]
else:
signals[signal] = receivers
try:
receivers.remove(receiver)
except ValueError:
pass
receivers.append(receiver)
def disconnect(receiver, signal=Any, sender=Any, weak=True):
"""Disconnect receiver from sender for signal.
Disconnecting is not required. The use of disconnect is the same as for
connect, only in reverse. Think of it as undoing a previous connection."""
if signal is None:
raise DispatcherError, 'signal cannot be None'
if weak:
receiver = safeRef(receiver)
senderkey = id(sender)
try:
receivers = connections[senderkey][signal]
except KeyError:
raise DispatcherError, \
'No receivers for signal %r from sender %s' % (signal, sender)
try:
receivers.remove(receiver)
except ValueError:
raise DispatcherError, \
'No connection to receiver %s for signal %r from sender %s' % \
(receiver, signal, sender)
_cleanupConnections(senderkey, signal)
def send(signal, sender=Anonymous, **kwds):
"""Send signal from sender to all connected receivers.
Return a list of tuple pairs [(receiver, response), ... ].
If sender is not specified, signal is sent anonymously."""
senderkey = id(sender)
anykey = id(Any)
# Get receivers that receive *this* signal from *this* sender.
receivers = []
try:
receivers.extend(connections[senderkey][signal])
except KeyError:
pass
# Add receivers that receive *any* signal from *this* sender.
anyreceivers = []
try:
anyreceivers = connections[senderkey][Any]
except KeyError:
pass
for receiver in anyreceivers:
if receivers.count(receiver) == 0:
receivers.append(receiver)
# Add receivers that receive *this* signal from *any* sender.
anyreceivers = []
try:
anyreceivers = connections[anykey][signal]
except KeyError:
pass
for receiver in anyreceivers:
if receivers.count(receiver) == 0:
receivers.append(receiver)
# Add receivers that receive *any* signal from *any* sender.
anyreceivers = []
try:
anyreceivers = connections[anykey][Any]
except KeyError:
pass
for receiver in anyreceivers:
if receivers.count(receiver) == 0:
receivers.append(receiver)
# Call each receiver with whatever arguments it can accept.
# Return a list of tuple pairs [(receiver, response), ... ].
responses = []
for receiver in receivers:
if type(receiver) is weakref.ReferenceType \
or isinstance(receiver, BoundMethodWeakref):
# Dereference the weak reference.
receiver = receiver()
if receiver is None:
# This receiver is dead, so skip it.
continue
response = _call(receiver, signal=signal, sender=sender, **kwds)
responses += [(receiver, response)]
return responses
def _call(receiver, **kwds):
"""Call receiver with only arguments it can accept."""
## if type(receiver) is types.InstanceType:
if hasattr(receiver, '__call__') and \
(hasattr(receiver.__call__, 'im_func') or hasattr(receiver.__call__, 'im_code')):
# receiver is a class instance; assume it is callable.
# Reassign receiver to the actual method that will be called.
receiver = receiver.__call__
if hasattr(receiver, 'im_func'):
# receiver is a method. Drop the first argument, usually 'self'.
fc = receiver.im_func.func_code
acceptable = fc.co_varnames[1:fc.co_argcount]
elif hasattr(receiver, 'func_code'):
# receiver is a function.
fc = receiver.func_code
acceptable = fc.co_varnames[0:fc.co_argcount]
else:
raise DispatcherError, 'Unknown receiver %s of type %s' % (receiver, type(receiver))
if not (fc.co_flags & 8):
# fc does not have a **kwds type parameter, therefore
# remove unacceptable arguments.
for arg in kwds.keys():
if arg not in acceptable:
del kwds[arg]
return receiver(**kwds)
def safeRef(object):
"""Return a *safe* weak reference to a callable object."""
if hasattr(object, 'im_self'):
if object.im_self is not None:
# Turn a bound method into a BoundMethodWeakref instance.
# Keep track of these instances for lookup by disconnect().
selfkey = object.im_self
funckey = object.im_func
if not _boundMethods.has_key(selfkey):
_boundMethods[selfkey] = weakref.WeakKeyDictionary()
if not _boundMethods[selfkey].has_key(funckey):
_boundMethods[selfkey][funckey] = \
BoundMethodWeakref(boundMethod=object)
return _boundMethods[selfkey][funckey]
return weakref.ref(object, _removeReceiver)
class BoundMethodWeakref:
"""BoundMethodWeakref class."""
def __init__(self, boundMethod):
"""Return a weak-reference-like instance for a bound method."""
self.isDead = 0
def remove(object, self=self):
"""Set self.isDead to true when method or instance is destroyed."""
self.isDead = 1
_removeReceiver(receiver=self)
self.weakSelf = weakref.ref(boundMethod.im_self, remove)
self.weakFunc = weakref.ref(boundMethod.im_func, remove)
def __repr__(self):
"""Return the closest representation."""
return '<bound method weakref for %s.%s>' % (self.weakSelf, self.weakFunc)
def __call__(self):
"""Return a strong reference to the bound method."""
if self.isDead:
return None
else:
object = self.weakSelf()
method = self.weakFunc().__name__
try: # wxPython hack to handle wxDead objects.
return getattr(object, method)
except AttributeError:
## _removeReceiver(receiver=self)
return None
def _removeReceiver(receiver):
"""Remove receiver from connections."""
for senderkey in connections.keys():
for signal in connections[senderkey].keys():
receivers = connections[senderkey][signal]
try:
receivers.remove(receiver)
except:
pass
_cleanupConnections(senderkey, signal)
def _cleanupConnections(senderkey, signal):
"""Delete any empty signals for senderkey. Delete senderkey if empty."""
receivers = connections[senderkey][signal]
if not receivers:
# No more connected receivers. Therefore, remove the signal.
signals = connections[senderkey]
del signals[signal]
if not signals:
# No more signal connections. Therefore, remove the sender.
_removeSender(senderkey)
def _removeSender(senderkey):
"""Remove senderkey from connections."""
del connections[senderkey]
# Senderkey will only be in senders dictionary if sender
# could be weakly referenced.
try:
del senders[senderkey]
except:
pass

View File

@@ -0,0 +1,43 @@
"""Document class."""
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
import os
class Document:
"""Document class."""
def __init__(self, filename=None):
"""Create a Document instance."""
self.filename = filename
self.filepath = None
self.filedir = None
self.filebase = None
self.fileext = None
if self.filename:
self.filepath = os.path.realpath(self.filename)
self.filedir, self.filename = os.path.split(self.filepath)
self.filebase, self.fileext = os.path.splitext(self.filename)
def read(self):
"""Return contents of file."""
if self.filepath and os.path.exists(self.filepath):
f = file(self.filepath, 'rb')
try:
return f.read()
finally:
f.close()
else:
return ''
def write(self, text):
"""Write text to file."""
try:
f = file(self.filepath, 'wb')
f.write(text)
finally:
if f:
f.close()

843
wxPython/wx/py/editor.py Normal file
View File

@@ -0,0 +1,843 @@
"""PyAlaCarte and PyAlaMode editors."""
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
import wx
from buffer import Buffer
import crust
import dispatcher
import editwindow
import frame
from shell import Shell
import version
class EditorFrame(frame.Frame):
"""Frame containing one editor."""
def __init__(self, parent=None, id=-1, title='PyAlaCarte',
pos=wx.DefaultPosition, size=(800, 600),
style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE,
filename=None):
"""Create EditorFrame instance."""
frame.Frame.__init__(self, parent, id, title, pos, size, style)
self.buffers = {}
self.buffer = None # Current buffer.
self.editor = None
self._defaultText = title + ' - the tastiest Python editor.'
self._statusText = self._defaultText
self.SetStatusText(self._statusText)
wx.EVT_IDLE(self, self.OnIdle)
self._setup()
if filename:
self.bufferCreate(filename)
def _setup(self):
"""Setup prior to first buffer creation.
Useful for subclasses."""
pass
def setEditor(self, editor):
self.editor = editor
self.buffer = self.editor.buffer
self.buffers[self.buffer.id] = self.buffer
def OnAbout(self, event):
"""Display an About window."""
title = 'About PyAlaCarte'
text = 'Another fine, flaky program.'
dialog = wx.MessageDialog(self, text, title,
wx.OK | wx.ICON_INFORMATION)
dialog.ShowModal()
dialog.Destroy()
def OnClose(self, event):
"""Event handler for closing."""
for buffer in self.buffers.values():
self.buffer = buffer
if buffer.hasChanged():
cancel = self.bufferSuggestSave()
if cancel and event.CanVeto():
event.Veto()
return
self.Destroy()
def OnIdle(self, event):
"""Event handler for idle time."""
self._updateStatus()
if hasattr(self, 'notebook'):
self._updateTabText()
self._updateTitle()
event.Skip()
def _updateStatus(self):
"""Show current status information."""
if self.editor and hasattr(self.editor, 'getStatus'):
status = self.editor.getStatus()
text = 'File: %s | Line: %d | Column: %d' % status
else:
text = self._defaultText
if text != self._statusText:
self.SetStatusText(text)
self._statusText = text
def _updateTabText(self):
"""Show current buffer information on notebook tab."""
## suffix = ' **'
## notebook = self.notebook
## selection = notebook.GetSelection()
## if selection == -1:
## return
## text = notebook.GetPageText(selection)
## window = notebook.GetPage(selection)
## if window.editor and window.editor.buffer.hasChanged():
## if text.endswith(suffix):
## pass
## else:
## notebook.SetPageText(selection, text + suffix)
## else:
## if text.endswith(suffix):
## notebook.SetPageText(selection, text[:len(suffix)])
def _updateTitle(self):
"""Show current title information."""
title = self.GetTitle()
if self.bufferHasChanged():
if title.startswith('* '):
pass
else:
self.SetTitle('* ' + title)
else:
if title.startswith('* '):
self.SetTitle(title[2:])
def hasBuffer(self):
"""Return True if there is a current buffer."""
if self.buffer:
return True
else:
return False
def bufferClose(self):
"""Close buffer."""
if self.bufferHasChanged():
cancel = self.bufferSuggestSave()
if cancel:
return cancel
self.bufferDestroy()
cancel = False
return cancel
def bufferCreate(self, filename=None):
"""Create new buffer."""
self.bufferDestroy()
buffer = Buffer()
self.panel = panel = wx.Panel(parent=self, id=-1)
wx.EVT_ERASE_BACKGROUND(panel, lambda x: x)
editor = Editor(parent=panel)
panel.editor = editor
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(editor.window, 1, wx.EXPAND)
panel.SetSizer(sizer)
panel.SetAutoLayout(True)
sizer.Layout()
buffer.addEditor(editor)
buffer.open(filename)
self.setEditor(editor)
self.editor.setFocus()
self.SendSizeEvent()
def bufferDestroy(self):
"""Destroy the current buffer."""
if self.buffer:
for editor in self.buffer.editors.values():
editor.destroy()
self.editor = None
del self.buffers[self.buffer.id]
self.buffer = None
self.panel.Destroy()
def bufferHasChanged(self):
"""Return True if buffer has changed since last save."""
if self.buffer:
return self.buffer.hasChanged()
else:
return False
def bufferNew(self):
"""Create new buffer."""
if self.bufferHasChanged():
cancel = self.bufferSuggestSave()
if cancel:
return cancel
self.bufferCreate()
cancel = False
return cancel
def bufferOpen(self):
"""Open file in buffer."""
if self.bufferHasChanged():
cancel = self.bufferSuggestSave()
if cancel:
return cancel
filedir = ''
if self.buffer and self.buffer.doc.filedir:
filedir = self.buffer.doc.filedir
result = openSingle(directory=filedir)
if result.path:
self.bufferCreate(result.path)
cancel = False
return cancel
## def bufferPrint(self):
## """Print buffer."""
## pass
## def bufferRevert(self):
## """Revert buffer to version of file on disk."""
## pass
def bufferSave(self):
"""Save buffer to its file."""
if self.buffer.doc.filepath:
self.buffer.save()
cancel = False
else:
cancel = self.bufferSaveAs()
return cancel
def bufferSaveAs(self):
"""Save buffer to a new filename."""
if self.bufferHasChanged() and self.buffer.doc.filepath:
cancel = self.bufferSuggestSave()
if cancel:
return cancel
filedir = ''
if self.buffer and self.buffer.doc.filedir:
filedir = self.buffer.doc.filedir
result = saveSingle(directory=filedir)
if result.path:
self.buffer.saveAs(result.path)
cancel = False
else:
cancel = True
return cancel
def bufferSuggestSave(self):
"""Suggest saving changes. Return True if user selected Cancel."""
result = messageDialog(parent=None,
message='%s has changed.\n'
'Would you like to save it first'
'?' % self.buffer.name,
title='Save current file?')
if result.positive:
cancel = self.bufferSave()
else:
cancel = result.text == 'Cancel'
return cancel
def updateNamespace(self):
"""Update the buffer namespace for autocompletion and calltips."""
if self.buffer.updateNamespace():
self.SetStatusText('Namespace updated')
else:
self.SetStatusText('Error executing, unable to update namespace')
class EditorNotebookFrame(EditorFrame):
"""Frame containing one or more editors in a notebook."""
def __init__(self, parent=None, id=-1, title='PyAlaMode',
pos=wx.DefaultPosition, size=(800, 600),
style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE,
filename=None):
"""Create EditorNotebookFrame instance."""
self.notebook = None
EditorFrame.__init__(self, parent, id, title, pos,
size, style, filename)
if self.notebook:
dispatcher.connect(receiver=self._editorChange,
signal='EditorChange', sender=self.notebook)
def _setup(self):
"""Setup prior to first buffer creation.
Called automatically by base class during init."""
self.notebook = EditorNotebook(parent=self)
intro = 'Py %s' % version.VERSION
import imp
module = imp.new_module('__main__')
import __builtin__
module.__dict__['__builtins__'] = __builtin__
namespace = module.__dict__.copy()
self.crust = crust.Crust(parent=self.notebook, intro=intro, locals=namespace)
self.shell = self.crust.shell
# Override the filling so that status messages go to the status bar.
self.crust.filling.tree.setStatusText = self.SetStatusText
# Override the shell so that status messages go to the status bar.
self.shell.setStatusText = self.SetStatusText
# Fix a problem with the sash shrinking to nothing.
self.crust.filling.SetSashPosition(200)
self.notebook.AddPage(page=self.crust, text='*Shell*', select=True)
self.setEditor(self.crust.editor)
self.crust.editor.SetFocus()
def _editorChange(self, editor):
"""Editor change signal receiver."""
self.setEditor(editor)
def OnAbout(self, event):
"""Display an About window."""
title = 'About PyAlaMode'
text = 'Another fine, flaky program.'
dialog = wx.MessageDialog(self, text, title,
wx.OK | wx.ICON_INFORMATION)
dialog.ShowModal()
dialog.Destroy()
def _updateTitle(self):
"""Show current title information."""
pass
## title = self.GetTitle()
## if self.bufferHasChanged():
## if title.startswith('* '):
## pass
## else:
## self.SetTitle('* ' + title)
## else:
## if title.startswith('* '):
## self.SetTitle(title[2:])
def bufferCreate(self, filename=None):
"""Create new buffer."""
buffer = Buffer()
panel = wx.Panel(parent=self.notebook, id=-1)
wx.EVT_ERASE_BACKGROUND(panel, lambda x: x)
editor = Editor(parent=panel)
panel.editor = editor
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(editor.window, 1, wx.EXPAND)
panel.SetSizer(sizer)
panel.SetAutoLayout(True)
sizer.Layout()
buffer.addEditor(editor)
buffer.open(filename)
self.setEditor(editor)
self.notebook.AddPage(page=panel, text=self.buffer.name, select=True)
self.editor.setFocus()
def bufferDestroy(self):
"""Destroy the current buffer."""
selection = self.notebook.GetSelection()
## print "Destroy Selection:", selection
if selection > 0: # Don't destroy the PyCrust tab.
if self.buffer:
del self.buffers[self.buffer.id]
self.buffer = None # Do this before DeletePage().
self.notebook.DeletePage(selection)
def bufferNew(self):
"""Create new buffer."""
self.bufferCreate()
cancel = False
return cancel
def bufferOpen(self):
"""Open file in buffer."""
filedir = ''
if self.buffer and self.buffer.doc.filedir:
filedir = self.buffer.doc.filedir
result = openMultiple(directory=filedir)
for path in result.paths:
self.bufferCreate(path)
cancel = False
return cancel
class EditorNotebook(wx.Notebook):
"""A notebook containing a page for each editor."""
def __init__(self, parent):
"""Create EditorNotebook instance."""
wx.Notebook.__init__(self, parent, id=-1, style=wx.CLIP_CHILDREN)
wx.EVT_NOTEBOOK_PAGE_CHANGING(self, self.GetId(),
self.OnPageChanging)
wx.EVT_NOTEBOOK_PAGE_CHANGED(self, self.GetId(),
self.OnPageChanged)
wx.EVT_IDLE(self, self.OnIdle)
def OnIdle(self, event):
"""Event handler for idle time."""
self._updateTabText()
event.Skip()
def _updateTabText(self):
"""Show current buffer display name on all but first tab."""
size = 3
changed = ' **'
unchanged = ' --'
selection = self.GetSelection()
if selection < 1:
return
text = self.GetPageText(selection)
window = self.GetPage(selection)
if not window.editor:
return
if text.endswith(changed) or text.endswith(unchanged):
name = text[:-size]
else:
name = text
if name != window.editor.buffer.name:
text = window.editor.buffer.name
if window.editor.buffer.hasChanged():
if text.endswith(changed):
text = None
elif text.endswith(unchanged):
text = text[:-size] + changed
else:
text += changed
else:
if text.endswith(changed):
text = text[:-size] + unchanged
elif text.endswith(unchanged):
text = None
else:
text += unchanged
if text is not None:
self.SetPageText(selection, text)
self.Refresh() # Needed on Win98.
def OnPageChanging(self, event):
"""Page changing event handler."""
event.Skip()
def OnPageChanged(self, event):
"""Page changed event handler."""
new = event.GetSelection()
window = self.GetPage(new)
dispatcher.send(signal='EditorChange', sender=self,
editor=window.editor)
window.SetFocus()
event.Skip()
class EditorShellNotebookFrame(EditorNotebookFrame):
"""Frame containing a notebook containing EditorShellNotebooks."""
def __init__(self, parent=None, id=-1, title='PyAlaModeTest',
pos=wx.DefaultPosition, size=(600, 400),
style=wx.DEFAULT_FRAME_STYLE,
filename=None, singlefile=False):
"""Create EditorShellNotebookFrame instance."""
self._singlefile = singlefile
EditorNotebookFrame.__init__(self, parent, id, title, pos,
size, style, filename)
def _setup(self):
"""Setup prior to first buffer creation.
Called automatically by base class during init."""
if not self._singlefile:
self.notebook = EditorNotebook(parent=self)
def OnAbout(self, event):
"""Display an About window."""
title = 'About PyAlaModePlus'
text = 'Another fine, flaky program.'
dialog = wx.MessageDialog(self, text, title,
wx.OK | wx.ICON_INFORMATION)
dialog.ShowModal()
dialog.Destroy()
def bufferCreate(self, filename=None):
"""Create new buffer."""
if self._singlefile:
self.bufferDestroy()
notebook = EditorShellNotebook(parent=self,
filename=filename)
self.notebook = notebook
else:
notebook = EditorShellNotebook(parent=self.notebook,
filename=filename)
self.setEditor(notebook.editor)
if not self._singlefile:
self.notebook.AddPage(page=notebook, text=self.buffer.name,
select=True)
self.editor.setFocus()
def bufferDestroy(self):
"""Destroy the current buffer."""
if self.buffer:
self.editor = None
del self.buffers[self.buffer.id]
self.buffer = None # Do this before DeletePage().
if self._singlefile:
self.notebook.Destroy()
self.notebook = None
else:
selection = self.notebook.GetSelection()
## print "Destroy Selection:", selection
self.notebook.DeletePage(selection)
def bufferNew(self):
"""Create new buffer."""
if self._singlefile and self.bufferHasChanged():
cancel = self.bufferSuggestSave()
if cancel:
return cancel
self.bufferCreate()
cancel = False
return cancel
def bufferOpen(self):
"""Open file in buffer."""
if self._singlefile and self.bufferHasChanged():
cancel = self.bufferSuggestSave()
if cancel:
return cancel
filedir = ''
if self.buffer and self.buffer.doc.filedir:
filedir = self.buffer.doc.filedir
if self._singlefile:
result = openSingle(directory=filedir)
if result.path:
self.bufferCreate(result.path)
else:
result = openMultiple(directory=filedir)
for path in result.paths:
self.bufferCreate(path)
cancel = False
return cancel
class EditorShellNotebook(wx.Notebook):
"""A notebook containing an editor page and a shell page."""
def __init__(self, parent, filename=None):
"""Create EditorShellNotebook instance."""
wx.Notebook.__init__(self, parent, id=-1)
usePanels = True
if usePanels:
editorparent = editorpanel = wx.Panel(self, -1)
shellparent = shellpanel = wx.Panel(self, -1)
else:
editorparent = self
shellparent = self
self.buffer = Buffer()
self.editor = Editor(parent=editorparent)
self.buffer.addEditor(self.editor)
self.buffer.open(filename)
self.shell = Shell(parent=shellparent, locals=self.buffer.interp.locals,
style=wx.CLIP_CHILDREN | wx.SUNKEN_BORDER)
self.buffer.interp.locals.clear()
if usePanels:
self.AddPage(page=editorpanel, text='Editor', select=True)
self.AddPage(page=shellpanel, text='Shell')
# Setup sizers
editorsizer = wx.BoxSizer(wx.VERTICAL)
editorsizer.Add(self.editor.window, 1, wx.EXPAND)
editorpanel.SetSizer(editorsizer)
editorpanel.SetAutoLayout(True)
shellsizer = wx.BoxSizer(wx.VERTICAL)
shellsizer.Add(self.shell, 1, wx.EXPAND)
shellpanel.SetSizer(shellsizer)
shellpanel.SetAutoLayout(True)
else:
self.AddPage(page=self.editor.window, text='Editor', select=True)
self.AddPage(page=self.shell, text='Shell')
self.editor.setFocus()
wx.EVT_NOTEBOOK_PAGE_CHANGED(self, self.GetId(), self.OnPageChanged)
def OnPageChanged(self, event):
"""Page changed event handler."""
selection = event.GetSelection()
if selection == 0:
self.editor.setFocus()
else:
self.shell.SetFocus()
event.Skip()
def SetFocus(self):
wx.Notebook.SetFocus(self)
selection = self.GetSelection()
if selection == 0:
self.editor.setFocus()
else:
self.shell.SetFocus()
class Editor:
"""Editor having an EditWindow."""
def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
size=wx.DefaultSize,
style=wx.CLIP_CHILDREN | wx.SUNKEN_BORDER):
"""Create Editor instance."""
self.window = EditWindow(self, parent, id, pos, size, style)
self.id = self.window.GetId()
self.buffer = None
# Assign handlers for keyboard events.
wx.EVT_CHAR(self.window, self.OnChar)
wx.EVT_KEY_DOWN(self.window, self.OnKeyDown)
def _setBuffer(self, buffer, text):
"""Set the editor to a buffer. Private callback called by buffer."""
self.buffer = buffer
self.autoCompleteKeys = buffer.interp.getAutoCompleteKeys()
self.clearAll()
self.setText(text)
self.emptyUndoBuffer()
self.setSavePoint()
def destroy(self):
"""Destroy all editor objects."""
self.window.Destroy()
def clearAll(self):
self.window.ClearAll()
def emptyUndoBuffer(self):
self.window.EmptyUndoBuffer()
def getStatus(self):
"""Return (filepath, line, column) status tuple."""
if self.window:
pos = self.window.GetCurrentPos()
line = self.window.LineFromPosition(pos) + 1
col = self.window.GetColumn(pos)
if self.buffer:
name = self.buffer.doc.filepath or self.buffer.name
else:
name = ''
status = (name, line, col)
return status
else:
return ('', 0, 0)
def getText(self):
"""Return contents of editor."""
return self.window.GetText()
def hasChanged(self):
"""Return True if contents have changed."""
return self.window.GetModify()
def setFocus(self):
"""Set the input focus to the editor window."""
self.window.SetFocus()
def setSavePoint(self):
self.window.SetSavePoint()
def setText(self, text):
"""Set contents of editor."""
self.window.SetText(text)
def OnChar(self, event):
"""Keypress event handler.
Only receives an event if OnKeyDown calls event.Skip() for the
corresponding event."""
key = event.KeyCode()
if key in self.autoCompleteKeys:
# Usually the dot (period) key activates auto completion.
if self.window.AutoCompActive():
self.window.AutoCompCancel()
self.window.ReplaceSelection('')
self.window.AddText(chr(key))
text, pos = self.window.GetCurLine()
text = text[:pos]
if self.window.autoComplete:
self.autoCompleteShow(text)
elif key == ord('('):
# The left paren activates a call tip and cancels an
# active auto completion.
if self.window.AutoCompActive():
self.window.AutoCompCancel()
self.window.ReplaceSelection('')
self.window.AddText('(')
text, pos = self.window.GetCurLine()
text = text[:pos]
self.autoCallTipShow(text)
else:
# Allow the normal event handling to take place.
event.Skip()
def OnKeyDown(self, event):
"""Key down event handler."""
key = event.KeyCode()
# If the auto-complete window is up let it do its thing.
if self.window.AutoCompActive():
event.Skip()
return
controlDown = event.ControlDown()
altDown = event.AltDown()
shiftDown = event.ShiftDown()
# Let Ctrl-Alt-* get handled normally.
if controlDown and altDown:
event.Skip()
# Increase font size.
elif controlDown and key in (ord(']'),):
dispatcher.send(signal='FontIncrease')
# Decrease font size.
elif controlDown and key in (ord('['),):
dispatcher.send(signal='FontDecrease')
# Default font size.
elif controlDown and key in (ord('='),):
dispatcher.send(signal='FontDefault')
else:
event.Skip()
def autoCompleteShow(self, command):
"""Display auto-completion popup list."""
list = self.buffer.interp.getAutoCompleteList(command,
includeMagic=self.window.autoCompleteIncludeMagic,
includeSingle=self.window.autoCompleteIncludeSingle,
includeDouble=self.window.autoCompleteIncludeDouble)
if list:
options = ' '.join(list)
offset = 0
self.window.AutoCompShow(offset, options)
def autoCallTipShow(self, command):
"""Display argument spec and docstring in a popup window."""
if self.window.CallTipActive():
self.window.CallTipCancel()
(name, argspec, tip) = self.buffer.interp.getCallTip(command)
if tip:
dispatcher.send(signal='Shell.calltip', sender=self, calltip=tip)
if not self.window.autoCallTip:
return
if argspec:
startpos = self.window.GetCurrentPos()
self.window.AddText(argspec + ')')
endpos = self.window.GetCurrentPos()
self.window.SetSelection(endpos, startpos)
if tip:
curpos = self.window.GetCurrentPos()
size = len(name)
tippos = curpos - (size + 1)
fallback = curpos - self.window.GetColumn(curpos)
# In case there isn't enough room, only go back to the
# fallback.
tippos = max(tippos, fallback)
self.window.CallTipShow(tippos, tip)
self.window.CallTipSetHighlight(0, size)
class EditWindow(editwindow.EditWindow):
"""EditWindow based on StyledTextCtrl."""
def __init__(self, editor, parent, id=-1, pos=wx.DefaultPosition,
size=wx.DefaultSize,
style=wx.CLIP_CHILDREN | wx.SUNKEN_BORDER):
"""Create EditWindow instance."""
editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
self.editor = editor
class DialogResults:
"""DialogResults class."""
def __init__(self, returned):
"""Create wrapper for results returned by dialog."""
self.returned = returned
self.positive = returned in (wx.ID_OK, wx.ID_YES)
self.text = self._asString()
def __repr__(self):
return str(self.__dict__)
def _asString(self):
returned = self.returned
if returned == wx.ID_OK:
return "Ok"
elif returned == wx.ID_CANCEL:
return "Cancel"
elif returned == wx.ID_YES:
return "Yes"
elif returned == wx.ID_NO:
return "No"
def fileDialog(parent=None, title='Open', directory='', filename='',
wildcard='All Files (*.*)|*.*',
style=wx.OPEN | wx.MULTIPLE):
"""File dialog wrapper function."""
dialog = wx.FileDialog(parent, title, directory, filename,
wildcard, style)
result = DialogResults(dialog.ShowModal())
if result.positive:
result.paths = dialog.GetPaths()
else:
result.paths = []
dialog.Destroy()
return result
def openSingle(parent=None, title='Open', directory='', filename='',
wildcard='All Files (*.*)|*.*', style=wx.OPEN):
"""File dialog wrapper function."""
dialog = wx.FileDialog(parent, title, directory, filename,
wildcard, style)
result = DialogResults(dialog.ShowModal())
if result.positive:
result.path = dialog.GetPath()
else:
result.path = None
dialog.Destroy()
return result
def openMultiple(parent=None, title='Open', directory='', filename='',
wildcard='All Files (*.*)|*.*',
style=wx.OPEN | wx.MULTIPLE):
"""File dialog wrapper function."""
return fileDialog(parent, title, directory, filename, wildcard, style)
def saveSingle(parent=None, title='Save', directory='', filename='',
wildcard='All Files (*.*)|*.*',
style=wx.SAVE | wx.HIDE_READONLY | wx.OVERWRITE_PROMPT):
"""File dialog wrapper function."""
dialog = wx.FileDialog(parent, title, directory, filename,
wildcard, style)
result = DialogResults(dialog.ShowModal())
if result.positive:
result.path = dialog.GetPath()
else:
result.path = None
dialog.Destroy()
return result
def directory(parent=None, message='Choose a directory', path='', style=0,
pos=wx.DefaultPosition, size=wx.DefaultSize):
"""Dir dialog wrapper function."""
dialog = wx.DirDialog(parent, message, path, style, pos, size)
result = DialogResults(dialog.ShowModal())
if result.positive:
result.path = dialog.GetPath()
else:
result.path = None
dialog.Destroy()
return result
def messageDialog(parent=None, message='', title='Message box',
style=wx.YES_NO | wx.CANCEL | wx.CENTRE | wx.ICON_QUESTION,
pos=wx.DefaultPosition):
"""Message dialog wrapper function."""
dialog = wx.MessageDialog(parent, message, title, style, pos)
result = DialogResults(dialog.ShowModal())
dialog.Destroy()
return result

View File

@@ -0,0 +1,225 @@
"""EditWindow class."""
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
import wx
from wx import stc
import keyword
import os
import sys
import time
import dispatcher
from version import VERSION
if 'wxMSW' in wx.PlatformInfo:
FACES = { 'times' : 'Times New Roman',
'mono' : 'Courier New',
'helv' : 'Arial',
'lucida' : 'Lucida Console',
'other' : 'Comic Sans MS',
'size' : 10,
'lnsize' : 8,
'backcol' : '#FFFFFF',
'calltipbg' : '#FFFFB8',
'calltipfg' : '#404040',
}
elif 'wxGTK' in wx.PlatformInfo and 'gtk2' in wx.PlatformInfo:
FACES = { 'times' : 'Serif',
'mono' : 'Monospace',
'helv' : 'Sans',
'other' : 'new century schoolbook',
'size' : 10,
'lnsize' : 9,
'backcol' : '#FFFFFF',
'calltipbg' : '#FFFFB8',
'calltipfg' : '#404040',
}
elif 'wxMac' in wx.PlatformInfo:
FACES = { 'times' : 'Lucida Grande',
'mono' : 'Courier New',
'helv' : 'Geneva',
'other' : 'new century schoolbook',
'size' : 13,
'lnsize' : 10,
'backcol' : '#FFFFFF',
'calltipbg' : '#FFFFB8',
'calltipfg' : '#404040',
}
else: # GTK1, etc.
FACES = { 'times' : 'Times',
'mono' : 'Courier',
'helv' : 'Helvetica',
'other' : 'new century schoolbook',
'size' : 12,
'lnsize' : 10,
'backcol' : '#FFFFFF',
'calltipbg' : '#FFFFB8',
'calltipfg' : '#404040',
}
class EditWindow(stc.StyledTextCtrl):
"""EditWindow based on StyledTextCtrl."""
revision = __revision__
def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.CLIP_CHILDREN | wx.SUNKEN_BORDER):
"""Create EditWindow instance."""
stc.StyledTextCtrl.__init__(self, parent, id, pos, size, style)
self.__config()
stc.EVT_STC_UPDATEUI(self, id, self.OnUpdateUI)
dispatcher.connect(receiver=self._fontsizer, signal='FontIncrease')
dispatcher.connect(receiver=self._fontsizer, signal='FontDecrease')
dispatcher.connect(receiver=self._fontsizer, signal='FontDefault')
def _fontsizer(self, signal):
"""Receiver for Font* signals."""
size = self.GetZoom()
if signal == 'FontIncrease':
size += 1
elif signal == 'FontDecrease':
size -= 1
elif signal == 'FontDefault':
size = 0
self.SetZoom(size)
def __config(self):
"""Configure shell based on user preferences."""
self.SetMarginType(1, stc.STC_MARGIN_NUMBER)
self.SetMarginWidth(1, 40)
self.SetLexer(stc.STC_LEX_PYTHON)
self.SetKeyWords(0, ' '.join(keyword.kwlist))
self.setStyles(FACES)
self.SetViewWhiteSpace(False)
self.SetTabWidth(4)
self.SetUseTabs(False)
# Do we want to automatically pop up command completion options?
self.autoComplete = True
self.autoCompleteIncludeMagic = True
self.autoCompleteIncludeSingle = True
self.autoCompleteIncludeDouble = True
self.autoCompleteCaseInsensitive = True
self.AutoCompSetIgnoreCase(self.autoCompleteCaseInsensitive)
self.autoCompleteAutoHide = False
self.AutoCompSetAutoHide(self.autoCompleteAutoHide)
self.AutoCompStops(' .,;:([)]}\'"\\<>%^&+-=*/|`')
# Do we want to automatically pop up command argument help?
self.autoCallTip = True
self.CallTipSetBackground(FACES['calltipbg'])
self.CallTipSetForeground(FACES['calltipfg'])
self.SetWrapMode(False)
try:
self.SetEndAtLastLine(False)
except AttributeError:
pass
def setStyles(self, faces):
"""Configure font size, typeface and color for lexer."""
# Default style
self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
"face:%(mono)s,size:%(size)d,back:%(backcol)s" % \
faces)
self.StyleClearAll()
# Built in styles
self.StyleSetSpec(stc.STC_STYLE_LINENUMBER,
"back:#C0C0C0,face:%(mono)s,size:%(lnsize)d" % faces)
self.StyleSetSpec(stc.STC_STYLE_CONTROLCHAR,
"face:%(mono)s" % faces)
self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
"fore:#0000FF,back:#FFFF88")
self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
"fore:#FF0000,back:#FFFF88")
# Python styles
self.StyleSetSpec(stc.STC_P_DEFAULT,
"face:%(mono)s" % faces)
self.StyleSetSpec(stc.STC_P_COMMENTLINE,
"fore:#007F00,face:%(mono)s" % faces)
self.StyleSetSpec(stc.STC_P_NUMBER,
"")
self.StyleSetSpec(stc.STC_P_STRING,
"fore:#7F007F,face:%(mono)s" % faces)
self.StyleSetSpec(stc.STC_P_CHARACTER,
"fore:#7F007F,face:%(mono)s" % faces)
self.StyleSetSpec(stc.STC_P_WORD,
"fore:#00007F,bold")
self.StyleSetSpec(stc.STC_P_TRIPLE,
"fore:#7F0000")
self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE,
"fore:#000033,back:#FFFFE8")
self.StyleSetSpec(stc.STC_P_CLASSNAME,
"fore:#0000FF,bold")
self.StyleSetSpec(stc.STC_P_DEFNAME,
"fore:#007F7F,bold")
self.StyleSetSpec(stc.STC_P_OPERATOR,
"")
self.StyleSetSpec(stc.STC_P_IDENTIFIER,
"")
self.StyleSetSpec(stc.STC_P_COMMENTBLOCK,
"fore:#7F7F7F")
self.StyleSetSpec(stc.STC_P_STRINGEOL,
"fore:#000000,face:%(mono)s,back:#E0C0E0,eolfilled" % faces)
def OnUpdateUI(self, event):
"""Check for matching braces."""
# If the auto-complete window is up let it do its thing.
if self.AutoCompActive() or self.CallTipActive():
return
braceAtCaret = -1
braceOpposite = -1
charBefore = None
caretPos = self.GetCurrentPos()
if caretPos > 0:
charBefore = self.GetCharAt(caretPos - 1)
styleBefore = self.GetStyleAt(caretPos - 1)
# Check before.
if charBefore and chr(charBefore) in '[]{}()' \
and styleBefore == stc.STC_P_OPERATOR:
braceAtCaret = caretPos - 1
# Check after.
if braceAtCaret < 0:
charAfter = self.GetCharAt(caretPos)
styleAfter = self.GetStyleAt(caretPos)
if charAfter and chr(charAfter) in '[]{}()' \
and styleAfter == stc.STC_P_OPERATOR:
braceAtCaret = caretPos
if braceAtCaret >= 0:
braceOpposite = self.BraceMatch(braceAtCaret)
if braceAtCaret != -1 and braceOpposite == -1:
self.BraceBadLight(braceAtCaret)
else:
self.BraceHighlight(braceAtCaret, braceOpposite)
def CanCopy(self):
"""Return True if text is selected and can be copied."""
return self.GetSelectionStart() != self.GetSelectionEnd()
def CanCut(self):
"""Return True if text is selected and can be cut."""
return self.CanCopy() and self.CanEdit()
def CanEdit(self):
"""Return True if editing should succeed."""
return not self.GetReadOnly()
def CanPaste(self):
"""Return True if pasting should succeed."""
return stc.StyledTextCtrl.CanPaste(self) and self.CanEdit()

332
wxPython/wx/py/filling.py Normal file
View File

@@ -0,0 +1,332 @@
"""Filling is the gui tree control through which a user can navigate
the local namespace or any object."""
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
import wx
import dispatcher
import editwindow
import inspect
import introspect
import keyword
import sys
import types
from version import VERSION
COMMONTYPES = [getattr(types, t) for t in dir(types) \
if not t.startswith('_') \
and t not in ('ClassType', 'InstanceType', 'ModuleType')]
DOCTYPES = ('BuiltinFunctionType', 'BuiltinMethodType', 'ClassType',
'FunctionType', 'GeneratorType', 'InstanceType',
'LambdaType', 'MethodType', 'ModuleType',
'UnboundMethodType', 'method-wrapper')
SIMPLETYPES = [getattr(types, t) for t in dir(types) \
if not t.startswith('_') and t not in DOCTYPES]
del t
try:
COMMONTYPES.append(type(''.__repr__)) # Method-wrapper in version 2.2.x.
except AttributeError:
pass
class FillingTree(wx.TreeCtrl):
"""FillingTree based on TreeCtrl."""
name = 'Filling Tree'
revision = __revision__
def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.TR_DEFAULT_STYLE,
rootObject=None, rootLabel=None, rootIsNamespace=False,
static=False):
"""Create FillingTree instance."""
wx.TreeCtrl.__init__(self, parent, id, pos, size, style)
self.rootIsNamespace = rootIsNamespace
import __main__
if rootObject is None:
rootObject = __main__.__dict__
self.rootIsNamespace = True
if rootObject is __main__.__dict__ and rootLabel is None:
rootLabel = 'locals()'
if not rootLabel:
rootLabel = 'Ingredients'
rootData = wx.TreeItemData(rootObject)
self.item = self.root = self.AddRoot(rootLabel, -1, -1, rootData)
self.SetItemHasChildren(self.root, self.objHasChildren(rootObject))
wx.EVT_TREE_ITEM_EXPANDING(self, self.GetId(), self.OnItemExpanding)
wx.EVT_TREE_ITEM_COLLAPSED(self, self.GetId(), self.OnItemCollapsed)
wx.EVT_TREE_SEL_CHANGED(self, self.GetId(), self.OnSelChanged)
wx.EVT_TREE_ITEM_ACTIVATED(self, self.GetId(), self.OnItemActivated)
if not static:
dispatcher.connect(receiver=self.push, signal='Interpreter.push')
def push(self, command, more):
"""Receiver for Interpreter.push signal."""
self.display()
def OnItemExpanding(self, event):
"""Add children to the item."""
busy = wx.BusyCursor()
item = event.GetItem()
if self.IsExpanded(item):
return
self.addChildren(item)
# self.SelectItem(item)
def OnItemCollapsed(self, event):
"""Remove all children from the item."""
busy = wx.BusyCursor()
item = event.GetItem()
# self.CollapseAndReset(item)
# self.DeleteChildren(item)
# self.SelectItem(item)
def OnSelChanged(self, event):
"""Display information about the item."""
busy = wx.BusyCursor()
self.item = event.GetItem()
self.display()
def OnItemActivated(self, event):
"""Launch a DirFrame."""
item = event.GetItem()
text = self.getFullName(item)
obj = self.GetPyData(item)
frame = FillingFrame(parent=self, size=(600, 100), rootObject=obj,
rootLabel=text, rootIsNamespace=False)
frame.Show()
def objHasChildren(self, obj):
"""Return true if object has children."""
if self.objGetChildren(obj):
return True
else:
return False
def objGetChildren(self, obj):
"""Return dictionary with attributes or contents of object."""
busy = wx.BusyCursor()
otype = type(obj)
if otype is types.DictType \
or str(otype)[17:23] == 'BTrees' and hasattr(obj, 'keys'):
return obj
d = {}
if otype is types.ListType or otype is types.TupleType:
for n in range(len(obj)):
key = '[' + str(n) + ']'
d[key] = obj[n]
if otype not in COMMONTYPES:
for key in introspect.getAttributeNames(obj):
# Believe it or not, some attributes can disappear,
# such as the exc_traceback attribute of the sys
# module. So this is nested in a try block.
try:
d[key] = getattr(obj, key)
except:
pass
return d
def addChildren(self, item):
self.DeleteChildren(item)
obj = self.GetPyData(item)
children = self.objGetChildren(obj)
if not children:
return
keys = children.keys()
keys.sort(lambda x, y: cmp(str(x).lower(), str(y).lower()))
for key in keys:
itemtext = str(key)
# Show string dictionary items with single quotes, except
# for the first level of items, if they represent a
# namespace.
if type(obj) is types.DictType \
and type(key) is types.StringType \
and (item != self.root \
or (item == self.root and not self.rootIsNamespace)):
itemtext = repr(key)
child = children[key]
data = wx.TreeItemData(child)
branch = self.AppendItem(parent=item, text=itemtext, data=data)
self.SetItemHasChildren(branch, self.objHasChildren(child))
def display(self):
item = self.item
if self.IsExpanded(item):
self.addChildren(item)
self.setText('')
obj = self.GetPyData(item)
if wx.Platform == '__WXMSW__':
if obj is None: # Windows bug fix.
return
self.SetItemHasChildren(item, self.objHasChildren(obj))
otype = type(obj)
text = ''
text += self.getFullName(item)
text += '\n\nType: ' + str(otype)
try:
value = str(obj)
except:
value = ''
if otype is types.StringType or otype is types.UnicodeType:
value = repr(obj)
text += '\n\nValue: ' + value
if otype not in SIMPLETYPES:
try:
text += '\n\nDocstring:\n\n"""' + \
inspect.getdoc(obj).strip() + '"""'
except:
pass
if otype is types.InstanceType:
try:
text += '\n\nClass Definition:\n\n' + \
inspect.getsource(obj.__class__)
except:
pass
else:
try:
text += '\n\nSource Code:\n\n' + \
inspect.getsource(obj)
except:
pass
self.setText(text)
def getFullName(self, item, partial=''):
"""Return a syntactically proper name for item."""
name = self.GetItemText(item)
parent = None
obj = None
if item != self.root:
parent = self.GetItemParent(item)
obj = self.GetPyData(parent)
# Apply dictionary syntax to dictionary items, except the root
# and first level children of a namepace.
if (type(obj) is types.DictType \
or str(type(obj))[17:23] == 'BTrees' \
and hasattr(obj, 'keys')) \
and ((item != self.root and parent != self.root) \
or (parent == self.root and not self.rootIsNamespace)):
name = '[' + name + ']'
# Apply dot syntax to multipart names.
if partial:
if partial[0] == '[':
name += partial
else:
name += '.' + partial
# Repeat for everything but the root item
# and first level children of a namespace.
if (item != self.root and parent != self.root) \
or (parent == self.root and not self.rootIsNamespace):
name = self.getFullName(parent, partial=name)
return name
def setText(self, text):
"""Display information about the current selection."""
# This method will likely be replaced by the enclosing app to
# do something more interesting, like write to a text control.
print text
def setStatusText(self, text):
"""Display status information."""
# This method will likely be replaced by the enclosing app to
# do something more interesting, like write to a status bar.
print text
class FillingText(editwindow.EditWindow):
"""FillingText based on StyledTextCtrl."""
name = 'Filling Text'
revision = __revision__
def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.CLIP_CHILDREN,
static=False):
"""Create FillingText instance."""
editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
# Configure various defaults and user preferences.
self.SetReadOnly(True)
self.SetWrapMode(True)
self.SetMarginWidth(1, 0)
if not static:
dispatcher.connect(receiver=self.push, signal='Interpreter.push')
def push(self, command, more):
"""Receiver for Interpreter.push signal."""
self.Refresh()
def SetText(self, *args, **kwds):
self.SetReadOnly(False)
editwindow.EditWindow.SetText(self, *args, **kwds)
self.SetReadOnly(True)
class Filling(wx.SplitterWindow):
"""Filling based on wxSplitterWindow."""
name = 'Filling'
revision = __revision__
def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.SP_3D,
name='Filling Window', rootObject=None,
rootLabel=None, rootIsNamespace=False, static=False):
"""Create a Filling instance."""
wx.SplitterWindow.__init__(self, parent, id, pos, size, style, name)
self.tree = FillingTree(parent=self, rootObject=rootObject,
rootLabel=rootLabel,
rootIsNamespace=rootIsNamespace,
static=static)
self.text = FillingText(parent=self, static=static)
self.SplitVertically(self.tree, self.text, 130)
self.SetMinimumPaneSize(1)
# Override the filling so that descriptions go to FillingText.
self.tree.setText = self.text.SetText
# Display the root item.
## self.tree.SelectItem(self.tree.root)
self.tree.display()
class FillingFrame(wx.Frame):
"""Frame containing the namespace tree component."""
name = 'Filling Frame'
revision = __revision__
def __init__(self, parent=None, id=-1, title='PyFilling',
pos=wx.DefaultPosition, size=(600, 400),
style=wx.DEFAULT_FRAME_STYLE, rootObject=None,
rootLabel=None, rootIsNamespace=False, static=False):
"""Create FillingFrame instance."""
wx.Frame.__init__(self, parent, id, title, pos, size, style)
intro = 'PyFilling - The Tastiest Namespace Inspector'
self.CreateStatusBar()
self.SetStatusText(intro)
import images
self.SetIcon(images.getPyIcon())
self.filling = Filling(parent=self, rootObject=rootObject,
rootLabel=rootLabel,
rootIsNamespace=rootIsNamespace,
static=static)
# Override so that status messages go to the status bar.
self.filling.tree.setStatusText = self.SetStatusText
class App(wx.App):
"""PyFilling standalone application."""
def OnInit(self):
wx.InitAllImageHandlers()
self.fillingFrame = FillingFrame()
self.fillingFrame.Show(True)
self.SetTopWindow(self.fillingFrame)
return True

362
wxPython/wx/py/frame.py Normal file
View File

@@ -0,0 +1,362 @@
"""Base frame with menu."""
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
import wx
from version import VERSION
ID_NEW = wx.ID_NEW
ID_OPEN = wx.ID_OPEN
ID_REVERT = wx.ID_REVERT
ID_CLOSE = wx.ID_CLOSE
ID_SAVE = wx.ID_SAVE
ID_SAVEAS = wx.ID_SAVEAS
ID_PRINT = wx.ID_PRINT
ID_EXIT = wx.ID_EXIT
ID_UNDO = wx.ID_UNDO
ID_REDO = wx.ID_REDO
ID_CUT = wx.ID_CUT
ID_COPY = wx.ID_COPY
ID_PASTE = wx.ID_PASTE
ID_CLEAR = wx.ID_CLEAR
ID_SELECTALL = wx.ID_SELECTALL
ID_ABOUT = wx.ID_ABOUT
ID_AUTOCOMP = wx.NewId()
ID_AUTOCOMP_SHOW = wx.NewId()
ID_AUTOCOMP_MAGIC = wx.NewId()
ID_AUTOCOMP_SINGLE = wx.NewId()
ID_AUTOCOMP_DOUBLE = wx.NewId()
ID_CALLTIPS = wx.NewId()
ID_CALLTIPS_SHOW = wx.NewId()
ID_COPY_PLUS = wx.NewId()
ID_NAMESPACE = wx.NewId()
ID_PASTE_PLUS = wx.NewId()
ID_WRAP = wx.NewId()
ID_USEAA = wx.NewId()
class Frame(wx.Frame):
"""Frame with standard menu items."""
revision = __revision__
def __init__(self, parent=None, id=-1, title='Editor',
pos=wx.DefaultPosition, size=wx.DefaultSize,
style=wx.DEFAULT_FRAME_STYLE):
"""Create a Frame instance."""
wx.Frame.__init__(self, parent, id, title, pos, size, style)
self.CreateStatusBar()
self.SetStatusText('Frame')
import images
self.SetIcon(images.getPyIcon())
self.__createMenus()
wx.EVT_CLOSE(self, self.OnClose)
def OnClose(self, event):
"""Event handler for closing."""
self.Destroy()
def __createMenus(self):
m = self.fileMenu = wx.Menu()
m.Append(ID_NEW, '&New \tCtrl+N',
'New file')
m.Append(ID_OPEN, '&Open... \tCtrl+O',
'Open file')
m.AppendSeparator()
m.Append(ID_REVERT, '&Revert \tCtrl+R',
'Revert to last saved version')
m.Append(ID_CLOSE, '&Close \tCtrl+W',
'Close file')
m.AppendSeparator()
m.Append(ID_SAVE, '&Save... \tCtrl+S',
'Save file')
m.Append(ID_SAVEAS, 'Save &As \tShift+Ctrl+S',
'Save file with new name')
m.AppendSeparator()
m.Append(ID_PRINT, '&Print... \tCtrl+P',
'Print file')
m.AppendSeparator()
m.Append(ID_NAMESPACE, '&Update Namespace \tShift+Ctrl+N',
'Update namespace for autocompletion and calltips')
m.AppendSeparator()
m.Append(ID_EXIT, 'E&xit', 'Exit Program')
m = self.editMenu = wx.Menu()
m.Append(ID_UNDO, '&Undo \tCtrl+Z',
'Undo the last action')
m.Append(ID_REDO, '&Redo \tCtrl+Y',
'Redo the last undone action')
m.AppendSeparator()
m.Append(ID_CUT, 'Cu&t \tCtrl+X',
'Cut the selection')
m.Append(ID_COPY, '&Copy \tCtrl+C',
'Copy the selection')
m.Append(ID_COPY_PLUS, 'Cop&y Plus \tShift+Ctrl+C',
'Copy the selection - retaining prompts')
m.Append(ID_PASTE, '&Paste \tCtrl+V', 'Paste from clipboard')
m.Append(ID_PASTE_PLUS, 'Past&e Plus \tShift+Ctrl+V',
'Paste and run commands')
m.AppendSeparator()
m.Append(ID_CLEAR, 'Cle&ar',
'Delete the selection')
m.Append(ID_SELECTALL, 'Select A&ll \tCtrl+A',
'Select all text')
m = self.autocompMenu = wx.Menu()
m.Append(ID_AUTOCOMP_SHOW, 'Show Auto Completion',
'Show auto completion list', wx.ITEM_CHECK)
m.Append(ID_AUTOCOMP_MAGIC, 'Include Magic Attributes',
'Include attributes visible to __getattr__ and __setattr__',
wx.ITEM_CHECK)
m.Append(ID_AUTOCOMP_SINGLE, 'Include Single Underscores',
'Include attibutes prefixed by a single underscore', wx.ITEM_CHECK)
m.Append(ID_AUTOCOMP_DOUBLE, 'Include Double Underscores',
'Include attibutes prefixed by a double underscore', wx.ITEM_CHECK)
m = self.calltipsMenu = wx.Menu()
m.Append(ID_CALLTIPS_SHOW, 'Show Call Tips',
'Show call tips with argument signature and docstring', wx.ITEM_CHECK)
m = self.optionsMenu = wx.Menu()
m.AppendMenu(ID_AUTOCOMP, '&Auto Completion', self.autocompMenu,
'Auto Completion Options')
m.AppendMenu(ID_CALLTIPS, '&Call Tips', self.calltipsMenu,
'Call Tip Options')
m.Append(ID_WRAP, '&Wrap Lines',
'Wrap lines at right edge', wx.ITEM_CHECK)
if wx.Platform == "__WXMAC__":
m.Append(ID_USEAA, '&Use AntiAliasing',
'Use anti-aliased fonts', wx.ITEM_CHECK)
m = self.helpMenu = wx.Menu()
m.AppendSeparator()
m.Append(ID_ABOUT, '&About...', 'About this program')
b = self.menuBar = wx.MenuBar()
b.Append(self.fileMenu, '&File')
b.Append(self.editMenu, '&Edit')
b.Append(self.optionsMenu, '&Options')
b.Append(self.helpMenu, '&Help')
self.SetMenuBar(b)
wx.EVT_MENU(self, ID_NEW, self.OnFileNew)
wx.EVT_MENU(self, ID_OPEN, self.OnFileOpen)
wx.EVT_MENU(self, ID_REVERT, self.OnFileRevert)
wx.EVT_MENU(self, ID_CLOSE, self.OnFileClose)
wx.EVT_MENU(self, ID_SAVE, self.OnFileSave)
wx.EVT_MENU(self, ID_SAVEAS, self.OnFileSaveAs)
wx.EVT_MENU(self, ID_NAMESPACE, self.OnFileUpdateNamespace)
wx.EVT_MENU(self, ID_PRINT, self.OnFilePrint)
wx.EVT_MENU(self, ID_EXIT, self.OnExit)
wx.EVT_MENU(self, ID_UNDO, self.OnUndo)
wx.EVT_MENU(self, ID_REDO, self.OnRedo)
wx.EVT_MENU(self, ID_CUT, self.OnCut)
wx.EVT_MENU(self, ID_COPY, self.OnCopy)
wx.EVT_MENU(self, ID_COPY_PLUS, self.OnCopyPlus)
wx.EVT_MENU(self, ID_PASTE, self.OnPaste)
wx.EVT_MENU(self, ID_PASTE_PLUS, self.OnPastePlus)
wx.EVT_MENU(self, ID_CLEAR, self.OnClear)
wx.EVT_MENU(self, ID_SELECTALL, self.OnSelectAll)
wx.EVT_MENU(self, ID_ABOUT, self.OnAbout)
wx.EVT_MENU(self, ID_AUTOCOMP_SHOW, self.OnAutoCompleteShow)
wx.EVT_MENU(self, ID_AUTOCOMP_MAGIC, self.OnAutoCompleteMagic)
wx.EVT_MENU(self, ID_AUTOCOMP_SINGLE, self.OnAutoCompleteSingle)
wx.EVT_MENU(self, ID_AUTOCOMP_DOUBLE, self.OnAutoCompleteDouble)
wx.EVT_MENU(self, ID_CALLTIPS_SHOW, self.OnCallTipsShow)
wx.EVT_MENU(self, ID_WRAP, self.OnWrap)
wx.EVT_MENU(self, ID_USEAA, self.OnUseAA)
wx.EVT_UPDATE_UI(self, ID_NEW, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_OPEN, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_REVERT, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_CLOSE, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_SAVE, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_SAVEAS, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_NAMESPACE, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_PRINT, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_UNDO, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_REDO, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_CUT, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_COPY, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_COPY_PLUS, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_PASTE, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_PASTE_PLUS, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_CLEAR, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_SELECTALL, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_AUTOCOMP_SHOW, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_AUTOCOMP_MAGIC, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_AUTOCOMP_SINGLE, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_AUTOCOMP_DOUBLE, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_CALLTIPS_SHOW, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_WRAP, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_USEAA, self.OnUpdateMenu)
def OnFileNew(self, event):
self.bufferNew()
def OnFileOpen(self, event):
self.bufferOpen()
def OnFileRevert(self, event):
self.bufferRevert()
def OnFileClose(self, event):
self.bufferClose()
def OnFileSave(self, event):
self.bufferSave()
def OnFileSaveAs(self, event):
self.bufferSaveAs()
def OnFileUpdateNamespace(self, event):
self.updateNamespace()
def OnFilePrint(self, event):
self.bufferPrint()
def OnExit(self, event):
self.Close(False)
def OnUndo(self, event):
win = wx.Window_FindFocus()
win.Undo()
def OnRedo(self, event):
win = wx.Window_FindFocus()
win.Redo()
def OnCut(self, event):
win = wx.Window_FindFocus()
win.Cut()
def OnCopy(self, event):
win = wx.Window_FindFocus()
win.Copy()
def OnCopyPlus(self, event):
win = wx.Window_FindFocus()
win.CopyWithPrompts()
def OnPaste(self, event):
win = wx.Window_FindFocus()
win.Paste()
def OnPastePlus(self, event):
win = wx.Window_FindFocus()
win.PasteAndRun()
def OnClear(self, event):
win = wx.Window_FindFocus()
win.Clear()
def OnSelectAll(self, event):
win = wx.Window_FindFocus()
win.SelectAll()
def OnAbout(self, event):
"""Display an About window."""
title = 'About'
text = 'Your message here.'
dialog = wx.MessageDialog(self, text, title,
wx.OK | wx.ICON_INFORMATION)
dialog.ShowModal()
dialog.Destroy()
def OnAutoCompleteShow(self, event):
win = wx.Window_FindFocus()
win.autoComplete = event.IsChecked()
def OnAutoCompleteMagic(self, event):
win = wx.Window_FindFocus()
win.autoCompleteIncludeMagic = event.IsChecked()
def OnAutoCompleteSingle(self, event):
win = wx.Window_FindFocus()
win.autoCompleteIncludeSingle = event.IsChecked()
def OnAutoCompleteDouble(self, event):
win = wx.Window_FindFocus()
win.autoCompleteIncludeDouble = event.IsChecked()
def OnCallTipsShow(self, event):
win = wx.Window_FindFocus()
win.autoCallTip = event.IsChecked()
def OnWrap(self, event):
win = wx.Window_FindFocus()
win.SetWrapMode(event.IsChecked())
def OnUseAA(self, event):
win = wx.Window_FindFocus()
win.SetUseAntiAliasing(event.IsChecked())
def OnUpdateMenu(self, event):
"""Update menu items based on current status and context."""
win = wx.Window_FindFocus()
id = event.GetId()
event.Enable(True)
try:
if id == ID_NEW:
event.Enable(hasattr(self, 'bufferNew'))
elif id == ID_OPEN:
event.Enable(hasattr(self, 'bufferOpen'))
elif id == ID_REVERT:
event.Enable(hasattr(self, 'bufferRevert')
and self.hasBuffer())
elif id == ID_CLOSE:
event.Enable(hasattr(self, 'bufferClose')
and self.hasBuffer())
elif id == ID_SAVE:
event.Enable(hasattr(self, 'bufferSave')
and self.bufferHasChanged())
elif id == ID_SAVEAS:
event.Enable(hasattr(self, 'bufferSaveAs')
and self.hasBuffer())
elif id == ID_NAMESPACE:
event.Enable(hasattr(self, 'updateNamespace')
and self.hasBuffer())
elif id == ID_PRINT:
event.Enable(hasattr(self, 'bufferPrint')
and self.hasBuffer())
elif id == ID_UNDO:
event.Enable(win.CanUndo())
elif id == ID_REDO:
event.Enable(win.CanRedo())
elif id == ID_CUT:
event.Enable(win.CanCut())
elif id == ID_COPY:
event.Enable(win.CanCopy())
elif id == ID_COPY_PLUS:
event.Enable(win.CanCopy() and hasattr(win, 'CopyWithPrompts'))
elif id == ID_PASTE:
event.Enable(win.CanPaste())
elif id == ID_PASTE_PLUS:
event.Enable(win.CanPaste() and hasattr(win, 'PasteAndRun'))
elif id == ID_CLEAR:
event.Enable(win.CanCut())
elif id == ID_SELECTALL:
event.Enable(hasattr(win, 'SelectAll'))
elif id == ID_AUTOCOMP_SHOW:
event.Check(win.autoComplete)
elif id == ID_AUTOCOMP_MAGIC:
event.Check(win.autoCompleteIncludeMagic)
elif id == ID_AUTOCOMP_SINGLE:
event.Check(win.autoCompleteIncludeSingle)
elif id == ID_AUTOCOMP_DOUBLE:
event.Check(win.autoCompleteIncludeDouble)
elif id == ID_CALLTIPS_SHOW:
event.Check(win.autoCallTip)
elif id == ID_WRAP:
event.Check(win.GetWrapMode())
elif id == ID_USEAA:
event.Check(win.GetUseAntiAliasing())
else:
event.Enable(False)
except AttributeError:
# This menu option is not supported in the current context.
event.Enable(False)

72
wxPython/wx/py/images.py Normal file
View File

@@ -0,0 +1,72 @@
"""Support for icons."""
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
import wx
import cStringIO
def getPyIcon():
icon = wx.EmptyIcon()
icon.CopyFromBitmap(getPyBitmap())
return icon
def getPyBitmap():
return wx.BitmapFromImage(getPyImage())
def getPyImage():
stream = cStringIO.StringIO(getPyData())
return wx.ImageFromStream(stream)
def getPyData():
return \
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\
\x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\x04\
\x95IDATx\x9c\xed\x97?lSG\x1c\xc7?\x97\x98\xd8Q\xa3\xdeY\xa2j\x06\xa4\xf7"QJ\
\xbb<3@\x01\xa9\xc2\x0c\xa8!\x1d\x1c6\xcaB\xa8D[uI2\xf4\x8f\xe8\x103\xb4\xa2\
,5\x0b\x03\x032C\xab\xc0\x92dh:t\xc0)*E\xcd@<Q\x01Rl\t\xd4D\xaa\xe4{R\xd0{&\
\xa5\xd7\xe1\xfc\xec\xe7\xfciR\x08e\xe9O\xb2\xee|\xfe\xbd\xfb}~\xdf\xdf\xbd\
\xbb\xb3PJ\xf1"\xad\xe3\x85F\xff\x1f\xe0y\x03h\xad\xcdA\xc7~\xb4\xd6f-\x9f\
\xc4\xf3\x0c>Y\x1c#\x97\xddCUk\xf4B\x8d3\x9f\x8d\x9a\x9bU%\xe2~b\xab\xdf\x82\
\x83N+\xd3\xe92\\\x1f\xcf\x93\xdd\x9f\xa1\xaa5\x95\xf9\n\xe7\xf3y\xe2\x10[V\
\x82H\xe6\xd3G\x1dN\xf7\xc3\xa7\xc7a\xc0\x83\xc3\xc7\xf3\xcc\xcc\xcd\xe3(\
\x85\xdb\xe7\xf2\xc9\xe8X\x1b\xe43+\x10\xd5\xb6\x94\x87Z\xe8\x90NU\x91I@\x00\
\x06\xbe\x18\xb7J\x98\xca$`\x98\xb9]&{,\x8fRV\x85\xa7V@k\x9bq)o\x83+\t\xe9T\
\xd5f\x95\x02\x91\xb4~_\r\xd9\xb6\xbaP\x03\x04n\x9f\xcbDa\xb8\t\xfe\xaf\x17a\
<\xe3\xc8\x94lo\x9b\xd6\xa8\xf4\x80\x07\xb7o\xcd\xe0\x0c\x0e\xa2R\x8a\xb4\
\x93n\xbal\x1a`e\xe0U\xc1\xd6\xb0\xb8\n\x99\x91"\x93\xaf\xba\xe4\x0ed\xda|6,\
\x81\xd6\xda\x9c|\xab]\xea\xcd\x04\x8f\x9b\t\xad\nz\xa1\x02\x80\xdb\xe7R\x1a\
\xcf\xa3\xb56\xeb\x02D5\x9e\xf8\xdc\xe1T\xff\xd3\x05\x8e\x82\x83U\xe1Z\xb1\
\x18\x9b\xbf\x06\xacQ\x82H\xea\x01/Z@Ut\x08R\xb4$}\x16\xd3\x81A&%\xde\xee\
\xbev\x80x\xe0]{\xb2\x1cR\xa5\xe6C*\xb5\xf1\xc4Q\xa6"e\xfbQ\x1b\x8dE\xe6\x87\
>\xaa[Q\xadi\x0b\xb0r\x8f\x9e.\xc3t\xb9\xc4]\xaf5\xf6\xfe\xdb\xddt&\x02\xfa\
\x9c\xf5\x01\xe2A\xa2\xbeX\x01>]ntR\x12\xe3[\x00\x01\x98\x89\x11[_\xed\xafn\
\xab\x81U\xa0\xe7I7\x00\x97o\x04\xcd\x89\x06<;\xe9\x80\x07]i\x97\xc17\x1f\
\xd2\xd3\x91`\xe9\xaf?\x01p^Y\x06Z\n\xfau8?a\xfb]i\x97\xec\xa1\x8c\x05(|\xd8\
N\xba\xb3\xab\x87\xfb\x8f\x97\xd8\xd9\xd5\x03\xc0\xfd\xc7K\xec\xd8\xd6\xdd\
\xfc\xfd\xc1r\xd0\xf4\x01\xda~\x03H\xf4\x04\xd4j :\xb75\xc7\xae\xfd\xbcLW\
\xda\xa5\xf0M\x1e\t\xcc\xcc\xcdq\xa9P@\x8c\xf5fL\xdaHF\x16g\x9a\x19\xad\xcc\
\xee\xcb\xa3\n\xad\xa1\xda\xf1\x08\xef\xe5\x97x\xf8\xc8f\xf8\xc7\x93:\xdb;\
\x93M\xc8\x08j\xc7\xb6n\x1e,\x07m`\x97o\x04|;>\xd1T\xc4\x17\x8a\x13\xb9\xc3\
\x88\x01\x0fs\xa4\x9cc}\xf3A\x190\x82\x1f\xddR{-\x1bV\xfc\xd8f\xba\xbd3\xd9\
\x06\x15\x07\xbb\xf8\xd3\x12\xdf]-"\x93\xb2\xb1C*\xde\xcd\x1d\xde\xccN(\xc1\
\xae\x17"\xd0#+<j\x17m{\xcd\x9bj\x00.\xaf\xf0Xb\xb8\xdfA\xa6\x14\x18\x03\x06\
\xb4o\xcf\x8d\xc4\xbervc\x86M\xdaz\x80\x00\x95T\x19?\xd0 @&%~c\xbc\xe3W\xaf\
\xb4e\x00\xffh\xc6@\xbd\x11\xbc\xde\x1a\xfe\xef.\xa5\xa2q4\n0\x81\xad\xe9\
\xae7<\x12\xaf\xf5\xc2hy\xaa\xe97\x9cS\\\x98\xb2\x0e\x03\xb1\xcdhW\xdaC\x1a\
\xa0\xa2\xa0\x0e"\x14`\xb0Y\x85\x1b\x1f\x12\xaa7\x03)\xd9\x84\xa8\xccW\xb8{\
\xa7L\xe2\xde\x02\x94\xc6Gp_\xcf\x80\x90\x98\xd0g\xf4\xac\x82Pc\x82\x1a\xd5\
\x10\x08}&\xa7J\xcc\xde.1]m\x80\xf6+\xee\xfd\xae\x9bo\xc4\xf0;\x80\xef\x90\
\x0e\x04\x06`Q!\x02\x05\xc2 \xb5\xc2\x95\x15d\xb4C&[\xf7\xd2\x04\x80\xbb\xdb\
\x9e\xd1\x8e\x02\x90\xd8\xd4$ I\x87\x80\xf1\xf1\xdc!4\xc3\x88\x94}\xd8,TH\
\xbb.5m\xf0C\x9f3\x1f\r\x01\x96.\x82\x1a9\xe9Q\xb8\xd2\xf8\xf25\x0c\xbe\xe7#\
\x92\x12\x1d[\x03\t\x00E\xf4\xa6\t\xaaZ7`$\x18\x90\xf8\xf8\x80JK\x94\xa1\x01\
\x07\xb8\x0e~X\xc3\xed\x16\xf8)\xf8~j\x12B\rI\x89_\xf7!0 \x04\xf9Q\xc0\x18\
\x0c\xd1i\xea\x13\xb7\x04\xc0\x89\x93C\xabj\xb6\xf7@\x96\xd9_J|0:\x86R\n\xb7\
\xd7@\xaa%\x9d\xa3$\xba.\x90RA]\xe3\x87\x1a\x89\xdd\xefeR\xc2\x1a\'\xa8\x1f\
\x82\x0e-@m\xd1\xde\x076\xbc\x15\x97~(\x9a\x89b\x9e\xd9[s\xab!\xf7g\xd6\x1c\
\x8f\xdb\xbel\x8e\xa1S\xc7\xda\xc6\xe6\xee\xccs\xe9\xdcYnV\x95\xd8\xf2?&q+\
\x9c\x1b1\xf3\xbf\xcd3{\xfdJ\xdb\xf8\xde\xfd\x19.\\\xad\x08\x80\xbf\x01\xd1\
\x86\xfa\x8b\xc7\xc0\xc8\xb7\x00\x00\x00\x00IEND\xaeB`\x82'

View File

@@ -0,0 +1,126 @@
"""Interpreter executes Python commands."""
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
import os
import sys
from code import InteractiveInterpreter
import dispatcher
import introspect
import wx
class Interpreter(InteractiveInterpreter):
"""Interpreter based on code.InteractiveInterpreter."""
revision = __revision__
def __init__(self, locals=None, rawin=None,
stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr):
"""Create an interactive interpreter object."""
InteractiveInterpreter.__init__(self, locals=locals)
self.stdin = stdin
self.stdout = stdout
self.stderr = stderr
if rawin:
import __builtin__
__builtin__.raw_input = rawin
del __builtin__
copyright = 'Type "help", "copyright", "credits" or "license"'
copyright += ' for more information.'
self.introText = 'Python %s on %s%s%s' % \
(sys.version, sys.platform, os.linesep, copyright)
try:
sys.ps1
except AttributeError:
sys.ps1 = '>>> '
try:
sys.ps2
except AttributeError:
sys.ps2 = '... '
self.more = 0
# List of lists to support recursive push().
self.commandBuffer = []
self.startupScript = os.environ.get('PYTHONSTARTUP')
def push(self, command):
"""Send command to the interpreter to be executed.
Because this may be called recursively, we append a new list
onto the commandBuffer list and then append commands into
that. If the passed in command is part of a multi-line
command we keep appending the pieces to the last list in
commandBuffer until we have a complete command. If not, we
delete that last list."""
# In case the command is unicode try encoding it
if type(command) == unicode:
try:
command = command.encode(wx.GetDefaultPyEncoding())
except UnicodeEncodeError:
pass # otherwise leave it alone
if not self.more:
try: del self.commandBuffer[-1]
except IndexError: pass
if not self.more: self.commandBuffer.append([])
self.commandBuffer[-1].append(command)
source = '\n'.join(self.commandBuffer[-1])
more = self.more = self.runsource(source)
dispatcher.send(signal='Interpreter.push', sender=self,
command=command, more=more, source=source)
return more
def runsource(self, source):
"""Compile and run source code in the interpreter."""
stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr
sys.stdin, sys.stdout, sys.stderr = \
self.stdin, self.stdout, self.stderr
more = InteractiveInterpreter.runsource(self, source)
# If sys.std* is still what we set it to, then restore it.
# But, if the executed source changed sys.std*, assume it was
# meant to be changed and leave it. Power to the people.
if sys.stdin == self.stdin:
sys.stdin = stdin
if sys.stdout == self.stdout:
sys.stdout = stdout
if sys.stderr == self.stderr:
sys.stderr = stderr
return more
def getAutoCompleteKeys(self):
"""Return list of auto-completion keycodes."""
return [ord('.')]
def getAutoCompleteList(self, command='', *args, **kwds):
"""Return list of auto-completion options for a command.
The list of options will be based on the locals namespace."""
stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr
sys.stdin, sys.stdout, sys.stderr = \
self.stdin, self.stdout, self.stderr
l = introspect.getAutoCompleteList(command, self.locals,
*args, **kwds)
sys.stdin, sys.stdout, sys.stderr = stdin, stdout, stderr
return l
def getCallTip(self, command='', *args, **kwds):
"""Return call tip text for a command.
Call tip information will be based on the locals namespace."""
return introspect.getCallTip(command, self.locals, *args, **kwds)
class InterpreterAlaCarte(Interpreter):
"""Demo Interpreter."""
def __init__(self, locals, rawin, stdin, stdout, stderr,
ps1='main prompt', ps2='continuation prompt'):
"""Create an interactive interpreter object."""
Interpreter.__init__(self, locals=locals, rawin=rawin,
stdin=stdin, stdout=stdout, stderr=stderr)
sys.ps1 = ps1
sys.ps2 = ps2

View File

@@ -0,0 +1,382 @@
"""Provides a variety of introspective-type support functions for
things like call tips and command auto completion."""
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
from __future__ import nested_scopes
import cStringIO
import inspect
import sys
import tokenize
import types
import wx
def getAutoCompleteList(command='', locals=None, includeMagic=1,
includeSingle=1, includeDouble=1):
"""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:
if locals is not None:
object = eval(root, locals)
else:
object = eval(root)
except:
pass
else:
attributes = getAttributeNames(object, includeMagic,
includeSingle, includeDouble)
return attributes
def getAttributeNames(object, includeMagic=1, includeSingle=1,
includeDouble=1):
"""Return list of unique attributes, including inherited, for object."""
attributes = []
dict = {}
if not hasattrAlwaysReturnsTrue(object):
# Add some attributes that don't always get picked up.
special_attrs = ['__bases__', '__class__', '__dict__', '__name__',
'func_closure', 'func_code', 'func_defaults',
'func_dict', 'func_doc', 'func_globals', 'func_name']
attributes += [attr for attr in special_attrs \
if hasattr(object, attr)]
if includeMagic:
try: attributes += object._getAttributeNames()
except: pass
# Get all attribute names.
str_type = str(type(object))
if str_type == "<type 'array'>":
attributes += dir(object)
else:
attrdict = getAllAttributeNames(object)
# Store the object's dir.
object_dir = dir(object)
for (obj_type_name, technique, count), attrlist in attrdict.items():
# This complexity is necessary to avoid accessing all the
# attributes of the object. This is very handy for objects
# whose attributes are lazily evaluated.
if type(object).__name__ == obj_type_name and technique == 'dir':
attributes += attrlist
else:
attributes += [attr for attr in attrlist \
if attr not in object_dir and hasattr(object, attr)]
# Remove duplicates from the attribute list.
for item in attributes:
dict[item] = None
attributes = dict.keys()
# new-style swig wrappings can result in non-string attributes
# e.g. ITK http://www.itk.org/
attributes = [attribute for attribute in attributes \
if type(attribute) == str]
attributes.sort(lambda x, y: cmp(x.upper(), y.upper()))
if not includeSingle:
attributes = filter(lambda item: item[0]!='_' \
or item[1]=='_', attributes)
if not includeDouble:
attributes = filter(lambda item: item[:2]!='__', attributes)
return attributes
def hasattrAlwaysReturnsTrue(object):
return hasattr(object, 'bogu5_123_aTTri8ute')
def getAllAttributeNames(object):
"""Return dict 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().
# !!!
try:
# This could(?) fail if the type is poorly defined without
# even a name.
key = type(object).__name__
except:
key = 'anonymous'
# 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)
attrdict[(key, 'dir', len(attributes))] = attributes
# Get attributes from the object's dictionary, if it has one.
try:
attributes = object.__dict__.keys()
attributes.sort()
except: # Must catch all because object might have __getattr__.
pass
else:
attrdict[(key, '__dict__', len(attributes))] = attributes
# For a class instance, get the attributes for the class.
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:
attrdict.update(getAllAttributeNames(klass))
# Also get attributes from any and all parent classes.
try:
bases = object.__bases__
except: # Must catch all because object might have __getattr__.
pass
else:
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:
attrdict.update(getAllAttributeNames(base))
return attrdict
def getCallTip(command='', locals=None):
"""For a command, return a tuple of object name, argspec, tip text.
The call tip information will be based on the locals namespace."""
calltip = ('', '', '') # object name, argspec, tip text.
# Get the proper chunk of code from the command.
root = getRoot(command, terminator='(')
try:
if locals is not None:
object = eval(root, locals)
else:
object = eval(root)
except:
return calltip
name = ''
object, dropSelf = getBaseObject(object)
try:
name = object.__name__
except AttributeError:
pass
tip1 = ''
argspec = ''
if inspect.isbuiltin(object):
# Builtin functions don't have an argspec that we can get.
pass
elif inspect.isfunction(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 an
# instance, usually coded as "self", and is usually passed
# automatically by Python; therefore we want to drop it.
temp = argspec.split(',')
if len(temp) == 1: # No other arguments.
argspec = '()'
elif temp[0][:2] == '(*': # first param is like *args, not self
pass
else: # Drop the first argument.
argspec = '(' + ','.join(temp[1:]).lstrip()
tip1 = name + argspec
doc = ''
if callable(object):
try:
doc = inspect.getdoc(object)
except:
pass
if doc:
# tip2 is the first separated line of the docstring, like:
# "Return call tip text for a command."
# tip3 is the rest of the docstring, like:
# "The call tip information will be based on ... <snip>
firstline = doc.split('\n')[0].lstrip()
if tip1 == firstline or firstline[:len(name)+1] == name+'(':
tip1 = ''
else:
tip1 += '\n\n'
docpieces = doc.split('\n\n')
tip2 = docpieces[0]
tip3 = '\n\n'.join(docpieces[1:])
tip = '%s%s\n\n%s' % (tip1, tip2, tip3)
else:
tip = tip1
calltip = (name, argspec[1:-1], tip.strip())
return calltip
def getRoot(command, terminator=None):
"""Return the rightmost root portion of an arbitrary Python command.
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."""
command = command.split('\n')[-1]
if command.startswith(sys.ps2):
command = command[len(sys.ps2):]
command = command.lstrip()
command = rtrimTerminus(command, terminator)
tokens = getTokens(command)
if not tokens:
return ''
if tokens[-1][0] is tokenize.ENDMARKER:
# Remove the end marker.
del tokens[-1]
if not tokens:
return ''
if terminator == '.' and \
(tokens[-1][1] <> '.' or tokens[-1][0] is not tokenize.OP):
# Trap decimals in numbers, versus the dot operator.
return ''
else:
# Strip off the terminator.
if terminator and command.endswith(terminator):
size = 0 - len(terminator)
command = command[:size]
command = command.rstrip()
tokens = getTokens(command)
tokens.reverse()
line = ''
start = None
prefix = ''
laststring = '.'
emptyTypes = ('[]', '()', '{}')
for token in tokens:
tokentype = token[0]
tokenstring = token[1]
line = token[4]
if tokentype is tokenize.ENDMARKER:
continue
if tokentype in (tokenize.NAME, tokenize.STRING, tokenize.NUMBER) \
and laststring != '.':
# We've reached something that's not part of the root.
if prefix and line[token[3][1]] != ' ':
# If it doesn't have a space after it, remove the prefix.
prefix = ''
break
if tokentype in (tokenize.NAME, tokenize.STRING, tokenize.NUMBER) \
or (tokentype is tokenize.OP and tokenstring == '.'):
if prefix:
# The prefix isn't valid because it comes after a dot.
prefix = ''
break
else:
# start represents the last known good point in the line.
start = token[2][1]
elif len(tokenstring) == 1 and tokenstring in ('[({])}'):
# Remember, we're working backwords.
# So prefix += tokenstring would be wrong.
if prefix in emptyTypes and tokenstring in ('[({'):
# We've already got an empty type identified so now we
# are in a nested situation and we can break out with
# what we've got.
break
else:
prefix = tokenstring + prefix
else:
# We've reached something that's not part of the root.
break
laststring = tokenstring
if start is None:
start = len(line)
root = line[start:]
if prefix in emptyTypes:
# Empty types are safe to be eval()'d and introspected.
root = prefix + root
return root
def getTokens(command):
"""Return list of token tuples for command."""
# In case the command is unicode try encoding it
if type(command) == unicode:
try:
command = command.encode(wx.GetDefaultPyEncoding())
except UnicodeEncodeError:
pass # otherwise leave it alone
f = cStringIO.StringIO(command)
# tokens is a list of token tuples, each looking like:
# (type, string, (srow, scol), (erow, ecol), line)
tokens = []
# Can't use list comprehension:
# tokens = [token for token in tokenize.generate_tokens(f.readline)]
# because of need to append as much as possible before TokenError.
try:
## This code wasn't backward compatible with Python 2.1.3.
##
## for token in tokenize.generate_tokens(f.readline):
## tokens.append(token)
# This works with Python 2.1.3 (with nested_scopes).
def eater(*args):
tokens.append(args)
tokenize.tokenize_loop(f.readline, eater)
except tokenize.TokenError:
# This is due to a premature EOF, which we expect since we are
# feeding in fragments of Python code.
pass
return tokens
def rtrimTerminus(command, terminator=None):
"""Return command minus anything that follows the final terminator."""
if terminator:
pieces = command.split(terminator)
if len(pieces) > 1:
command = terminator.join(pieces[:-1]) + terminator
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

101
wxPython/wx/py/pseudo.py Normal file
View File

@@ -0,0 +1,101 @@
"""Provides a variety of classes to create pseudo keywords and pseudo files."""
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
class PseudoKeyword:
"""A callable class that calls a method passed as a parameter.
Good for creating a pseudo keyword in the python runtime
environment. The keyword is really an object that has a repr()
that calls itself which calls the method that was passed in the
init of the object. All this just to avoid having to type in the
closing parens on a method. So, for example:
>>> quit = PseudoKeyword(SomeObject.someMethod)
>>> quit
SomeObject.someMethod gets executed as if it had been called
directly and the user didn't have to type the parens, like
'quit()'. This technique is most applicable for pseudo keywords
like quit, exit and help.
If SomeObject.someMethod can take parameters, they can still be
passed by using the keyword in the traditional way with parens."""
def __init__(self, method):
"""Create a callable object that executes method when called."""
if callable(method):
self.method = method
else:
raise ValueError, 'method must be callable'
def __call__(self, *args, **kwds):
self.method(*args, **kwds)
def __repr__(self):
self()
return ''
class PseudoFile:
def __init__(self):
"""Create a file-like object."""
pass
def readline(self):
pass
def write(self, s):
pass
def writelines(self, l):
map(self.write, l)
def flush(self):
pass
def isatty(self):
pass
class PseudoFileIn(PseudoFile):
def __init__(self, readline, readlines=None):
if callable(readline):
self.readline = readline
else:
raise ValueError, 'readline must be callable'
if callable(readlines):
self.readlines = readlines
def isatty(self):
return 1
class PseudoFileOut(PseudoFile):
def __init__(self, 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):
if callable(write):
self.write = write
else:
raise ValueError, 'write must be callable'
def isatty(self):
return 1

1036
wxPython/wx/py/shell.py Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,82 @@
#!/usr/bin/env python
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
import unittest
# Import from this module's parent directory.
import os
import sys
sys.path.insert(0, os.pardir)
import interpreter
del sys.path[0]
del sys
del os
"""
These unittest methods are preferred:
-------------------------------------
self.assert_(expr, msg=None)
self.assertEqual(first, second, msg=None)
self.assertRaises(excClass, callableObj, *args, **kwargs)
self.fail(msg=None)
self.failIf(expr, msg=None)
"""
class ModuleTestCase(unittest.TestCase):
def test_module(self):
module = interpreter
self.assert_(module.__author__)
self.assert_(module.__cvsid__)
self.assert_(module.__revision__)
self.assert_(module.Interpreter)
self.assert_(module.Interpreter.push)
self.assert_(module.Interpreter.runsource)
self.assert_(module.Interpreter.getAutoCompleteList)
self.assert_(module.Interpreter.getCallTip)
self.assert_(module.InterpreterAlaCarte)
class InterpreterTestCase(unittest.TestCase):
def setUp(self):
self.output = ''
self.i = interpreter.Interpreter(stdout=self)
def write(self, text):
"""Capture output from self.i.push()."""
self.output += text
def tearDown(self):
self.output = ''
self.i = None
del self.i
def test_more(self):
self.assertEqual(self.i.push('dir()'), 0)
self.assertEqual(self.i.push('for n in range(3):'), 1)
def test_push(self):
values = (
('dir', '<built-in function dir>'),
('dir()', "['__builtins__', '__doc__', '__name__']"),
('2 + 2', '4'),
('d = {}', ''),
('d', '{}'),
('del d', ''),
('len([4,5,6])', '3'),
)
for input, output in values:
if output: output += '\n'
self.i.push(input)
self.assertEqual(self.output, output)
self.output = ''
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,862 @@
#!/usr/bin/env python
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
import unittest
# Import from this module's parent directory.
import os
import sys
sys.path.insert(0, os.pardir)
import introspect
del sys.path[0]
del sys
del os
"""
These unittest methods are preferred:
-------------------------------------
self.assert_(expr, msg=None)
self.assertEqual(first, second, msg=None)
self.assertRaises(excClass, callableObj, *args, **kwargs)
self.fail(msg=None)
self.failIf(expr, msg=None)
"""
class ModuleTestCase(unittest.TestCase):
def test_module(self):
module = introspect
self.assert_(module.__author__)
self.assert_(module.__cvsid__)
self.assert_(module.__revision__)
self.assert_(module.getAllAttributeNames)
self.assert_(module.getAttributeNames)
self.assert_(module.getAutoCompleteList)
self.assert_(module.getBaseObject)
self.assert_(module.getCallTip)
self.assert_(module.getConstructor)
self.assert_(module.getRoot)
self.assert_(module.rtrimTerminus)
class RtrimTerminusTestCase(unittest.TestCase):
def test_rtrimTerminus(self):
values = (
('', '', ''),
('', None, ''),
('', '.', ''),
('', '(', ''),
('.', '', '.'),
('.', None, '.'),
('.', '.', '.'),
('.', '(', '.'),
('(', '', '('),
('(', None, '('),
('(', '.', '('),
('(', '(', '('),
('spam', '', 'spam'),
('spam', None, 'spam'),
('spam', '.', 'spam'),
('spam', '(', 'spam'),
('spam.', '', 'spam.'),
('spam.', None, 'spam.'),
('spam.', '.', 'spam.'),
('spam.', '(', 'spam.'),
('spam(', '', 'spam('),
('spam(', None, 'spam('),
('spam(', '.', 'spam('),
('spam(', '(', 'spam('),
('spam.eggs', '.', 'spam.'),
('spam.eggs.', '.', 'spam.eggs.'),
('spam.eggs(', '(', 'spam.eggs('),
('spam.eggs.', '(', 'spam.eggs.'),
('spam.eggs(', '.', 'spam.'),
('x = spam.', '.', 'x = spam.'),
('x = spam.eggs', '.', 'x = spam.'),
('x = spam.eggs.', '.', 'x = spam.eggs.'),
('x = spam.eggs(', '(', 'x = spam.eggs('),
)
for input, terminator, output in values:
result = introspect.rtrimTerminus(input, terminator)
self.assertEqual(result, output,
':in: %r :t: %r :out: %r :result: %r' %
(input, terminator, output, result))
class GetRootTestCase(unittest.TestCase):
def _checkRoot(self, input, terminator, output):
root = introspect.getRoot(command=input, terminator=terminator)
self.assertEqual(root, output,
':in: %r :t: %r :out: %r :root: %r' %
(input, terminator, output, root))
def test_getRoot(self):
values = (
('', '', ''),
('', None, ''),
('', '.', ''),
('', '(', ''),
('.', '', '.'),
('.', None, '.'),
('.', '.', ''),
('.', '(', '.'),
('(', '', ''),
('(', None, ''),
('(', '.', ''),
('(', '(', ''),
('spam', '', 'spam'),
('spam', None, 'spam'),
('spam', '.', ''),
('spam', '(', 'spam'),
('spam.', '', 'spam.'),
('spam.', None, 'spam.'),
('spam.', '.', 'spam'),
('spam.', '(', 'spam.'),
('spam(', '', ''),
('spam(', None, ''),
('spam(', '.', ''),
('spam(', '(', 'spam'),
('spam.eggs', '.', 'spam'),
('spam.eggs.', '.', 'spam.eggs'),
('spam.eggs(', '(', 'spam.eggs'),
('spam.eggs.', '(', 'spam.eggs.'),
('spam.eggs(', '.', 'spam'),
('x = spam.', '.', 'spam'),
('x = spam.eggs', '.', 'spam'),
('x = spam.eggs.', '.', 'spam.eggs'),
('x = spam.eggs(', '(', 'spam.eggs'),
('for n in range(3):\n d.', '.', 'd'),
('for n in range(3):\n... d.', '.', 'd'),
)
for input, terminator, output in values:
self._checkRoot(input, terminator, output)
def test_getRoot_Advanced(self):
values = (
('spam_', '', 'spam_'),
('spam_', None, 'spam_'),
('spam_', '.', ''),
('spam_', '(', 'spam_'),
('_spam', '', '_spam'),
('_spam', None, '_spam'),
('_spam', '.', ''),
('_spam', '(', '_spam'),
('spam_eggs', '', 'spam_eggs'),
('spam_eggs', None, 'spam_eggs'),
('spam_eggs', '.', ''),
('spam_eggs', '(', 'spam_eggs'),
('spam123', '', 'spam123'),
('spam123', None, 'spam123'),
('spam123', '.', ''),
('spam123', '(', 'spam123'),
('spam_123', '', 'spam_123'),
('spam_123', None, 'spam_123'),
('spam_123', '.', ''),
('spam_123', '(', 'spam_123'),
)
for input, terminator, output in values:
self._checkRoot(input, terminator, output)
## The original intent was to detect when we were inside a string.
## That has proven to be very difficult, for little benefit.
## The fact that autocomplete or calltips might be triggered inside
## a string is not a big deal. Sometimes it is even helpful.
## def test_getRoot_InsideStrings(self):
## values = (
## ('x = ".', '.', ''),
## ("x = '.", '.', ''),
## ('x = """.', '.', ''),
## ("x = '''.", '.', ''),
##
## ('x = "(', '(', ''),
## ("x = '(", '(', ''),
## ('x = """(', '(', ''),
## ("x = '''(", '(', ''),
##
## ('x = "spam', '.', ''),
## ('x = "spam.', '.', ''),
## ("x = 'spam.", '.', ''),
## ('x = """spam.', '.', ''),
## ("x = '''spam.", '.', ''),
##
## ('x = "spam', '(', ''),
## ('x = "spam(', '(', ''),
## ("x = 'spam(", '(', ''),
## ('x = """spam(', '(', ''),
## ("x = '''spam(", '(', ''),
##
## ('x = "spam.eggs.', '.', ''),
## ("x = 'spam.eggs.", '.', ''),
## ('x = """spam.eggs.', '.', ''),
## ("x = '''spam.eggs.", '.', ''),
##
## ('x = "spam.eggs(', '(', ''),
## ("x = 'spam.eggs(", '(', ''),
## ('x = """spam.eggs(', '(', ''),
## ("x = '''spam.eggs(", '(', ''),
## )
## for input, terminator, output in values:
## self._checkRoot(input, terminator, output)
def test_getRoot_EmptyTypes(self):
values = (
("''.", '.', "''"),
('"".', '.', '""'),
('"""""".', '.', '""""""'),
("''''''.", '.', "''''''"),
('[].', '.', '[]'),
('().', '.', '()'),
('{}.', '.', '{}'),
('[](', '(', '[]'),
('()(', '(', '()'),
('{}(', '(', '{}'),
("x = ''.", '.', "''"),
('x = "".', '.', '""'),
('x = """""".', '.', '""""""'),
("x = ''''''.", '.', "''''''"),
('x = [].', '.', '[]'),
('x = ().', '.', '()'),
('x = {}.', '.', '{}'),
('x = [](', '(', '[]'),
('x = ()(', '(', '()'),
('x = {}(', '(', '{}'),
('print [].', '.', '[]'),
('print ().', '.', '()'),
('print {}.', '.', '{}'),
('print [](', '(', '[]'),
('print ()(', '(', '()'),
('print {}(', '(', '{}'),
("''.attr.", '.', "''.attr"),
('"".attr.', '.', '"".attr'),
('"""""".attr.', '.', '"""""".attr'),
("''''''.attr.", '.', "''''''.attr"),
('[].attr.', '.', '[].attr'),
('().attr.', '.', '().attr'),
('{}.attr.', '.', '{}.attr'),
('[].attr(', '(', '[].attr'),
('().attr(', '(', '().attr'),
('{}.attr(', '(', '{}.attr'),
('spam().', '.', ''),
('spam_().', '.', ''),
('spam5().', '.', ''),
('spam[]().', '.', ''),
('spam()[].', '.', ''),
('spam[]{}.', '.', ''),
("spam(''.", '.', "''"),
('spam("".', '.', '""'),
('spam("""""".', '.', '""""""'),
("spam(''''''.", '.', "''''''"),
('spam([].', '.', '[]'),
('spam(().', '.', '()'),
('spam({}.', '.', '{}'),
('spam[[].', '.', '[]'),
('spam[().', '.', '()'),
('spam[{}.', '.', '{}'),
('x = {[].', '.', '[]'),
('x = {().', '.', '()'),
('x = {{}.', '.', '{}'),
('spam,[].', '.', '[]'),
('spam+[].', '.', '[]'),
('spam-[].', '.', '[]'),
('spam*[].', '.', '[]'),
('spam/[].', '.', '[]'),
('spam=[].', '.', '[]'),
('spam%[].', '.', '[]'),
('spam<[].', '.', '[]'),
('spam>[].', '.', '[]'),
('spam&[].', '.', '[]'),
('spam|[].', '.', '[]'),
('spam^[].', '.', '[]'),
('spam~[].', '.', '[]'),
('spam:[].', '.', '[]'),
('spam,().', '.', '()'),
('spam+().', '.', '()'),
('spam-().', '.', '()'),
('spam*().', '.', '()'),
('spam/().', '.', '()'),
('spam=().', '.', '()'),
('spam%().', '.', '()'),
('spam<().', '.', '()'),
('spam>().', '.', '()'),
('spam&().', '.', '()'),
('spam|().', '.', '()'),
('spam^().', '.', '()'),
('spam~().', '.', '()'),
('spam:().', '.', '()'),
('spam,{}.', '.', '{}'),
('spam+{}.', '.', '{}'),
('spam-{}.', '.', '{}'),
('spam*{}.', '.', '{}'),
('spam/{}.', '.', '{}'),
('spam={}.', '.', '{}'),
('spam%{}.', '.', '{}'),
('spam<{}.', '.', '{}'),
('spam>{}.', '.', '{}'),
('spam&{}.', '.', '{}'),
('spam|{}.', '.', '{}'),
('spam^{}.', '.', '{}'),
('spam~{}.', '.', '{}'),
('spam:{}.', '.', '{}'),
)
for input, terminator, output in values:
self._checkRoot(input, terminator, output)
# Support for GetBaseObjectTestCase and GetAttributeNamesTestCase.
class Foo:
def __init__(self):
pass
def __del__(self):
pass
def _private(self):
pass
class Bar:
pass
class Spam:
def __call__(self):
pass
def foo(self):
pass
def bar(spam):
# It shouldn't matter what we call "self".
pass
def eggs(self):
pass
def ham(eggs):
pass
class GetBaseObjectTestCase(unittest.TestCase):
def test_getBaseObject(self):
spam = Spam()
eggs = Spam.eggs
listappend = [].append
spamda = lambda: None
values = (
('spam', 'spam', 0),
(123, 123, 0),
(12.3, 12.3, 0),
([], [], 0),
((), (), 0),
({}, {}, 0),
# Builtin function.
(len, len, 0),
# Builtin method.
(listappend, listappend, 0),
# User function.
(ham, ham, 0),
# Byte-compiled code.
(ham.func_code, ham.func_code, 0),
# Lambda.
(spamda, spamda, 0),
# Class with init.
(Foo, Foo.__init__.im_func, 1),
# Class with no init.
(Bar, Bar, 0),
# Bound method.
(spam.foo, spam.foo.im_func, 1),
# Bound method with self named something else (spam).
(spam.bar, spam.bar.im_func, 1),
# Unbound method. (Do not drop the self argument.)
(eggs, eggs.im_func, 0),
# Callable instance.
(spam, spam.__call__.im_func, 1),
)
for object, baseObject, dropSelf in values:
result = introspect.getBaseObject(object)
self.assertEqual(result, (baseObject, dropSelf))
class GetAttributeTestCase(unittest.TestCase):
"""Base class for other test case classes."""
def setUp(self):
self.values = (
'__abs__',
'__add__',
'__and__',
'__base__',
'__bases__',
'__basicsize__',
'__builtins__',
'__call__',
'__class__',
'__cmp__',
'__coerce__',
'__contains__',
'__del__',
'__delattr__',
'__delitem__',
'__delslice__',
'__dict__',
'__dictoffset__',
'__div__',
'__divmod__',
'__doc__',
'__eq__',
'__file__',
'__flags__',
'__float__',
'__floordiv__',
'__ge__',
'__get__',
'__getattr__',
'__getattribute__',
'__getitem__',
'__getslice__',
'__gt__',
'__hash__',
'__hex__',
'__iadd__',
'__imul__',
'__init__',
'__int__',
'__invert__',
'__itemsize__',
'__iter__',
'__le__',
'__len__',
'__long__',
'__lshift__',
'__lt__',
'__mod__',
'__module__',
'__mro__',
'__mul__',
'__name__',
'__ne__',
'__neg__',
'__new__',
'__nonzero__',
'__oct__',
'__or__',
'__path__',
'__pos__',
'__pow__',
'__radd__',
'__rand__',
'__rdiv__',
'__rdivmod__',
'__reduce__',
'__repr__',
'__rfloordiv__',
'__rlshift__',
'__rmod__',
'__rmul__',
'__ror__',
'__rpow__',
'__rrshift__',
'__rshift__',
'__rsub__',
'__rtruediv__',
'__rxor__',
'__self__',
'__setattr__',
'__setitem__',
'__setslice__',
'__str__',
'__sub__',
'__subclasses__',
'__truediv__',
'__warningregistry__',
'__weakrefoffset__',
'__xor__',
'append',
'capitalize',
'center',
'clear',
'close',
'closed',
'co_argcount',
'co_cellvars',
'co_code',
'co_consts',
'co_filename',
'co_firstlineno',
'co_flags',
'co_freevars',
'co_lnotab',
'co_name',
'co_names',
'co_nlocals',
'co_stacksize',
'co_varnames',
'conjugate',
'copy',
'count',
'decode',
'encode',
'endswith',
'expandtabs',
'extend',
'fileno',
'find',
'flush',
'func_closure',
'func_code',
'func_defaults',
'func_dict',
'func_doc',
'func_globals',
'func_name',
'get',
'has_key',
'im_class',
'im_func',
'im_self',
'imag',
'index',
'insert',
'isalnum',
'isalpha',
'isatty',
'isdigit',
'islower',
'isspace',
'istitle',
'isupper',
'items',
'iteritems',
'iterkeys',
'itervalues',
'join',
'keys',
'ljust',
'lower',
'lstrip',
'mode',
'mro',
'name',
'pop',
'popitem',
'real',
'read',
'readinto',
'readline',
'readlines',
'remove',
'replace',
'reverse',
'rfind',
'rindex',
'rjust',
'rstrip',
'seek',
'setdefault',
'softspace',
'sort',
'split',
'splitlines',
'start',
'startswith',
'step',
'stop',
'strip',
'swapcase',
'tell',
'title',
'tolist',
'translate',
'truncate',
'update',
'upper',
'values',
'write',
'writelines',
'xreadlines',
)
# Since getAllAttributeNames() calls str(object),
# we need to test for a broken __str__ method.
class BrokenStr:
def __str__(self):
raise Exception
brokenStr = BrokenStr()
class GetAttributeNamesTestCase(GetAttributeTestCase):
def setUp(self):
GetAttributeTestCase.setUp(self)
from wx import py
spam = Spam()
self.f = open('test_introspect.py')
self.items = (
None,
int(123),
long(123),
float(123),
complex(123),
"",
unicode(""),
[],
(),
xrange(0),
{},
# Builtin function.
len,
# Builtin method.
[].append,
# User function.
ham,
# Byte-compiled code.
ham.func_code,
# Lambda.
lambda: None,
# Class with no init.
Bar,
# Instance with no init.
Bar(),
# Class with init and del.
Foo,
# Instance with init and del.
Foo(),
# Bound method.
spam.foo,
# Unbound method.
Spam.eggs,
# Callable instance.
spam,
# Module.
introspect,
# Package.
py,
# Buffer.
buffer(''),
# File.
self.f,
# Slice.
slice(0),
# Ellipsis.
Ellipsis,
# BrokenStr class.
BrokenStr,
# BrokenStr instance.
brokenStr,
)
def tearDown(self):
self.items = None
self.f.close()
def test_getAttributeNames(self):
for item in self.items:
self._checkAttributeNames(item)
if __builtins__.has_key('object'):
self._checkAttributeNames(object)
def test_getAttributeNames_NoSingle(self):
for item in self.items:
result = introspect.getAttributeNames(item, includeSingle=0)
attributes = [attribute for attribute in result \
if attribute[0] != '_' or attribute[:2] == '__']
self.assertEqual(result, attributes,
':item: %r' % (item,))
def test_getAttributeNames_NoDouble(self):
for item in self.items:
result = introspect.getAttributeNames(item, includeDouble=0)
attributes = [attribute for attribute in result \
if attribute[:2] != '__']
self.assertEqual(result, attributes,
':item: %r' % (item,))
def test_getAttributeNames_NoSingleOrDouble(self):
for item in self.items:
result = introspect.getAttributeNames(item, includeSingle=0,
includeDouble=0)
attributes = [attribute for attribute in result \
if attribute[0] != '_']
self.assertEqual(result, attributes,
':item: %r' % (item,))
def _checkAttributeNames(self, item):
result = introspect.getAttributeNames(item)
attributes = [attribute for attribute in self.values \
if hasattr(item, attribute)]
for attribute in attributes:
self.assert_(attribute in result,
':item: %r :attribute: %r' % (item, attribute))
class GetAutoCompleteListTestCase(GetAttributeTestCase):
def setUp(self):
GetAttributeTestCase.setUp(self)
self.items = (
'None.',
'123 .',
'"".',
'[].',
'().',
'{}.',
# Builtin function.
'len.',
# Builtin method.
'[].append.',
)
def test_getAutoCompleteList(self):
for item in self.items:
result = introspect.getAutoCompleteList(item)
object = eval(item[:-1])
attributes = [attribute for attribute in self.values \
if hasattr(object, attribute)]
for attribute in attributes:
self.assert_(attribute in result,
':item: %r :attribute: %r' % (item, attribute))
def test_getAutoCompleteList_NoSingle(self):
for item in self.items:
result = introspect.getAutoCompleteList(item, includeSingle=0)
attributes = [attribute for attribute in result \
if attribute[0] != '_' or attribute[:2] == '__']
self.assertEqual(result, attributes,
':item: %r' % (item,))
def test_getAutoCompleteList_NoDouble(self):
for item in self.items:
result = introspect.getAutoCompleteList(item, includeDouble=0)
attributes = [attribute for attribute in result \
if attribute[:2] != '__']
self.assertEqual(result, attributes,
':item: %r' % (item,))
def test_getAutoCompleteList_NoSingleOrDouble(self):
for item in self.items:
result = introspect.getAutoCompleteList(item, includeSingle=0,
includeDouble=0)
attributes = [attribute for attribute in result \
if attribute[0] != '_']
self.assertEqual(result, attributes,
':item: %r' % (item,))
# Support for GetConstructorTestCase.
class A1:
def __init__(self, a):
self.a = a
class B1(A1):
def __init__(self, b):
self.b = b
class C1(A1):
pass
class D1(C1, B1):
pass
if __builtins__.has_key('object'):
class A2(object):
def __init__(self, a):
self.a = a
class B2(A2):
def __init__(self, b):
self.b = b
class C2(A2):
pass
class D2(C2, B2):
pass
class N:
pass
class O:
def __init__(self, a, b=2, *args, **kwargs):
pass
class P(O):
pass
class Q(P):
def __init__(self, c, d=4):
pass
class GetConstructorTestCase(unittest.TestCase):
def test_getConstructor(self):
args = ('self', 'a', 'b', 'args', 'kwargs')
varnames = introspect.getConstructor(O).func_code.co_varnames
self.assertEqual(varnames, args)
varnames = introspect.getConstructor(P).func_code.co_varnames
self.assertEqual(varnames, args)
args = ('self', 'c', 'd')
varnames = introspect.getConstructor(Q).func_code.co_varnames
self.assertEqual(varnames, args)
def test_getConstructor_None(self):
values = (N, 1, 'spam', {}, [], (), dir)
for value in values:
self.assertEqual(introspect.getConstructor(N), None)
def test_getConstructor_MultipleInheritance(self):
# Test old style inheritance rules.
args = ('self', 'a')
varnames = introspect.getConstructor(D1).func_code.co_varnames
self.assertEqual(varnames, args)
if __builtins__.has_key('object'):
# Test new style inheritance rules as well.
args = ('self', 'b')
varnames = introspect.getConstructor(D2).func_code.co_varnames
self.assertEqual(varnames, args)
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,81 @@
#!/usr/bin/env python
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
import unittest
# Import from this module's parent directory.
import os
import sys
sys.path.insert(0, os.pardir)
import pseudo
del sys.path[0]
del sys
del os
"""
These unittest methods are preferred:
-------------------------------------
self.assert_(expr, msg=None)
self.assertEqual(first, second, msg=None)
self.assertRaises(excClass, callableObj, *args, **kwargs)
self.fail(msg=None)
self.failIf(expr, msg=None)
"""
class ModuleTestCase(unittest.TestCase):
def test_module(self):
module = pseudo
self.assert_(module.__author__)
self.assert_(module.__cvsid__)
self.assert_(module.__revision__)
self.assert_(module.PseudoFile)
self.assert_(module.PseudoFileErr)
self.assert_(module.PseudoFileIn)
self.assert_(module.PseudoFileOut)
self.assert_(module.PseudoKeyword)
class PseudoTestCase(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
class PseudoFileTestCase(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
class PseudoFileOutTestCase(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
def _write(self):
pass
def test_PseudoFileOut_goodInit(self):
self.assert_(pseudo.PseudoFileOut(write=self._write))
def test_PseudoFileOut_badInit(self):
self.assertRaises(ValueError, pseudo.PseudoFileOut, write='bad')
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,49 @@
#!/usr/bin/env python
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
import unittest
import types
# Import from this module's parent directory.
import os
import sys
sys.path.insert(0, os.pardir)
import version
del sys.path[0]
del sys
del os
"""
These unittest methods are preferred:
-------------------------------------
self.assert_(expr, msg=None)
self.assertEqual(first, second, msg=None)
self.assertRaises(excClass, callableObj, *args, **kwargs)
self.fail(msg=None)
self.failIf(expr, msg=None)
"""
class ModuleTestCase(unittest.TestCase):
def test_module(self):
module = version
self.assert_(module.__author__)
self.assert_(module.__cvsid__)
self.assert_(module.__revision__)
self.assert_(module.VERSION)
class VersionTestCase(unittest.TestCase):
def test_VERSION(self):
self.assert_(type(version.VERSION) is types.StringType)
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,25 @@
#!/usr/bin/env python
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
import unittest
import glob
import os
def suite():
"""Return a test suite containing all test cases in all test modules.
Searches the current directory for any modules matching test_*.py."""
suite = unittest.TestSuite()
for filename in glob.glob('test_*.py'):
module = __import__(os.path.splitext(filename)[0])
suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(module))
return suite
if __name__ == '__main__':
unittest.main(defaultTest='suite')

View File

@@ -0,0 +1,9 @@
"""Provides an object representing the current 'version' or 'release'
of Py as a whole. Individual classes, such as the shell, filling and
interpreter, each have a revision property based on the CVS Revision."""
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
VERSION = '0.9.4'