Compare commits
1 Commits
CPPUNIT_1_
...
b4_big_upd
Author | SHA1 | Date | |
---|---|---|---|
|
0b2c8aadbb |
@@ -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
617
wxPython/wx/py/CHANGES.txt
Normal 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
BIN
wxPython/wx/py/Py.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
36
wxPython/wx/py/PyAlaCarte.py
Normal file
36
wxPython/wx/py/PyAlaCarte.py
Normal 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()
|
36
wxPython/wx/py/PyAlaMode.py
Normal file
36
wxPython/wx/py/PyAlaMode.py
Normal 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
35
wxPython/wx/py/PyAlaModeTest.py
Executable 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
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
70
wxPython/wx/py/PyCrust.py
Normal 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()
|
BIN
wxPython/wx/py/PyCrust_16.png
Normal file
BIN
wxPython/wx/py/PyCrust_16.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 706 B |
BIN
wxPython/wx/py/PyCrust_32.png
Normal file
BIN
wxPython/wx/py/PyCrust_32.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
35
wxPython/wx/py/PyFilling.py
Normal file
35
wxPython/wx/py/PyFilling.py
Normal 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
71
wxPython/wx/py/PyShell.py
Normal 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
48
wxPython/wx/py/PyWrap.py
Normal 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
83
wxPython/wx/py/README.txt
Normal 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$
|
20
wxPython/wx/py/__init__.py
Normal file
20
wxPython/wx/py/__init__.py
Normal 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
138
wxPython/wx/py/buffer.py
Normal 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
218
wxPython/wx/py/crust.py
Normal 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()
|
260
wxPython/wx/py/dispatcher.py
Normal file
260
wxPython/wx/py/dispatcher.py
Normal 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
|
43
wxPython/wx/py/document.py
Normal file
43
wxPython/wx/py/document.py
Normal 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
843
wxPython/wx/py/editor.py
Normal 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
|
225
wxPython/wx/py/editwindow.py
Normal file
225
wxPython/wx/py/editwindow.py
Normal 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
332
wxPython/wx/py/filling.py
Normal 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
362
wxPython/wx/py/frame.py
Normal 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
72
wxPython/wx/py/images.py
Normal 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'
|
126
wxPython/wx/py/interpreter.py
Normal file
126
wxPython/wx/py/interpreter.py
Normal 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
|
||||
|
||||
|
382
wxPython/wx/py/introspect.py
Normal file
382
wxPython/wx/py/introspect.py
Normal 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
101
wxPython/wx/py/pseudo.py
Normal 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
1036
wxPython/wx/py/shell.py
Normal file
File diff suppressed because it is too large
Load Diff
82
wxPython/wx/py/tests/test_interpreter.py
Normal file
82
wxPython/wx/py/tests/test_interpreter.py
Normal 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()
|
862
wxPython/wx/py/tests/test_introspect.py
Normal file
862
wxPython/wx/py/tests/test_introspect.py
Normal 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()
|
81
wxPython/wx/py/tests/test_pseudo.py
Normal file
81
wxPython/wx/py/tests/test_pseudo.py
Normal 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()
|
49
wxPython/wx/py/tests/test_version.py
Normal file
49
wxPython/wx/py/tests/test_version.py
Normal 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()
|
25
wxPython/wx/py/tests/testall.py
Normal file
25
wxPython/wx/py/tests/testall.py
Normal 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')
|
||||
|
9
wxPython/wx/py/version.py
Normal file
9
wxPython/wx/py/version.py
Normal 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'
|
Reference in New Issue
Block a user