From 22768184cbbaa4bd6083c51c28183be7f4fc3d69 Mon Sep 17 00:00:00 2001 From: cvs2svn Date: Fri, 28 Dec 2001 04:27:46 +0000 Subject: This commit was manufactured by cvs2svn to create branch 'release22-maint'. --- Demo/sgi/video/vcopy.py | 134 --- Demo/sgi/video/vinfo.py | 90 -- Demo/sgi/video/vtime.py | 106 --- Doc/Makefile | 2 +- Doc/texinputs/boilerplate.tex | 4 +- Doc/whatsnew/whatsnew20.tex | 1335 -------------------------- Doc/whatsnew/whatsnew21.tex | 868 ----------------- Include/patchlevel.h | 6 +- Lib/compiler/ast.py | 15 + Lib/compiler/pycodegen.py | 12 +- Lib/compiler/symbols.py | 2 + Lib/compiler/transformer.py | 2 +- Lib/dumbdbm.py | 6 + Lib/idlelib/AutoExpand.py | 91 -- Lib/idlelib/AutoIndent.py | 554 ----------- Lib/idlelib/Bindings.py | 76 -- Lib/idlelib/CREDITS.txt | 17 - Lib/idlelib/CallTipWindow.py | 71 -- Lib/idlelib/CallTips.py | 190 ---- Lib/idlelib/ChangeLog | 1587 ------------------------------- Lib/idlelib/ClassBrowser.py | 224 ----- Lib/idlelib/ColorDelegator.py | 249 ----- Lib/idlelib/Debugger.py | 308 ------ Lib/idlelib/Delegator.py | 33 - Lib/idlelib/EditorWindow.py | 735 -------------- Lib/idlelib/ExecBinding.py | 198 ---- Lib/idlelib/FileList.py | 146 --- Lib/idlelib/FormatParagraph.py | 155 --- Lib/idlelib/FrameViewer.py | 38 - Lib/idlelib/GrepDialog.py | 135 --- Lib/idlelib/INSTALL.txt | 58 -- Lib/idlelib/IOBinding.py | 254 ----- Lib/idlelib/Icons/folder.gif | Bin 120 -> 0 bytes Lib/idlelib/Icons/minusnode.gif | Bin 96 -> 0 bytes Lib/idlelib/Icons/openfolder.gif | Bin 125 -> 0 bytes Lib/idlelib/Icons/plusnode.gif | Bin 79 -> 0 bytes Lib/idlelib/Icons/python.gif | Bin 125 -> 0 bytes Lib/idlelib/Icons/tk.gif | Bin 85 -> 0 bytes Lib/idlelib/IdleConf.py | 113 --- Lib/idlelib/IdleHistory.py | 88 -- Lib/idlelib/LICENSE.txt | 50 - Lib/idlelib/MultiScrolledLists.py | 138 --- Lib/idlelib/MultiStatusBar.py | 32 - Lib/idlelib/NEWS.txt | 173 ---- Lib/idlelib/ObjectBrowser.py | 151 --- Lib/idlelib/OldStackViewer.py | 276 ------ Lib/idlelib/OutputWindow.py | 279 ------ Lib/idlelib/ParenMatch.py | 191 ---- Lib/idlelib/PathBrowser.py | 95 -- Lib/idlelib/Percolator.py | 85 -- Lib/idlelib/PyParse.py | 589 ------------ Lib/idlelib/PyShell.py | 903 ------------------ Lib/idlelib/README.txt | 158 --- Lib/idlelib/Remote.py | 101 -- Lib/idlelib/RemoteInterp.py | 342 ------- Lib/idlelib/ReplaceDialog.py | 188 ---- Lib/idlelib/ScriptBinding.py | 173 ---- Lib/idlelib/ScrolledList.py | 139 --- Lib/idlelib/SearchBinding.py | 97 -- Lib/idlelib/SearchDialog.py | 67 -- Lib/idlelib/SearchDialogBase.py | 129 --- Lib/idlelib/SearchEngine.py | 221 ----- Lib/idlelib/Separator.py | 92 -- Lib/idlelib/StackViewer.py | 147 --- Lib/idlelib/TODO.txt | 212 ----- Lib/idlelib/ToolTip.py | 87 -- Lib/idlelib/TreeWidget.py | 471 --------- Lib/idlelib/UndoDelegator.py | 352 ------- Lib/idlelib/WidgetRedirector.py | 92 -- Lib/idlelib/WindowList.py | 85 -- Lib/idlelib/ZoomHeight.py | 46 - Lib/idlelib/__init__.py | 1 - Lib/idlelib/aboutDialog.py | 135 --- Lib/idlelib/config-extensions.def | 34 - Lib/idlelib/config-highlight.def | 56 -- Lib/idlelib/config-keys.def | 64 -- Lib/idlelib/config-main.def | 79 -- Lib/idlelib/config-unix.txt | 3 - Lib/idlelib/config-win.txt | 3 - Lib/idlelib/config.txt | 66 -- Lib/idlelib/configDialog.py | 623 ------------ Lib/idlelib/configHandler.py | 254 ----- Lib/idlelib/dynOptionMenuWidget.py | 41 - Lib/idlelib/eventparse.py | 93 -- Lib/idlelib/extend.txt | 120 --- Lib/idlelib/help.txt | 165 ---- Lib/idlelib/idle | 4 - Lib/idlelib/idle.bat | 3 - Lib/idlelib/idle.py | 4 - Lib/idlelib/idle.pyw | 12 - Lib/idlelib/idlever.py | 1 - Lib/idlelib/keydefs.py | 55 -- Lib/idlelib/loader.py | 64 -- Lib/idlelib/protocol.py | 369 ------- Lib/idlelib/setup.py | 86 -- Lib/idlelib/spawn.py | 58 -- Lib/idlelib/tabpage.py | 110 --- Lib/idlelib/testcode.py | 31 - Lib/idlelib/textView.py | 77 -- Lib/test/test_cpickle.py | 7 + Mac/Build/PythonCore.mcp | Bin 201534 -> 201534 bytes Mac/Distributions/(vise)/Python 2.2.vct | Bin 673637 -> 674056 bytes Mac/Distributions/binary.exclude | 1 + Mac/Distributions/binary.include | 4 +- Mac/Distributions/dev.exclude | 1 + Mac/Distributions/dev.include | 26 +- Mac/Include/macbuildno.h | 2 +- Mac/Python/macglue.c | 11 + Mac/ReadMe | 45 +- Mac/Relnotes | 24 +- Mac/Unsupported/mactcp/dnrglue.c | 301 ------ Mac/_checkversion.py | 2 +- Misc/NEWS | 41 + Modules/cPickle.c | 8 +- Python/mysnprintf.c | 4 +- 115 files changed, 155 insertions(+), 16996 deletions(-) delete mode 100755 Demo/sgi/video/vcopy.py delete mode 100755 Demo/sgi/video/vinfo.py delete mode 100755 Demo/sgi/video/vtime.py delete mode 100644 Doc/whatsnew/whatsnew20.tex delete mode 100644 Doc/whatsnew/whatsnew21.tex delete mode 100644 Lib/idlelib/AutoExpand.py delete mode 100644 Lib/idlelib/AutoIndent.py delete mode 100644 Lib/idlelib/Bindings.py delete mode 100644 Lib/idlelib/CREDITS.txt delete mode 100644 Lib/idlelib/CallTipWindow.py delete mode 100644 Lib/idlelib/CallTips.py delete mode 100644 Lib/idlelib/ChangeLog delete mode 100644 Lib/idlelib/ClassBrowser.py delete mode 100644 Lib/idlelib/ColorDelegator.py delete mode 100644 Lib/idlelib/Debugger.py delete mode 100644 Lib/idlelib/Delegator.py delete mode 100644 Lib/idlelib/EditorWindow.py delete mode 100644 Lib/idlelib/ExecBinding.py delete mode 100644 Lib/idlelib/FileList.py delete mode 100644 Lib/idlelib/FormatParagraph.py delete mode 100644 Lib/idlelib/FrameViewer.py delete mode 100644 Lib/idlelib/GrepDialog.py delete mode 100644 Lib/idlelib/INSTALL.txt delete mode 100644 Lib/idlelib/IOBinding.py delete mode 100644 Lib/idlelib/Icons/folder.gif delete mode 100644 Lib/idlelib/Icons/minusnode.gif delete mode 100644 Lib/idlelib/Icons/openfolder.gif delete mode 100644 Lib/idlelib/Icons/plusnode.gif delete mode 100644 Lib/idlelib/Icons/python.gif delete mode 100644 Lib/idlelib/Icons/tk.gif delete mode 100644 Lib/idlelib/IdleConf.py delete mode 100644 Lib/idlelib/IdleHistory.py delete mode 100644 Lib/idlelib/LICENSE.txt delete mode 100644 Lib/idlelib/MultiScrolledLists.py delete mode 100644 Lib/idlelib/MultiStatusBar.py delete mode 100644 Lib/idlelib/NEWS.txt delete mode 100644 Lib/idlelib/ObjectBrowser.py delete mode 100644 Lib/idlelib/OldStackViewer.py delete mode 100644 Lib/idlelib/OutputWindow.py delete mode 100644 Lib/idlelib/ParenMatch.py delete mode 100644 Lib/idlelib/PathBrowser.py delete mode 100644 Lib/idlelib/Percolator.py delete mode 100644 Lib/idlelib/PyParse.py delete mode 100644 Lib/idlelib/PyShell.py delete mode 100644 Lib/idlelib/README.txt delete mode 100644 Lib/idlelib/Remote.py delete mode 100644 Lib/idlelib/RemoteInterp.py delete mode 100644 Lib/idlelib/ReplaceDialog.py delete mode 100644 Lib/idlelib/ScriptBinding.py delete mode 100644 Lib/idlelib/ScrolledList.py delete mode 100644 Lib/idlelib/SearchBinding.py delete mode 100644 Lib/idlelib/SearchDialog.py delete mode 100644 Lib/idlelib/SearchDialogBase.py delete mode 100644 Lib/idlelib/SearchEngine.py delete mode 100644 Lib/idlelib/Separator.py delete mode 100644 Lib/idlelib/StackViewer.py delete mode 100644 Lib/idlelib/TODO.txt delete mode 100644 Lib/idlelib/ToolTip.py delete mode 100644 Lib/idlelib/TreeWidget.py delete mode 100644 Lib/idlelib/UndoDelegator.py delete mode 100644 Lib/idlelib/WidgetRedirector.py delete mode 100644 Lib/idlelib/WindowList.py delete mode 100644 Lib/idlelib/ZoomHeight.py delete mode 100644 Lib/idlelib/__init__.py delete mode 100644 Lib/idlelib/aboutDialog.py delete mode 100644 Lib/idlelib/config-extensions.def delete mode 100644 Lib/idlelib/config-highlight.def delete mode 100644 Lib/idlelib/config-keys.def delete mode 100644 Lib/idlelib/config-main.def delete mode 100644 Lib/idlelib/config-unix.txt delete mode 100644 Lib/idlelib/config-win.txt delete mode 100644 Lib/idlelib/config.txt delete mode 100644 Lib/idlelib/configDialog.py delete mode 100644 Lib/idlelib/configHandler.py delete mode 100644 Lib/idlelib/dynOptionMenuWidget.py delete mode 100644 Lib/idlelib/eventparse.py delete mode 100644 Lib/idlelib/extend.txt delete mode 100644 Lib/idlelib/help.txt delete mode 100755 Lib/idlelib/idle delete mode 100755 Lib/idlelib/idle.bat delete mode 100644 Lib/idlelib/idle.py delete mode 100644 Lib/idlelib/idle.pyw delete mode 100644 Lib/idlelib/idlever.py delete mode 100644 Lib/idlelib/keydefs.py delete mode 100644 Lib/idlelib/loader.py delete mode 100644 Lib/idlelib/protocol.py delete mode 100644 Lib/idlelib/setup.py delete mode 100644 Lib/idlelib/spawn.py delete mode 100644 Lib/idlelib/tabpage.py delete mode 100644 Lib/idlelib/testcode.py delete mode 100644 Lib/idlelib/textView.py delete mode 100644 Mac/Unsupported/mactcp/dnrglue.c diff --git a/Demo/sgi/video/vcopy.py b/Demo/sgi/video/vcopy.py deleted file mode 100755 index d32bc1f..0000000 --- a/Demo/sgi/video/vcopy.py +++ /dev/null @@ -1,134 +0,0 @@ -# Copy a video file, interactively, frame-by-frame. - -import sys -import getopt -from gl import * -from DEVICE import * -import VFile -import string -import imageop - -def report(time, iframe): - print 'Frame', iframe, ': t =', time - -def usage(): - sys.stderr.write('usage: vcopy [-t type] [-m treshold] [-a] infile outfile\n') - sys.stderr.write('-t Convert to other type\n') - sys.stderr.write('-a Automatic\n') - sys.stderr.write('-m Convert grey to mono with treshold\n') - sys.stderr.write('-d Convert grey to mono with dithering\n') - sys.exit(2) - -def help(): - print 'Command summary:' - print 'n get next image from input' - print 'w write current image to output' - -def main(): - foreground() - opts, args = getopt.getopt(sys.argv[1:], 't:am:d') - if len(args) <> 2: - usage() - [ifile, ofile] = args - print 'open film ', ifile - ifilm = VFile.VinFile().init(ifile) - print 'open output ', ofile - ofilm = VFile.VoutFile().init(ofile) - - ofilm.setinfo(ifilm.getinfo()) - - use_grabber = 0 - continuous = 0 - tomono = 0 - tomonodither = 0 - for o, a in opts: - if o == '-t': - ofilm.format = a - use_grabber = 1 - if o == '-a': - continuous = 1 - if o == '-m': - if ifilm.format <> 'grey': - print '-m only supported for greyscale' - sys.exit(1) - tomono = 1 - treshold = string.atoi(a) - ofilm.format = 'mono' - if o == '-d': - if ifilm.format <> 'grey': - print '-m only supported for greyscale' - sys.exit(1) - tomonodither = 1 - ofilm.format = 'mono' - - ofilm.writeheader() - # - prefsize(ifilm.width, ifilm.height) - w = winopen(ifile) - qdevice(KEYBD) - qdevice(ESCKEY) - qdevice(WINQUIT) - qdevice(WINSHUT) - print 'qdevice calls done' - # - help() - # - time, data, cdata = ifilm.getnextframe() - ifilm.showframe(data, cdata) - iframe = 1 - report(time, iframe) - # - while 1: - if continuous: - dev = KEYBD - else: - dev, val = qread() - if dev in (ESCKEY, WINQUIT, WINSHUT): - break - if dev == REDRAW: - reshapeviewport() - elif dev == KEYBD: - if continuous: - c = '0' - else: - c = chr(val) - #XXX Debug - if c == 'R': - c3i(255,0,0) - clear() - if c == 'G': - c3i(0,255,0) - clear() - if c == 'B': - c3i(0,0,255) - clear() - if c == 'w' or continuous: - if use_grabber: - data, cdata = ofilm.grabframe() - if tomono: - data = imageop.grey2mono(data, \ - ifilm.width, ifilm.height, \ - treshold) - if tomonodither: - data = imageop.dither2mono(data, \ - ifilm.width, ifilm.height) - ofilm.writeframe(time, data, cdata) - print 'Frame', iframe, 'written.' - if c == 'n' or continuous: - try: - time,data,cdata = ifilm.getnextframe() - ifilm.showframe(data, cdata) - iframe = iframe+1 - report(time, iframe) - except EOFError: - print 'EOF' - if continuous: - break - ringbell() - elif dev == INPUTCHANGE: - pass - else: - print '(dev, val) =', (dev, val) - ofilm.close() - -main() diff --git a/Demo/sgi/video/vinfo.py b/Demo/sgi/video/vinfo.py deleted file mode 100755 index 7f98237..0000000 --- a/Demo/sgi/video/vinfo.py +++ /dev/null @@ -1,90 +0,0 @@ -from gl import * -from GL import * -from DEVICE import * -import time -import sys -import getopt - -class Struct(): pass -epoch = Struct() -EndOfFile = 'End of file' -bye = 'bye' - -def openvideo(filename): - f = open(filename, 'r') - line = f.readline() - if not line: raise EndOfFile - if line[:4] == 'CMIF': line = f.readline() - x = eval(line[:-1]) - if len(x) == 3: w, h, pf = x - else: w, h = x; pf = 2 - return f, w, h, pf - -def loadframe(f, w, h, pf): - line = f.readline() - if line == '': - raise EndOfFile - x = eval(line[:-1]) - if type(x) == type(0) or type(x) == type(0.0): - tijd = x - if pf == 0: - size = w*h*4 - else: - size = (w/pf) * (h/pf) - else: - tijd, size = x - f.seek(size, 1) - return tijd - -def main(): - delta = 0 - short = 0 - try: - opts, names = getopt.getopt(sys.argv[1:], 'ds') - except getopt.error, msg: - sys.stderr.write(msg + '\n') - sys.stderr.write('usage: vinfo [-d] [-s] [file] ...\n') - sys.exit(2) - for opt, arg in opts: - if opt == '-d': delta = 1 # print delta between frames - elif opt == '-s': short = 1 # short: don't print times - if names == []: - names = ['film.video'] - for name in names: - try: - f, w, h, pf = openvideo(name) - except: - sys.stderr.write(name + ': cannot open\n') - continue - if pf == 0: - size = w*h*4 - else: - size = (w/pf) * (h/pf) - print name, ':', w, 'x', h, '; pf =', pf, ', size =', size, - if pf == 0: - print '(color)', - else: - print '(' + `(w/pf)` + 'x' + `(h/pf)` + ')', - if (w/pf)%4 <> 0: print '!!!', - print - num = 0 - try: - otijd = 0 - while not short: - try: - tijd = loadframe(f, w, h, pf) - if delta: print '\t' + `tijd-otijd`, - else: print '\t' + `tijd`, - otijd = tijd - num = num + 1 - if num % 8 == 0: - print - except EndOfFile: - raise bye - except bye: - pass - if num % 8 <> 0: - print - f.close() - -main() diff --git a/Demo/sgi/video/vtime.py b/Demo/sgi/video/vtime.py deleted file mode 100755 index c333e57..0000000 --- a/Demo/sgi/video/vtime.py +++ /dev/null @@ -1,106 +0,0 @@ -# -# Module vtime - Keep virtual time between two nodes. -# -# We try for synchronised clocks by sending a packet of the for -# (1,mytime,0) to the other side, and waiting (at most) a second for -# a reply. This reply has the form (2,mytime,histime), and we can -# estimate the time difference by defining histime to be exactly half-way -# between the time we sent our message and got our reply. We send a -# final (3,mynewtime,histime) message to allow the other side to do the -# same computations. -# -# Note that the protocol suffers heavily from the 2-army problem. -# It'll have to do until I can read up on time-sync protocols, though. -# -from socket import * -import time - -MSGSIZE = 100 -MSGTIMEOUT = 1000 - -recv_timeout = 'receive timeout' -bad_connect = 'Bad connection' - -def timeavg(a,b): - return int((long(a)+b)/2L) -def tryrecv(s): - cnt = 0 - while 1: - if s.avail(): - return s.recvfrom(MSGSIZE) - time.millisleep(100) - cnt = cnt + 100 - if cnt > MSGTIMEOUT: - raise recv_timeout - -class VTime(): - def init(self,(client,host,port)): - s = socket(AF_INET, SOCK_DGRAM) - host = gethostbyname(host) - localhost = gethostbyname(gethostname()) - raddr = (host,port) - s.bind((localhost,port)) - if client: - # - # We loop here because we want the *second* measurement - # for accuracy - for loopct in (0,2): - curtijd = time.millitimer() - check = `(loopct,curtijd,0)` - s.sendto(check,raddr) - while 1: - try: - if loopct: - data, other = s.recvfrom(MSGSIZE) - else: - data, other = tryrecv(s) - newtijd = time.millitimer() - if other <> raddr: - print 'Someone else syncing to us: ', other - raise bad_connect - data = eval(data) - if data[:2] == (loopct+1,curtijd): - break - if data[0] <> 2: - print 'Illegal sync reply: ', data - raise bad_connect - except recv_timeout: - curtijd = time.millitimer() - check = `(loopct,curtijd,0)` - s.sendto(check,raddr) - histime = data[2] - s.sendto(`(4,newtijd,histime)`,raddr) - mytime = timeavg(curtijd,newtijd) - #mytime = curtijd - self.timediff = histime - mytime - else: - while 1: - data,other = s.recvfrom(MSGSIZE) - if other <> raddr: - print 'Someone else syncing to us: ', other, ' Wanted ', raddr - raise bad_connect - data = eval(data) - if data[0] in (0,2): - curtijd = time.millitimer() - s.sendto(`(data[0]+1,data[1],curtijd)`,raddr) - elif data[0] == 4: - newtijd = time.millitimer() - histime = data[1] - mytime = timeavg(curtijd,newtijd) - #mytime = curtijd - self.timediff = histime-mytime - break - else: - print 'Funny data: ', data - raise bad_connect - return self - # - def his2mine(self,tijd): - return tijd - self.timediff - # - def mine2his(self, tijd): - return tijd + self.timediff - -def test(clt, host, port): - xx = VTime().init(clt,host,port) - print 'Time diff: ', xx.his2mine(0) diff --git a/Doc/Makefile b/Doc/Makefile index 5911fd0..dbdc98a 100644 --- a/Doc/Makefile +++ b/Doc/Makefile @@ -66,7 +66,7 @@ TOOLSDIR= tools # This is the *documentation* release, and is used to construct the file # names of the downloadable tarballs. -RELEASE=2.2c1+ +RELEASE=2.2 PYTHON= python DVIPS= dvips -N0 -t $(PAPER) diff --git a/Doc/texinputs/boilerplate.tex b/Doc/texinputs/boilerplate.tex index 97ee49e..9107e54 100644 --- a/Doc/texinputs/boilerplate.tex +++ b/Doc/texinputs/boilerplate.tex @@ -5,7 +5,7 @@ Email: \email{python-docs@python.org} } -\date{\today} % XXX update before release! +\date{December 21, 2001} % XXX update before release! \release{2.2} % software release, not documentation -\setreleaseinfo{c1+} % empty for final release +\setreleaseinfo{} % empty for final release \setshortversion{2.2} % major.minor only for software diff --git a/Doc/whatsnew/whatsnew20.tex b/Doc/whatsnew/whatsnew20.tex deleted file mode 100644 index 229f9ee..0000000 --- a/Doc/whatsnew/whatsnew20.tex +++ /dev/null @@ -1,1335 +0,0 @@ -\documentclass{howto} - -% $Id$ - -\title{What's New in Python 2.0} -\release{1.01} -\author{A.M. Kuchling and Moshe Zadka} -\authoraddress{\email{akuchlin@mems-exchange.org}, \email{moshez@math.huji.ac.il} } -\begin{document} -\maketitle\tableofcontents - -\section{Introduction} - -A new release of Python, version 2.0, will be released some time this -autumn. Beta versions are already available from -\url{http://www.pythonlabs.com/products/python2.0/}. This article -covers the exciting new features in 2.0, highlights some other useful -changes, and points out a few incompatible changes that may require -rewriting code. - -Python's development never completely stops between releases, and a -steady flow of bug fixes and improvements are always being submitted. -A host of minor fixes, a few optimizations, additional docstrings, and -better error messages went into 2.0; to list them all would be -impossible, but they're certainly significant. Consult the -publicly-available CVS logs if you want to see the full list. This -progress is due to the five developers working for -PythonLabs are now getting paid to spend their days fixing bugs, -and also due to the improved communication resulting -from moving to SourceForge. - -% ====================================================================== -\section{What About Python 1.6?} - -Python 1.6 can be thought of as the Contractual Obligations Python -release. After the core development team left CNRI in May 2000, CNRI -requested that a 1.6 release be created, containing all the work on -Python that had been performed at CNRI. Python 1.6 therefore -represents the state of the CVS tree as of May 2000, with the most -significant new feature being Unicode support. Development continued -after May, of course, so the 1.6 tree received a few fixes to ensure -that it's forward-compatible with Python 2.0. 1.6 is therefore part -of Python's evolution, and not a side branch. - -So, should you take much interest in Python 1.6? Probably not. The -1.6final and 2.0beta1 releases were made on the same day (September 5, -2000), the plan being to finalize Python 2.0 within a month or so. If -you have applications to maintain, there seems little point in -breaking things by moving to 1.6, fixing them, and then having another -round of breakage within a month by moving to 2.0; you're better off -just going straight to 2.0. Most of the really interesting features -described in this document are only in 2.0, because a lot of work was -done between May and September. - -% ====================================================================== -\section{New Development Process} - -The most important change in Python 2.0 may not be to the code at all, -but to how Python is developed: in May 2000 the Python developers -began using the tools made available by SourceForge for storing -source code, tracking bug reports, and managing the queue of patch -submissions. To report bugs or submit patches for Python 2.0, use the -bug tracking and patch manager tools available from Python's project -page, located at \url{http://sourceforge.net/projects/python/}. - -The most important of the services now hosted at SourceForge is the -Python CVS tree, the version-controlled repository containing the -source code for Python. Previously, there were roughly 7 or so people -who had write access to the CVS tree, and all patches had to be -inspected and checked in by one of the people on this short list. -Obviously, this wasn't very scalable. By moving the CVS tree to -SourceForge, it became possible to grant write access to more people; -as of September 2000 there were 27 people able to check in changes, a -fourfold increase. This makes possible large-scale changes that -wouldn't be attempted if they'd have to be filtered through the small -group of core developers. For example, one day Peter Schneider-Kamp -took it into his head to drop K\&R C compatibility and convert the C -source for Python to ANSI C. After getting approval on the python-dev -mailing list, he launched into a flurry of checkins that lasted about -a week, other developers joined in to help, and the job was done. If -there were only 5 people with write access, probably that task would -have been viewed as ``nice, but not worth the time and effort needed'' -and it would never have gotten done. - -The shift to using SourceForge's services has resulted in a remarkable -increase in the speed of development. Patches now get submitted, -commented on, revised by people other than the original submitter, and -bounced back and forth between people until the patch is deemed worth -checking in. Bugs are tracked in one central location and can be -assigned to a specific person for fixing, and we can count the number -of open bugs to measure progress. This didn't come without a cost: -developers now have more e-mail to deal with, more mailing lists to -follow, and special tools had to be written for the new environment. -For example, SourceForge sends default patch and bug notification -e-mail messages that are completely unhelpful, so Ka-Ping Yee wrote an -HTML screen-scraper that sends more useful messages. - -The ease of adding code caused a few initial growing pains, such as -code was checked in before it was ready or without getting clear -agreement from the developer group. The approval process that has -emerged is somewhat similar to that used by the Apache group. -Developers can vote +1, +0, -0, or -1 on a patch; +1 and -1 denote -acceptance or rejection, while +0 and -0 mean the developer is mostly -indifferent to the change, though with a slight positive or negative -slant. The most significant change from the Apache model is that the -voting is essentially advisory, letting Guido van Rossum, who has -Benevolent Dictator For Life status, know what the general opinion is. -He can still ignore the result of a vote, and approve or -reject a change even if the community disagrees with him. - -Producing an actual patch is the last step in adding a new feature, -and is usually easy compared to the earlier task of coming up with a -good design. Discussions of new features can often explode into -lengthy mailing list threads, making the discussion hard to follow, -and no one can read every posting to python-dev. Therefore, a -relatively formal process has been set up to write Python Enhancement -Proposals (PEPs), modelled on the Internet RFC process. PEPs are -draft documents that describe a proposed new feature, and are -continually revised until the community reaches a consensus, either -accepting or rejecting the proposal. Quoting from the introduction to -PEP 1, ``PEP Purpose and Guidelines'': - -\begin{quotation} - PEP stands for Python Enhancement Proposal. A PEP is a design - document providing information to the Python community, or - describing a new feature for Python. The PEP should provide a - concise technical specification of the feature and a rationale for - the feature. - - We intend PEPs to be the primary mechanisms for proposing new - features, for collecting community input on an issue, and for - documenting the design decisions that have gone into Python. The - PEP author is responsible for building consensus within the - community and documenting dissenting opinions. -\end{quotation} - -Read the rest of PEP 1 for the details of the PEP editorial process, -style, and format. PEPs are kept in the Python CVS tree on -SourceForge, though they're not part of the Python 2.0 distribution, -and are also available in HTML form from -\url{http://python.sourceforge.net/peps/}. As of September 2000, -there are 25 PEPS, ranging from PEP 201, ``Lockstep Iteration'', to -PEP 225, ``Elementwise/Objectwise Operators''. - -% ====================================================================== -\section{Unicode} - -The largest new feature in Python 2.0 is a new fundamental data type: -Unicode strings. Unicode uses 16-bit numbers to represent characters -instead of the 8-bit number used by ASCII, meaning that 65,536 -distinct characters can be supported. - -The final interface for Unicode support was arrived at through -countless often-stormy discussions on the python-dev mailing list, and -mostly implemented by Marc-Andr\'e Lemburg, based on a Unicode string -type implementation by Fredrik Lundh. A detailed explanation of the -interface is in the file \file{Misc/unicode.txt} in the Python source -distribution; it's also available on the Web at -\url{http://starship.python.net/crew/lemburg/unicode-proposal.txt}. -This article will simply cover the most significant points about the Unicode -interfaces. - -In Python source code, Unicode strings are written as -\code{u"string"}. Arbitrary Unicode characters can be written using a -new escape sequence, \code{\e u\var{HHHH}}, where \var{HHHH} is a -4-digit hexadecimal number from 0000 to FFFF. The existing -\code{\e x\var{HHHH}} escape sequence can also be used, and octal -escapes can be used for characters up to U+01FF, which is represented -by \code{\e 777}. - -Unicode strings, just like regular strings, are an immutable sequence -type. They can be indexed and sliced, but not modified in place. -Unicode strings have an \method{encode( \optional{encoding} )} method -that returns an 8-bit string in the desired encoding. Encodings are -named by strings, such as \code{'ascii'}, \code{'utf-8'}, -\code{'iso-8859-1'}, or whatever. A codec API is defined for -implementing and registering new encodings that are then available -throughout a Python program. If an encoding isn't specified, the -default encoding is usually 7-bit ASCII, though it can be changed for -your Python installation by calling the -\function{sys.setdefaultencoding(\var{encoding})} function in a -customised version of \file{site.py}. - -Combining 8-bit and Unicode strings always coerces to Unicode, using -the default ASCII encoding; the result of \code{'a' + u'bc'} is -\code{u'abc'}. - -New built-in functions have been added, and existing built-ins -modified to support Unicode: - -\begin{itemize} -\item \code{unichr(\var{ch})} returns a Unicode string 1 character -long, containing the character \var{ch}. - -\item \code{ord(\var{u})}, where \var{u} is a 1-character regular or Unicode string, returns the number of the character as an integer. - -\item \code{unicode(\var{string} \optional{, \var{encoding}} -\optional{, \var{errors}} ) } creates a Unicode string from an 8-bit -string. \code{encoding} is a string naming the encoding to use. -The \code{errors} parameter specifies the treatment of characters that -are invalid for the current encoding; passing \code{'strict'} as the -value causes an exception to be raised on any encoding error, while -\code{'ignore'} causes errors to be silently ignored and -\code{'replace'} uses U+FFFD, the official replacement character, in -case of any problems. - -\item The \keyword{exec} statement, and various built-ins such as -\code{eval()}, \code{getattr()}, and \code{setattr()} will also -accept Unicode strings as well as regular strings. (It's possible -that the process of fixing this missed some built-ins; if you find a -built-in function that accepts strings but doesn't accept Unicode -strings at all, please report it as a bug.) - -\end{itemize} - -A new module, \module{unicodedata}, provides an interface to Unicode -character properties. For example, \code{unicodedata.category(u'A')} -returns the 2-character string 'Lu', the 'L' denoting it's a letter, -and 'u' meaning that it's uppercase. -\code{u.bidirectional(u'\e x0660')} returns 'AN', meaning that U+0660 is -an Arabic number. - -The \module{codecs} module contains functions to look up existing encodings -and register new ones. Unless you want to implement a -new encoding, you'll most often use the -\function{codecs.lookup(\var{encoding})} function, which returns a -4-element tuple: \code{(\var{encode_func}, -\var{decode_func}, \var{stream_reader}, \var{stream_writer})}. - -\begin{itemize} -\item \var{encode_func} is a function that takes a Unicode string, and -returns a 2-tuple \code{(\var{string}, \var{length})}. \var{string} -is an 8-bit string containing a portion (perhaps all) of the Unicode -string converted into the given encoding, and \var{length} tells you -how much of the Unicode string was converted. - -\item \var{decode_func} is the opposite of \var{encode_func}, taking -an 8-bit string and returning a 2-tuple \code{(\var{ustring}, -\var{length})}, consisting of the resulting Unicode string -\var{ustring} and the integer \var{length} telling how much of the -8-bit string was consumed. - -\item \var{stream_reader} is a class that supports decoding input from -a stream. \var{stream_reader(\var{file_obj})} returns an object that -supports the \method{read()}, \method{readline()}, and -\method{readlines()} methods. These methods will all translate from -the given encoding and return Unicode strings. - -\item \var{stream_writer}, similarly, is a class that supports -encoding output to a stream. \var{stream_writer(\var{file_obj})} -returns an object that supports the \method{write()} and -\method{writelines()} methods. These methods expect Unicode strings, -translating them to the given encoding on output. -\end{itemize} - -For example, the following code writes a Unicode string into a file, -encoding it as UTF-8: - -\begin{verbatim} -import codecs - -unistr = u'\u0660\u2000ab ...' - -(UTF8_encode, UTF8_decode, - UTF8_streamreader, UTF8_streamwriter) = codecs.lookup('UTF-8') - -output = UTF8_streamwriter( open( '/tmp/output', 'wb') ) -output.write( unistr ) -output.close() -\end{verbatim} - -The following code would then read UTF-8 input from the file: - -\begin{verbatim} -input = UTF8_streamreader( open( '/tmp/output', 'rb') ) -print repr(input.read()) -input.close() -\end{verbatim} - -Unicode-aware regular expressions are available through the -\module{re} module, which has a new underlying implementation called -SRE written by Fredrik Lundh of Secret Labs AB. - -A \code{-U} command line option was added which causes the Python -compiler to interpret all string literals as Unicode string literals. -This is intended to be used in testing and future-proofing your Python -code, since some future version of Python may drop support for 8-bit -strings and provide only Unicode strings. - -% ====================================================================== -\section{List Comprehensions} - -Lists are a workhorse data type in Python, and many programs -manipulate a list at some point. Two common operations on lists are -to loop over them, and either pick out the elements that meet a -certain criterion, or apply some function to each element. For -example, given a list of strings, you might want to pull out all the -strings containing a given substring, or strip off trailing whitespace -from each line. - -The existing \function{map()} and \function{filter()} functions can be -used for this purpose, but they require a function as one of their -arguments. This is fine if there's an existing built-in function that -can be passed directly, but if there isn't, you have to create a -little function to do the required work, and Python's scoping rules -make the result ugly if the little function needs additional -information. Take the first example in the previous paragraph, -finding all the strings in the list containing a given substring. You -could write the following to do it: - -\begin{verbatim} -# Given the list L, make a list of all strings -# containing the substring S. -sublist = filter( lambda s, substring=S: - string.find(s, substring) != -1, - L) -\end{verbatim} - -Because of Python's scoping rules, a default argument is used so that -the anonymous function created by the \keyword{lambda} statement knows -what substring is being searched for. List comprehensions make this -cleaner: - -\begin{verbatim} -sublist = [ s for s in L if string.find(s, S) != -1 ] -\end{verbatim} - -List comprehensions have the form: - -\begin{verbatim} -[ expression for expr in sequence1 - for expr2 in sequence2 ... - for exprN in sequenceN - if condition -\end{verbatim} - -The \keyword{for}...\keyword{in} clauses contain the sequences to be -iterated over. The sequences do not have to be the same length, -because they are \emph{not} iterated over in parallel, but -from left to right; this is explained more clearly in the following -paragraphs. The elements of the generated list will be the successive -values of \var{expression}. The final \keyword{if} clause is -optional; if present, \var{expression} is only evaluated and added to -the result if \var{condition} is true. - -To make the semantics very clear, a list comprehension is equivalent -to the following Python code: - -\begin{verbatim} -for expr1 in sequence1: - for expr2 in sequence2: - ... - for exprN in sequenceN: - if (condition): - # Append the value of - # the expression to the - # resulting list. -\end{verbatim} - -This means that when there are \keyword{for}...\keyword{in} clauses, -the resulting list will be equal to the product of the lengths of all -the sequences. If you have two lists of length 3, the output list is -9 elements long: - -\begin{verbatim} -seq1 = 'abc' -seq2 = (1,2,3) ->>> [ (x,y) for x in seq1 for y in seq2] -[('a', 1), ('a', 2), ('a', 3), ('b', 1), ('b', 2), ('b', 3), ('c', 1), -('c', 2), ('c', 3)] -\end{verbatim} - -To avoid introducing an ambiguity into Python's grammar, if -\var{expression} is creating a tuple, it must be surrounded with -parentheses. The first list comprehension below is a syntax error, -while the second one is correct: - -\begin{verbatim} -# Syntax error -[ x,y for x in seq1 for y in seq2] -# Correct -[ (x,y) for x in seq1 for y in seq2] -\end{verbatim} - -The idea of list comprehensions originally comes from the functional -programming language Haskell (\url{http://www.haskell.org}). Greg -Ewing argued most effectively for adding them to Python and wrote the -initial list comprehension patch, which was then discussed for a -seemingly endless time on the python-dev mailing list and kept -up-to-date by Skip Montanaro. - -% ====================================================================== -\section{Augmented Assignment} - -Augmented assignment operators, another long-requested feature, have -been added to Python 2.0. Augmented assignment operators include -\code{+=}, \code{-=}, \code{*=}, and so forth. For example, the -statement \code{a += 2} increments the value of the variable -\code{a} by 2, equivalent to the slightly lengthier \code{a = a + 2}. - -The full list of supported assignment operators is \code{+=}, -\code{-=}, \code{*=}, \code{/=}, \code{\%=}, \code{**=}, \code{\&=}, -\code{|=}, \verb|^=|, \code{>>=}, and \code{<<=}. Python classes can -override the augmented assignment operators by defining methods named -\method{__iadd__}, \method{__isub__}, etc. For example, the following -\class{Number} class stores a number and supports using += to create a -new instance with an incremented value. - -\begin{verbatim} -class Number: - def __init__(self, value): - self.value = value - def __iadd__(self, increment): - return Number( self.value + increment) - -n = Number(5) -n += 3 -print n.value -\end{verbatim} - -The \method{__iadd__} special method is called with the value of the -increment, and should return a new instance with an appropriately -modified value; this return value is bound as the new value of the -variable on the left-hand side. - -Augmented assignment operators were first introduced in the C -programming language, and most C-derived languages, such as -\program{awk}, C++, Java, Perl, and PHP also support them. The augmented -assignment patch was implemented by Thomas Wouters. - -% ====================================================================== -\section{String Methods} - -Until now string-manipulation functionality was in the \module{string} -module, which was usually a front-end for the \module{strop} -module written in C. The addition of Unicode posed a difficulty for -the \module{strop} module, because the functions would all need to be -rewritten in order to accept either 8-bit or Unicode strings. For -functions such as \function{string.replace()}, which takes 3 string -arguments, that means eight possible permutations, and correspondingly -complicated code. - -Instead, Python 2.0 pushes the problem onto the string type, making -string manipulation functionality available through methods on both -8-bit strings and Unicode strings. - -\begin{verbatim} ->>> 'andrew'.capitalize() -'Andrew' ->>> 'hostname'.replace('os', 'linux') -'hlinuxtname' ->>> 'moshe'.find('sh') -2 -\end{verbatim} - -One thing that hasn't changed, a noteworthy April Fools' joke -notwithstanding, is that Python strings are immutable. Thus, the -string methods return new strings, and do not modify the string on -which they operate. - -The old \module{string} module is still around for backwards -compatibility, but it mostly acts as a front-end to the new string -methods. - -Two methods which have no parallel in pre-2.0 versions, although they -did exist in JPython for quite some time, are \method{startswith()} -and \method{endswith}. \code{s.startswith(t)} is equivalent to \code{s[:len(t)] -== t}, while \code{s.endswith(t)} is equivalent to \code{s[-len(t):] == t}. - -One other method which deserves special mention is \method{join}. The -\method{join} method of a string receives one parameter, a sequence of -strings, and is equivalent to the \function{string.join} function from -the old \module{string} module, with the arguments reversed. In other -words, \code{s.join(seq)} is equivalent to the old -\code{string.join(seq, s)}. - -% ====================================================================== -\section{Garbage Collection of Cycles} - -The C implementation of Python uses reference counting to implement -garbage collection. Every Python object maintains a count of the -number of references pointing to itself, and adjusts the count as -references are created or destroyed. Once the reference count reaches -zero, the object is no longer accessible, since you need to have a -reference to an object to access it, and if the count is zero, no -references exist any longer. - -Reference counting has some pleasant properties: it's easy to -understand and implement, and the resulting implementation is -portable, fairly fast, and reacts well with other libraries that -implement their own memory handling schemes. The major problem with -reference counting is that it sometimes doesn't realise that objects -are no longer accessible, resulting in a memory leak. This happens -when there are cycles of references. - -Consider the simplest possible cycle, -a class instance which has a reference to itself: - -\begin{verbatim} -instance = SomeClass() -instance.myself = instance -\end{verbatim} - -After the above two lines of code have been executed, the reference -count of \code{instance} is 2; one reference is from the variable -named \samp{'instance'}, and the other is from the \samp{myself} -attribute of the instance. - -If the next line of code is \code{del instance}, what happens? The -reference count of \code{instance} is decreased by 1, so it has a -reference count of 1; the reference in the \samp{myself} attribute -still exists. Yet the instance is no longer accessible through Python -code, and it could be deleted. Several objects can participate in a -cycle if they have references to each other, causing all of the -objects to be leaked. - -Python 2.0 fixes this problem by periodically executing a cycle -detection algorithm which looks for inaccessible cycles and deletes -the objects involved. A new \module{gc} module provides functions to -perform a garbage collection, obtain debugging statistics, and tuning -the collector's parameters. - -Running the cycle detection algorithm takes some time, and therefore -will result in some additional overhead. It is hoped that after we've -gotten experience with the cycle collection from using 2.0, Python 2.1 -will be able to minimize the overhead with careful tuning. It's not -yet obvious how much performance is lost, because benchmarking this is -tricky and depends crucially on how often the program creates and -destroys objects. The detection of cycles can be disabled when Python -is compiled, if you can't afford even a tiny speed penalty or suspect -that the cycle collection is buggy, by specifying the -\samp{--without-cycle-gc} switch when running the \file{configure} -script. - -Several people tackled this problem and contributed to a solution. An -early implementation of the cycle detection approach was written by -Toby Kelsey. The current algorithm was suggested by Eric Tiedemann -during a visit to CNRI, and Guido van Rossum and Neil Schemenauer -wrote two different implementations, which were later integrated by -Neil. Lots of other people offered suggestions along the way; the -March 2000 archives of the python-dev mailing list contain most of the -relevant discussion, especially in the threads titled ``Reference -cycle collection for Python'' and ``Finalization again''. - -% ====================================================================== -\section{Other Core Changes} - -Various minor changes have been made to Python's syntax and built-in -functions. None of the changes are very far-reaching, but they're -handy conveniences. - -\subsection{Minor Language Changes} - -A new syntax makes it more convenient to call a given function -with a tuple of arguments and/or a dictionary of keyword arguments. -In Python 1.5 and earlier, you'd use the \function{apply()} -built-in function: \code{apply(f, \var{args}, \var{kw})} calls the -function \function{f()} with the argument tuple \var{args} and the -keyword arguments in the dictionary \var{kw}. \function{apply()} -is the same in 2.0, but thanks to a patch from -Greg Ewing, \code{f(*\var{args}, **\var{kw})} as a shorter -and clearer way to achieve the same effect. This syntax is -symmetrical with the syntax for defining functions: - -\begin{verbatim} -def f(*args, **kw): - # args is a tuple of positional args, - # kw is a dictionary of keyword args - ... -\end{verbatim} - -The \keyword{print} statement can now have its output directed to a -file-like object by following the \keyword{print} with -\verb|>> file|, similar to the redirection operator in Unix shells. -Previously you'd either have to use the \method{write()} method of the -file-like object, which lacks the convenience and simplicity of -\keyword{print}, or you could assign a new value to -\code{sys.stdout} and then restore the old value. For sending output to standard error, -it's much easier to write this: - -\begin{verbatim} -print >> sys.stderr, "Warning: action field not supplied" -\end{verbatim} - -Modules can now be renamed on importing them, using the syntax -\code{import \var{module} as \var{name}} or \code{from \var{module} -import \var{name} as \var{othername}}. The patch was submitted by -Thomas Wouters. - -A new format style is available when using the \code{\%} operator; -'\%r' will insert the \function{repr()} of its argument. This was -also added from symmetry considerations, this time for symmetry with -the existing '\%s' format style, which inserts the \function{str()} of -its argument. For example, \code{'\%r \%s' \% ('abc', 'abc')} returns a -string containing \verb|'abc' abc|. - -Previously there was no way to implement a class that overrode -Python's built-in \keyword{in} operator and implemented a custom -version. \code{\var{obj} in \var{seq}} returns true if \var{obj} is -present in the sequence \var{seq}; Python computes this by simply -trying every index of the sequence until either \var{obj} is found or -an \exception{IndexError} is encountered. Moshe Zadka contributed a -patch which adds a \method{__contains__} magic method for providing a -custom implementation for \keyword{in}. Additionally, new built-in -objects written in C can define what \keyword{in} means for them via a -new slot in the sequence protocol. - -Earlier versions of Python used a recursive algorithm for deleting -objects. Deeply nested data structures could cause the interpreter to -fill up the C stack and crash; Christian Tismer rewrote the deletion -logic to fix this problem. On a related note, comparing recursive -objects recursed infinitely and crashed; Jeremy Hylton rewrote the -code to no longer crash, producing a useful result instead. For -example, after this code: - -\begin{verbatim} -a = [] -b = [] -a.append(a) -b.append(b) -\end{verbatim} - -The comparison \code{a==b} returns true, because the two recursive -data structures are isomorphic. See the thread ``trashcan -and PR\#7'' in the April 2000 archives of the python-dev mailing list -for the discussion leading up to this implementation, and some useful -relevant links. -% Starting URL: -% http://www.python.org/pipermail/python-dev/2000-April/004834.html - -Note that comparisons can now also raise exceptions. In earlier -versions of Python, a comparison operation such as \code{cmp(a,b)} -would always produce an answer, even if a user-defined -\method{__cmp__} method encountered an error, since the resulting -exception would simply be silently swallowed. - -Work has been done on porting Python to 64-bit Windows on the Itanium -processor, mostly by Trent Mick of ActiveState. (Confusingly, -\code{sys.platform} is still \code{'win32'} on Win64 because it seems -that for ease of porting, MS Visual C++ treats code as 32 bit on Itanium.) -PythonWin also supports Windows CE; see the Python CE page at -\url{http://starship.python.net/crew/mhammond/ce/} for more -information. - -Another new platform is Darwin/MacOS X; inital support for it is in -Python 2.0. Dynamic loading works, if you specify ``configure ---with-dyld --with-suffix=.x''. Consult the README in the Python -source distribution for more instructions. - -An attempt has been made to alleviate one of Python's warts, the -often-confusing \exception{NameError} exception when code refers to a -local variable before the variable has been assigned a value. For -example, the following code raises an exception on the \keyword{print} -statement in both 1.5.2 and 2.0; in 1.5.2 a \exception{NameError} -exception is raised, while 2.0 raises a new -\exception{UnboundLocalError} exception. -\exception{UnboundLocalError} is a subclass of \exception{NameError}, -so any existing code that expects \exception{NameError} to be raised -should still work. - -\begin{verbatim} -def f(): - print "i=",i - i = i + 1 -f() -\end{verbatim} - -Two new exceptions, \exception{TabError} and -\exception{IndentationError}, have been introduced. They're both -subclasses of \exception{SyntaxError}, and are raised when Python code -is found to be improperly indented. - -\subsection{Changes to Built-in Functions} - -A new built-in, \function{zip(\var{seq1}, \var{seq2}, ...)}, has been -added. \function{zip()} returns a list of tuples where each tuple -contains the i-th element from each of the argument sequences. The -difference between \function{zip()} and \code{map(None, \var{seq1}, -\var{seq2})} is that \function{map()} pads the sequences with -\code{None} if the sequences aren't all of the same length, while -\function{zip()} truncates the returned list to the length of the -shortest argument sequence. - -The \function{int()} and \function{long()} functions now accept an -optional ``base'' parameter when the first argument is a string. -\code{int('123', 10)} returns 123, while \code{int('123', 16)} returns -291. \code{int(123, 16)} raises a \exception{TypeError} exception -with the message ``can't convert non-string with explicit base''. - -A new variable holding more detailed version information has been -added to the \module{sys} module. \code{sys.version_info} is a tuple -\code{(\var{major}, \var{minor}, \var{micro}, \var{level}, -\var{serial})} For example, in a hypothetical 2.0.1beta1, -\code{sys.version_info} would be \code{(2, 0, 1, 'beta', 1)}. -\var{level} is a string such as \code{"alpha"}, \code{"beta"}, or -\code{"final"} for a final release. - -Dictionaries have an odd new method, \method{setdefault(\var{key}, -\var{default})}, which behaves similarly to the existing -\method{get()} method. However, if the key is missing, -\method{setdefault()} both returns the value of \var{default} as -\method{get()} would do, and also inserts it into the dictionary as -the value for \var{key}. Thus, the following lines of code: - -\begin{verbatim} -if dict.has_key( key ): return dict[key] -else: - dict[key] = [] - return dict[key] -\end{verbatim} - -can be reduced to a single \code{return dict.setdefault(key, [])} statement. - -The interpreter sets a maximum recursion depth in order to catch -runaway recursion before filling the C stack and causing a core dump -or GPF.. Previously this limit was fixed when you compiled Python, -but in 2.0 the maximum recursion depth can be read and modified using -\function{sys.getrecursionlimit} and \function{sys.setrecursionlimit}. -The default value is 1000, and a rough maximum value for a given -platform can be found by running a new script, -\file{Misc/find_recursionlimit.py}. - -% ====================================================================== -\section{Porting to 2.0} - -New Python releases try hard to be compatible with previous releases, -and the record has been pretty good. However, some changes are -considered useful enough, usually because they fix initial design decisions that -turned out to be actively mistaken, that breaking backward compatibility -can't always be avoided. This section lists the changes in Python 2.0 -that may cause old Python code to break. - -The change which will probably break the most code is tightening up -the arguments accepted by some methods. Some methods would take -multiple arguments and treat them as a tuple, particularly various -list methods such as \method{.append()} and \method{.insert()}. -In earlier versions of Python, if \code{L} is a list, \code{L.append( -1,2 )} appends the tuple \code{(1,2)} to the list. In Python 2.0 this -causes a \exception{TypeError} exception to be raised, with the -message: 'append requires exactly 1 argument; 2 given'. The fix is to -simply add an extra set of parentheses to pass both values as a tuple: -\code{L.append( (1,2) )}. - -The earlier versions of these methods were more forgiving because they -used an old function in Python's C interface to parse their arguments; -2.0 modernizes them to use \function{PyArg_ParseTuple}, the current -argument parsing function, which provides more helpful error messages -and treats multi-argument calls as errors. If you absolutely must use -2.0 but can't fix your code, you can edit \file{Objects/listobject.c} -and define the preprocessor symbol \code{NO_STRICT_LIST_APPEND} to -preserve the old behaviour; this isn't recommended. - -Some of the functions in the \module{socket} module are still -forgiving in this way. For example, \function{socket.connect( -('hostname', 25) )} is the correct form, passing a tuple representing -an IP address, but \function{socket.connect( 'hostname', 25 )} also -works. \function{socket.connect_ex()} and \function{socket.bind()} are -similarly easy-going. 2.0alpha1 tightened these functions up, but -because the documentation actually used the erroneous multiple -argument form, many people wrote code which would break with the -stricter checking. GvR backed out the changes in the face of public -reaction, so for the \module{socket} module, the documentation was -fixed and the multiple argument form is simply marked as deprecated; -it \emph{will} be tightened up again in a future Python version. - -The \code{\e x} escape in string literals now takes exactly 2 hex -digits. Previously it would consume all the hex digits following the -'x' and take the lowest 8 bits of the result, so \code{\e x123456} was -equivalent to \code{\e x56}. - -The \exception{AttributeError} exception has a more friendly error message, -whose text will be something like \code{'Spam' instance has no attribute 'eggs'}. -Previously the error message was just the missing attribute name \code{eggs}, and -code written to take advantage of this fact will break in 2.0. - -Some work has been done to make integers and long integers a bit more -interchangeable. In 1.5.2, large-file support was added for Solaris, -to allow reading files larger than 2Gb; this made the \method{tell()} -method of file objects return a long integer instead of a regular -integer. Some code would subtract two file offsets and attempt to use -the result to multiply a sequence or slice a string, but this raised a -\exception{TypeError}. In 2.0, long integers can be used to multiply -or slice a sequence, and it'll behave as you'd intuitively expect it -to; \code{3L * 'abc'} produces 'abcabcabc', and \code{ -(0,1,2,3)[2L:4L]} produces (2,3). Long integers can also be used in -various contexts where previously only integers were accepted, such -as in the \method{seek()} method of file objects, and in the formats -supported by the \verb|%| operator (\verb|%d|, \verb|%i|, \verb|%x|, -etc.). For example, \code{"\%d" \% 2L**64} will produce the string -\samp{18446744073709551616}. - -The subtlest long integer change of all is that the \function{str()} -of a long integer no longer has a trailing 'L' character, though -\function{repr()} still includes it. The 'L' annoyed many people who -wanted to print long integers that looked just like regular integers, -since they had to go out of their way to chop off the character. This -is no longer a problem in 2.0, but code which does \code{str(longval)[:-1]} and assumes the 'L' is there, will now lose -the final digit. - -Taking the \function{repr()} of a float now uses a different -formatting precision than \function{str()}. \function{repr()} uses -\code{\%.17g} format string for C's \function{sprintf()}, while -\function{str()} uses \code{\%.12g} as before. The effect is that -\function{repr()} may occasionally show more decimal places than -\function{str()}, for certain numbers. -For example, the number 8.1 can't be represented exactly in binary, so -\code{repr(8.1)} is \code{'8.0999999999999996'}, while str(8.1) is -\code{'8.1'}. - -The \code{-X} command-line option, which turned all standard -exceptions into strings instead of classes, has been removed; the -standard exceptions will now always be classes. The -\module{exceptions} module containing the standard exceptions was -translated from Python to a built-in C module, written by Barry Warsaw -and Fredrik Lundh. - -% Commented out for now -- I don't think anyone will care. -%The pattern and match objects provided by SRE are C types, not Python -%class instances as in 1.5. This means you can no longer inherit from -%\class{RegexObject} or \class{MatchObject}, but that shouldn't be much -%of a problem since no one should have been doing that in the first -%place. - -% ====================================================================== -\section{Extending/Embedding Changes} - -Some of the changes are under the covers, and will only be apparent to -people writing C extension modules or embedding a Python interpreter -in a larger application. If you aren't dealing with Python's C API, -you can safely skip this section. - -The version number of the Python C API was incremented, so C -extensions compiled for 1.5.2 must be recompiled in order to work with -2.0. On Windows, it's not possible for Python 2.0 to import a third -party extension built for Python 1.5.x due to how Windows DLLs work, -so Python will raise an exception and the import will fail. - -Users of Jim Fulton's ExtensionClass module will be pleased to find -out that hooks have been added so that ExtensionClasses are now -supported by \function{isinstance()} and \function{issubclass()}. -This means you no longer have to remember to write code such as -\code{if type(obj) == myExtensionClass}, but can use the more natural -\code{if isinstance(obj, myExtensionClass)}. - -The \file{Python/importdl.c} file, which was a mass of \#ifdefs to -support dynamic loading on many different platforms, was cleaned up -and reorganised by Greg Stein. \file{importdl.c} is now quite small, -and platform-specific code has been moved into a bunch of -\file{Python/dynload_*.c} files. Another cleanup: there were also a -number of \file{my*.h} files in the Include/ directory that held -various portability hacks; they've been merged into a single file, -\file{Include/pyport.h}. - -Vladimir Marangozov's long-awaited malloc restructuring was completed, -to make it easy to have the Python interpreter use a custom allocator -instead of C's standard \function{malloc()}. For documentation, read -the comments in \file{Include/pymem.h} and -\file{Include/objimpl.h}. For the lengthy discussions during which -the interface was hammered out, see the Web archives of the 'patches' -and 'python-dev' lists at python.org. - -Recent versions of the GUSI development environment for MacOS support -POSIX threads. Therefore, Python's POSIX threading support now works -on the Macintosh. Threading support using the user-space GNU \texttt{pth} -library was also contributed. - -Threading support on Windows was enhanced, too. Windows supports -thread locks that use kernel objects only in case of contention; in -the common case when there's no contention, they use simpler functions -which are an order of magnitude faster. A threaded version of Python -1.5.2 on NT is twice as slow as an unthreaded version; with the 2.0 -changes, the difference is only 10\%. These improvements were -contributed by Yakov Markovitch. - -Python 2.0's source now uses only ANSI C prototypes, so compiling Python now -requires an ANSI C compiler, and can no longer be done using a compiler that -only supports K\&R C. - -Previously the Python virtual machine used 16-bit numbers in its -bytecode, limiting the size of source files. In particular, this -affected the maximum size of literal lists and dictionaries in Python -source; occasionally people who are generating Python code would run -into this limit. A patch by Charles G. Waldman raises the limit from -\verb|2^16| to \verb|2^{32}|. - -Three new convenience functions intended for adding constants to a -module's dictionary at module initialization time were added: -\function{PyModule_AddObject()}, \function{PyModule_AddIntConstant()}, -and \function{PyModule_AddStringConstant()}. Each of these functions -takes a module object, a null-terminated C string containing the name -to be added, and a third argument for the value to be assigned to the -name. This third argument is, respectively, a Python object, a C -long, or a C string. - -A wrapper API was added for Unix-style signal handlers. -\function{PyOS_getsig()} gets a signal handler and -\function{PyOS_setsig()} will set a new handler. - -% ====================================================================== -\section{Distutils: Making Modules Easy to Install} - -Before Python 2.0, installing modules was a tedious affair -- there -was no way to figure out automatically where Python is installed, or -what compiler options to use for extension modules. Software authors -had to go through an arduous ritual of editing Makefiles and -configuration files, which only really work on Unix and leave Windows -and MacOS unsupported. Python users faced wildly differing -installation instructions which varied between different extension -packages, which made adminstering a Python installation something of a -chore. - -The SIG for distribution utilities, shepherded by Greg Ward, has -created the Distutils, a system to make package installation much -easier. They form the \module{distutils} package, a new part of -Python's standard library. In the best case, installing a Python -module from source will require the same steps: first you simply mean -unpack the tarball or zip archive, and the run ``\code{python setup.py -install}''. The platform will be automatically detected, the compiler -will be recognized, C extension modules will be compiled, and the -distribution installed into the proper directory. Optional -command-line arguments provide more control over the installation -process, the distutils package offers many places to override defaults --- separating the build from the install, building or installing in -non-default directories, and more. - -In order to use the Distutils, you need to write a \file{setup.py} -script. For the simple case, when the software contains only .py -files, a minimal \file{setup.py} can be just a few lines long: - -\begin{verbatim} -from distutils.core import setup -setup (name = "foo", version = "1.0", - py_modules = ["module1", "module2"]) -\end{verbatim} - -The \file{setup.py} file isn't much more complicated if the software -consists of a few packages: - -\begin{verbatim} -from distutils.core import setup -setup (name = "foo", version = "1.0", - packages = ["package", "package.subpackage"]) -\end{verbatim} - -A C extension can be the most complicated case; here's an example taken from -the PyXML package: - - -\begin{verbatim} -from distutils.core import setup, Extension - -expat_extension = Extension('xml.parsers.pyexpat', - define_macros = [('XML_NS', None)], - include_dirs = [ 'extensions/expat/xmltok', - 'extensions/expat/xmlparse' ], - sources = [ 'extensions/pyexpat.c', - 'extensions/expat/xmltok/xmltok.c', - 'extensions/expat/xmltok/xmlrole.c', - ] - ) -setup (name = "PyXML", version = "0.5.4", - ext_modules =[ expat_extension ] ) -\end{verbatim} - -The Distutils can also take care of creating source and binary -distributions. The ``sdist'' command, run by ``\code{python setup.py -sdist}', builds a source distribution such as \file{foo-1.0.tar.gz}. -Adding new commands isn't difficult, ``bdist_rpm'' and -``bdist_wininst'' commands have already been contributed to create an -RPM distribution and a Windows installer for the software, -respectively. Commands to create other distribution formats such as -Debian packages and Solaris \file{.pkg} files are in various stages of -development. - -All this is documented in a new manual, \textit{Distributing Python -Modules}, that joins the basic set of Python documentation. - -% ====================================================================== -\section{XML Modules} - -Python 1.5.2 included a simple XML parser in the form of the -\module{xmllib} module, contributed by Sjoerd Mullender. Since -1.5.2's release, two different interfaces for processing XML have -become common: SAX2 (version 2 of the Simple API for XML) provides an -event-driven interface with some similarities to \module{xmllib}, and -the DOM (Document Object Model) provides a tree-based interface, -transforming an XML document into a tree of nodes that can be -traversed and modified. Python 2.0 includes a SAX2 interface and a -stripped-down DOM interface as part of the \module{xml} package. -Here we will give a brief overview of these new interfaces; consult -the Python documentation or the source code for complete details. -The Python XML SIG is also working on improved documentation. - -\subsection{SAX2 Support} - -SAX defines an event-driven interface for parsing XML. To use SAX, -you must write a SAX handler class. Handler classes inherit from -various classes provided by SAX, and override various methods that -will then be called by the XML parser. For example, the -\method{startElement} and \method{endElement} methods are called for -every starting and end tag encountered by the parser, the -\method{characters()} method is called for every chunk of character -data, and so forth. - -The advantage of the event-driven approach is that that the whole -document doesn't have to be resident in memory at any one time, which -matters if you are processing really huge documents. However, writing -the SAX handler class can get very complicated if you're trying to -modify the document structure in some elaborate way. - -For example, this little example program defines a handler that prints -a message for every starting and ending tag, and then parses the file -\file{hamlet.xml} using it: - -\begin{verbatim} -from xml import sax - -class SimpleHandler(sax.ContentHandler): - def startElement(self, name, attrs): - print 'Start of element:', name, attrs.keys() - - def endElement(self, name): - print 'End of element:', name - -# Create a parser object -parser = sax.make_parser() - -# Tell it what handler to use -handler = SimpleHandler() -parser.setContentHandler( handler ) - -# Parse a file! -parser.parse( 'hamlet.xml' ) -\end{verbatim} - -For more information, consult the Python documentation, or the XML -HOWTO at \url{http://www.python.org/doc/howto/xml/}. - -\subsection{DOM Support} - -The Document Object Model is a tree-based representation for an XML -document. A top-level \class{Document} instance is the root of the -tree, and has a single child which is the top-level \class{Element} -instance. This \class{Element} has children nodes representing -character data and any sub-elements, which may have further children -of their own, and so forth. Using the DOM you can traverse the -resulting tree any way you like, access element and attribute values, -insert and delete nodes, and convert the tree back into XML. - -The DOM is useful for modifying XML documents, because you can create -a DOM tree, modify it by adding new nodes or rearranging subtrees, and -then produce a new XML document as output. You can also construct a -DOM tree manually and convert it to XML, which can be a more flexible -way of producing XML output than simply writing -\code{}...\code{} to a file. - -The DOM implementation included with Python lives in the -\module{xml.dom.minidom} module. It's a lightweight implementation of -the Level 1 DOM with support for XML namespaces. The -\function{parse()} and \function{parseString()} convenience -functions are provided for generating a DOM tree: - -\begin{verbatim} -from xml.dom import minidom -doc = minidom.parse('hamlet.xml') -\end{verbatim} - -\code{doc} is a \class{Document} instance. \class{Document}, like all -the other DOM classes such as \class{Element} and \class{Text}, is a -subclass of the \class{Node} base class. All the nodes in a DOM tree -therefore support certain common methods, such as \method{toxml()} -which returns a string containing the XML representation of the node -and its children. Each class also has special methods of its own; for -example, \class{Element} and \class{Document} instances have a method -to find all child elements with a given tag name. Continuing from the -previous 2-line example: - -\begin{verbatim} -perslist = doc.getElementsByTagName( 'PERSONA' ) -print perslist[0].toxml() -print perslist[1].toxml() -\end{verbatim} - -For the \textit{Hamlet} XML file, the above few lines output: - -\begin{verbatim} -CLAUDIUS, king of Denmark. -HAMLET, son to the late, and nephew to the present king. -\end{verbatim} - -The root element of the document is available as -\code{doc.documentElement}, and its children can be easily modified -by deleting, adding, or removing nodes: - -\begin{verbatim} -root = doc.documentElement - -# Remove the first child -root.removeChild( root.childNodes[0] ) - -# Move the new first child to the end -root.appendChild( root.childNodes[0] ) - -# Insert the new first child (originally, -# the third child) before the 20th child. -root.insertBefore( root.childNodes[0], root.childNodes[20] ) -\end{verbatim} - -Again, I will refer you to the Python documentation for a complete -listing of the different \class{Node} classes and their various methods. - -\subsection{Relationship to PyXML} - -The XML Special Interest Group has been working on XML-related Python -code for a while. Its code distribution, called PyXML, is available -from the SIG's Web pages at \url{http://www.python.org/sigs/xml-sig/}. -The PyXML distribution also used the package name \samp{xml}. If -you've written programs that used PyXML, you're probably wondering -about its compatibility with the 2.0 \module{xml} package. - -The answer is that Python 2.0's \module{xml} package isn't compatible -with PyXML, but can be made compatible by installing a recent version -PyXML. Many applications can get by with the XML support that is -included with Python 2.0, but more complicated applications will -require that the full PyXML package will be installed. When -installed, PyXML versions 0.6.0 or greater will replace the -\module{xml} package shipped with Python, and will be a strict -superset of the standard package, adding a bunch of additional -features. Some of the additional features in PyXML include: - -\begin{itemize} -\item 4DOM, a full DOM implementation -from FourThought, Inc. -\item The xmlproc validating parser, written by Lars Marius Garshol. -\item The \module{sgmlop} parser accelerator module, written by Fredrik Lundh. -\end{itemize} - -% ====================================================================== -\section{Module changes} - -Lots of improvements and bugfixes were made to Python's extensive -standard library; some of the affected modules include -\module{readline}, \module{ConfigParser}, \module{cgi}, -\module{calendar}, \module{posix}, \module{readline}, \module{xmllib}, -\module{aifc}, \module{chunk, wave}, \module{random}, \module{shelve}, -and \module{nntplib}. Consult the CVS logs for the exact -patch-by-patch details. - -Brian Gallew contributed OpenSSL support for the \module{socket} -module. OpenSSL is an implementation of the Secure Socket Layer, -which encrypts the data being sent over a socket. When compiling -Python, you can edit \file{Modules/Setup} to include SSL support, -which adds an additional function to the \module{socket} module: -\function{socket.ssl(\var{socket}, \var{keyfile}, \var{certfile})}, -which takes a socket object and returns an SSL socket. The -\module{httplib} and \module{urllib} modules were also changed to -support ``https://'' URLs, though no one has implemented FTP or SMTP -over SSL. - -The \module{httplib} module has been rewritten by Greg Stein to -support HTTP/1.1. Backward compatibility with the 1.5 version of -\module{httplib} is provided, though using HTTP/1.1 features such as -pipelining will require rewriting code to use a different set of -interfaces. - -The \module{Tkinter} module now supports Tcl/Tk version 8.1, 8.2, or -8.3, and support for the older 7.x versions has been dropped. The -Tkinter module now supports displaying Unicode strings in Tk widgets. -Also, Fredrik Lundh contributed an optimization which makes operations -like \code{create_line} and \code{create_polygon} much faster, -especially when using lots of coordinates. - -The \module{curses} module has been greatly extended, starting from -Oliver Andrich's enhanced version, to provide many additional -functions from ncurses and SYSV curses, such as colour, alternative -character set support, pads, and mouse support. This means the module -is no longer compatible with operating systems that only have BSD -curses, but there don't seem to be any currently maintained OSes that -fall into this category. - -As mentioned in the earlier discussion of 2.0's Unicode support, the -underlying implementation of the regular expressions provided by the -\module{re} module has been changed. SRE, a new regular expression -engine written by Fredrik Lundh and partially funded by Hewlett -Packard, supports matching against both 8-bit strings and Unicode -strings. - -% ====================================================================== -\section{New modules} - -A number of new modules were added. We'll simply list them with brief -descriptions; consult the 2.0 documentation for the details of a -particular module. - -\begin{itemize} - -\item{\module{atexit}}: -For registering functions to be called before the Python interpreter exits. -Code that currently sets -\code{sys.exitfunc} directly should be changed to -use the \module{atexit} module instead, importing \module{atexit} -and calling \function{atexit.register()} with -the function to be called on exit. -(Contributed by Skip Montanaro.) - -\item{\module{codecs}, \module{encodings}, \module{unicodedata}:} Added as part of the new Unicode support. - -\item{\module{filecmp}:} Supersedes the old \module{cmp}, \module{cmpcache} and -\module{dircmp} modules, which have now become deprecated. -(Contributed by Gordon MacMillan and Moshe Zadka.) - -\item{\module{gettext}:} This module provides internationalization -(I18N) and localization (L10N) support for Python programs by -providing an interface to the GNU gettext message catalog library. -(Integrated by Barry Warsaw, from separate contributions by Martin von -Loewis, Peter Funk, and James Henstridge.) - -\item{\module{linuxaudiodev}:} Support for the \file{/dev/audio} -device on Linux, a twin to the existing \module{sunaudiodev} module. -(Contributed by Peter Bosch, with fixes by Jeremy Hylton.) - -\item{\module{mmap}:} An interface to memory-mapped files on both -Windows and Unix. A file's contents can be mapped directly into -memory, at which point it behaves like a mutable string, so its -contents can be read and modified. They can even be passed to -functions that expect ordinary strings, such as the \module{re} -module. (Contributed by Sam Rushing, with some extensions by -A.M. Kuchling.) - -\item{\module{pyexpat}:} An interface to the Expat XML parser. -(Contributed by Paul Prescod.) - -\item{\module{robotparser}:} Parse a \file{robots.txt} file, which is -used for writing Web spiders that politely avoid certain areas of a -Web site. The parser accepts the contents of a \file{robots.txt} file, -builds a set of rules from it, and can then answer questions about -the fetchability of a given URL. (Contributed by Skip Montanaro.) - -\item{\module{tabnanny}:} A module/script to -check Python source code for ambiguous indentation. -(Contributed by Tim Peters.) - -\item{\module{UserString}:} A base class useful for deriving objects that behave like strings. - -\item{\module{webbrowser}:} A module that provides a platform independent -way to launch a web browser on a specific URL. For each platform, various -browsers are tried in a specific order. The user can alter which browser -is launched by setting the \var{BROWSER} environment variable. -(Originally inspired by Eric S. Raymond's patch to \module{urllib} -which added similar functionality, but -the final module comes from code originally -implemented by Fred Drake as \file{Tools/idle/BrowserControl.py}, -and adapted for the standard library by Fred.) - -\item{\module{_winreg}:} An interface to the -Windows registry. \module{_winreg} is an adaptation of functions that -have been part of PythonWin since 1995, but has now been added to the core -distribution, and enhanced to support Unicode. -\module{_winreg} was written by Bill Tutt and Mark Hammond. - -\item{\module{zipfile}:} A module for reading and writing ZIP-format -archives. These are archives produced by \program{PKZIP} on -DOS/Windows or \program{zip} on Unix, not to be confused with -\program{gzip}-format files (which are supported by the \module{gzip} -module) -(Contributed by James C. Ahlstrom.) - -\item{\module{imputil}:} A module that provides a simpler way for -writing customised import hooks, in comparison to the existing -\module{ihooks} module. (Implemented by Greg Stein, with much -discussion on python-dev along the way.) - -\end{itemize} - -% ====================================================================== -\section{IDLE Improvements} - -IDLE is the official Python cross-platform IDE, written using Tkinter. -Python 2.0 includes IDLE 0.6, which adds a number of new features and -improvements. A partial list: - -\begin{itemize} -\item UI improvements and optimizations, -especially in the area of syntax highlighting and auto-indentation. - -\item The class browser now shows more information, such as the top -level functions in a module. - -\item Tab width is now a user settable option. When opening an existing Python -file, IDLE automatically detects the indentation conventions, and adapts. - -\item There is now support for calling browsers on various platforms, -used to open the Python documentation in a browser. - -\item IDLE now has a command line, which is largely similar to -the vanilla Python interpreter. - -\item Call tips were added in many places. - -\item IDLE can now be installed as a package. - -\item In the editor window, there is now a line/column bar at the bottom. - -\item Three new keystroke commands: Check module (Alt-F5), Import -module (F5) and Run script (Ctrl-F5). - -\end{itemize} - -% ====================================================================== -\section{Deleted and Deprecated Modules} - -A few modules have been dropped because they're obsolete, or because -there are now better ways to do the same thing. The \module{stdwin} -module is gone; it was for a platform-independent windowing toolkit -that's no longer developed. - -A number of modules have been moved to the -\file{lib-old} subdirectory: -\module{cmp}, \module{cmpcache}, \module{dircmp}, \module{dump}, -\module{find}, \module{grep}, \module{packmail}, -\module{poly}, \module{util}, \module{whatsound}, \module{zmod}. -If you have code which relies on a module that's been moved to -\file{lib-old}, you can simply add that directory to \code{sys.path} -to get them back, but you're encouraged to update any code that uses -these modules. - -\section{Acknowledgements} - -The authors would like to thank the following people for offering -suggestions on various drafts of this article: David Bolen, Mark Hammond, Gregg Hauser, -Jeremy Hylton, Fredrik Lundh, Detlef Lannert, Aahz Maruch, Skip -Montanaro, Vladimir Marangozov, Guido van Rossum, Neil Schemenauer, -and Russ Schmidt. - -\end{document} diff --git a/Doc/whatsnew/whatsnew21.tex b/Doc/whatsnew/whatsnew21.tex deleted file mode 100644 index d296f4c..0000000 --- a/Doc/whatsnew/whatsnew21.tex +++ /dev/null @@ -1,868 +0,0 @@ -\documentclass{howto} - -\usepackage{distutils} - -% $Id$ - -\title{What's New in Python 2.1} -\release{1.00} -\author{A.M. Kuchling} -\authoraddress{\email{akuchlin@mems-exchange.org}} -\begin{document} -\maketitle\tableofcontents - -\section{Introduction} - -It's that time again... time for a new Python release, Python 2.1. -One recent goal of the Python development team has been to accelerate -the pace of new releases, with a new release coming every 6 to 9 -months. 2.1 is the first release to come out at this faster pace, with -the first alpha appearing in January, 3 months after the final version -of 2.0 was released. - -This article explains the new features in 2.1. While there aren't as -many changes in 2.1 as there were in Python 2.0, there are still some -pleasant surprises in store. 2.1 is the first release to be steered -through the use of Python Enhancement Proposals, or PEPs, so most of -the sizable changes have accompanying PEPs that provide more complete -documentation and a design rationale for the change. This article -doesn't attempt to document the new features completely, but simply -provides an overview of the new features for Python programmers. -Refer to the Python 2.1 documentation, or to the specific PEP, for -more details about any new feature that particularly interests you. - -The final release of Python 2.1 was made on April 17, 2001. - -%====================================================================== -\section{PEP 227: Nested Scopes} - -The largest change in Python 2.1 is to Python's scoping rules. In -Python 2.0, at any given time there are at most three namespaces used -to look up variable names: local, module-level, and the built-in -namespace. This often surprised people because it didn't match their -intuitive expectations. For example, a nested recursive function -definition doesn't work: - -\begin{verbatim} -def f(): - ... - def g(value): - ... - return g(value-1) + 1 - ... -\end{verbatim} - -The function \function{g()} will always raise a \exception{NameError} -exception, because the binding of the name \samp{g} isn't in either -its local namespace or in the module-level namespace. This isn't much -of a problem in practice (how often do you recursively define interior -functions like this?), but this also made using the \keyword{lambda} -statement clumsier, and this was a problem in practice. In code which -uses \keyword{lambda} you can often find local variables being copied -by passing them as the default values of arguments. - -\begin{verbatim} -def find(self, name): - "Return list of any entries equal to 'name'" - L = filter(lambda x, name=name: x == name, - self.list_attribute) - return L -\end{verbatim} - -The readability of Python code written in a strongly functional style -suffers greatly as a result. - -The most significant change to Python 2.1 is that static scoping has -been added to the language to fix this problem. As a first effect, -the \code{name=name} default argument is now unnecessary in the above -example. Put simply, when a given variable name is not assigned a -value within a function (by an assignment, or the \keyword{def}, -\keyword{class}, or \keyword{import} statements), references to the -variable will be looked up in the local namespace of the enclosing -scope. A more detailed explanation of the rules, and a dissection of -the implementation, can be found in the PEP. - -This change may cause some compatibility problems for code where the -same variable name is used both at the module level and as a local -variable within a function that contains further function definitions. -This seems rather unlikely though, since such code would have been -pretty confusing to read in the first place. - -One side effect of the change is that the \code{from \var{module} -import *} and \keyword{exec} statements have been made illegal inside -a function scope under certain conditions. The Python reference -manual has said all along that \code{from \var{module} import *} is -only legal at the top level of a module, but the CPython interpreter -has never enforced this before. As part of the implementation of -nested scopes, the compiler which turns Python source into bytecodes -has to generate different code to access variables in a containing -scope. \code{from \var{module} import *} and \keyword{exec} make it -impossible for the compiler to figure this out, because they add names -to the local namespace that are unknowable at compile time. -Therefore, if a function contains function definitions or -\keyword{lambda} expressions with free variables, the compiler will -flag this by raising a \exception{SyntaxError} exception. - -To make the preceding explanation a bit clearer, here's an example: - -\begin{verbatim} -x = 1 -def f(): - # The next line is a syntax error - exec 'x=2' - def g(): - return x -\end{verbatim} - -Line 4 containing the \keyword{exec} statement is a syntax error, -since \keyword{exec} would define a new local variable named \samp{x} -whose value should be accessed by \function{g()}. - -This shouldn't be much of a limitation, since \keyword{exec} is rarely -used in most Python code (and when it is used, it's often a sign of a -poor design anyway). - -Compatibility concerns have led to nested scopes being introduced -gradually; in Python 2.1, they aren't enabled by default, but can be -turned on within a module by using a future statement as described in -PEP 236. (See the following section for further discussion of PEP -236.) In Python 2.2, nested scopes will become the default and there -will be no way to turn them off, but users will have had all of 2.1's -lifetime to fix any breakage resulting from their introduction. - -\begin{seealso} - -\seepep{227}{Statically Nested Scopes}{Written and implemented by -Jeremy Hylton.} - -\end{seealso} - - -%====================================================================== -\section{PEP 236: \module{__future__} Directives} - -The reaction to nested scopes was widespread concern about the dangers -of breaking code with the 2.1 release, and it was strong enough to -make the Pythoneers take a more conservative approach. This approach -consists of introducing a convention for enabling optional -functionality in release N that will become compulsory in release N+1. - -The syntax uses a \code{from...import} statement using the reserved -module name \module{__future__}. Nested scopes can be enabled by the -following statement: - -\begin{verbatim} -from __future__ import nested_scopes -\end{verbatim} - -While it looks like a normal \keyword{import} statement, it's not; -there are strict rules on where such a future statement can be put. -They can only be at the top of a module, and must precede any Python -code or regular \keyword{import} statements. This is because such -statements can affect how the Python bytecode compiler parses code and -generates bytecode, so they must precede any statement that will -result in bytecodes being produced. - -\begin{seealso} - -\seepep{236}{Back to the \module{__future__}}{Written by Tim Peters, -and primarily implemented by Jeremy Hylton.} - -\end{seealso} - -%====================================================================== -\section{PEP 207: Rich Comparisons} - -In earlier versions, Python's support for implementing comparisons on -user-defined classes and extension types was quite simple. Classes -could implement a \method{__cmp__} method that was given two instances -of a class, and could only return 0 if they were equal or +1 or -1 if -they weren't; the method couldn't raise an exception or return -anything other than a Boolean value. Users of Numeric Python often -found this model too weak and restrictive, because in the -number-crunching programs that numeric Python is used for, it would be -more useful to be able to perform elementwise comparisons of two -matrices, returning a matrix containing the results of a given -comparison for each element. If the two matrices are of different -sizes, then the compare has to be able to raise an exception to signal -the error. - -In Python 2.1, rich comparisons were added in order to support this -need. Python classes can now individually overload each of the -\code{<}, \code{<=}, \code{>}, \code{>=}, \code{==}, and \code{!=} -operations. The new magic method names are: - -\begin{tableii}{c|l}{code}{Operation}{Method name} - \lineii{<}{\method{__lt__}} \lineii{<=}{\method{__le__}} - \lineii{>}{\method{__gt__}} \lineii{>=}{\method{__ge__}} - \lineii{==}{\method{__eq__}} \lineii{!=}{\method{__ne__}} - \end{tableii} - -(The magic methods are named after the corresponding Fortran operators -\code{.LT.}. \code{.LE.}, \&c. Numeric programmers are almost -certainly quite familar with these names and will find them easy to -remember.) - -Each of these magic methods is of the form \code{\var{method}(self, -other)}, where \code{self} will be the object on the left-hand side of -the operator, while \code{other} will be the object on the right-hand -side. For example, the expression \code{A < B} will cause -\code{A.__lt__(B)} to be called. - -Each of these magic methods can return anything at all: a Boolean, a -matrix, a list, or any other Python object. Alternatively they can -raise an exception if the comparison is impossible, inconsistent, or -otherwise meaningless. - -The built-in \function{cmp(A,B)} function can use the rich comparison -machinery, and now accepts an optional argument specifying which -comparison operation to use; this is given as one of the strings -\code{"<"}, \code{"<="}, \code{">"}, \code{">="}, \code{"=="}, or -\code{"!="}. If called without the optional third argument, -\function{cmp()} will only return -1, 0, or +1 as in previous versions -of Python; otherwise it will call the appropriate method and can -return any Python object. - -There are also corresponding changes of interest to C programmers; -there's a new slot \code{tp_richcmp} in type objects and an API for -performing a given rich comparison. I won't cover the C API here, but -will refer you to PEP 207, or to 2.1's C API documentation, for the -full list of related functions. - -\begin{seealso} - -\seepep{207}{Rich Comparisions}{Written by Guido van Rossum, heavily -based on earlier work by David Ascher, and implemented by Guido van -Rossum.} - -\end{seealso} - -%====================================================================== -\section{PEP 230: Warning Framework} - -Over its 10 years of existence, Python has accumulated a certain -number of obsolete modules and features along the way. It's difficult -to know when a feature is safe to remove, since there's no way of -knowing how much code uses it --- perhaps no programs depend on the -feature, or perhaps many do. To enable removing old features in a -more structured way, a warning framework was added. When the Python -developers want to get rid of a feature, it will first trigger a -warning in the next version of Python. The following Python version -can then drop the feature, and users will have had a full release -cycle to remove uses of the old feature. - -Python 2.1 adds the warning framework to be used in this scheme. It -adds a \module{warnings} module that provide functions to issue -warnings, and to filter out warnings that you don't want to be -displayed. Third-party modules can also use this framework to -deprecate old features that they no longer wish to support. - -For example, in Python 2.1 the \module{regex} module is deprecated, so -importing it causes a warning to be printed: - -\begin{verbatim} ->>> import regex -__main__:1: DeprecationWarning: the regex module - is deprecated; please use the re module ->>> -\end{verbatim} - -Warnings can be issued by calling the \function{warnings.warn} -function: - -\begin{verbatim} -warnings.warn("feature X no longer supported") -\end{verbatim} - -The first parameter is the warning message; an additional optional -parameters can be used to specify a particular warning category. - -Filters can be added to disable certain warnings; a regular expression -pattern can be applied to the message or to the module name in order -to suppress a warning. For example, you may have a program that uses -the \module{regex} module and not want to spare the time to convert it -to use the \module{re} module right now. The warning can be -suppressed by calling - -\begin{verbatim} -import warnings -warnings.filterwarnings(action = 'ignore', - message='.*regex module is deprecated', - category=DeprecationWarning, - module = '__main__') -\end{verbatim} - -This adds a filter that will apply only to warnings of the class -\class{DeprecationWarning} triggered in the \module{__main__} module, -and applies a regular expression to only match the message about the -\module{regex} module being deprecated, and will cause such warnings -to be ignored. Warnings can also be printed only once, printed every -time the offending code is executed, or turned into exceptions that -will cause the program to stop (unless the exceptions are caught in -the usual way, of course). - -Functions were also added to Python's C API for issuing warnings; -refer to PEP 230 or to Python's API documentation for the details. - -\begin{seealso} - -\seepep{5}{Guidelines for Language Evolution}{Written -by Paul Prescod, to specify procedures to be followed when removing -old features from Python. The policy described in this PEP hasn't -been officially adopted, but the eventual policy probably won't be too -different from Prescod's proposal.} - -\seepep{230}{Warning Framework}{Written and implemented by Guido van -Rossum.} - -\end{seealso} - -%====================================================================== -\section{PEP 229: New Build System} - -When compiling Python, the user had to go in and edit the -\file{Modules/Setup} file in order to enable various additional -modules; the default set is relatively small and limited to modules -that compile on most Unix platforms. This means that on Unix -platforms with many more features, most notably Linux, Python -installations often don't contain all useful modules they could. - -Python 2.0 added the Distutils, a set of modules for distributing and -installing extensions. In Python 2.1, the Distutils are used to -compile much of the standard library of extension modules, -autodetecting which ones are supported on the current machine. It's -hoped that this will make Python installations easier and more -featureful. - -Instead of having to edit the \file{Modules/Setup} file in order to -enable modules, a \file{setup.py} script in the top directory of the -Python source distribution is run at build time, and attempts to -discover which modules can be enabled by examining the modules and -header files on the system. If a module is configured in -\file{Modules/Setup}, the \file{setup.py} script won't attempt to -compile that module and will defer to the \file{Modules/Setup} file's -contents. This provides a way to specific any strange command-line -flags or libraries that are required for a specific platform. - -In another far-reaching change to the build mechanism, Neil -Schemenauer restructured things so Python now uses a single makefile -that isn't recursive, instead of makefiles in the top directory and in -each of the \file{Python/}, \file{Parser/}, \file{Objects/}, and -\file{Modules/} subdirectories. This makes building Python faster -and also makes hacking the Makefiles clearer and simpler. - -\begin{seealso} - -\seepep{229}{Using Distutils to Build Python}{Written -and implemented by A.M. Kuchling.} - -\end{seealso} - -%====================================================================== -\section{PEP 205: Weak References} - -Weak references, available through the \module{weakref} module, are a -minor but useful new data type in the Python programmer's toolbox. - -Storing a reference to an object (say, in a dictionary or a list) has -the side effect of keeping that object alive forever. There are a few -specific cases where this behaviour is undesirable, object caches -being the most common one, and another being circular references in -data structures such as trees. - -For example, consider a memoizing function that caches the results of -another function \function{f(\var{x})} by storing the function's -argument and its result in a dictionary: - -\begin{verbatim} -_cache = {} -def memoize(x): - if _cache.has_key(x): - return _cache[x] - - retval = f(x) - - # Cache the returned object - _cache[x] = retval - - return retval -\end{verbatim} - -This version works for simple things such as integers, but it has a -side effect; the \code{_cache} dictionary holds a reference to the -return values, so they'll never be deallocated until the Python -process exits and cleans up This isn't very noticeable for integers, -but if \function{f()} returns an object, or a data structure that -takes up a lot of memory, this can be a problem. - -Weak references provide a way to implement a cache that won't keep -objects alive beyond their time. If an object is only accessible -through weak references, the object will be deallocated and the weak -references will now indicate that the object it referred to no longer -exists. A weak reference to an object \var{obj} is created by calling -\code{wr = weakref.ref(\var{obj})}. The object being referred to is -returned by calling the weak reference as if it were a function: -\code{wr()}. It will return the referenced object, or \code{None} if -the object no longer exists. - -This makes it possible to write a \function{memoize()} function whose -cache doesn't keep objects alive, by storing weak references in the -cache. - -\begin{verbatim} -_cache = {} -def memoize(x): - if _cache.has_key(x): - obj = _cache[x]() - # If weak reference object still exists, - # return it - if obj is not None: return obj - - retval = f(x) - - # Cache a weak reference - _cache[x] = weakref.ref(retval) - - return retval -\end{verbatim} - -The \module{weakref} module also allows creating proxy objects which -behave like weak references --- an object referenced only by proxy -objects is deallocated -- but instead of requiring an explicit call to -retrieve the object, the proxy transparently forwards all operations -to the object as long as the object still exists. If the object is -deallocated, attempting to use a proxy will cause a -\exception{weakref.ReferenceError} exception to be raised. - -\begin{verbatim} -proxy = weakref.proxy(obj) -proxy.attr # Equivalent to obj.attr -proxy.meth() # Equivalent to obj.meth() -del obj -proxy.attr # raises weakref.ReferenceError -\end{verbatim} - -\begin{seealso} - -\seepep{205}{Weak References}{Written and implemented by -Fred~L. Drake,~Jr.} - -\end{seealso} - -%====================================================================== -\section{PEP 232: Function Attributes} - -In Python 2.1, functions can now have arbitrary information attached -to them. People were often using docstrings to hold information about -functions and methods, because the \code{__doc__} attribute was the -only way of attaching any information to a function. For example, in -the Zope Web application server, functions are marked as safe for -public access by having a docstring, and in John Aycock's SPARK -parsing framework, docstrings hold parts of the BNF grammar to be -parsed. This overloading is unfortunate, since docstrings are really -intended to hold a function's documentation; for example, it means you -can't properly document functions intended for private use in Zope. - -Arbitrary attributes can now be set and retrieved on functions using the -regular Python syntax: - -\begin{verbatim} -def f(): pass - -f.publish = 1 -f.secure = 1 -f.grammar = "A ::= B (C D)*" -\end{verbatim} - -The dictionary containing attributes can be accessed as the function's -\member{__dict__}. Unlike the \member{__dict__} attribute of class -instances, in functions you can actually assign a new dictionary to -\member{__dict__}, though the new value is restricted to a regular -Python dictionary; you \emph{can't} be tricky and set it to a -\class{UserDict} instance, or any other random object that behaves -like a mapping. - -\begin{seealso} - -\seepep{232}{Function Attributes}{Written and implemented by Barry -Warsaw.} - -\end{seealso} - - -%====================================================================== - -\section{PEP 235: Case-Insensitive Platforms and \keyword{import}} - -Some operating systems have filesystems that are case-insensitive, -MacOS and Windows being the primary examples; on these systems, it's -impossible to distinguish the filenames \samp{FILE.PY} and -\samp{file.py}, even though they do store the file's name -in its original case (they're case-preserving, too). - -In Python 2.1, the \keyword{import} statement will work to simulate -case-sensitivity on case-insensitive platforms. Python will now -search for the first case-sensitive match by default, raising an -\exception{ImportError} if no such file is found, so \code{import file} -will not import a module named \samp{FILE.PY}. Case-insensitive -matching can be requested by setting the \envvar{PYTHONCASEOK} environment -variable before starting the Python interpreter. - -%====================================================================== -\section{PEP 217: Interactive Display Hook} - -When using the Python interpreter interactively, the output of -commands is displayed using the built-in \function{repr()} function. -In Python 2.1, the variable \function{sys.displayhook} can be set to a -callable object which will be called instead of \function{repr()}. -For example, you can set it to a special pretty-printing function: - -\begin{verbatim} ->>> # Create a recursive data structure -... L = [1,2,3] ->>> L.append(L) ->>> L # Show Python's default output -[1, 2, 3, [...]] ->>> # Use pprint.pprint() as the display function -... import sys, pprint ->>> sys.displayhook = pprint.pprint ->>> L -[1, 2, 3, ] ->>> -\end{verbatim} - -\begin{seealso} - -\seepep{217}{Display Hook for Interactive Use}{Written and implemented -by Moshe Zadka.} - -\end{seealso} - -%====================================================================== -\section{PEP 208: New Coercion Model} - -How numeric coercion is done at the C level was significantly -modified. This will only affect the authors of C extensions to -Python, allowing them more flexibility in writing extension types that -support numeric operations. - -Extension types can now set the type flag \code{Py_TPFLAGS_CHECKTYPES} -in their \code{PyTypeObject} structure to indicate that they support -the new coercion model. In such extension types, the numeric slot -functions can no longer assume that they'll be passed two arguments of -the same type; instead they may be passed two arguments of differing -types, and can then perform their own internal coercion. If the slot -function is passed a type it can't handle, it can indicate the failure -by returning a reference to the \code{Py_NotImplemented} singleton -value. The numeric functions of the other type will then be tried, -and perhaps they can handle the operation; if the other type also -returns \code{Py_NotImplemented}, then a \exception{TypeError} will be -raised. Numeric methods written in Python can also return -\code{Py_NotImplemented}, causing the interpreter to act as if the -method did not exist (perhaps raising a \exception{TypeError}, perhaps -trying another object's numeric methods). - -\begin{seealso} - -\seepep{208}{Reworking the Coercion Model}{Written and implemented by -Neil Schemenauer, heavily based upon earlier work by Marc-Andr\'e -Lemburg. Read this to understand the fine points of how numeric -operations will now be processed at the C level.} - -\end{seealso} - -%====================================================================== -\section{PEP 241: Metadata in Python Packages} - -A common complaint from Python users is that there's no single catalog -of all the Python modules in existence. T.~Middleton's Vaults of -Parnassus at \url{http://www.vex.net/parnassus} are the largest -catalog of Python modules, but registering software at the Vaults is -optional, and many people don't bother. - -As a first small step toward fixing the problem, Python software -packaged using the Distutils \command{sdist} command will include a -file named \file{PKG-INFO} containing information about the package -such as its name, version, and author (metadata, in cataloguing -terminology). PEP 241 contains the full list of fields that can be -present in the \file{PKG-INFO} file. As people began to package their -software using Python 2.1, more and more packages will include -metadata, making it possible to build automated cataloguing systems -and experiment with them. With the result experience, perhaps it'll -be possible to design a really good catalog and then build support for -it into Python 2.2. For example, the Distutils \command{sdist} -and \command{bdist_*} commands could support a \option{upload} option -that would automatically upload your package to a catalog server. - -You can start creating packages containing \file{PKG-INFO} even if -you're not using Python 2.1, since a new release of the Distutils will -be made for users of earlier Python versions. Version 1.0.2 of the -Distutils includes the changes described in PEP 241, as well as -various bugfixes and enhancements. It will be available from -the Distutils SIG at \url{http://www.python.org/sigs/distutils-sig}. - -% XXX update when I actually release 1.0.2 - -\begin{seealso} - -\seepep{241}{Metadata for Python Software Packages}{Written and -implemented by A.M. Kuchling.} - -\seepep{243}{Module Repository Upload Mechanism}{Written by Sean -Reifschneider, this draft PEP describes a proposed mechanism for uploading -Python packages to a central server. -} - -\end{seealso} - -%====================================================================== -\section{New and Improved Modules} - -\begin{itemize} - -\item Ka-Ping Yee contributed two new modules: \module{inspect.py}, a -module for getting information about live Python code, and -\module{pydoc.py}, a module for interactively converting docstrings to -HTML or text. As a bonus, \file{Tools/scripts/pydoc}, which is now -automatically installed, uses \module{pydoc.py} to display -documentation given a Python module, package, or class name. For -example, \samp{pydoc xml.dom} displays the following: - -\begin{verbatim} -Python Library Documentation: package xml.dom in xml - -NAME - xml.dom - W3C Document Object Model implementation for Python. - -FILE - /usr/local/lib/python2.1/xml/dom/__init__.pyc - -DESCRIPTION - The Python mapping of the Document Object Model is documented in the - Python Library Reference in the section on the xml.dom package. - - This package contains the following modules: - ... -\end{verbatim} - -\file{pydoc} also includes a Tk-based interactive help browser. -\file{pydoc} quickly becomes addictive; try it out! - -\item Two different modules for unit testing were added to the -standard library. The \module{doctest} module, contributed by Tim -Peters, provides a testing framework based on running embedded -examples in docstrings and comparing the results against the expected -output. PyUnit, contributed by Steve Purcell, is a unit testing -framework inspired by JUnit, which was in turn an adaptation of Kent -Beck's Smalltalk testing framework. See -\url{http://pyunit.sourceforge.net/} for more information about -PyUnit. - -\item The \module{difflib} module contains a class, -\class{SequenceMatcher}, which compares two sequences and computes the -changes required to transform one sequence into the other. For -example, this module can be used to write a tool similar to the Unix -\program{diff} program, and in fact the sample program -\file{Tools/scripts/ndiff.py} demonstrates how to write such a script. - -\item \module{curses.panel}, a wrapper for the panel library, part of -ncurses and of SYSV curses, was contributed by Thomas Gellekum. The -panel library provides windows with the additional feature of depth. -Windows can be moved higher or lower in the depth ordering, and the -panel library figures out where panels overlap and which sections are -visible. - -\item The PyXML package has gone through a few releases since Python -2.0, and Python 2.1 includes an updated version of the \module{xml} -package. Some of the noteworthy changes include support for Expat 1.2 -and later versions, the ability for Expat parsers to handle files in -any encoding supported by Python, and various bugfixes for SAX, DOM, -and the \module{minidom} module. - -\item Ping also contributed another hook for handling uncaught -exceptions. \function{sys.excepthook} can be set to a callable -object. When an exception isn't caught by any -\keyword{try}...\keyword{except} blocks, the exception will be passed -to \function{sys.excepthook}, which can then do whatever it likes. At -the Ninth Python Conference, Ping demonstrated an application for this -hook: printing an extended traceback that not only lists the stack -frames, but also lists the function arguments and the local variables -for each frame. - -\item Various functions in the \module{time} module, such as -\function{asctime()} and \function{localtime()}, require a floating -point argument containing the time in seconds since the epoch. The -most common use of these functions is to work with the current time, -so the floating point argument has been made optional; when a value -isn't provided, the current time will be used. For example, log file -entries usually need a string containing the current time; in Python -2.1, \code{time.asctime()} can be used, instead of the lengthier -\code{time.asctime(time.localtime(time.time()))} that was previously -required. - -This change was proposed and implemented by Thomas Wouters. - -\item The \module{ftplib} module now defaults to retrieving files in -passive mode, because passive mode is more likely to work from behind -a firewall. This request came from the Debian bug tracking system, -since other Debian packages use \module{ftplib} to retrieve files and -then don't work from behind a firewall. It's deemed unlikely that -this will cause problems for anyone, because Netscape defaults to -passive mode and few people complain, but if passive mode is -unsuitable for your application or network setup, call -\method{set_pasv(0)} on FTP objects to disable passive mode. - -\item Support for raw socket access has been added to the -\module{socket} module, contributed by Grant Edwards. - -\item The \module{pstats} module now contains a simple interactive -statistics browser for displaying timing profiles for Python programs, -invoked when the module is run as a script. Contributed by -Eric S.\ Raymond. - -\item A new implementation-dependent function, \function{sys._getframe(\optional{depth})}, -has been added to return a given frame object from the current call stack. -\function{sys._getframe()} returns the frame at the top of the call stack; -if the optional integer argument \var{depth} is supplied, the function returns the frame -that is \var{depth} calls below the top of the stack. For example, \code{sys._getframe(1)} -returns the caller's frame object. - -This function is only present in CPython, not in Jython or the .NET -implementation. Use it for debugging, and resist the temptation to -put it into production code. - - - -\end{itemize} - -%====================================================================== -\section{Other Changes and Fixes} - -There were relatively few smaller changes made in Python 2.1 due to -the shorter release cycle. A search through the CVS change logs turns -up 117 patches applied, and 136 bugs fixed; both figures are likely to -be underestimates. Some of the more notable changes are: - -\begin{itemize} - - -\item A specialized object allocator is now optionally available, that -should be faster than the system \function{malloc()} and have less -memory overhead. The allocator uses C's \function{malloc()} function -to get large pools of memory, and then fulfills smaller memory -requests from these pools. It can be enabled by providing the -\longprogramopt{with-pymalloc} option to the \program{configure} script; see -\file{Objects/obmalloc.c} for the implementation details. - -Authors of C extension modules should test their code with the object -allocator enabled, because some incorrect code may break, causing core -dumps at runtime. There are a bunch of memory allocation functions in -Python's C API that have previously been just aliases for the C -library's \function{malloc()} and \function{free()}, meaning that if -you accidentally called mismatched functions, the error wouldn't be -noticeable. When the object allocator is enabled, these functions -aren't aliases of \function{malloc()} and \function{free()} any more, -and calling the wrong function to free memory will get you a core -dump. For example, if memory was allocated using -\function{PyMem_New()}, it has to be freed using -\function{PyMem_Del()}, not \function{free()}. A few modules included -with Python fell afoul of this and had to be fixed; doubtless there -are more third-party modules that will have the same problem. - -The object allocator was contributed by Vladimir Marangozov. - -\item The speed of line-oriented file I/O has been improved because -people often complain about its lack of speed, and because it's often -been used as a na\"ive benchmark. The \method{readline()} method of -file objects has therefore been rewritten to be much faster. The -exact amount of the speedup will vary from platform to platform -depending on how slow the C library's \function{getc()} was, but is -around 66\%, and potentially much faster on some particular operating -systems. Tim Peters did much of the benchmarking and coding for this -change, motivated by a discussion in comp.lang.python. - -A new module and method for file objects was also added, contributed -by Jeff Epler. The new method, \method{xreadlines()}, is similar to -the existing \function{xrange()} built-in. \function{xreadlines()} -returns an opaque sequence object that only supports being iterated -over, reading a line on every iteration but not reading the entire -file into memory as the existing \method{readlines()} method does. -You'd use it like this: - -\begin{verbatim} -for line in sys.stdin.xreadlines(): - # ... do something for each line ... - ... -\end{verbatim} - -For a fuller discussion of the line I/O changes, see the python-dev -summary for January 1-15, 2001 at -\url{http://www.amk.ca/python/dev/2001-01-1.html}. - -\item A new method, \method{popitem()}, was added to dictionaries to -enable destructively iterating through the contents of a dictionary; -this can be faster for large dictionaries because there's no need to -construct a list containing all the keys or values. -\code{D.popitem()} removes a random \code{(\var{key}, \var{value})} -pair from the dictionary~\code{D} and returns it as a 2-tuple. This -was implemented mostly by Tim Peters and Guido van Rossum, after a -suggestion and preliminary patch by Moshe Zadka. - -\item Modules can now control which names are imported when \code{from -\var{module} import *} is used, by defining an \code{__all__} -attribute containing a list of names that will be imported. One -common complaint is that if the module imports other modules such as -\module{sys} or \module{string}, \code{from \var{module} import *} -will add them to the importing module's namespace. To fix this, -simply list the public names in \code{__all__}: - -\begin{verbatim} -# List public names -__all__ = ['Database', 'open'] -\end{verbatim} - -A stricter version of this patch was first suggested and implemented -by Ben Wolfson, but after some python-dev discussion, a weaker final -version was checked in. - -\item Applying \function{repr()} to strings previously used octal -escapes for non-printable characters; for example, a newline was -\code{'\e 012'}. This was a vestigial trace of Python's C ancestry, but -today octal is of very little practical use. Ka-Ping Yee suggested -using hex escapes instead of octal ones, and using the \code{\e n}, -\code{\e t}, \code{\e r} escapes for the appropriate characters, and -implemented this new formatting. - -\item Syntax errors detected at compile-time can now raise exceptions -containing the filename and line number of the error, a pleasant side -effect of the compiler reorganization done by Jeremy Hylton. - -\item C extensions which import other modules have been changed to use -\function{PyImport_ImportModule()}, which means that they will use any -import hooks that have been installed. This is also encouraged for -third-party extensions that need to import some other module from C -code. - -\item The size of the Unicode character database was shrunk by another -340K thanks to Fredrik Lundh. - -\item Some new ports were contributed: MacOS X (by Steven Majewski), -Cygwin (by Jason Tishler); RISCOS (by Dietmar Schwertberger); Unixware~7 -(by Billy G. Allie). - -\end{itemize} - -And there's the usual list of minor bugfixes, minor memory leaks, -docstring edits, and other tweaks, too lengthy to be worth itemizing; -see the CVS logs for the full details if you want them. - - -%====================================================================== -\section{Acknowledgements} - -The author would like to thank the following people for offering -suggestions on various drafts of this article: Graeme Cross, David -Goodger, Jay Graves, Michael Hudson, Marc-Andr\'e Lemburg, Fredrik -Lundh, Neil Schemenauer, Thomas Wouters. - -\end{document} diff --git a/Include/patchlevel.h b/Include/patchlevel.h index a16559e..12c89e0 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -22,11 +22,11 @@ #define PY_MAJOR_VERSION 2 #define PY_MINOR_VERSION 2 #define PY_MICRO_VERSION 0 -#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_GAMMA -#define PY_RELEASE_SERIAL 1 +#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL +#define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "2.2c1+" +#define PY_VERSION "2.2" /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. Use this for numeric comparisons, e.g. #if PY_VERSION_HEX >= ... */ diff --git a/Lib/compiler/ast.py b/Lib/compiler/ast.py index 23c463b..680afee 100644 --- a/Lib/compiler/ast.py +++ b/Lib/compiler/ast.py @@ -282,6 +282,21 @@ class Module(Node): def __repr__(self): return "Module(%s, %s)" % (repr(self.doc), repr(self.node)) +class Expression(Node): + # Expression is an artifical node class to support "eval" + nodes["expression"] = "Expression" + def __init__(self, node): + self.node = node + + def getChildren(self): + return self.node, + + def getChildNodes(self): + return self.node, + + def __repr__(self): + return "Expression(%s)" % (repr(self.node)) + class UnaryAdd(Node): nodes["unaryadd"] = "UnaryAdd" def __init__(self, expr): diff --git a/Lib/compiler/pycodegen.py b/Lib/compiler/pycodegen.py index f526ae1..4194d27 100644 --- a/Lib/compiler/pycodegen.py +++ b/Lib/compiler/pycodegen.py @@ -34,6 +34,7 @@ EXCEPT = 2 TRY_FINALLY = 3 END_FINALLY = 4 +# XXX this doesn't seem to be used class BlockStack(misc.Stack): __super_init = misc.Stack.__init__ @@ -351,6 +352,13 @@ class CodeGenerator: self.emit('LOAD_CONST', None) self.emit('RETURN_VALUE') + def visitExpression(self, node): + self.set_lineno(node) + self.scopes = self.parseSymbols(node) + self.scope = self.scopes[node] + self.visit(node.node) + self.emit('RETURN_VALUE') + def visitFunction(self, node): self._visitFuncOrLambda(node, isLambda=0) if node.doc: @@ -1158,9 +1166,7 @@ class ExpressionCodeGenerator(NestedScopeMixin, CodeGenerator): def __init__(self, tree): self.graph = pyassem.PyFlowGraph("", tree.filename) self.__super_init() - self.set_lineno(tree) walk(tree, self) - self.emit('RETURN_VALUE') def get_module(self): return self @@ -1181,6 +1187,7 @@ class InteractiveCodeGenerator(NestedScopeMixin, CodeGenerator): def get_module(self): return self + def visitDiscard(self, node): # XXX Discard means it's an expression. Perhaps this is a bad # name. @@ -1299,7 +1306,6 @@ class ClassCodeGenerator(NestedScopeMixin, AbstractClassCode, CodeGenerator): self.__super_init(klass, scopes, module) self.graph.setFreeVars(self.scope.get_free_vars()) self.graph.setCellVars(self.scope.get_cell_vars()) -## self.graph.setFlag(CO_NESTED) def generateArgList(arglist): """Generate an arg list marking TupleArgs""" diff --git a/Lib/compiler/symbols.py b/Lib/compiler/symbols.py index 200341f..cd7bceb 100644 --- a/Lib/compiler/symbols.py +++ b/Lib/compiler/symbols.py @@ -206,6 +206,8 @@ class SymbolVisitor: scope = self.module = self.scopes[node] = ModuleScope() self.visit(node.node, scope) + visitExpression = visitModule + def visitFunction(self, node, parent): parent.add_def(node.name) for n in node.defaults: diff --git a/Lib/compiler/transformer.py b/Lib/compiler/transformer.py index 9875561..cd36aae 100644 --- a/Lib/compiler/transformer.py +++ b/Lib/compiler/transformer.py @@ -172,7 +172,7 @@ class Transformer: def eval_input(self, nodelist): # from the built-in function input() ### is this sufficient? - return self.com_node(nodelist[0]) + return Expression(self.com_node(nodelist[0])) def funcdef(self, nodelist): # funcdef: 'def' NAME parameters ':' suite diff --git a/Lib/dumbdbm.py b/Lib/dumbdbm.py index 0fd2dad..920a464 100644 --- a/Lib/dumbdbm.py +++ b/Lib/dumbdbm.py @@ -143,9 +143,15 @@ class _Database: return len(self._index) def close(self): + self._commit() self._index = None self._datfile = self._dirfile = self._bakfile = None + def __del__(self): + if self._index is not None: + self._commit() + + def open(file, flag=None, mode=0666): # flag, mode arguments are currently ignored diff --git a/Lib/idlelib/AutoExpand.py b/Lib/idlelib/AutoExpand.py deleted file mode 100644 index 09f34b3..0000000 --- a/Lib/idlelib/AutoExpand.py +++ /dev/null @@ -1,91 +0,0 @@ -import string -import re - -###$ event <> -###$ win -###$ unix - -class AutoExpand: - - keydefs = { - '<>': [''], - } - - unix_keydefs = { - '<>': ['', ''], - } - - menudefs = [ - ('edit', [ - ('E_xpand word', '<>'), - ]), - ] - - wordchars = string.letters + string.digits + "_" - - def __init__(self, editwin): - self.text = editwin.text - self.state = None - - def expand_word_event(self, event): - curinsert = self.text.index("insert") - curline = self.text.get("insert linestart", "insert lineend") - if not self.state: - words = self.getwords() - index = 0 - else: - words, index, insert, line = self.state - if insert != curinsert or line != curline: - words = self.getwords() - index = 0 - if not words: - self.text.bell() - return "break" - word = self.getprevword() - self.text.delete("insert - %d chars" % len(word), "insert") - newword = words[index] - index = (index + 1) % len(words) - if index == 0: - self.text.bell() # Warn we cycled around - self.text.insert("insert", newword) - curinsert = self.text.index("insert") - curline = self.text.get("insert linestart", "insert lineend") - self.state = words, index, curinsert, curline - return "break" - - def getwords(self): - word = self.getprevword() - if not word: - return [] - before = self.text.get("1.0", "insert wordstart") - wbefore = re.findall(r"\b" + word + r"\w+\b", before) - del before - after = self.text.get("insert wordend", "end") - wafter = re.findall(r"\b" + word + r"\w+\b", after) - del after - if not wbefore and not wafter: - return [] - words = [] - dict = {} - # search backwards through words before - wbefore.reverse() - for w in wbefore: - if dict.get(w): - continue - words.append(w) - dict[w] = w - # search onwards through words after - for w in wafter: - if dict.get(w): - continue - words.append(w) - dict[w] = w - words.append(word) - return words - - def getprevword(self): - line = self.text.get("insert linestart", "insert") - i = len(line) - while i > 0 and line[i-1] in self.wordchars: - i = i-1 - return line[i:] diff --git a/Lib/idlelib/AutoIndent.py b/Lib/idlelib/AutoIndent.py deleted file mode 100644 index 6d38481..0000000 --- a/Lib/idlelib/AutoIndent.py +++ /dev/null @@ -1,554 +0,0 @@ -import string -#from Tkinter import TclError -#import tkMessageBox -#import tkSimpleDialog - -###$ event <> -###$ win -###$ win -###$ unix -###$ unix - -###$ event <> -###$ win -###$ unix -###$ unix - -###$ event <> -###$ win -###$ unix -###$ unix - -###$ event <> -###$ win -###$ unix - -###$ event <> -###$ win -###$ unix - -###$ event <> -###$ win -###$ unix - -###$ event <> -###$ win -###$ unix - -import PyParse - -class AutoIndent: - - menudefs = [ - ('format', [ # /s/edit/format dscherer@cmu.edu - None, - ('_Indent region', '<>'), - ('_Dedent region', '<>'), - ('Comment _out region', '<>'), - ('U_ncomment region', '<>'), - ('Tabify region', '<>'), - ('Untabify region', '<>'), - ('Toggle tabs', '<>'), - ('New indent width', '<>'), - ]), - ] - - keydefs = { - '<>': [''], - '<>': ['', ''], - '<>': [''] - } - - windows_keydefs = { - '<>': [''], - '<>': ['', # dscherer@cmu.edu - ''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - } - - unix_keydefs = { - '<>': ['', - '', - ''], - '<>': ['', - '', - ''], - '<>': ['', ''], - '<>': ['', ''], - '<>': ['', ''], - '<>': ['', ''], - '<>': [''], - '<>': [''], - } - - # usetabs true -> literal tab characters are used by indent and - # dedent cmds, possibly mixed with spaces if - # indentwidth is not a multiple of tabwidth - # false -> tab characters are converted to spaces by indent - # and dedent cmds, and ditto TAB keystrokes - # indentwidth is the number of characters per logical indent level. - # tabwidth is the display width of a literal tab character. - # CAUTION: telling Tk to use anything other than its default - # tab setting causes it to use an entirely different tabbing algorithm, - # treating tab stops as fixed distances from the left margin. - # Nobody expects this, so for now tabwidth should never be changed. - usetabs = 1 - indentwidth = 4 - tabwidth = 8 # for IDLE use, must remain 8 until Tk is fixed - - # If context_use_ps1 is true, parsing searches back for a ps1 line; - # else searches for a popular (if, def, ...) Python stmt. - context_use_ps1 = 0 - - # When searching backwards for a reliable place to begin parsing, - # first start num_context_lines[0] lines back, then - # num_context_lines[1] lines back if that didn't work, and so on. - # The last value should be huge (larger than the # of lines in a - # conceivable file). - # Making the initial values larger slows things down more often. - num_context_lines = 50, 500, 5000000 - - def __init__(self, editwin): - self.editwin = editwin - self.text = editwin.text - - def config(self, **options): - for key, value in options.items(): - if key == 'usetabs': - self.usetabs = value - elif key == 'indentwidth': - self.indentwidth = value - elif key == 'tabwidth': - self.tabwidth = value - elif key == 'context_use_ps1': - self.context_use_ps1 = value - else: - raise KeyError, "bad option name: %s" % `key` - - # If ispythonsource and guess are true, guess a good value for - # indentwidth based on file content (if possible), and if - # indentwidth != tabwidth set usetabs false. - # In any case, adjust the Text widget's view of what a tab - # character means. - - def set_indentation_params(self, ispythonsource, guess=1): - if guess and ispythonsource: - i = self.guess_indent() - if 2 <= i <= 8: - self.indentwidth = i - if self.indentwidth != self.tabwidth: - self.usetabs = 0 - - self.editwin.set_tabwidth(self.tabwidth) - - def smart_backspace_event(self, event): - text = self.text - first, last = self.editwin.get_selection_indices() - if first and last: - text.delete(first, last) - text.mark_set("insert", first) - return "break" - # Delete whitespace left, until hitting a real char or closest - # preceding virtual tab stop. - chars = text.get("insert linestart", "insert") - if chars == '': - if text.compare("insert", ">", "1.0"): - # easy: delete preceding newline - text.delete("insert-1c") - else: - text.bell() # at start of buffer - return "break" - if chars[-1] not in " \t": - # easy: delete preceding real char - text.delete("insert-1c") - return "break" - # Ick. It may require *inserting* spaces if we back up over a - # tab character! This is written to be clear, not fast. - expand, tabwidth = string.expandtabs, self.tabwidth - have = len(expand(chars, tabwidth)) - assert have > 0 - want = int((have - 1) / self.indentwidth) * self.indentwidth - ncharsdeleted = 0 - while 1: - chars = chars[:-1] - ncharsdeleted = ncharsdeleted + 1 - have = len(expand(chars, tabwidth)) - if have <= want or chars[-1] not in " \t": - break - text.undo_block_start() - text.delete("insert-%dc" % ncharsdeleted, "insert") - if have < want: - text.insert("insert", ' ' * (want - have)) - text.undo_block_stop() - return "break" - - def smart_indent_event(self, event): - # if intraline selection: - # delete it - # elif multiline selection: - # do indent-region & return - # indent one level - text = self.text - first, last = self.editwin.get_selection_indices() - text.undo_block_start() - try: - if first and last: - if index2line(first) != index2line(last): - return self.indent_region_event(event) - text.delete(first, last) - text.mark_set("insert", first) - prefix = text.get("insert linestart", "insert") - raw, effective = classifyws(prefix, self.tabwidth) - if raw == len(prefix): - # only whitespace to the left - self.reindent_to(effective + self.indentwidth) - else: - if self.usetabs: - pad = '\t' - else: - effective = len(string.expandtabs(prefix, - self.tabwidth)) - n = self.indentwidth - pad = ' ' * (n - effective % n) - text.insert("insert", pad) - text.see("insert") - return "break" - finally: - text.undo_block_stop() - - def newline_and_indent_event(self, event): - text = self.text - first, last = self.editwin.get_selection_indices() - text.undo_block_start() - try: - if first and last: - text.delete(first, last) - text.mark_set("insert", first) - line = text.get("insert linestart", "insert") - i, n = 0, len(line) - while i < n and line[i] in " \t": - i = i+1 - if i == n: - # the cursor is in or at leading indentation; just inject - # an empty line at the start - text.insert("insert linestart", '\n') - return "break" - indent = line[:i] - # strip whitespace before insert point - i = 0 - while line and line[-1] in " \t": - line = line[:-1] - i = i+1 - if i: - text.delete("insert - %d chars" % i, "insert") - # strip whitespace after insert point - while text.get("insert") in " \t": - text.delete("insert") - # start new line - text.insert("insert", '\n') - - # adjust indentation for continuations and block - # open/close first need to find the last stmt - lno = index2line(text.index('insert')) - y = PyParse.Parser(self.indentwidth, self.tabwidth) - for context in self.num_context_lines: - startat = max(lno - context, 1) - startatindex = `startat` + ".0" - rawtext = text.get(startatindex, "insert") - y.set_str(rawtext) - bod = y.find_good_parse_start( - self.context_use_ps1, - self._build_char_in_string_func(startatindex)) - if bod is not None or startat == 1: - break - y.set_lo(bod or 0) - c = y.get_continuation_type() - if c != PyParse.C_NONE: - # The current stmt hasn't ended yet. - if c == PyParse.C_STRING: - # inside a string; just mimic the current indent - text.insert("insert", indent) - elif c == PyParse.C_BRACKET: - # line up with the first (if any) element of the - # last open bracket structure; else indent one - # level beyond the indent of the line with the - # last open bracket - self.reindent_to(y.compute_bracket_indent()) - elif c == PyParse.C_BACKSLASH: - # if more than one line in this stmt already, just - # mimic the current indent; else if initial line - # has a start on an assignment stmt, indent to - # beyond leftmost =; else to beyond first chunk of - # non-whitespace on initial line - if y.get_num_lines_in_stmt() > 1: - text.insert("insert", indent) - else: - self.reindent_to(y.compute_backslash_indent()) - else: - assert 0, "bogus continuation type " + `c` - return "break" - - # This line starts a brand new stmt; indent relative to - # indentation of initial line of closest preceding - # interesting stmt. - indent = y.get_base_indent_string() - text.insert("insert", indent) - if y.is_block_opener(): - self.smart_indent_event(event) - elif indent and y.is_block_closer(): - self.smart_backspace_event(event) - return "break" - finally: - text.see("insert") - text.undo_block_stop() - - auto_indent = newline_and_indent_event - - # Our editwin provides a is_char_in_string function that works - # with a Tk text index, but PyParse only knows about offsets into - # a string. This builds a function for PyParse that accepts an - # offset. - - def _build_char_in_string_func(self, startindex): - def inner(offset, _startindex=startindex, - _icis=self.editwin.is_char_in_string): - return _icis(_startindex + "+%dc" % offset) - return inner - - def indent_region_event(self, event): - head, tail, chars, lines = self.get_region() - for pos in range(len(lines)): - line = lines[pos] - if line: - raw, effective = classifyws(line, self.tabwidth) - effective = effective + self.indentwidth - lines[pos] = self._make_blanks(effective) + line[raw:] - self.set_region(head, tail, chars, lines) - return "break" - - def dedent_region_event(self, event): - head, tail, chars, lines = self.get_region() - for pos in range(len(lines)): - line = lines[pos] - if line: - raw, effective = classifyws(line, self.tabwidth) - effective = max(effective - self.indentwidth, 0) - lines[pos] = self._make_blanks(effective) + line[raw:] - self.set_region(head, tail, chars, lines) - return "break" - - def comment_region_event(self, event): - head, tail, chars, lines = self.get_region() - for pos in range(len(lines) - 1): - line = lines[pos] - lines[pos] = '##' + line - self.set_region(head, tail, chars, lines) - - def uncomment_region_event(self, event): - head, tail, chars, lines = self.get_region() - for pos in range(len(lines)): - line = lines[pos] - if not line: - continue - if line[:2] == '##': - line = line[2:] - elif line[:1] == '#': - line = line[1:] - lines[pos] = line - self.set_region(head, tail, chars, lines) - - def tabify_region_event(self, event): - head, tail, chars, lines = self.get_region() - tabwidth = self._asktabwidth() - for pos in range(len(lines)): - line = lines[pos] - if line: - raw, effective = classifyws(line, tabwidth) - ntabs, nspaces = divmod(effective, tabwidth) - lines[pos] = '\t' * ntabs + ' ' * nspaces + line[raw:] - self.set_region(head, tail, chars, lines) - - def untabify_region_event(self, event): - head, tail, chars, lines = self.get_region() - tabwidth = self._asktabwidth() - for pos in range(len(lines)): - lines[pos] = string.expandtabs(lines[pos], tabwidth) - self.set_region(head, tail, chars, lines) - - def toggle_tabs_event(self, event): - if self.editwin.askyesno( - "Toggle tabs", - "Turn tabs " + ("on", "off")[self.usetabs] + "?", - parent=self.text): - self.usetabs = not self.usetabs - return "break" - - # XXX this isn't bound to anything -- see class tabwidth comments - def change_tabwidth_event(self, event): - new = self._asktabwidth() - if new != self.tabwidth: - self.tabwidth = new - self.set_indentation_params(0, guess=0) - return "break" - - def change_indentwidth_event(self, event): - new = self.editwin.askinteger( - "Indent width", - "New indent width (1-16)", - parent=self.text, - initialvalue=self.indentwidth, - minvalue=1, - maxvalue=16) - if new and new != self.indentwidth: - self.indentwidth = new - return "break" - - def get_region(self): - text = self.text - first, last = self.editwin.get_selection_indices() - if first and last: - head = text.index(first + " linestart") - tail = text.index(last + "-1c lineend +1c") - else: - head = text.index("insert linestart") - tail = text.index("insert lineend +1c") - chars = text.get(head, tail) - lines = string.split(chars, "\n") - return head, tail, chars, lines - - def set_region(self, head, tail, chars, lines): - text = self.text - newchars = string.join(lines, "\n") - if newchars == chars: - text.bell() - return - text.tag_remove("sel", "1.0", "end") - text.mark_set("insert", head) - text.undo_block_start() - text.delete(head, tail) - text.insert(head, newchars) - text.undo_block_stop() - text.tag_add("sel", head, "insert") - - # Make string that displays as n leading blanks. - - def _make_blanks(self, n): - if self.usetabs: - ntabs, nspaces = divmod(n, self.tabwidth) - return '\t' * ntabs + ' ' * nspaces - else: - return ' ' * n - - # Delete from beginning of line to insert point, then reinsert - # column logical (meaning use tabs if appropriate) spaces. - - def reindent_to(self, column): - text = self.text - text.undo_block_start() - if text.compare("insert linestart", "!=", "insert"): - text.delete("insert linestart", "insert") - if column: - text.insert("insert", self._make_blanks(column)) - text.undo_block_stop() - - def _asktabwidth(self): - return self.editwin.askinteger( - "Tab width", - "Spaces per tab?", - parent=self.text, - initialvalue=self.tabwidth, - minvalue=1, - maxvalue=16) or self.tabwidth - - # Guess indentwidth from text content. - # Return guessed indentwidth. This should not be believed unless - # it's in a reasonable range (e.g., it will be 0 if no indented - # blocks are found). - - def guess_indent(self): - opener, indented = IndentSearcher(self.text, self.tabwidth).run() - if opener and indented: - raw, indentsmall = classifyws(opener, self.tabwidth) - raw, indentlarge = classifyws(indented, self.tabwidth) - else: - indentsmall = indentlarge = 0 - return indentlarge - indentsmall - -# "line.col" -> line, as an int -def index2line(index): - return int(float(index)) - -# Look at the leading whitespace in s. -# Return pair (# of leading ws characters, -# effective # of leading blanks after expanding -# tabs to width tabwidth) - -def classifyws(s, tabwidth): - raw = effective = 0 - for ch in s: - if ch == ' ': - raw = raw + 1 - effective = effective + 1 - elif ch == '\t': - raw = raw + 1 - effective = (effective / tabwidth + 1) * tabwidth - else: - break - return raw, effective - -import tokenize -_tokenize = tokenize -del tokenize - -class IndentSearcher: - - # .run() chews over the Text widget, looking for a block opener - # and the stmt following it. Returns a pair, - # (line containing block opener, line containing stmt) - # Either or both may be None. - - def __init__(self, text, tabwidth): - self.text = text - self.tabwidth = tabwidth - self.i = self.finished = 0 - self.blkopenline = self.indentedline = None - - def readline(self): - if self.finished: - return "" - i = self.i = self.i + 1 - mark = `i` + ".0" - if self.text.compare(mark, ">=", "end"): - return "" - return self.text.get(mark, mark + " lineend+1c") - - def tokeneater(self, type, token, start, end, line, - INDENT=_tokenize.INDENT, - NAME=_tokenize.NAME, - OPENERS=('class', 'def', 'for', 'if', 'try', 'while')): - if self.finished: - pass - elif type == NAME and token in OPENERS: - self.blkopenline = line - elif type == INDENT and self.blkopenline: - self.indentedline = line - self.finished = 1 - - def run(self): - save_tabsize = _tokenize.tabsize - _tokenize.tabsize = self.tabwidth - try: - try: - _tokenize.tokenize(self.readline, self.tokeneater) - except _tokenize.TokenError: - # since we cut off the tokenizer early, we can trigger - # spurious errors - pass - finally: - _tokenize.tabsize = save_tabsize - return self.blkopenline, self.indentedline diff --git a/Lib/idlelib/Bindings.py b/Lib/idlelib/Bindings.py deleted file mode 100644 index 1a8374b..0000000 --- a/Lib/idlelib/Bindings.py +++ /dev/null @@ -1,76 +0,0 @@ -# This file defines the menu contents and key bindings. Note that -# there is additional configuration information in the EditorWindow -# class (and subclasses): the menus are created there based on the -# menu_specs (class) variable, and menus not created are silently -# skipped by the code here. This makes it possible to define the -# Debug menu here, which is only present in the PythonShell window. - -# changes by dscherer@cmu.edu: -# - Python shell moved to 'Run' menu -# - "Help" renamed to "IDLE Help" to distinguish from Python help. -# The distinction between the environment and the language is dim -# or nonexistent in a novice's mind. -# - Silly advice added - -import sys -import string -#from keydefs import * -from configHandler import idleConf - -menudefs = [ - # underscore prefixes character to underscore - ('file', [ - ('_New window', '<>'), - ('_Open...', '<>'), - ('Open _module...', '<>'), - ('Class _browser', '<>'), - ('_Path browser', '<>'), - None, - ('_Save', '<>'), - ('Save _As...', '<>'), - ('Save Co_py As...', '<>'), - None, - ('_Close', '<>'), - ('E_xit', '<>'), - ]), - ('edit', [ - ('_Undo', '<>'), - ('_Redo', '<>'), - None, - ('Cu_t', '<>'), - ('_Copy', '<>'), - ('_Paste', '<>'), - ('Select _All', '<>'), - ]), - ('run',[ - ('Python shell', '<>'), - ]), - ('debug', [ - ('_Go to file/line', '<>'), - ('_Stack viewer', '<>'), - ('!_Debugger', '<>'), - ('!_Auto-open stack viewer', '<>' ), - ]), -# ('settings', [ -# ('_Configure Idle...', '<>'), -# None, -# ('Revert to _Default Settings', '<>'), -# ]), - ('help', [ - ('_IDLE Help...', '<>'), - ('Python _Documentation...', '<>'), - ('_Advice...', '<>'), - ('View IDLE _Readme...', '<>'), - None, - ('_About IDLE...', '<>'), - ]), -] - -#if sys.platform == 'win32': -# default_keydefs = windows_keydefs -#else: -# default_keydefs = unix_keydefs - -default_keydefs = idleConf.GetKeys(keySetName=None) - -del sys diff --git a/Lib/idlelib/CREDITS.txt b/Lib/idlelib/CREDITS.txt deleted file mode 100644 index 30c2073..0000000 --- a/Lib/idlelib/CREDITS.txt +++ /dev/null @@ -1,17 +0,0 @@ -IDLEfork Credits -================== - -Guido van Rossum, as well as being the creator of the Python language, was -the original creator of IDLE. His great work continues as both a contributor -to, and 'benevolent dictator for life' of Python and IDLE/IDLEfork. - -The main developers who have been so far active on IDLEfork version 0.8.1 -and greater are, Guido van Rossum, Stephen M. Gava and Kurt B. Kaiser. - -The IDLE fork project was initiated and brought up to version 0.7.1 by -David Scherer, Peter Schneider-Kamp and Nicholas Riley. - -There are doubtless others who should be included here, especially those -who may have contributed to IDLE versions prior ot 0.8. Please contact -the IDLEfork coordinator to have yourself included here if you are one of -those I have missed! (contact details at http://idlefork.sourceforge.net) diff --git a/Lib/idlelib/CallTipWindow.py b/Lib/idlelib/CallTipWindow.py deleted file mode 100644 index d253fa5..0000000 --- a/Lib/idlelib/CallTipWindow.py +++ /dev/null @@ -1,71 +0,0 @@ -# A CallTip window class for Tkinter/IDLE. -# After ToolTip.py, which uses ideas gleaned from PySol - -# Used by the CallTips IDLE extension. -import os -from Tkinter import * - -class CallTip: - - def __init__(self, widget): - self.widget = widget - self.tipwindow = None - self.id = None - self.x = self.y = 0 - - def showtip(self, text): - self.text = text - if self.tipwindow or not self.text: - return - self.widget.see("insert") - x, y, cx, cy = self.widget.bbox("insert") - x = x + self.widget.winfo_rootx() + 2 - y = y + cy + self.widget.winfo_rooty() - self.tipwindow = tw = Toplevel(self.widget) - tw.wm_overrideredirect(1) - tw.wm_geometry("+%d+%d" % (x, y)) - label = Label(tw, text=self.text, justify=LEFT, - background="#ffffe0", relief=SOLID, borderwidth=1, - font = self.widget['font']) - label.pack() - - def hidetip(self): - tw = self.tipwindow - self.tipwindow = None - if tw: - tw.destroy() - - -############################### -# -# Test Code -# -class container: # Conceptually an editor_window - def __init__(self): - root = Tk() - text = self.text = Text(root) - text.pack(side=LEFT, fill=BOTH, expand=1) - text.insert("insert", "string.split") - root.update() - self.calltip = CallTip(text) - - text.event_add("<>", "(") - text.event_add("<>", ")") - text.bind("<>", self.calltip_show) - text.bind("<>", self.calltip_hide) - - text.focus_set() - # root.mainloop() # not in idle - - def calltip_show(self, event): - self.calltip.showtip("Hello world") - - def calltip_hide(self, event): - self.calltip.hidetip() - -def main(): - # Test code - c=container() - -if __name__=='__main__': - main() diff --git a/Lib/idlelib/CallTips.py b/Lib/idlelib/CallTips.py deleted file mode 100644 index 7c5f41c..0000000 --- a/Lib/idlelib/CallTips.py +++ /dev/null @@ -1,190 +0,0 @@ -# CallTips.py - An IDLE extension that provides "Call Tips" - ie, a floating window that -# displays parameter information as you open parens. - -import string -import sys -import types - -class CallTips: - - menudefs = [ - ] - - keydefs = { - '<>': [''], - '<>': [''], - '<>': [''], - '<>': ['', ''], - } - - windows_keydefs = { - } - - unix_keydefs = { - } - - def __init__(self, editwin): - self.editwin = editwin - self.text = editwin.text - self.calltip = None - if hasattr(self.text, "make_calltip_window"): - self._make_calltip_window = self.text.make_calltip_window - else: - self._make_calltip_window = self._make_tk_calltip_window - - def close(self): - self._make_calltip_window = None - - # Makes a Tk based calltip window. Used by IDLE, but not Pythonwin. - # See __init__ above for how this is used. - def _make_tk_calltip_window(self): - import CallTipWindow - return CallTipWindow.CallTip(self.text) - - def _remove_calltip_window(self): - if self.calltip: - self.calltip.hidetip() - self.calltip = None - - def paren_open_event(self, event): - self._remove_calltip_window() - arg_text = get_arg_text(self.get_object_at_cursor()) - if arg_text: - self.calltip_start = self.text.index("insert") - self.calltip = self._make_calltip_window() - self.calltip.showtip(arg_text) - return "" #so the event is handled normally. - - def paren_close_event(self, event): - # Now just hides, but later we should check if other - # paren'd expressions remain open. - self._remove_calltip_window() - return "" #so the event is handled normally. - - def check_calltip_cancel_event(self, event): - if self.calltip: - # If we have moved before the start of the calltip, - # or off the calltip line, then cancel the tip. - # (Later need to be smarter about multi-line, etc) - if self.text.compare("insert", "<=", self.calltip_start) or \ - self.text.compare("insert", ">", self.calltip_start + " lineend"): - self._remove_calltip_window() - return "" #so the event is handled normally. - - def calltip_cancel_event(self, event): - self._remove_calltip_window() - return "" #so the event is handled normally. - - def get_object_at_cursor(self, - wordchars="._" + string.uppercase + string.lowercase + string.digits): - # XXX - This needs to be moved to a better place - # so the "." attribute lookup code can also use it. - text = self.text - chars = text.get("insert linestart", "insert") - i = len(chars) - while i and chars[i-1] in wordchars: - i = i-1 - word = chars[i:] - if word: - # How is this for a hack! - import sys, __main__ - namespace = sys.modules.copy() - namespace.update(__main__.__dict__) - try: - return eval(word, namespace) - except: - pass - return None # Can't find an object. - -def _find_constructor(class_ob): - # Given a class object, return a function object used for the - # constructor (ie, __init__() ) or None if we can't find one. - try: - return class_ob.__init__.im_func - except AttributeError: - for base in class_ob.__bases__: - rc = _find_constructor(base) - if rc is not None: return rc - return None - -def get_arg_text(ob): - # Get a string describing the arguments for the given object. - argText = "" - if ob is not None: - argOffset = 0 - if type(ob)==types.ClassType: - # Look for the highest __init__ in the class chain. - fob = _find_constructor(ob) - if fob is None: - fob = lambda: None - else: - argOffset = 1 - elif type(ob)==types.MethodType: - # bit of a hack for methods - turn it into a function - # but we drop the "self" param. - fob = ob.im_func - argOffset = 1 - else: - fob = ob - # Try and build one for Python defined functions - if type(fob) in [types.FunctionType, types.LambdaType]: - try: - realArgs = fob.func_code.co_varnames[argOffset:fob.func_code.co_argcount] - defaults = fob.func_defaults or [] - defaults = list(map(lambda name: "=%s" % name, defaults)) - defaults = [""] * (len(realArgs)-len(defaults)) + defaults - items = map(lambda arg, dflt: arg+dflt, realArgs, defaults) - if fob.func_code.co_flags & 0x4: - items.append("...") - if fob.func_code.co_flags & 0x8: - items.append("***") - argText = string.join(items , ", ") - argText = "(%s)" % argText - except: - pass - # See if we can use the docstring - if hasattr(ob, "__doc__") and ob.__doc__: - pos = string.find(ob.__doc__, "\n") - if pos<0 or pos>70: pos=70 - if argText: argText = argText + "\n" - argText = argText + ob.__doc__[:pos] - - return argText - -################################################# -# -# Test code -# -if __name__=='__main__': - - def t1(): "()" - def t2(a, b=None): "(a, b=None)" - def t3(a, *args): "(a, ...)" - def t4(*args): "(...)" - def t5(a, *args): "(a, ...)" - def t6(a, b=None, *args, **kw): "(a, b=None, ..., ***)" - - class TC: - "(a=None, ...)" - def __init__(self, a=None, *b): "(a=None, ...)" - def t1(self): "()" - def t2(self, a, b=None): "(a, b=None)" - def t3(self, a, *args): "(a, ...)" - def t4(self, *args): "(...)" - def t5(self, a, *args): "(a, ...)" - def t6(self, a, b=None, *args, **kw): "(a, b=None, ..., ***)" - - def test( tests ): - failed=[] - for t in tests: - expected = t.__doc__ + "\n" + t.__doc__ - if get_arg_text(t) != expected: - failed.append(t) - print "%s - expected %s, but got %s" % (t, `expected`, `get_arg_text(t)`) - print "%d of %d tests failed" % (len(failed), len(tests)) - - tc = TC() - tests = t1, t2, t3, t4, t5, t6, \ - TC, tc.t1, tc.t2, tc.t3, tc.t4, tc.t5, tc.t6 - - test(tests) diff --git a/Lib/idlelib/ChangeLog b/Lib/idlelib/ChangeLog deleted file mode 100644 index 8991427..0000000 --- a/Lib/idlelib/ChangeLog +++ /dev/null @@ -1,1587 +0,0 @@ -IDLEfork ChangeLog -================== - -2001-07-20 11:35 elguavas - - * README.txt, NEWS.txt: bring up to date for 0.8.1 release - -2001-07-19 16:40 elguavas - - * IDLEFORK.html: replaced by IDLEFORK-index.html - -2001-07-19 16:39 elguavas - - * IDLEFORK-index.html: updated placeholder idlefork homepage - -2001-07-19 14:49 elguavas - - * ChangeLog, EditorWindow.py, INSTALLATION, NEWS.txt, README.txt, - TODO.txt, idlever.py: - minor tidy-ups ready for 0.8.1 alpha tarball release - -2001-07-17 15:12 kbk - - * INSTALLATION, setup.py: INSTALLATION: Remove the coexist.patch - instructions - - **************** setup.py: - - Remove the idles script, add some words on IDLE Fork to the - long_description, and clean up some line spacing. - -2001-07-17 15:01 kbk - - * coexist.patch: Put this in the attic, at least for now... - -2001-07-17 14:59 kbk - - * PyShell.py, idle, idles: Implement idle command interface as - suggested by GvR [idle-dev] 16 July **************** PyShell: Added - functionality: - - usage: idle.py [-c command] [-d] [-i] [-r script] [-s] [-t title] - [arg] ... - - idle file(s) (without options) edit the file(s) - - -c cmd run the command in a shell -d enable the - debugger -i open an interactive shell -i file(s) open a - shell and also an editor window for each file -r script run a file - as a script in a shell -s run $IDLESTARTUP or - $PYTHONSTARTUP before anything else -t title set title of shell - window - - Remaining arguments are applied to the command (-c) or script (-r). - - ****************** idles: Removed the idles script, not needed - - ****************** idle: Removed the IdleConf references, not - required anymore - -2001-07-16 17:08 kbk - - * INSTALLATION, coexist.patch: Added installation instructions. - - Added a patch which modifies idlefork so that it can co-exist with - "official" IDLE in the site-packages directory. This patch is not - necessary if only idlefork IDLE is installed. See INSTALLATION for - further details. - -2001-07-16 15:50 kbk - - * idles: Add a script "idles" which opens a Python Shell window. - - The default behaviour of idlefork idle is to open an editor window - instead of a shell. Complex expressions may be run in a fresh - environment by selecting "run". There are times, however, when a - shell is desired. Though one can be started by "idle -t 'foo'", - this script is more convenient. In addition, a shell and an editor - window can be started in parallel by "idles -e foo.py". - -2001-07-16 15:25 kbk - - * PyShell.py: Call out IDLE Fork in startup message. - -2001-07-16 14:00 kbk - - * PyShell.py, setup.py: Add a script "idles" which opens a Python - Shell window. - - The default behaviour of idlefork idle is to open an editor window - instead of a shell. Complex expressions may be run in a fresh - environment by selecting "run". There are times, however, when a - shell is desired. Though one can be started by "idle -t 'foo'", - this script is more convenient. In addition, a shell and an editor - window can be started in parallel by "idles -e foo.py". - -2001-07-15 03:06 kbk - - * pyclbr.py, tabnanny.py: tabnanny and pyclbr are now found in /Lib - -2001-07-15 02:29 kbk - - * BrowserControl.py: Remove, was retained for 1.5.2 support - -2001-07-14 15:48 kbk - - * setup.py: Installing Idle to site-packages via Distutils does not - copy the Idle help.txt file. - - Ref SF Python Patch 422471 - -2001-07-14 15:26 kbk - - * keydefs.py: py-cvs-2001_07_13 (Rev 1.3) merge - - "Make copy, cut and paste events case insensitive. Reported by - Patrick K. O'Brien on idle-dev. (Should other bindings follow - suit?)" --GvR - -2001-07-14 15:21 kbk - - * idle.py: py-cvs-2001_07_13 (Rev 1.4) merge - - "Move the action of loading the configuration to the IdleConf - module rather than the idle.py script. This has advantages and - disadvantages; the biggest advantage being that we can more easily - have an alternative main program." --GvR - -2001-07-14 15:18 kbk - - * extend.txt: py-cvs-2001_07_13 (Rev 1.4) merge - - "Quick update to the extension mechanism (extend.py is gone, long - live config.txt)" --GvR - -2001-07-14 15:15 kbk - - * StackViewer.py: py-cvs-2001_07_13 (Rev 1.16) merge - - "Refactored, with some future plans in mind. This now uses the new - gotofileline() method defined in FileList.py" --GvR - -2001-07-14 15:10 kbk - - * PyShell.py: py-cvs-2001_07_13 (Rev 1.34) merge - - "Amazing. A very subtle change in policy in descr-branch actually - found a bug here. Here's the deal: Class PyShell derives from - class OutputWindow. Method PyShell.close() wants to invoke its - parent method, but because PyShell long ago was inherited from - class PyShellEditorWindow, it invokes - PyShelEditorWindow.close(self). Now, class PyShellEditorWindow - itself derives from class OutputWindow, and inherits the close() - method from there without overriding it. Under the old rules, - PyShellEditorWindow.close would return an unbound method restricted - to the class that defined the implementation of close(), which was - OutputWindow.close. Under the new rules, the unbound method is - restricted to the class whose method was requested, that is - PyShellEditorWindow, and this was correctly trapped as an error." - --GvR - -2001-07-14 14:59 kbk - - * PyParse.py: py-cvs-2001_07_13 (Rel 1.9) merge - - "Taught IDLE's autoident parser that "yield" is a keyword that - begins a stmt. Along w/ the preceding change to keyword.py, making - all this work w/ a future-stmt just looks harder and harder." - --tim_one - - (From Rel 1.8: "Hack to make this still work with Python 1.5.2. - ;-( " --fdrake) - -2001-07-14 14:51 kbk - - * IdleConf.py: py-cvs-2001_07_13 (Rel 1.7) merge - - "Move the action of loading the configuration to the IdleConf - module rather than the idle.py script. This has advantages and - disadvantages; the biggest advantage being that we can more easily - have an alternative main program." --GvR - -2001-07-14 14:45 kbk - - * FileList.py: py-cvs-2000_07_13 (Rev 1.9) merge - - "Delete goodname() method, which is unused. Add gotofileline(), a - convenience method which I intend to use in a variant. Rename - test() to _test()." --GvR - - This was an interesting merge. The join completely missed removing - goodname(), which was adjacent, but outside of, a small conflict. - I only caught it by comparing the 1.1.3.2/1.1.3.3 diff. CVS ain't - infallible. - -2001-07-14 13:58 kbk - - * EditorWindow.py: py-cvs-2000_07_13 (Rev 1.38) merge "Remove - legacy support for the BrowserControl module; the webbrowser module - has been included since Python 2.0, and that is the preferred - interface." --fdrake - -2001-07-14 13:32 kbk - - * EditorWindow.py, FileList.py, IdleConf.py, PyParse.py, - PyShell.py, StackViewer.py, extend.txt, idle.py, keydefs.py: Import - the 2001 July 13 23:59 GMT version of Python CVS IDLE on the - existing 1.1.3 vendor branch named py-cvs-vendor-branch. Release - tag is py-cvs-2001_07_13. - -2001-07-14 12:02 kbk - - * Icons/python.gif: py-cvs-rel2_1 (Rev 1.2) merge Copied py-cvs rev - 1.2 changed file to idlefork MAIN - -2001-07-14 11:58 kbk - - * Icons/minusnode.gif: py-cvs-rel2_1 (Rev 1.2) merge Copied py-cvs - 1.2 changed file to idlefork MAIN - -2001-07-14 11:23 kbk - - * ScrolledList.py: py-cvs-rel2_1 (rev 1.5) merge - whitespace - normalization - -2001-07-14 11:20 kbk - - * Separator.py: py-cvs-rel2_1 (Rev 1.3) merge - whitespace - normalization - -2001-07-14 11:16 kbk - - * StackViewer.py: py-cvs-rel2_1 (Rev 1.15) merge - whitespace - normalization - -2001-07-14 11:14 kbk - - * ToolTip.py: py-cvs-rel2_1 (Rev 1.2) merge - whitespace - normalization - -2001-07-14 10:13 kbk - - * PyShell.py: cvs-py-rel2_1 (Rev 1.29 - 1.33) merge - - Merged the following py-cvs revs without conflict: 1.29 Reduce - copyright text output at startup 1.30 Delay setting sys.args until - Tkinter is fully initialized 1.31 Whitespace normalization 1.32 - Turn syntax warning into error when interactive 1.33 Fix warning - initialization bug - - Note that module is extensively modified wrt py-cvs - -2001-07-14 06:33 kbk - - * PyParse.py: py-cvs-rel2_1 (Rev 1.6 - 1.8) merge Fix autoindent - bug and deflect Unicode from text.get() - -2001-07-14 06:00 kbk - - * Percolator.py: py-cvs-rel2_1 (Rev 1.3) "move "from Tkinter import - *" to module level" --jhylton - -2001-07-14 05:57 kbk - - * PathBrowser.py: py-cvs-rel2_1 (Rev 1.6) merge - whitespace - normalization - -2001-07-14 05:49 kbk - - * ParenMatch.py: cvs-py-rel2_1 (Rev 1.5) merge - whitespace - normalization - -2001-07-14 03:57 kbk - - * ObjectBrowser.py: py-cvs-rel2_1 (Rev 1.3) merge "Make the test - program work outside IDLE." -- GvR - -2001-07-14 03:52 kbk - - * MultiStatusBar.py: py-cvs-rel2_1 (Rev 1.2) merge - whitespace - normalization - -2001-07-14 03:44 kbk - - * MultiScrolledLists.py: py-cvs-rel2_1 (Rev 1.2) merge - whitespace - normalization - -2001-07-14 03:40 kbk - - * IdleHistory.py: py-cvs-rel2_1 (Rev 1.4) merge - whitespace - normalization - -2001-07-14 03:38 kbk - - * IdleConf.py: py-cvs-rel2_1 (Rev 1.6) merge - whitespace - normalization - -2001-07-13 14:18 kbk - - * IOBinding.py: py-cvs-rel2_1 (Rev 1.4) merge - move "import *" to - module level - -2001-07-13 14:12 kbk - - * FormatParagraph.py: py-cvs-rel2_1 (Rev 1.9) merge - whitespace - normalization - -2001-07-13 14:07 kbk - - * FileList.py: py-cvs-rel2_1 (Rev 1.8) merge - whitespace - normalization - -2001-07-13 13:35 kbk - - * EditorWindow.py: py-cvs-rel2_1 (Rev 1.33 - 1.37) merge - - VP IDLE version depended on VP's ExecBinding.py and spawn.py to get - the path to the Windows Doc directory (relative to python.exe). - Removed this conflicting code in favor of py-cvs updates which on - Windows use a hard coded path relative to the location of this - module. py-cvs updates include support for webbrowser.py. Module - still has BrowserControl.py for 1.5.2 support. - - At this point, the differences wrt py-cvs relate to menu - functionality. - -2001-07-13 11:30 kbk - - * ConfigParser.py: py-cvs-rel2_1 merge - Remove, lives in /Lib - -2001-07-13 10:10 kbk - - * Delegator.py: py-cvs-rel2_1 (Rev 1.3) merge - whitespace - normalization - -2001-07-13 10:07 kbk - - * Debugger.py: py-cvs-rel2_1 (Rev 1.15) merge - whitespace - normalization - -2001-07-13 10:04 kbk - - * ColorDelegator.py: py-cvs-rel2_1 (Rev 1.11 and 1.12) merge - Colorize "as" after "import" / use DEBUG instead of __debug__ - -2001-07-13 09:54 kbk - - * ClassBrowser.py: py-cvs-rel2_1 (Rev 1.12) merge - whitespace - normalization - -2001-07-13 09:41 kbk - - * BrowserControl.py: py-cvs-rel2_1 (Rev 1.1) merge - New File - - Force HEAD to trunk with -f Note: browser.py was renamed - BrowserControl.py 10 May 2000. It provides a collection of classes - and convenience functions to control external browsers "for 1.5.2 - support". It was removed from py-cvs 18 April 2001. - -2001-07-13 09:10 kbk - - * CallTips.py: py-cvs-rel2_1 (Rev 1.8) merge - whitespace - normalization - -2001-07-13 08:26 kbk - - * CallTipWindow.py: py-cvs-rel2_1 (Rev 1.3) merge - whitespace - normalization - -2001-07-13 08:13 kbk - - * AutoExpand.py: py-cvs-rel1_2 (Rev 1.4) merge, "Add Alt-slash to - Unix keydefs (I somehow need it on RH 6.2). Get rid of assignment - to unused self.text.wordlist." --GvR - -2001-07-12 16:54 elguavas - - * ReplaceDialog.py: py-cvs merge, python 1.5.2 compatability - -2001-07-12 16:46 elguavas - - * ScriptBinding.py: py-cvs merge, better error dialog - -2001-07-12 16:38 elguavas - - * TODO.txt: py-cvs merge, additions - -2001-07-12 15:35 elguavas - - * WindowList.py: py-cvs merge, correct indentation - -2001-07-12 15:24 elguavas - - * config.txt: py-cvs merge, correct typo - -2001-07-12 15:21 elguavas - - * help.txt: py-cvs merge, update colour changing info - -2001-07-12 14:51 elguavas - - * idle.py: py-cvs merge, idle_dir loading changed - -2001-07-12 14:44 elguavas - - * idlever.py: py-cvs merge, version update - -2001-07-11 12:53 kbk - - * BrowserControl.py: Initial revision - -2001-07-11 12:53 kbk - - * AutoExpand.py, BrowserControl.py, CallTipWindow.py, CallTips.py, - ClassBrowser.py, ColorDelegator.py, Debugger.py, Delegator.py, - EditorWindow.py, FileList.py, FormatParagraph.py, IOBinding.py, - IdleConf.py, IdleHistory.py, MultiScrolledLists.py, - MultiStatusBar.py, ObjectBrowser.py, OutputWindow.py, - ParenMatch.py, PathBrowser.py, Percolator.py, PyParse.py, - PyShell.py, RemoteInterp.py, ReplaceDialog.py, ScriptBinding.py, - ScrolledList.py, Separator.py, StackViewer.py, TODO.txt, - ToolTip.py, WindowList.py, config.txt, help.txt, idle, idle.bat, - idle.py, idlever.py, setup.py, Icons/minusnode.gif, - Icons/python.gif: Import the release 2.1 version of Python CVS IDLE - on the existing 1.1.3 vendor branch named py-cvs-vendor-branch, - with release tag py-cvs-rel2_1. - -2001-07-11 12:34 kbk - - * AutoExpand.py, AutoIndent.py, Bindings.py, CallTipWindow.py, - CallTips.py, ChangeLog, ClassBrowser.py, ColorDelegator.py, - Debugger.py, Delegator.py, EditorWindow.py, FileList.py, - FormatParagraph.py, FrameViewer.py, GrepDialog.py, IOBinding.py, - IdleConf.py, IdleHistory.py, MultiScrolledLists.py, - MultiStatusBar.py, NEWS.txt, ObjectBrowser.py, OldStackViewer.py, - OutputWindow.py, ParenMatch.py, PathBrowser.py, Percolator.py, - PyParse.py, PyShell.py, README.txt, RemoteInterp.py, - ReplaceDialog.py, ScriptBinding.py, ScrolledList.py, - SearchBinding.py, SearchDialog.py, SearchDialogBase.py, - SearchEngine.py, Separator.py, StackViewer.py, TODO.txt, - ToolTip.py, TreeWidget.py, UndoDelegator.py, WidgetRedirector.py, - WindowList.py, ZoomHeight.py, __init__.py, config-unix.txt, - config-win.txt, config.txt, eventparse.py, extend.txt, help.txt, - idle.bat, idle.py, idle.pyw, idlever.py, keydefs.py, pyclbr.py, - tabnanny.py, testcode.py, Icons/folder.gif, Icons/minusnode.gif, - Icons/openfolder.gif, Icons/plusnode.gif, Icons/python.gif, - Icons/tk.gif: Import the 9 March 2000 version of Python CVS IDLE as - 1.1.3 vendor branch named py-cvs-vendor-branch. - -2001-07-04 13:43 kbk - - * Icons/: folder.gif, minusnode.gif, openfolder.gif, plusnode.gif, - python.gif, tk.gif: Null commit with -f option to force an uprev - and put HEADs firmly on the trunk. - -2001-07-04 13:15 kbk - - * AutoExpand.py, AutoIndent.py, Bindings.py, CallTipWindow.py, - CallTips.py, ChangeLog, ClassBrowser.py, ColorDelegator.py, - ConfigParser.py, Debugger.py, Delegator.py, EditorWindow.py, - ExecBinding.py, FileList.py, FormatParagraph.py, FrameViewer.py, - GrepDialog.py, IDLEFORK.html, IOBinding.py, IdleConf.py, - IdleHistory.py, MultiScrolledLists.py, MultiStatusBar.py, NEWS.txt, - ObjectBrowser.py, OldStackViewer.py, OutputWindow.py, - ParenMatch.py, PathBrowser.py, Percolator.py, PyParse.py, - PyShell.py, README.txt, Remote.py, RemoteInterp.py, - ReplaceDialog.py, ScriptBinding.py, ScrolledList.py, - SearchBinding.py, SearchDialog.py, SearchDialogBase.py, - SearchEngine.py, Separator.py, StackViewer.py, TODO.txt, - ToolTip.py, TreeWidget.py, UndoDelegator.py, WidgetRedirector.py, - WindowList.py, ZoomHeight.py, __init__.py, config-unix.txt, - config-win.txt, config.txt, eventparse.py, extend.txt, help.txt, - idle, idle.bat, idle.py, idle.pyw, idlever.py, keydefs.py, - loader.py, protocol.py, pyclbr.py, setup.py, spawn.py, tabnanny.py, - testcode.py: Null commit with -f option to force an uprev and put - HEADs firmly on the trunk. - -2001-06-27 10:24 elguavas - - * IDLEFORK.html: updated contact details - -2001-06-25 17:23 elguavas - - * idle, RemoteInterp.py, setup.py: Initial revision - -2001-06-25 17:23 elguavas - - * idle, RemoteInterp.py, setup.py: import current python cvs idle - as a vendor branch - -2001-06-24 15:10 elguavas - - * IDLEFORK.html: tiny change to test new syncmail setup - -2001-06-24 14:41 elguavas - - * IDLEFORK.html: change to new developer contact, also a test - commit for new syncmail setup - -2001-06-23 18:15 elguavas - - * IDLEFORK.html: tiny test update for revitalised idle-fork - -2000-09-24 17:29 nriley - - * protocol.py: Fixes for Python 1.6 compatibility - socket bind and - connect get a tuple instead two arguments. - -2000-09-24 17:28 nriley - - * spawn.py: Change for Python 1.6 compatibility - UNIX's 'os' - module defines 'spawnv' now, so we check for 'fork' first. - -2000-08-15 22:51 nowonder - - * IDLEFORK.html: - corrected email address - -2000-08-15 22:47 nowonder - - * IDLEFORK.html: - added .html file for http://idlefork.sourceforge.net - -2000-08-15 11:13 dscherer - - * AutoExpand.py, AutoIndent.py, Bindings.py, CallTipWindow.py, - CallTips.py, __init__.py, ChangeLog, ClassBrowser.py, - ColorDelegator.py, ConfigParser.py, Debugger.py, Delegator.py, - FileList.py, FormatParagraph.py, FrameViewer.py, GrepDialog.py, - IOBinding.py, IdleConf.py, IdleHistory.py, MultiScrolledLists.py, - MultiStatusBar.py, NEWS.txt, ObjectBrowser.py, OldStackViewer.py, - OutputWindow.py, ParenMatch.py, PathBrowser.py, Percolator.py, - PyParse.py, PyShell.py, README.txt, ReplaceDialog.py, - ScriptBinding.py, ScrolledList.py, SearchBinding.py, - SearchDialog.py, SearchDialogBase.py, SearchEngine.py, - Separator.py, StackViewer.py, TODO.txt, ToolTip.py, TreeWidget.py, - UndoDelegator.py, WidgetRedirector.py, WindowList.py, help.txt, - ZoomHeight.py, config-unix.txt, config-win.txt, config.txt, - eventparse.py, extend.txt, idle.bat, idle.py, idle.pyw, idlever.py, - keydefs.py, loader.py, pyclbr.py, tabnanny.py, testcode.py, - EditorWindow.py, ExecBinding.py, Remote.py, protocol.py, spawn.py, - Icons/folder.gif, Icons/minusnode.gif, Icons/openfolder.gif, - Icons/plusnode.gif, Icons/python.gif, Icons/tk.gif: Initial - revision - -2000-08-15 11:13 dscherer - - * AutoExpand.py, AutoIndent.py, Bindings.py, CallTipWindow.py, - CallTips.py, __init__.py, ChangeLog, ClassBrowser.py, - ColorDelegator.py, ConfigParser.py, Debugger.py, Delegator.py, - FileList.py, FormatParagraph.py, FrameViewer.py, GrepDialog.py, - IOBinding.py, IdleConf.py, IdleHistory.py, MultiScrolledLists.py, - MultiStatusBar.py, NEWS.txt, ObjectBrowser.py, OldStackViewer.py, - OutputWindow.py, ParenMatch.py, PathBrowser.py, Percolator.py, - PyParse.py, PyShell.py, README.txt, ReplaceDialog.py, - ScriptBinding.py, ScrolledList.py, SearchBinding.py, - SearchDialog.py, SearchDialogBase.py, SearchEngine.py, - Separator.py, StackViewer.py, TODO.txt, ToolTip.py, TreeWidget.py, - UndoDelegator.py, WidgetRedirector.py, WindowList.py, help.txt, - ZoomHeight.py, config-unix.txt, config-win.txt, config.txt, - eventparse.py, extend.txt, idle.bat, idle.py, idle.pyw, idlever.py, - keydefs.py, loader.py, pyclbr.py, tabnanny.py, testcode.py, - EditorWindow.py, ExecBinding.py, Remote.py, protocol.py, spawn.py, - Icons/folder.gif, Icons/minusnode.gif, Icons/openfolder.gif, - Icons/plusnode.gif, Icons/python.gif, Icons/tk.gif: Modified IDLE - from VPython 0.2 - - -original IDLE ChangeLog: -======================== - -Tue Feb 15 18:08:19 2000 Guido van Rossum - - * NEWS.txt: Notice status bar and stack viewer. - - * EditorWindow.py: Support for Moshe's status bar. - - * MultiStatusBar.py: Status bar code -- by Moshe Zadka. - - * OldStackViewer.py: - Adding the old stack viewer implementation back, for the debugger. - - * StackViewer.py: New stack viewer, uses a tree widget. - (XXX: the debugger doesn't yet use this.) - - * WindowList.py: - Correct a typo and remove an unqualified except that was hiding the error. - - * ClassBrowser.py: Add an XXX comment about the ClassBrowser AIP. - - * ChangeLog: Updated change log. - - * NEWS.txt: News update. Probably incomplete; what else is new? - - * README.txt: - Updated for pending IDLE 0.5 release (still very rough -- just getting - it out in a more convenient format than CVS). - - * TODO.txt: Tiny addition. - -Thu Sep 9 14:16:02 1999 Guido van Rossum - - * TODO.txt: A few new TODO entries. - -Thu Aug 26 23:06:22 1999 Guido van Rossum - - * Bindings.py: Add Python Documentation entry to Help menu. - - * EditorWindow.py: - Find the help.txt file relative to __file__ or ".", not in sys.path. - (Suggested by Moshe Zadka, but implemented differently.) - - Add <> event which, on Unix, brings up Netscape pointing - to http://www.python.doc/current/ (a local copy would be nice but its - location can't be predicted). Windows solution TBD. - -Wed Aug 11 14:55:43 1999 Guido van Rossum - - * TreeWidget.py: - Moshe noticed an inconsistency in his comment, so I'm rephrasing it to - be clearer. - - * TreeWidget.py: - Patch inspired by Moshe Zadka to search for the Icons directory in the - same directory as __file__, rather than searching for it along sys.path. - This works better when idle is a package. - -Thu Jul 15 13:11:02 1999 Guido van Rossum - - * TODO.txt: New wishes. - -Sat Jul 10 13:17:35 1999 Guido van Rossum - - * IdlePrefs.py: - Make the color for stderr red (i.e. the standard warning/danger/stop - color) rather than green. Suggested by Sam Schulenburg. - -Fri Jun 25 17:26:34 1999 Guido van Rossum - - * PyShell.py: Close debugger when closing. This may break a cycle. - - * Debugger.py: Break cycle on close. - - * ClassBrowser.py: Destroy the tree when closing. - - * TreeWidget.py: Add destroy() method to recursively destroy a tree. - - * PyShell.py: Extend _close() to break cycles. - Break some other cycles too (and destroy the root when done). - - * EditorWindow.py: - Add _close() method that does the actual cleanup (close() asks the - user what they want first if there's unsaved stuff, and may cancel). - It closes more than before. - - Add unload_extensions() method to unload all extensions; called from - _close(). It calls an extension's close() method if it has one. - - * Percolator.py: Add close() method that breaks cycles. - - * WidgetRedirector.py: Add unregister() method. - Unregister everything at closing. - Don't call close() in __del__, rely on explicit call to close(). - - * IOBinding.py, FormatParagraph.py, CallTips.py: - Add close() method that breaks a cycle. - -Fri Jun 11 15:03:00 1999 Guido van Rossum - - * AutoIndent.py, EditorWindow.py, FormatParagraph.py: - Tim Peters smart.patch: - - EditorWindow.py: - - + Added get_tabwidth & set_tabwidth "virtual text" methods, that get/set the - widget's view of what a tab means. - - + Moved TK_TABWIDTH_DEFAULT here from AutoIndent. - - + Renamed Mark's get_selection_index to get_selection_indices (sorry, Mark, - but the name was plain wrong ). - - FormatParagraph.py: renamed use of get_selection_index. - - AutoIndent.py: - - + Moved TK_TABWIDTH_DEFAULT to EditorWindow. - - + Rewrote set_indentation_params to use new VTW get/set_tabwidth methods. - - + Changed smart_backspace_event to delete whitespace back to closest - preceding virtual tab stop or real character (note that this may require - inserting characters if backspacing over a tab!). - - + Nuked almost references to the selection tag, in favor of using - get_selection_indices. The sole exception is in set_region, for which no - "set_selection" abstraction has yet been agreed upon. - - + Had too much fun using the spiffy new features of the format-paragraph - cmd. - -Thu Jun 10 17:48:02 1999 Guido van Rossum - - * FormatParagraph.py: - Code by Mark Hammond to format paragraphs embedded in comments. - Read the comments (which I reformatted using the new feature :-) - for some limitations. - - * EditorWindow.py: - Added abstraction get_selection_index() (Mark Hammond). Also - reformatted some comment blocks to show off a cool feature I'm about - to check in next. - - * ClassBrowser.py: - Adapt to the new pyclbr's support of listing top-level functions. If - this functionality is not present (e.g. when used with a vintage - Python 1.5.2 installation) top-level functions are not listed. - - (Hmm... Any distribution of IDLE 0.5 should probably include a copy - of the new pyclbr.py!) - - * AutoIndent.py: - Fix off-by-one error in Tim's recent change to comment_region(): the - list of lines returned by get_region() contains an empty line at the - end representing the start of the next line, and this shouldn't be - commented out! - - * CallTips.py: - Mark Hammond writes: Here is another change that allows it to work for - class creation - tries to locate an __init__ function. Also updated - the test code to reflect your new "***" change. - - * CallTipWindow.py: - Mark Hammond writes: Tim's suggestion of copying the font for the - CallTipWindow from the text control makes sense, and actually makes - the control look better IMO. - -Wed Jun 9 20:34:57 1999 Guido van Rossum - - * CallTips.py: - Append "..." if the appropriate flag (for varargs) in co_flags is set. - Ditto "***" for kwargs. - -Tue Jun 8 13:06:07 1999 Guido van Rossum - - * ReplaceDialog.py: - Hmm... Tim didn't turn "replace all" into a single undo block. - I think I like it better if it os, so here. - - * ReplaceDialog.py: Tim Peters: made replacement atomic for undo/redo. - - * AutoIndent.py: Tim Peters: - - + Set usetabs=1. Editing pyclbr.py was driving me nuts <0.6 wink>. - usetabs=1 is the Emacs pymode default too, and thanks to indentwidth != - tabwidth magical usetabs disabling, new files are still created with tabs - turned off. The only implication is that if you open a file whose first - indent is a single tab, IDLE will now magically use tabs for that file (and - set indentwidth to 8). Note that the whole scheme doesn't work right for - PythonWin, though, since Windows users typically set tabwidth to 4; Mark - probably has to hide the IDLE algorithm from them (which he already knows). - - + Changed comment_region_event to stick "##" in front of every line. The - "holes" previously left on blank lines were visually confusing (made it - needlessly hard to figure out what to uncomment later). - -Mon Jun 7 15:38:40 1999 Guido van Rossum - - * TreeWidget.py, ObjectBrowser.py: - Remove unnecessary reference to pyclbr from test() code. - - * PyParse.py: Tim Peters: - - Smarter logic for finding a parse synch point. - - Does a half to a fifth the work in normal cases; don't notice the speedup, - but makes more breathing room for other extensions. - - Speeds terrible cases by at least a factor of 10. "Terrible" == e.g. you put - """ at the start of Tkinter.py, undo it, zoom to the bottom, and start - typing in code. Used to take about 8 seconds for ENTER to respond, now some - large fraction of a second. The new code gets indented correctly, despite - that it all remains "string colored" until the colorizer catches up (after - which, ENTER appears instantaneous again). - -Fri Jun 4 19:21:19 1999 Guido van Rossum - - * extend.py: Might as well enable CallTips by default. - If there are too many complaints I'll remove it again or fix it. - -Thu Jun 3 14:32:16 1999 Guido van Rossum - - * AutoIndent.py, EditorWindow.py, PyParse.py: - New offerings by Tim Peters; he writes: - - IDLE is now the first Python editor in the Universe not confused by my - doctest.py . - - As threatened, this defines IDLE's is_char_in_string function as a - method of EditorWindow. You just need to define one similarly in - whatever it is you pass as editwin to AutoIndent; looking at the - EditorWindow.py part of the patch should make this clear. - - * GrepDialog.py: Enclose pattern in quotes in status message. - - * CallTips.py: - Mark Hammond fixed some comments and improved the way the tip text is - constructed. - -Wed Jun 2 18:18:57 1999 Guido van Rossum - - * CallTips.py: - My fix to Mark's code: restore the universal check on . - Always cancel on or . - - * CallTips.py: - A version that Mark Hammond posted to the newsgroup. Has some newer - stuff for getting the tip. Had to fix the Key-( and Key-) events - for Unix. Will have to re-apply my patch for catching KeyRelease and - ButtonRelease events. - - * CallTipWindow.py, CallTips.py: - Call tips by Mark Hammond (plus tiny fix by me.) - - * IdleHistory.py: - Changes by Mark Hammond: (1) support optional output_sep argument to - the constructor so he can eliminate the sys.ps2 that PythonWin leaves - in the source; (2) remove duplicate history items. - - * AutoIndent.py: - Changes by Mark Hammond to allow using IDLE extensions in PythonWin as - well: make three dialog routines instance variables. - - * EditorWindow.py: - Change by Mark Hammond to allow using IDLE extensions in PythonWin as - well: make three dialog routines instance variables. - -Tue Jun 1 20:06:44 1999 Guido van Rossum - - * AutoIndent.py: Hah! A fix of my own to Tim's code! - Unix bindings for <> and <> were - missing, and somehow that meant the events were never generated, - even though they were in the menu. The new Unix bindings are now - the same as the Windows bindings (M-t and M-u). - - * AutoIndent.py, PyParse.py, PyShell.py: Tim Peters again: - - The new version (attached) is fast enough all the time in every real module - I have . You can make it slow by, e.g., creating an open list with - 5,000 90-character identifiers (+ trailing comma) each on its own line, then - adding an item to the end -- but that still consumes less than a second on - my P5-166. Response time in real code appears instantaneous. - - Fixed some bugs. - - New feature: when hitting ENTER and the cursor is beyond the line's leading - indentation, whitespace is removed on both sides of the cursor; before - whitespace was removed only on the left; e.g., assuming the cursor is - between the comma and the space: - - def something(arg1, arg2): - ^ cursor to the left of here, and hit ENTER - arg2): # new line used to end up here - arg2): # but now lines up the way you expect - - New hack: AutoIndent has grown a context_use_ps1 Boolean config option, - defaulting to 0 (false) and set to 1 (only) by PyShell. Reason: handling - the fancy stuff requires looking backward for a parsing synch point; ps1 - lines are the only sensible thing to look for in a shell window, but are a - bad thing to look for in a file window (ps1 lines show up in my module - docstrings often). PythonWin's shell should set this true too. - - Persistent problem: strings containing def/class can still screw things up - completely. No improvement. Simplest workaround is on the user's head, and - consists of inserting e.g. - - def _(): pass - - (or any other def/class) after the end of the multiline string that's - screwing them up. This is especially irksome because IDLE's syntax coloring - is *not* confused, so when this happens the colors don't match the - indentation behavior they see. - - * AutoIndent.py: Tim Peters again: - - [Tim, after adding some bracket smarts to AutoIndent.py] - > ... - > What it can't possibly do without reparsing large gobs of text is - > suggest a reasonable indent level after you've *closed* a bracket - > left open on some previous line. - > ... - - The attached can, and actually fast enough to use -- most of the time. The - code is tricky beyond belief to achieve that, but it works so far; e.g., - - return len(string.expandtabs(str[self.stmt_start : - ^ indents to caret - i], - ^ indents to caret - self.tabwidth)) + 1 - ^ indents to caret - - It's about as smart as pymode now, wrt both bracket and backslash - continuation rules. It does require reparsing large gobs of text, and if it - happens to find something that looks like a "def" or "class" or sys.ps1 - buried in a multiline string, but didn't suck up enough preceding text to - see the start of the string, it's completely hosed. I can't repair that -- - it's just too slow to reparse from the start of the file all the time. - - AutoIndent has grown a new num_context_lines tuple attribute that controls - how far to look back, and-- like other params --this could/should be made - user-overridable at startup and per-file on the fly. - - * PyParse.py: New file by Tim Peters: - - One new file in the attached, PyParse.py. The LineStudier (whatever it was - called ) class was removed from AutoIndent; PyParse subsumes its - functionality. - - * AutoIndent.py: Tim Peters keeps revising this module (more to come): - - Removed "New tabwidth" menu binding. - - Added "a tab means how many spaces?" dialog to block tabify and untabify. I - think prompting for this is good now: they're usually at-most-once-per-file - commands, and IDLE can't let them change tabwidth from the Tk default - anymore, so IDLE can no longer presume to have any idea what a tab means. - - Irony: for the purpose of keeping comments aligned via tabs, Tk's - non-default approach is much nicer than the Emacs/Notepad/Codewright/vi/etc - approach. - - * EditorWindow.py: - 1. Catch NameError on import (could be raised by case mismatch on Windows). - 2. No longer need to reset pyclbr cache and show watch cursor when calling - ClassBrowser -- the ClassBrowser takes care of pyclbr and the TreeWidget - takes care of the watch cursor. - 3. Reset the focus to the current window after error message about class - browser on buffer without filename. - - * Icons/minusnode.gif, Icons/plusnode.gif: Missed a few. - - * ClassBrowser.py, PathBrowser.py: Rewritten based on TreeWidget.py - - * ObjectBrowser.py: Object browser, based on TreeWidget.py. - - * TreeWidget.py: Tree widget done right. - - * ToolTip.py: As yet unused code for tool tips. - - * ScriptBinding.py: - Ensure sys.argv[0] is the script name on Run Script. - - * ZoomHeight.py: Move zoom height functionality to separate function. - - * Icons/folder.gif, Icons/openfolder.gif, Icons/python.gif, Icons/tk.gif: - A few icons used by ../TreeWidget.py and its callers. - - * AutoIndent.py: New version by Tim Peters improves block opening test. - -Fri May 21 04:46:17 1999 Guido van Rossum - - * Attic/History.py, PyShell.py: Rename History to IdleHistory. - Add isatty() to pseudo files. - - * StackViewer.py: Make initial stack viewer wider - - * TODO.txt: New wishes - - * AutoIndent.py, EditorWindow.py, PyShell.py: - Much improved autoindent and handling of tabs, - by Tim Peters. - -Mon May 3 15:49:52 1999 Guido van Rossum - - * AutoIndent.py, EditorWindow.py, FormatParagraph.py, UndoDelegator.py: - Tim Peters writes: - - I'm still unsure, but couldn't stand the virtual event trickery so tried a - different sin (adding undo_block_start/stop methods to the Text instance in - EditorWindow.py). Like it or not, it's efficient and works . Better - idea? - - Give the attached a whirl. Even if you hate the implementation, I think - you'll like the results. Think I caught all the "block edit" cmds, - including Format Paragraph, plus subtler ones involving smart indents and - backspacing. - - * WidgetRedirector.py: Tim Peters writes: - - [W]hile trying to dope out how redirection works, stumbled into two - possible glitches. In the first, it doesn't appear to make sense to try to - rename a command that's already been destroyed; in the second, the name - "previous" doesn't really bring to mind "ignore the previous value" . - -Fri Apr 30 19:39:25 1999 Guido van Rossum - - * __init__.py: Support for using idle as a package. - - * PathBrowser.py: - Avoid listing files more than once (e.g. foomodule.so has two hits: - once for foo + module.so, once for foomodule + .so). - -Mon Apr 26 22:20:38 1999 Guido van Rossum - - * ChangeLog, ColorDelegator.py, PyShell.py: Tim Peters strikes again: - - Ho ho ho -- that's trickier than it sounded! The colorizer is working with - "line.col" strings instead of Text marks, and the absolute coordinates of - the point of interest can change across the self.update call (voice of - baffled experience, when two quick backspaces no longer fooled it, but a - backspace followed by a quick ENTER did ). - - Anyway, the attached appears to do the trick. CPU usage goes way up when - typing quickly into a long triple-quoted string, but the latency is fine for - me (a relatively fast typist on a relatively slow machine). Most of the - changes here are left over from reducing the # of vrbl names to help me - reason about the logic better; I hope the code is a *little* easier to - -Fri Apr 23 14:01:25 1999 Guido van Rossum - - * EditorWindow.py: - Provide full arguments to __import__ so it works in packagized IDLE. - -Thu Apr 22 23:20:17 1999 Guido van Rossum - - * help.txt: - Bunch of updates necessary due to recent changes; added docs for File - menu, command line and color preferences. - - * Bindings.py: Remove obsolete 'script' menu. - - * TODO.txt: Several wishes fulfilled. - - * OutputWindow.py: - Moved classes OnDemandOutputWindow and PseudoFile here, - from ScriptBinding.py where they are no longer needed. - - * ScriptBinding.py: - Mostly rewritten. Instead of the old Run module and Debug module, - there are two new commands: - - Import module (F5) imports or reloads the module and also adds its - name to the __main__ namespace. This gets executed in the PyShell - window under control of its debug settings. - - Run script (Control-F5) is similar but executes the contents of the - file directly in the __main__ namespace. - - * PyShell.py: Nits: document use of $IDLESTARTUP; display idle version - - * idlever.py: New version to celebrate new command line - - * OutputWindow.py: Added flush(), for completeness. - - * PyShell.py: - A lot of changes to make the command line more useful. You can now do: - idle.py -e file ... -- to edit files - idle.py script arg ... -- to run a script - idle.py -c cmd arg ... -- to run a command - Other options, see also the usage message (also new!) for more details: - -d -- enable debugger - -s -- run $IDLESTARTUP or $PYTHONSTARTUP - -t title -- set Python Shell window's title - sys.argv is set accordingly, unless -e is used. - sys.path is absolutized, and all relevant paths are inserted into it. - - Other changes: - - the environment in which commands are executed is now the - __main__ module - - explicitly save sys.stdout etc., don't restore from sys.__stdout__ - - new interpreter methods execsource(), execfile(), stuffsource() - - a few small nits - - * TODO.txt: - Some more TODO items. Made up my mind about command line args, - Run/Import, __main__. - - * ColorDelegator.py: - Super-elegant patch by Tim Peters that speeds up colorization - dramatically (up to 15 times he claims). Works by reading more than - one line at a time, up to 100-line chunks (starting with one line and - then doubling up to the limit). On a typical machine (e.g. Tim's - P5-166) this doesn't reduce interactive responsiveness in a noticeable - way. - -Wed Apr 21 15:49:34 1999 Guido van Rossum - - * ColorDelegator.py: - Patch by Tim Peters to speed up colorizing of big multiline strings. - -Tue Apr 20 17:32:52 1999 Guido van Rossum - - * extend.txt: - For an event 'foo-bar', the corresponding method must be called - foo_bar_event(). Therefore, fix the references to zoom_height() in - the example. - - * IdlePrefs.py: Restored the original IDLE color scheme. - - * PyShell.py, IdlePrefs.py, ColorDelegator.py, EditorWindow.py: - Color preferences code by Loren Luke (massaged by me somewhat) - - * SearchEngine.py: - Patch by Mark Favas: it fixes the search engine behaviour where an - unsuccessful search wraps around and re-searches that part of the file - between the start of the search and the end of the file - only really - an issue for very large files, but... (also removes a redundant - m.span() call). - -Mon Apr 19 16:26:02 1999 Guido van Rossum - - * TODO.txt: A few wishes are now fulfilled. - - * AutoIndent.py: Tim Peters implements some of my wishes: - - o Makes the tab key intelligently insert spaces when appropriate - (see Help list banter twixt David Ascher and me; idea stolen from - every other editor on earth ). - - o newline_and_indent_event trims trailing whitespace on the old - line (pymode and Codewright). - - o newline_and_indent_event no longer fooled by trailing whitespace or - comment after ":" (pymode, PTUI). - - o newline_and_indent_event now reduces the new line's indentation after - return, break, continue, raise and pass stmts (pymode). - - The last two are easy to fool in the presence of strings & - continuations, but pymode requires Emacs's high-powered C parsing - functions to avoid that in finite time. - -====================================================================== - Python release 1.5.2c1, IDLE version 0.4 -====================================================================== - -Wed Apr 7 18:41:59 1999 Guido van Rossum - - * README.txt, NEWS.txt: New version. - - * idlever.py: Version bump awaiting impending new release. - (Not much has changed :-( ) - -Mon Mar 29 14:52:28 1999 Guido van Rossum - - * ScriptBinding.py, PyShell.py: - At Tim Peters' recommendation, add a dummy flush() method to - PseudoFile. - -Thu Mar 11 23:21:23 1999 Guido van Rossum - - * PathBrowser.py: Don't crash when sys.path contains an empty string. - - * Attic/Outline.py: This file was never supposed to be part of IDLE. - - * PathBrowser.py: - - Don't crash in the case where a superclass is a string instead of a - pyclbr.Class object; this can happen when the superclass is - unrecognizable (to pyclbr), e.g. when module renaming is used. - - - Show a watch cursor when calling pyclbr (since it may take a while - recursively parsing imported modules!). - -Wed Mar 10 05:18:02 1999 Guido van Rossum - - * EditorWindow.py, Bindings.py: Add PathBrowser to File module - - * PathBrowser.py: "Path browser" - 4 scrolled lists displaying: - directories on sys.path - modules in selected directory - classes in selected module - methods of selected class - - Sinlge clicking in a directory, module or class item updates the next - column with info about the selected item. Double clicking in a - module, class or method item opens the file (and selects the clicked - item if it is a class or method). - - I guess eventually I should be using a tree widget for this, but the - ones I've seen don't work well enough, so for now I use the old - Smalltalk or NeXT style multi-column hierarchical browser. - - * MultiScrolledLists.py: - New utility: multiple scrolled lists in parallel - - * ScrolledList.py: - White background. - - Display "(None)" (or text of your choosing) when empty. - - Don't set the focus. - -====================================================================== - Python release 1.5.2b2, IDLE version 0.3 -====================================================================== - -Wed Feb 17 22:47:41 1999 Guido van Rossum - - * NEWS.txt: News in 0.3. - - * README.txt, idlever.py: Bump version to 0.3. - - * EditorWindow.py: - After all, we don't need to call the callbacks ourselves! - - * WindowList.py: - When deleting, call the callbacks *after* deleting the window from our list! - - * EditorWindow.py: - Fix up the Windows menu via the new callback mechanism instead of - depending on menu post commands (which don't work when the menu is - torn off). - - * WindowList.py: - Support callbacks to patch up Windows menus everywhere. - - * ChangeLog: Oh, why not. Checking in the Emacs-generated change log. - -Tue Feb 16 22:34:17 1999 Guido van Rossum - - * ScriptBinding.py: - Only pop up the stack viewer when requested in the Debug menu. - -Mon Feb 8 22:27:49 1999 Guido van Rossum - - * WindowList.py: Don't crash if a window no longer exists. - - * TODO.txt: Restructured a bit. - -Mon Feb 1 23:06:17 1999 Guido van Rossum - - * PyShell.py: Add current dir or paths of file args to sys.path. - - * Debugger.py: Add canonic() function -- for brand new bdb.py feature. - - * StackViewer.py: Protect against accessing an empty stack. - -Fri Jan 29 20:44:45 1999 Guido van Rossum - - * ZoomHeight.py: - Use only the height to decide whether to zoom in or out. - -Thu Jan 28 22:24:30 1999 Guido van Rossum - - * EditorWindow.py, FileList.py: - Make sure the Tcl variables are shared between windows. - - * PyShell.py, EditorWindow.py, Bindings.py: - Move menu/key binding code from Bindings.py to EditorWindow.py, - with changed APIs -- it makes much more sense there. - Also add a new feature: if the first character of a menu label is - a '!', it gets a checkbox. Checkboxes are bound to Boolean Tcl variables - that can be accessed through the new getvar/setvar/getrawvar API; - the variable is named after the event to which the menu is bound. - - * Debugger.py: Add Quit button to the debugger window. - - * SearchDialog.py: - When find_again() finds exactly the current selection, it's a failure. - - * idle.py, Attic/idle: Rename idle -> idle.py - -Mon Jan 18 15:18:57 1999 Guido van Rossum - - * EditorWindow.py, WindowList.py: Only deiconify when iconic. - - * TODO.txt: Misc - -Tue Jan 12 22:14:34 1999 Guido van Rossum - - * testcode.py, Attic/test.py: - Renamed test.py to testcode.py so one can import Python's - test package from inside IDLE. (Suggested by Jack Jansen.) - - * EditorWindow.py, ColorDelegator.py: - Hack to close a window that is colorizing. - - * Separator.py: Vladimir Marangozov's patch: - The separator dances too much and seems to jump by arbitrary amounts - in arbitrary directions when I try to move it for resizing the frames. - This patch makes it more quiet. - -Mon Jan 11 14:52:40 1999 Guido van Rossum - - * TODO.txt: Some requests have been fulfilled. - - * EditorWindow.py: - Set the cursor to a watch when opening the class browser (which may - take quite a while, browsing multiple files). - - Newer, better center() -- but assumes no wrapping. - - * SearchBinding.py: - Got rid of debug print statement in goto_line_event(). - - * ScriptBinding.py: - I think I like it better if it prints the traceback even when it displays - the stack viewer. - - * Debugger.py: Bind ESC to close-window. - - * ClassBrowser.py: Use a HSeparator between the classes and the items. - Make the list of classes wider by default (40 chars). - Bind ESC to close-window. - - * Separator.py: - Separator classes (draggable divider between two panes). - -Sat Jan 9 22:01:33 1999 Guido van Rossum - - * WindowList.py: - Don't traceback when wakeup() is called when the window has been destroyed. - This can happen when a torn-of Windows menu references closed windows. - And Tim Peters claims that the Windows menu is his favorite to tear off... - - * EditorWindow.py: Allow tearing off of the Windows menu. - - * StackViewer.py: Close on ESC. - - * help.txt: Updated a bunch of things (it was mostly still 0.1!) - - * extend.py: Added ScriptBinding to standard bindings. - - * ScriptBinding.py: - This now actually works. See doc string. It can run a module (i.e. - import or reload) or debug it (same with debugger control). Output - goes to a fresh output window, only created when needed. - -====================================================================== - Python release 1.5.2b1, IDLE version 0.2 -====================================================================== - -Fri Jan 8 17:26:02 1999 Guido van Rossum - - * README.txt, NEWS.txt: What's new in this release. - - * Bindings.py, PyShell.py: - Paul Prescod's patches to allow the stack viewer to pop up when a - traceback is printed. - -Thu Jan 7 00:12:15 1999 Guido van Rossum - - * FormatParagraph.py: - Change paragraph width limit to 70 (like Emacs M-Q). - - * README.txt: - Separating TODO from README. Slight reformulation of features. No - exact release date. - - * TODO.txt: Separating TODO from README. - -Mon Jan 4 21:19:09 1999 Guido van Rossum - - * FormatParagraph.py: - Hm. There was a boundary condition error at the end of the file too. - - * SearchBinding.py: Hm. Add Unix binding for replace, too. - - * keydefs.py: Ran eventparse.py again. - - * FormatParagraph.py: Added Unix Meta-q key binding; - fix find_paragraph when at start of file. - - * AutoExpand.py: Added Meta-/ binding for Unix as alt for Alt-/. - - * SearchBinding.py: - Add unix binding for grep (otherwise the menu entry doesn't work!) - - * ZoomHeight.py: Adjusted Unix height to work with fvwm96. :=( - - * GrepDialog.py: Need to import sys! - - * help.txt, extend.txt, README.txt: Formatted some paragraphs - - * extend.py, FormatParagraph.py: - Add new extension to reformat a (text) paragraph. - - * ZoomHeight.py: Typo in Win specific height setting. - -Sun Jan 3 00:47:35 1999 Guido van Rossum - - * AutoIndent.py: Added something like Tim Peters' backspace patch. - - * ZoomHeight.py: Adapted to Unix (i.e., more hardcoded constants). - -Sat Jan 2 21:28:54 1999 Guido van Rossum - - * keydefs.py, idlever.py, idle.pyw, idle.bat, help.txt, extend.txt, extend.py, eventparse.py, ZoomHeight.py, WindowList.py, UndoDelegator.py, StackViewer.py, SearchEngine.py, SearchDialogBase.py, SearchDialog.py, ScrolledList.py, SearchBinding.py, ScriptBinding.py, ReplaceDialog.py, Attic/README, README.txt, PyShell.py, Attic/PopupMenu.py, OutputWindow.py, IOBinding.py, Attic/HelpWindow.py, History.py, GrepDialog.py, FileList.py, FrameViewer.py, EditorWindow.py, Debugger.py, Delegator.py, ColorDelegator.py, Bindings.py, ClassBrowser.py, AutoExpand.py, AutoIndent.py: - Checking in IDLE 0.2. - - Much has changed -- too much, in fact, to write down. - The big news is that there's a standard way to write IDLE extensions; - see extend.txt. Some sample extensions have been provided, and - some existing code has been converted to extensions. Probably the - biggest new user feature is a new search dialog with more options, - search and replace, and even search in files (grep). - - This is exactly as downloaded from my laptop after returning - from the holidays -- it hasn't even been tested on Unix yet. - -Fri Dec 18 15:52:54 1998 Guido van Rossum - - * FileList.py, ClassBrowser.py: - Fix the class browser to work even when the file is not on sys.path. - -Tue Dec 8 20:39:36 1998 Guido van Rossum - - * Attic/turtle.py: Moved to Python 1.5.2/Lib - -Fri Nov 27 03:19:20 1998 Guido van Rossum - - * help.txt: Typo - - * EditorWindow.py, FileList.py: Support underlining of menu labels - - * Bindings.py: - New approach, separate tables for menus (platform-independent) and key - definitions (platform-specific), and generating accelerator strings - automatically from the key definitions. - -Mon Nov 16 18:37:42 1998 Guido van Rossum - - * Attic/README: Clarify portability and main program. - - * Attic/README: Added intro for 0.1 release and append Grail notes. - -Mon Oct 26 18:49:00 1998 Guido van Rossum - - * Attic/turtle.py: root is now a global called _root - -Sat Oct 24 16:38:38 1998 Guido van Rossum - - * Attic/turtle.py: Raise the root window on reset(). - Different action on WM_DELETE_WINDOW is more likely to do the right thing, - allowing us to destroy old windows. - - * Attic/turtle.py: - Split the goto() function in two: _goto() is the internal one, - using Canvas coordinates, and goto() uses turtle coordinates - and accepts variable argument lists. - - * Attic/turtle.py: Cope with destruction of the window - - * Attic/turtle.py: Turtle graphics - - * Debugger.py: Use of Breakpoint class should be bdb.Breakpoint. - -Mon Oct 19 03:33:40 1998 Guido van Rossum - - * SearchBinding.py: - Speed up the search a bit -- don't drag a mark around... - - * PyShell.py: - Change our special entries from to . - Patch linecache.checkcache() to keep our special entries alive. - Add popup menu to all editor windows to set a breakpoint. - - * Debugger.py: - Use and pass through the 'force' flag to set_dict() where appropriate. - Default source and globals checkboxes to false. - Don't interact in user_return(). - Add primitive set_breakpoint() method. - - * ColorDelegator.py: - Raise priority of 'sel' tag so its foreground (on Windows) will take - priority over text colorization (which on Windows is almost the - same color as the selection background). - - Define a tag and color for breakpoints ("BREAK"). - - * Attic/PopupMenu.py: Disable "Open stack viewer" and "help" commands. - - * StackViewer.py: - Add optional 'force' argument (default 0) to load_dict(). - If set, redo the display even if it's the same dict. - -Fri Oct 16 21:10:12 1998 Guido van Rossum - - * StackViewer.py: Do nothing when loading the same dict as before. - - * PyShell.py: Details for debugger interface. - - * Debugger.py: - Restructured and more consistent. Save checkboxes across instantiations. - - * EditorWindow.py, Attic/README, Bindings.py: - Get rid of conflicting ^X binding. Use ^W. - - * Debugger.py, StackViewer.py: - Debugger can now show local and global variables. - - * Debugger.py: Oops - - * Debugger.py, PyShell.py: Better debugger support (show stack etc). - - * Attic/PopupMenu.py: Follow renames in StackViewer module - - * StackViewer.py: - Rename classes to StackViewer (the widget) and StackBrowser (the toplevel). - - * ScrolledList.py: Add close() method - - * EditorWindow.py: Clarify 'Open Module' dialog text - - * StackViewer.py: Restructured into a browser and a widget. - -Thu Oct 15 23:27:08 1998 Guido van Rossum - - * ClassBrowser.py, ScrolledList.py: - Generalized the scrolled list which is the base for the class and - method browser into a separate class in its own module. - - * Attic/test.py: Cosmetic change - - * Debugger.py: Don't show function name if there is none - -Wed Oct 14 03:43:05 1998 Guido van Rossum - - * Debugger.py, PyShell.py: Polish the Debugger GUI a bit. - Closing it now also does the right thing. - -Tue Oct 13 23:51:13 1998 Guido van Rossum - - * Debugger.py, PyShell.py, Bindings.py: - Ad primitive debugger interface (so far it will step and show you the - source, but it doesn't yet show the stack). - - * Attic/README: Misc - - * StackViewer.py: Whoops -- referenced self.top before it was set. - - * help.txt: Added history and completion commands. - - * help.txt: Updated - - * FileList.py: Add class browser functionality. - - * StackViewer.py: - Add a close() method and bind to WM_DELETE_WINDOW protocol - - * PyShell.py: Clear the linecache before printing a traceback - - * Bindings.py: Added class browser binding. - - * ClassBrowser.py: Much improved, much left to do. - - * PyShell.py: Make the return key do what I mean more often. - - * ClassBrowser.py: - Adding the beginnings of a Class browser. Incomplete, yet. - - * EditorWindow.py, Bindings.py: - Add new command, "Open module". You select or type a module name, - and it opens the source. - -Mon Oct 12 23:59:27 1998 Guido van Rossum - - * PyShell.py: Subsume functionality from Popup menu in Debug menu. - Other stuff so the PyShell window can be resurrected from the Windows menu. - - * FileList.py: Get rid of PopUp menu. - Create a simple Windows menu. (Imperfect when Untitled windows exist.) - Add wakeup() method: deiconify, raise, focus. - - * EditorWindow.py: Generalize menu creation. - - * Bindings.py: Add Debug and Help menu items. - - * EditorWindow.py: Added a menu bar to every window. - - * Bindings.py: Add menu configuration to the event configuration. - - * Attic/PopupMenu.py: Pass a root to the help window. - - * SearchBinding.py: - Add parent argument to 'to to line number' dialog box. - -Sat Oct 10 19:15:32 1998 Guido van Rossum - - * StackViewer.py: - Add a label at the top showing (very basic) help for the stack viewer. - Add a label at the bottom showing the exception info. - - * Attic/test.py, Attic/idle: Add Unix main script and test program. - - * idle.pyw, help.txt, WidgetRedirector.py, UndoDelegator.py, StackViewer.py, SearchBinding.py, Attic/README, PyShell.py, Attic/PopupMenu.py, Percolator.py, Outline.py, IOBinding.py, History.py, Attic/HelpWindow.py, FrameViewer.py, FileList.py, EditorWindow.py, Delegator.py, ColorDelegator.py, Bindings.py, AutoIndent.py, AutoExpand.py: - Initial checking of Tk-based Python IDE. - Features: text editor with syntax coloring and undo; - subclassed into interactive Python shell which adds history. - diff --git a/Lib/idlelib/ClassBrowser.py b/Lib/idlelib/ClassBrowser.py deleted file mode 100644 index 19f3b7e..0000000 --- a/Lib/idlelib/ClassBrowser.py +++ /dev/null @@ -1,224 +0,0 @@ -"""Class browser. - -XXX TO DO: - -- reparse when source changed (maybe just a button would be OK?) - (or recheck on window popup) -- add popup menu with more options (e.g. doc strings, base classes, imports) -- show function argument list? (have to do pattern matching on source) -- should the classes and methods lists also be in the module's menu bar? -- add base classes to class browser tree -""" - -import os -import sys -import string -import pyclbr - -# XXX Patch pyclbr with dummies if it's vintage Python 1.5.2: -if not hasattr(pyclbr, "readmodule_ex"): - pyclbr.readmodule_ex = pyclbr.readmodule -if not hasattr(pyclbr, "Function"): - class Function(pyclbr.Class): - pass - pyclbr.Function = Function - -import PyShell -from WindowList import ListedToplevel -from TreeWidget import TreeNode, TreeItem, ScrolledCanvas - -class ClassBrowser: - - def __init__(self, flist, name, path): - # XXX This API should change, if the file doesn't end in ".py" - # XXX the code here is bogus! - self.name = name - self.file = os.path.join(path[0], self.name + ".py") - self.init(flist) - - def close(self, event=None): - self.top.destroy() - self.node.destroy() - - def init(self, flist): - self.flist = flist - # reset pyclbr - pyclbr._modules.clear() - # create top - self.top = top = ListedToplevel(flist.root) - top.protocol("WM_DELETE_WINDOW", self.close) - top.bind("", self.close) - self.settitle() - top.focus_set() - # create scrolled canvas - sc = ScrolledCanvas(top, bg="white", highlightthickness=0, takefocus=1) - sc.frame.pack(expand=1, fill="both") - item = self.rootnode() - self.node = node = TreeNode(sc.canvas, None, item) - node.update() - node.expand() - - def settitle(self): - self.top.wm_title("Class Browser - " + self.name) - self.top.wm_iconname("Class Browser") - - def rootnode(self): - return ModuleBrowserTreeItem(self.file) - -class ModuleBrowserTreeItem(TreeItem): - - def __init__(self, file): - self.file = file - - def GetText(self): - return os.path.basename(self.file) - - def GetIconName(self): - return "python" - - def GetSubList(self): - sublist = [] - for name in self.listclasses(): - item = ClassBrowserTreeItem(name, self.classes, self.file) - sublist.append(item) - return sublist - - def OnDoubleClick(self): - if os.path.normcase(self.file[-3:]) != ".py": - return - if not os.path.exists(self.file): - return - PyShell.flist.open(self.file) - - def IsExpandable(self): - return os.path.normcase(self.file[-3:]) == ".py" - - def listclasses(self): - dir, file = os.path.split(self.file) - name, ext = os.path.splitext(file) - if os.path.normcase(ext) != ".py": - return [] - try: - dict = pyclbr.readmodule_ex(name, [dir] + sys.path) - except ImportError, msg: - return [] - items = [] - self.classes = {} - for key, cl in dict.items(): - if cl.module == name: - s = key - if cl.super: - supers = [] - for sup in cl.super: - if type(sup) is type(''): - sname = sup - else: - sname = sup.name - if sup.module != cl.module: - sname = "%s.%s" % (sup.module, sname) - supers.append(sname) - s = s + "(%s)" % string.join(supers, ", ") - items.append((cl.lineno, s)) - self.classes[s] = cl - items.sort() - list = [] - for item, s in items: - list.append(s) - return list - -class ClassBrowserTreeItem(TreeItem): - - def __init__(self, name, classes, file): - self.name = name - self.classes = classes - self.file = file - try: - self.cl = self.classes[self.name] - except (IndexError, KeyError): - self.cl = None - self.isfunction = isinstance(self.cl, pyclbr.Function) - - def GetText(self): - if self.isfunction: - return "def " + self.name + "(...)" - else: - return "class " + self.name - - def GetIconName(self): - if self.isfunction: - return "python" - else: - return "folder" - - def IsExpandable(self): - if self.cl: - return not not self.cl.methods - - def GetSubList(self): - if not self.cl: - return [] - sublist = [] - for name in self.listmethods(): - item = MethodBrowserTreeItem(name, self.cl, self.file) - sublist.append(item) - return sublist - - def OnDoubleClick(self): - if not os.path.exists(self.file): - return - edit = PyShell.flist.open(self.file) - if hasattr(self.cl, 'lineno'): - lineno = self.cl.lineno - edit.gotoline(lineno) - - def listmethods(self): - if not self.cl: - return [] - items = [] - for name, lineno in self.cl.methods.items(): - items.append((lineno, name)) - items.sort() - list = [] - for item, name in items: - list.append(name) - return list - -class MethodBrowserTreeItem(TreeItem): - - def __init__(self, name, cl, file): - self.name = name - self.cl = cl - self.file = file - - def GetText(self): - return "def " + self.name + "(...)" - - def GetIconName(self): - return "python" # XXX - - def IsExpandable(self): - return 0 - - def OnDoubleClick(self): - if not os.path.exists(self.file): - return - edit = PyShell.flist.open(self.file) - edit.gotoline(self.cl.methods[self.name]) - -def main(): - try: - file = __file__ - except NameError: - file = sys.argv[0] - if sys.argv[1:]: - file = sys.argv[1] - else: - file = sys.argv[0] - dir, file = os.path.split(file) - name = os.path.splitext(file)[0] - ClassBrowser(PyShell.flist, name, [dir]) - if sys.stdin is sys.__stdin__: - mainloop() - -if __name__ == "__main__": - main() diff --git a/Lib/idlelib/ColorDelegator.py b/Lib/idlelib/ColorDelegator.py deleted file mode 100644 index b4d6559..0000000 --- a/Lib/idlelib/ColorDelegator.py +++ /dev/null @@ -1,249 +0,0 @@ -import time -import string -import re -import keyword -from Tkinter import * -from Delegator import Delegator -from configHandler import idleConf - -#$ event <> -#$ win -#$ unix - -DEBUG = 0 - - -def any(name, list): - return "(?P<%s>" % name + string.join(list, "|") + ")" - -def make_pat(): - kw = r"\b" + any("KEYWORD", keyword.kwlist) + r"\b" - comment = any("COMMENT", [r"#[^\n]*"]) - sqstring = r"(\b[rR])?'[^'\\\n]*(\\.[^'\\\n]*)*'?" - dqstring = r'(\b[rR])?"[^"\\\n]*(\\.[^"\\\n]*)*"?' - sq3string = r"(\b[rR])?'''[^'\\]*((\\.|'(?!''))[^'\\]*)*(''')?" - dq3string = r'(\b[rR])?"""[^"\\]*((\\.|"(?!""))[^"\\]*)*(""")?' - string = any("STRING", [sq3string, dq3string, sqstring, dqstring]) - return kw + "|" + comment + "|" + string + "|" + any("SYNC", [r"\n"]) - -prog = re.compile(make_pat(), re.S) -idprog = re.compile(r"\s+(\w+)", re.S) -asprog = re.compile(r".*?\b(as)\b", re.S) - -class ColorDelegator(Delegator): - - def __init__(self): - Delegator.__init__(self) - self.prog = prog - self.idprog = idprog - self.asprog = asprog - - def setdelegate(self, delegate): - if self.delegate is not None: - self.unbind("<>") - Delegator.setdelegate(self, delegate) - if delegate is not None: - self.config_colors() - self.bind("<>", self.toggle_colorize_event) - self.notify_range("1.0", "end") - - def config_colors(self): - for tag, cnf in self.tagdefs.items(): - if cnf: - apply(self.tag_configure, (tag,), cnf) - self.tag_raise('sel') - - theme = idleConf.GetOption('main','Theme','name') - - tagdefs = { - "COMMENT": idleConf.GetHighlight(theme, "comment"), - "KEYWORD": idleConf.GetHighlight(theme, "keyword"), - "STRING": idleConf.GetHighlight(theme, "string"), - "DEFINITION": idleConf.GetHighlight(theme, "definition"), - "SYNC": idleConf.GetHighlight(theme, "sync"), - "TODO": idleConf.GetHighlight(theme, "todo"), - "BREAK": idleConf.GetHighlight(theme, "break"), - # The following is used by ReplaceDialog: - "hit": idleConf.GetHighlight(theme, "hit"), - } - - if DEBUG: print 'tagdefs',tagdefs - - def insert(self, index, chars, tags=None): - index = self.index(index) - self.delegate.insert(index, chars, tags) - self.notify_range(index, index + "+%dc" % len(chars)) - - def delete(self, index1, index2=None): - index1 = self.index(index1) - self.delegate.delete(index1, index2) - self.notify_range(index1) - - after_id = None - allow_colorizing = 1 - colorizing = 0 - - def notify_range(self, index1, index2=None): - self.tag_add("TODO", index1, index2) - if self.after_id: - if DEBUG: print "colorizing already scheduled" - return - if self.colorizing: - self.stop_colorizing = 1 - if DEBUG: print "stop colorizing" - if self.allow_colorizing: - if DEBUG: print "schedule colorizing" - self.after_id = self.after(1, self.recolorize) - - close_when_done = None # Window to be closed when done colorizing - - def close(self, close_when_done=None): - if self.after_id: - after_id = self.after_id - self.after_id = None - if DEBUG: print "cancel scheduled recolorizer" - self.after_cancel(after_id) - self.allow_colorizing = 0 - self.stop_colorizing = 1 - if close_when_done: - if not self.colorizing: - close_when_done.destroy() - else: - self.close_when_done = close_when_done - - def toggle_colorize_event(self, event): - if self.after_id: - after_id = self.after_id - self.after_id = None - if DEBUG: print "cancel scheduled recolorizer" - self.after_cancel(after_id) - if self.allow_colorizing and self.colorizing: - if DEBUG: print "stop colorizing" - self.stop_colorizing = 1 - self.allow_colorizing = not self.allow_colorizing - if self.allow_colorizing and not self.colorizing: - self.after_id = self.after(1, self.recolorize) - if DEBUG: - print "auto colorizing turned", self.allow_colorizing and "on" or "off" - return "break" - - def recolorize(self): - self.after_id = None - if not self.delegate: - if DEBUG: print "no delegate" - return - if not self.allow_colorizing: - if DEBUG: print "auto colorizing is off" - return - if self.colorizing: - if DEBUG: print "already colorizing" - return - try: - self.stop_colorizing = 0 - self.colorizing = 1 - if DEBUG: print "colorizing..." - t0 = time.clock() - self.recolorize_main() - t1 = time.clock() - if DEBUG: print "%.3f seconds" % (t1-t0) - finally: - self.colorizing = 0 - if self.allow_colorizing and self.tag_nextrange("TODO", "1.0"): - if DEBUG: print "reschedule colorizing" - self.after_id = self.after(1, self.recolorize) - if self.close_when_done: - top = self.close_when_done - self.close_when_done = None - top.destroy() - - def recolorize_main(self): - next = "1.0" - while 1: - item = self.tag_nextrange("TODO", next) - if not item: - break - head, tail = item - self.tag_remove("SYNC", head, tail) - item = self.tag_prevrange("SYNC", head) - if item: - head = item[1] - else: - head = "1.0" - - chars = "" - next = head - lines_to_get = 1 - ok = 0 - while not ok: - mark = next - next = self.index(mark + "+%d lines linestart" % - lines_to_get) - lines_to_get = min(lines_to_get * 2, 100) - ok = "SYNC" in self.tag_names(next + "-1c") - line = self.get(mark, next) - ##print head, "get", mark, next, "->", `line` - if not line: - return - for tag in self.tagdefs.keys(): - self.tag_remove(tag, mark, next) - chars = chars + line - m = self.prog.search(chars) - while m: - for key, value in m.groupdict().items(): - if value: - a, b = m.span(key) - self.tag_add(key, - head + "+%dc" % a, - head + "+%dc" % b) - if value in ("def", "class"): - m1 = self.idprog.match(chars, b) - if m1: - a, b = m1.span(1) - self.tag_add("DEFINITION", - head + "+%dc" % a, - head + "+%dc" % b) - elif value == "import": - # color all the "as" words on same line; - # cheap approximation to the truth - while 1: - m1 = self.asprog.match(chars, b) - if not m1: - break - a, b = m1.span(1) - self.tag_add("KEYWORD", - head + "+%dc" % a, - head + "+%dc" % b) - m = self.prog.search(chars, m.end()) - if "SYNC" in self.tag_names(next + "-1c"): - head = next - chars = "" - else: - ok = 0 - if not ok: - # We're in an inconsistent state, and the call to - # update may tell us to stop. It may also change - # the correct value for "next" (since this is a - # line.col string, not a true mark). So leave a - # crumb telling the next invocation to resume here - # in case update tells us to leave. - self.tag_add("TODO", next) - self.update() - if self.stop_colorizing: - if DEBUG: print "colorizing stopped" - return - - -def main(): - from Percolator import Percolator - root = Tk() - root.wm_protocol("WM_DELETE_WINDOW", root.quit) - text = Text(background="white") - text.pack(expand=1, fill="both") - text.focus_set() - p = Percolator(text) - d = ColorDelegator() - p.insertfilter(d) - root.mainloop() - -if __name__ == "__main__": - main() diff --git a/Lib/idlelib/Debugger.py b/Lib/idlelib/Debugger.py deleted file mode 100644 index e4591ff..0000000 --- a/Lib/idlelib/Debugger.py +++ /dev/null @@ -1,308 +0,0 @@ -import os -import bdb -import traceback -from Tkinter import * -from WindowList import ListedToplevel - -import StackViewer - - -class Debugger(bdb.Bdb): - - interacting = 0 - - vstack = vsource = vlocals = vglobals = None - - def __init__(self, pyshell): - bdb.Bdb.__init__(self) - self.pyshell = pyshell - self.make_gui() - - def canonic(self, filename): - # Canonicalize filename -- called by Bdb - return os.path.normcase(os.path.abspath(filename)) - - def close(self, event=None): - if self.interacting: - self.top.bell() - return - if self.stackviewer: - self.stackviewer.close(); self.stackviewer = None - self.pyshell.close_debugger() - self.top.destroy() - - def run(self, *args): - try: - self.interacting = 1 - return apply(bdb.Bdb.run, (self,) + args) - finally: - self.interacting = 0 - - def user_line(self, frame): - self.interaction(frame) - - def user_return(self, frame, rv): - # XXX show rv? - ##self.interaction(frame) - pass - - def user_exception(self, frame, info): - self.interaction(frame, info) - - def make_gui(self): - pyshell = self.pyshell - self.flist = pyshell.flist - self.root = root = pyshell.root - self.top = top =ListedToplevel(root) - self.top.wm_title("Debug Control") - self.top.wm_iconname("Debug") - top.wm_protocol("WM_DELETE_WINDOW", self.close) - self.top.bind("", self.close) - # - self.bframe = bframe = Frame(top) - self.bframe.pack(anchor="w") - self.buttons = bl = [] - # - self.bcont = b = Button(bframe, text="Go", command=self.cont) - bl.append(b) - self.bstep = b = Button(bframe, text="Step", command=self.step) - bl.append(b) - self.bnext = b = Button(bframe, text="Over", command=self.next) - bl.append(b) - self.bret = b = Button(bframe, text="Out", command=self.ret) - bl.append(b) - self.bret = b = Button(bframe, text="Quit", command=self.quit) - bl.append(b) - # - for b in bl: - b.configure(state="disabled") - b.pack(side="left") - # - self.cframe = cframe = Frame(bframe) - self.cframe.pack(side="left") - # - if not self.vstack: - self.__class__.vstack = BooleanVar(top) - self.vstack.set(1) - self.bstack = Checkbutton(cframe, - text="Stack", command=self.show_stack, variable=self.vstack) - self.bstack.grid(row=0, column=0) - if not self.vsource: - self.__class__.vsource = BooleanVar(top) - ##self.vsource.set(1) - self.bsource = Checkbutton(cframe, - text="Source", command=self.show_source, variable=self.vsource) - self.bsource.grid(row=0, column=1) - if not self.vlocals: - self.__class__.vlocals = BooleanVar(top) - self.vlocals.set(1) - self.blocals = Checkbutton(cframe, - text="Locals", command=self.show_locals, variable=self.vlocals) - self.blocals.grid(row=1, column=0) - if not self.vglobals: - self.__class__.vglobals = BooleanVar(top) - ##self.vglobals.set(1) - self.bglobals = Checkbutton(cframe, - text="Globals", command=self.show_globals, variable=self.vglobals) - self.bglobals.grid(row=1, column=1) - # - self.status = Label(top, anchor="w") - self.status.pack(anchor="w") - self.error = Label(top, anchor="w") - self.error.pack(anchor="w", fill="x") - self.errorbg = self.error.cget("background") - # - self.fstack = Frame(top, height=1) - self.fstack.pack(expand=1, fill="both") - self.flocals = Frame(top) - self.flocals.pack(expand=1, fill="both") - self.fglobals = Frame(top, height=1) - self.fglobals.pack(expand=1, fill="both") - # - if self.vstack.get(): - self.show_stack() - if self.vlocals.get(): - self.show_locals() - if self.vglobals.get(): - self.show_globals() - - frame = None - - def interaction(self, frame, info=None): - self.frame = frame - code = frame.f_code - file = code.co_filename - base = os.path.basename(file) - lineno = frame.f_lineno - # - message = "%s:%s" % (base, lineno) - if code.co_name != "?": - message = "%s: %s()" % (message, code.co_name) - self.status.configure(text=message) - # - if info: - type, value, tb = info - try: - m1 = type.__name__ - except AttributeError: - m1 = "%s" % str(type) - if value is not None: - try: - m1 = "%s: %s" % (m1, str(value)) - except: - pass - bg = "yellow" - else: - m1 = "" - tb = None - bg = self.errorbg - self.error.configure(text=m1, background=bg) - # - sv = self.stackviewer - if sv: - stack, i = self.get_stack(self.frame, tb) - sv.load_stack(stack, i) - # - self.show_variables(1) - # - if self.vsource.get(): - self.sync_source_line() - # - for b in self.buttons: - b.configure(state="normal") - # - self.top.tkraise() - self.root.mainloop() - # - for b in self.buttons: - b.configure(state="disabled") - self.status.configure(text="") - self.error.configure(text="", background=self.errorbg) - self.frame = None - - def sync_source_line(self): - frame = self.frame - if not frame: - return - code = frame.f_code - file = code.co_filename - lineno = frame.f_lineno - if file[:1] + file[-1:] != "<>" and os.path.exists(file): - edit = self.flist.open(file) - if edit: - edit.gotoline(lineno) - - def cont(self): - self.set_continue() - self.root.quit() - - def step(self): - self.set_step() - self.root.quit() - - def next(self): - self.set_next(self.frame) - self.root.quit() - - def ret(self): - self.set_return(self.frame) - self.root.quit() - - def quit(self): - self.set_quit() - self.root.quit() - - stackviewer = None - - def show_stack(self): - if not self.stackviewer and self.vstack.get(): - self.stackviewer = sv = StackViewer.StackViewer( - self.fstack, self.flist, self) - if self.frame: - stack, i = self.get_stack(self.frame, None) - sv.load_stack(stack, i) - else: - sv = self.stackviewer - if sv and not self.vstack.get(): - self.stackviewer = None - sv.close() - self.fstack['height'] = 1 - - def show_source(self): - if self.vsource.get(): - self.sync_source_line() - - def show_frame(self, (frame, lineno)): - self.frame = frame - self.show_variables() - - localsviewer = None - globalsviewer = None - - def show_locals(self): - lv = self.localsviewer - if self.vlocals.get(): - if not lv: - self.localsviewer = StackViewer.NamespaceViewer( - self.flocals, "Locals") - else: - if lv: - self.localsviewer = None - lv.close() - self.flocals['height'] = 1 - self.show_variables() - - def show_globals(self): - gv = self.globalsviewer - if self.vglobals.get(): - if not gv: - self.globalsviewer = StackViewer.NamespaceViewer( - self.fglobals, "Globals") - else: - if gv: - self.globalsviewer = None - gv.close() - self.fglobals['height'] = 1 - self.show_variables() - - def show_variables(self, force=0): - lv = self.localsviewer - gv = self.globalsviewer - frame = self.frame - if not frame: - ldict = gdict = None - else: - ldict = frame.f_locals - gdict = frame.f_globals - if lv and gv and ldict is gdict: - ldict = None - if lv: - lv.load_dict(ldict, force) - if gv: - gv.load_dict(gdict, force) - - def set_breakpoint_here(self, edit): - text = edit.text - filename = edit.io.filename - if not filename: - text.bell() - return - lineno = int(float(text.index("insert"))) - msg = self.set_break(filename, lineno) - if msg: - text.bell() - return - text.tag_add("BREAK", "insert linestart", "insert lineend +1char") - - # A literal copy of Bdb.set_break() without the print statement at the end - def set_break(self, filename, lineno, temporary=0, cond = None): - import linecache # Import as late as possible - line = linecache.getline(filename, lineno) - if not line: - return 'That line does not exist!' - if not self.breaks.has_key(filename): - self.breaks[filename] = [] - list = self.breaks[filename] - if not lineno in list: - list.append(lineno) - bp = bdb.Breakpoint(filename, lineno, temporary, cond) diff --git a/Lib/idlelib/Delegator.py b/Lib/idlelib/Delegator.py deleted file mode 100644 index 6125591..0000000 --- a/Lib/idlelib/Delegator.py +++ /dev/null @@ -1,33 +0,0 @@ -class Delegator: - - # The cache is only used to be able to change delegates! - - def __init__(self, delegate=None): - self.delegate = delegate - self.__cache = {} - - def __getattr__(self, name): - attr = getattr(self.delegate, name) # May raise AttributeError - setattr(self, name, attr) - self.__cache[name] = attr - return attr - - def resetcache(self): - for key in self.__cache.keys(): - try: - delattr(self, key) - except AttributeError: - pass - self.__cache.clear() - - def cachereport(self): - keys = self.__cache.keys() - keys.sort() - print keys - - def setdelegate(self, delegate): - self.resetcache() - self.delegate = delegate - - def getdelegate(self): - return self.delegate diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py deleted file mode 100644 index 2fe1810..0000000 --- a/Lib/idlelib/EditorWindow.py +++ /dev/null @@ -1,735 +0,0 @@ -# changes by dscherer@cmu.edu -# - created format and run menus -# - added silly advice dialog (apologies to Douglas Adams) -# - made Python Documentation work on Windows (requires win32api to -# do a ShellExecute(); other ways of starting a web browser are awkward) - -import sys -import os -import string -import re -import imp -from Tkinter import * -import tkSimpleDialog -import tkMessageBox - -import webbrowser -import idlever -import WindowList -from IdleConf import idleconf -import aboutDialog, textView, configDialog - -# The default tab setting for a Text widget, in average-width characters. -TK_TABWIDTH_DEFAULT = 8 - -# File menu - -#$ event <> -#$ win -#$ unix - -#$ event <> -#$ win -#$ unix - -#$ event <> - -#$ event <> - -#$ unix -#$ unix -#$ win - -# Edit menu - -#$ event <> -#$ win -#$ unix - -#$ event <> -#$ win -#$ unix - -#$ event <> -#$ win -#$ unix - -#$ event <> -#$ win -#$ unix - -# Help menu - -#$ event <> -#$ win -#$ unix - -#$ event <> - -# Events without menu entries - -#$ event <> -#$ win - -#$ event <> -#$ win -#$ unix - -#$ event <> -#$ unix - -class EditorWindow: - - from Percolator import Percolator - from ColorDelegator import ColorDelegator - from UndoDelegator import UndoDelegator - from IOBinding import IOBinding - import Bindings - from Tkinter import Toplevel - from MultiStatusBar import MultiStatusBar - - vars = {} - - def __init__(self, flist=None, filename=None, key=None, root=None): - edconf = idleconf.getsection('EditorWindow') - coconf = idleconf.getsection('Colors') - self.flist = flist - root = root or flist.root - self.root = root - if flist: - self.vars = flist.vars - self.menubar = Menu(root) - self.top = top = self.Toplevel(root, menu=self.menubar) - self.vbar = vbar = Scrollbar(top, name='vbar') - self.text_frame = text_frame = Frame(top) - self.text = text = Text(text_frame, name='text', padx=5, - foreground=coconf.getdef('normal-foreground'), - background=coconf.getdef('normal-background'), - highlightcolor=coconf.getdef('hilite-foreground'), - highlightbackground=coconf.getdef('hilite-background'), - insertbackground=coconf.getdef('cursor-background'), - width=edconf.getint('width'), - height=edconf.getint('height'), - wrap="none") - - self.createmenubar() - self.apply_bindings() - - self.top.protocol("WM_DELETE_WINDOW", self.close) - self.top.bind("<>", self.close_event) - text.bind("<>", self.center_insert_event) - text.bind("<>", self.help_dialog) - text.bind("<>", self.good_advice) - text.bind("<>", self.view_readme) - text.bind("<>", self.python_docs) - text.bind("<>", self.about_dialog) - text.bind("<>", self.config_dialog) - text.bind("<>", self.open_module) - text.bind("<>", lambda event: "break") - text.bind("<>", self.select_all) - text.bind("<>", self.remove_selection) - text.bind("<3>", self.right_menu_event) - if flist: - flist.inversedict[self] = key - if key: - flist.dict[key] = self - text.bind("<>", self.flist.new_callback) - text.bind("<>", self.flist.close_all_callback) - text.bind("<>", self.open_class_browser) - text.bind("<>", self.open_path_browser) - - self.set_status_bar() - - vbar['command'] = text.yview - vbar.pack(side=RIGHT, fill=Y) - - text['yscrollcommand'] = vbar.set - text['font'] = edconf.get('font-name'), edconf.get('font-size') - text_frame.pack(side=LEFT, fill=BOTH, expand=1) - text.pack(side=TOP, fill=BOTH, expand=1) - text.focus_set() - - self.per = per = self.Percolator(text) - if self.ispythonsource(filename): - self.color = color = self.ColorDelegator(); per.insertfilter(color) - ##print "Initial colorizer" - else: - ##print "No initial colorizer" - self.color = None - self.undo = undo = self.UndoDelegator(); per.insertfilter(undo) - self.io = io = self.IOBinding(self) - - text.undo_block_start = undo.undo_block_start - text.undo_block_stop = undo.undo_block_stop - undo.set_saved_change_hook(self.saved_change_hook) - io.set_filename_change_hook(self.filename_change_hook) - - if filename: - if os.path.exists(filename): - io.loadfile(filename) - else: - io.set_filename(filename) - - self.saved_change_hook() - - self.load_extensions() - - menu = self.menudict.get('windows') - if menu: - end = menu.index("end") - if end is None: - end = -1 - if end >= 0: - menu.add_separator() - end = end + 1 - self.wmenu_end = end - WindowList.register_callback(self.postwindowsmenu) - - # Some abstractions so IDLE extensions are cross-IDE - self.askyesno = tkMessageBox.askyesno - self.askinteger = tkSimpleDialog.askinteger - self.showerror = tkMessageBox.showerror - - if self.extensions.has_key('AutoIndent'): - self.extensions['AutoIndent'].set_indentation_params( - self.ispythonsource(filename)) - - - def set_status_bar(self): - self.status_bar = self.MultiStatusBar(self.top) - self.status_bar.set_label('column', 'Col: ?', side=RIGHT) - self.status_bar.set_label('line', 'Ln: ?', side=RIGHT) - self.status_bar.pack(side=BOTTOM, fill=X) - self.text.bind('', self.set_line_and_column) - self.text.bind('', self.set_line_and_column) - self.text.after_idle(self.set_line_and_column) - - def set_line_and_column(self, event=None): - line, column = string.split(self.text.index(INSERT), '.') - self.status_bar.set_label('column', 'Col: %s' % column) - self.status_bar.set_label('line', 'Ln: %s' % line) - - def wakeup(self): - if self.top.wm_state() == "iconic": - self.top.wm_deiconify() - else: - self.top.tkraise() - self.text.focus_set() - - menu_specs = [ - ("file", "_File"), - ("edit", "_Edit"), - ("format", "F_ormat"), - ("run", "_Run"), - #("settings", "_Settings"), - ("windows", "_Windows"), - ("help", "_Help"), - ] - - def createmenubar(self): - mbar = self.menubar - self.menudict = menudict = {} - for name, label in self.menu_specs: - underline, label = prepstr(label) - menudict[name] = menu = Menu(mbar, name=name) - mbar.add_cascade(label=label, menu=menu, underline=underline) - self.fill_menus() - - def postwindowsmenu(self): - # Only called when Windows menu exists - # XXX Actually, this Just-In-Time updating interferes badly - # XXX with the tear-off feature. It would be better to update - # XXX all Windows menus whenever the list of windows changes. - menu = self.menudict['windows'] - end = menu.index("end") - if end is None: - end = -1 - if end > self.wmenu_end: - menu.delete(self.wmenu_end+1, end) - WindowList.add_windows_to_menu(menu) - - rmenu = None - - def right_menu_event(self, event): - self.text.tag_remove("sel", "1.0", "end") - self.text.mark_set("insert", "@%d,%d" % (event.x, event.y)) - if not self.rmenu: - self.make_rmenu() - rmenu = self.rmenu - self.event = event - iswin = sys.platform[:3] == 'win' - if iswin: - self.text.config(cursor="arrow") - rmenu.tk_popup(event.x_root, event.y_root) - if iswin: - self.text.config(cursor="ibeam") - - rmenu_specs = [ - # ("Label", "<>"), ... - ("Close", "<>"), # Example - ] - - def make_rmenu(self): - rmenu = Menu(self.text, tearoff=0) - for label, eventname in self.rmenu_specs: - def command(text=self.text, eventname=eventname): - text.event_generate(eventname) - rmenu.add_command(label=label, command=command) - self.rmenu = rmenu - - def about_dialog(self, event=None): - aboutDialog.AboutDialog(self.top,'About IDLEfork') - - def config_dialog(self, event=None): - configDialog.ConfigDialog(self.top,'Settings') - - def good_advice(self, event=None): - tkMessageBox.showinfo('Advice', "Don't Panic!", master=self.text) - - def view_readme(self, event=None): - fn=os.path.join(os.path.abspath(os.path.dirname(__file__)),'README.txt') - textView.TextViewer(self.top,'IDLEfork - README',fn) - - def help_dialog(self, event=None): - fn=os.path.join(os.path.abspath(os.path.dirname(__file__)),'help.txt') - textView.TextViewer(self.top,'Help',fn) - - help_url = "http://www.python.org/doc/current/" - if sys.platform[:3] == "win": - fn = os.path.dirname(__file__) - fn = os.path.join(fn, os.pardir, os.pardir, "Doc", "index.html") - fn = os.path.normpath(fn) - if os.path.isfile(fn): - help_url = fn - del fn - - def python_docs(self, event=None): - webbrowser.open(self.help_url) - - def select_all(self, event=None): - self.text.tag_add("sel", "1.0", "end-1c") - self.text.mark_set("insert", "1.0") - self.text.see("insert") - return "break" - - def remove_selection(self, event=None): - self.text.tag_remove("sel", "1.0", "end") - self.text.see("insert") - - def open_module(self, event=None): - # XXX Shouldn't this be in IOBinding or in FileList? - try: - name = self.text.get("sel.first", "sel.last") - except TclError: - name = "" - else: - name = string.strip(name) - if not name: - name = tkSimpleDialog.askstring("Module", - "Enter the name of a Python module\n" - "to search on sys.path and open:", - parent=self.text) - if name: - name = string.strip(name) - if not name: - return - # XXX Ought to support package syntax - # XXX Ought to insert current file's directory in front of path - try: - (f, file, (suffix, mode, type)) = imp.find_module(name) - except (NameError, ImportError), msg: - tkMessageBox.showerror("Import error", str(msg), parent=self.text) - return - if type != imp.PY_SOURCE: - tkMessageBox.showerror("Unsupported type", - "%s is not a source module" % name, parent=self.text) - return - if f: - f.close() - if self.flist: - self.flist.open(file) - else: - self.io.loadfile(file) - - def open_class_browser(self, event=None): - filename = self.io.filename - if not filename: - tkMessageBox.showerror( - "No filename", - "This buffer has no associated filename", - master=self.text) - self.text.focus_set() - return None - head, tail = os.path.split(filename) - base, ext = os.path.splitext(tail) - import ClassBrowser - ClassBrowser.ClassBrowser(self.flist, base, [head]) - - def open_path_browser(self, event=None): - import PathBrowser - PathBrowser.PathBrowser(self.flist) - - def gotoline(self, lineno): - if lineno is not None and lineno > 0: - self.text.mark_set("insert", "%d.0" % lineno) - self.text.tag_remove("sel", "1.0", "end") - self.text.tag_add("sel", "insert", "insert +1l") - self.center() - - def ispythonsource(self, filename): - if not filename: - return 1 - base, ext = os.path.splitext(os.path.basename(filename)) - if os.path.normcase(ext) in (".py", ".pyw"): - return 1 - try: - f = open(filename) - line = f.readline() - f.close() - except IOError: - return 0 - return line[:2] == '#!' and string.find(line, 'python') >= 0 - - def close_hook(self): - if self.flist: - self.flist.close_edit(self) - - def set_close_hook(self, close_hook): - self.close_hook = close_hook - - def filename_change_hook(self): - if self.flist: - self.flist.filename_changed_edit(self) - self.saved_change_hook() - if self.ispythonsource(self.io.filename): - self.addcolorizer() - else: - self.rmcolorizer() - - def addcolorizer(self): - if self.color: - return - ##print "Add colorizer" - self.per.removefilter(self.undo) - self.color = self.ColorDelegator() - self.per.insertfilter(self.color) - self.per.insertfilter(self.undo) - - def rmcolorizer(self): - if not self.color: - return - ##print "Remove colorizer" - self.per.removefilter(self.undo) - self.per.removefilter(self.color) - self.color = None - self.per.insertfilter(self.undo) - - def saved_change_hook(self): - short = self.short_title() - long = self.long_title() - if short and long: - title = short + " - " + long - elif short: - title = short - elif long: - title = long - else: - title = "Untitled" - icon = short or long or title - if not self.get_saved(): - title = "*%s*" % title - icon = "*%s" % icon - self.top.wm_title(title) - self.top.wm_iconname(icon) - - def get_saved(self): - return self.undo.get_saved() - - def set_saved(self, flag): - self.undo.set_saved(flag) - - def reset_undo(self): - self.undo.reset_undo() - - def short_title(self): - filename = self.io.filename - if filename: - filename = os.path.basename(filename) - return filename - - def long_title(self): - return self.io.filename or "" - - def center_insert_event(self, event): - self.center() - - def center(self, mark="insert"): - text = self.text - top, bot = self.getwindowlines() - lineno = self.getlineno(mark) - height = bot - top - newtop = max(1, lineno - height/2) - text.yview(float(newtop)) - - def getwindowlines(self): - text = self.text - top = self.getlineno("@0,0") - bot = self.getlineno("@0,65535") - if top == bot and text.winfo_height() == 1: - # Geometry manager hasn't run yet - height = int(text['height']) - bot = top + height - 1 - return top, bot - - def getlineno(self, mark="insert"): - text = self.text - return int(float(text.index(mark))) - - def close_event(self, event): - self.close() - - def maybesave(self): - if self.io: - return self.io.maybesave() - - def close(self): - self.top.wm_deiconify() - self.top.tkraise() - reply = self.maybesave() - if reply != "cancel": - self._close() - return reply - - def _close(self): - WindowList.unregister_callback(self.postwindowsmenu) - if self.close_hook: - self.close_hook() - self.flist = None - colorizing = 0 - self.unload_extensions() - self.io.close(); self.io = None - self.undo = None # XXX - if self.color: - colorizing = self.color.colorizing - doh = colorizing and self.top - self.color.close(doh) # Cancel colorization - self.text = None - self.vars = None - self.per.close(); self.per = None - if not colorizing: - self.top.destroy() - - def load_extensions(self): - self.extensions = {} - self.load_standard_extensions() - - def unload_extensions(self): - for ins in self.extensions.values(): - if hasattr(ins, "close"): - ins.close() - self.extensions = {} - - def load_standard_extensions(self): - for name in self.get_standard_extension_names(): - try: - self.load_extension(name) - except: - print "Failed to load extension", `name` - import traceback - traceback.print_exc() - - def get_standard_extension_names(self): - return idleconf.getextensions() - - def load_extension(self, name): - mod = __import__(name, globals(), locals(), []) - cls = getattr(mod, name) - ins = cls(self) - self.extensions[name] = ins - kdnames = ["keydefs"] - if sys.platform == 'win32': - kdnames.append("windows_keydefs") - elif sys.platform == 'mac': - kdnames.append("mac_keydefs") - else: - kdnames.append("unix_keydefs") - keydefs = {} - for kdname in kdnames: - if hasattr(ins, kdname): - keydefs.update(getattr(ins, kdname)) - if keydefs: - self.apply_bindings(keydefs) - for vevent in keydefs.keys(): - methodname = string.replace(vevent, "-", "_") - while methodname[:1] == '<': - methodname = methodname[1:] - while methodname[-1:] == '>': - methodname = methodname[:-1] - methodname = methodname + "_event" - if hasattr(ins, methodname): - self.text.bind(vevent, getattr(ins, methodname)) - if hasattr(ins, "menudefs"): - self.fill_menus(ins.menudefs, keydefs) - return ins - - def apply_bindings(self, keydefs=None): - if keydefs is None: - keydefs = self.Bindings.default_keydefs - text = self.text - text.keydefs = keydefs - for event, keylist in keydefs.items(): - if keylist: - apply(text.event_add, (event,) + tuple(keylist)) - - def fill_menus(self, defs=None, keydefs=None): - # Fill the menus. Menus that are absent or None in - # self.menudict are ignored. - if defs is None: - defs = self.Bindings.menudefs - if keydefs is None: - keydefs = self.Bindings.default_keydefs - menudict = self.menudict - text = self.text - for mname, itemlist in defs: - menu = menudict.get(mname) - if not menu: - continue - for item in itemlist: - if not item: - menu.add_separator() - else: - label, event = item - checkbutton = (label[:1] == '!') - if checkbutton: - label = label[1:] - underline, label = prepstr(label) - accelerator = get_accelerator(keydefs, event) - def command(text=text, event=event): - text.event_generate(event) - if checkbutton: - var = self.getrawvar(event, BooleanVar) - menu.add_checkbutton(label=label, underline=underline, - command=command, accelerator=accelerator, - variable=var) - else: - menu.add_command(label=label, underline=underline, - command=command, accelerator=accelerator) - - def getvar(self, name): - var = self.getrawvar(name) - if var: - return var.get() - - def setvar(self, name, value, vartype=None): - var = self.getrawvar(name, vartype) - if var: - var.set(value) - - def getrawvar(self, name, vartype=None): - var = self.vars.get(name) - if not var and vartype: - self.vars[name] = var = vartype(self.text) - return var - - # Tk implementations of "virtual text methods" -- each platform - # reusing IDLE's support code needs to define these for its GUI's - # flavor of widget. - - # Is character at text_index in a Python string? Return 0 for - # "guaranteed no", true for anything else. This info is expensive - # to compute ab initio, but is probably already known by the - # platform's colorizer. - - def is_char_in_string(self, text_index): - if self.color: - # Return true iff colorizer hasn't (re)gotten this far - # yet, or the character is tagged as being in a string - return self.text.tag_prevrange("TODO", text_index) or \ - "STRING" in self.text.tag_names(text_index) - else: - # The colorizer is missing: assume the worst - return 1 - - # If a selection is defined in the text widget, return (start, - # end) as Tkinter text indices, otherwise return (None, None) - def get_selection_indices(self): - try: - first = self.text.index("sel.first") - last = self.text.index("sel.last") - return first, last - except TclError: - return None, None - - # Return the text widget's current view of what a tab stop means - # (equivalent width in spaces). - - def get_tabwidth(self): - current = self.text['tabs'] or TK_TABWIDTH_DEFAULT - return int(current) - - # Set the text widget's current view of what a tab stop means. - - def set_tabwidth(self, newtabwidth): - text = self.text - if self.get_tabwidth() != newtabwidth: - pixels = text.tk.call("font", "measure", text["font"], - "-displayof", text.master, - "n" * newtabwidth) - text.configure(tabs=pixels) - -def prepstr(s): - # Helper to extract the underscore from a string, e.g. - # prepstr("Co_py") returns (2, "Copy"). - i = string.find(s, '_') - if i >= 0: - s = s[:i] + s[i+1:] - return i, s - - -keynames = { - 'bracketleft': '[', - 'bracketright': ']', - 'slash': '/', -} - -def get_accelerator(keydefs, event): - keylist = keydefs.get(event) - if not keylist: - return "" - s = keylist[0] - s = re.sub(r"-[a-z]\b", lambda m: string.upper(m.group()), s) - s = re.sub(r"\b\w+\b", lambda m: keynames.get(m.group(), m.group()), s) - s = re.sub("Key-", "", s) - s = re.sub("Cancel","Ctrl-Break",s) # dscherer@cmu.edu - s = re.sub("Control-", "Ctrl-", s) - s = re.sub("-", "+", s) - s = re.sub("><", " ", s) - s = re.sub("<", "", s) - s = re.sub(">", "", s) - return s - - -def fixwordbreaks(root): - # Make sure that Tk's double-click and next/previous word - # operations use our definition of a word (i.e. an identifier) - tk = root.tk - tk.call('tcl_wordBreakAfter', 'a b', 0) # make sure word.tcl is loaded - tk.call('set', 'tcl_wordchars', '[a-zA-Z0-9_]') - tk.call('set', 'tcl_nonwordchars', '[^a-zA-Z0-9_]') - - -def test(): - root = Tk() - fixwordbreaks(root) - root.withdraw() - if sys.argv[1:]: - filename = sys.argv[1] - else: - filename = None - edit = EditorWindow(root=root, filename=filename) - edit.set_close_hook(root.quit) - root.mainloop() - root.destroy() - -if __name__ == '__main__': - test() diff --git a/Lib/idlelib/ExecBinding.py b/Lib/idlelib/ExecBinding.py deleted file mode 100644 index 67b0822..0000000 --- a/Lib/idlelib/ExecBinding.py +++ /dev/null @@ -1,198 +0,0 @@ -"""Extension to execute a script in a separate process - -David Scherer - - The ExecBinding module, a replacement for ScriptBinding, executes - programs in a separate process. Unlike previous versions, this version - communicates with the user process via an RPC protocol (see the 'protocol' - module). The user program is loaded by the 'loader' and 'Remote' - modules. Its standard output and input are directed back to the - ExecBinding class through the RPC mechanism and implemented here. - - A "stop program" command is provided and bound to control-break. Closing - the output window also stops the running program. -""" - -import sys -import os -import imp -import OutputWindow -import protocol -import spawn -import traceback -import tempfile - -# Find Python and the loader. This should be done as early in execution -# as possible, because if the current directory or sys.path is changed -# it may no longer be possible to get correct paths for these things. - -pyth_exe = spawn.hardpath( sys.executable ) -load_py = spawn.hardpath( imp.find_module("loader")[1] ) - -# The following mechanism matches loaders up with ExecBindings that are -# trying to load something. - -waiting_for_loader = [] - -def loader_connect(client, addr): - if waiting_for_loader: - a = waiting_for_loader.pop(0) - try: - return a.connect(client, addr) - except: - return loader_connect(client,addr) - -protocol.publish('ExecBinding', loader_connect) - -class ExecBinding: - keydefs = { - '<>': [''], - '<>': [''], #'' - } - - menudefs = [ - ('run', [None, - ('Run program', '<>'), - ('Stop program', '<>'), - ] - ), - ] - - delegate = 1 - - def __init__(self, editwin): - self.editwin = editwin - self.client = None - self.temp = [] - - if not hasattr(editwin, 'source_window'): - self.delegate = 0 - self.output = OutputWindow.OnDemandOutputWindow(editwin.flist) - self.output.close_hook = self.stopProgram - self.output.source_window = editwin - else: - if (self.editwin.source_window and - self.editwin.source_window.extensions.has_key('ExecBinding') and - not self.editwin.source_window.extensions['ExecBinding'].delegate): - delegate = self.editwin.source_window.extensions['ExecBinding'] - self.run_complete_script_event = delegate.run_complete_script_event - self.stop_execution_event = delegate.stop_execution_event - - def __del__(self): - self.stopProgram() - - def stop_execution_event(self, event): - if self.client: - self.stopProgram() - self.write('\nProgram stopped.\n','stderr') - - def run_complete_script_event(self, event): - filename = self.getfilename() - if not filename: return - filename = os.path.abspath(filename) - - self.stopProgram() - - self.commands = [ ('run', filename) ] - waiting_for_loader.append(self) - spawn.spawn( pyth_exe, load_py ) - - def connect(self, client, addr): - # Called by loader_connect() above. It is remotely possible that - # we get connected to two loaders if the user is running the - # program repeatedly in a short span of time. In this case, we - # simply return None, refusing to connect and letting the redundant - # loader die. - if self.client: return None - - self.client = client - client.set_close_hook( self.connect_lost ) - - title = self.editwin.short_title() - if title: - self.output.set_title(title + " Output") - else: - self.output.set_title("Output") - self.output.write('\n',"stderr") - self.output.scroll_clear() - - return self - - def connect_lost(self): - # Called by the client's close hook when the loader closes its - # socket. - - # We print a disconnect message only if the output window is already - # open. - if self.output.owin and self.output.owin.text: - self.output.owin.interrupt() - self.output.write("\nProgram disconnected.\n","stderr") - - for t in self.temp: - try: - os.remove(t) - except: - pass - self.temp = [] - self.client = None - - def get_command(self): - # Called by Remote to find out what it should be executing. - # Later this will be used to implement debugging, interactivity, etc. - if self.commands: - return self.commands.pop(0) - return ('finish',) - - def program_exception(self, type, value, tb, first, last): - if type == SystemExit: return 0 - - for i in range(len(tb)): - filename, lineno, name, line = tb[i] - if filename in self.temp: - filename = 'Untitled' - tb[i] = filename, lineno, name, line - - list = traceback.format_list(tb[first:last]) - exc = traceback.format_exception_only( type, value ) - - self.write('Traceback (innermost last)\n', 'stderr') - for i in (list+exc): - self.write(i, 'stderr') - - self.commands = [] - return 1 - - def write(self, text, tag): - self.output.write(text,tag) - - def readline(self): - return self.output.readline() - - def stopProgram(self): - if self.client: - self.client.close() - self.client = None - - def getfilename(self): - # Save all files which have been named, because they might be modules - for edit in self.editwin.flist.inversedict.keys(): - if edit.io and edit.io.filename and not edit.get_saved(): - edit.io.save(None) - - # Experimental: execute unnamed buffer - if not self.editwin.io.filename: - filename = os.path.normcase(os.path.abspath(tempfile.mktemp())) - self.temp.append(filename) - if self.editwin.io.writefile(filename): - return filename - - # If the file isn't save, we save it. If it doesn't have a filename, - # the user will be prompted. - if self.editwin.io and not self.editwin.get_saved(): - self.editwin.io.save(None) - - # If the file *still* isn't saved, we give up. - if not self.editwin.get_saved(): - return - - return self.editwin.io.filename diff --git a/Lib/idlelib/FileList.py b/Lib/idlelib/FileList.py deleted file mode 100644 index e01ce3c..0000000 --- a/Lib/idlelib/FileList.py +++ /dev/null @@ -1,146 +0,0 @@ -# changes by dscherer@cmu.edu -# - FileList.open() takes an optional 3rd parameter action, which is -# called instead of creating a new EditorWindow. This enables -# things like 'open in same window'. - -import os -from Tkinter import * -import tkMessageBox - -import WindowList - -#$ event <> -#$ win -#$ unix - -# (This is labeled as 'Exit'in the File menu) -#$ event <> -#$ win -#$ unix - -class FileList: - - from EditorWindow import EditorWindow - EditorWindow.Toplevel = WindowList.ListedToplevel # XXX Patch it! - - def __init__(self, root): - self.root = root - self.dict = {} - self.inversedict = {} - self.vars = {} # For EditorWindow.getrawvar (shared Tcl variables) - - def open(self, filename, action=None): - assert filename - filename = self.canonize(filename) - if os.path.isdir(filename): - tkMessageBox.showerror( - "Is A Directory", - "The path %s is a directory." % `filename`, - master=self.root) - return None - key = os.path.normcase(filename) - if self.dict.has_key(key): - edit = self.dict[key] - edit.wakeup() - return edit - if not os.path.exists(filename): - tkMessageBox.showinfo( - "New File", - "Opening non-existent file %s" % `filename`, - master=self.root) - if action is None: - return self.EditorWindow(self, filename, key) - else: - return action(filename) - - def gotofileline(self, filename, lineno=None): - edit = self.open(filename) - if edit is not None and lineno is not None: - edit.gotoline(lineno) - - def new(self): - return self.EditorWindow(self) - - def new_callback(self, event): - self.new() - return "break" - - def close_all_callback(self, event): - for edit in self.inversedict.keys(): - reply = edit.close() - if reply == "cancel": - break - return "break" - - def close_edit(self, edit): - try: - key = self.inversedict[edit] - except KeyError: - print "Don't know this EditorWindow object. (close)" - return - if key: - del self.dict[key] - del self.inversedict[edit] - if not self.inversedict: - self.root.quit() - - def filename_changed_edit(self, edit): - edit.saved_change_hook() - try: - key = self.inversedict[edit] - except KeyError: - print "Don't know this EditorWindow object. (rename)" - return - filename = edit.io.filename - if not filename: - if key: - del self.dict[key] - self.inversedict[edit] = None - return - filename = self.canonize(filename) - newkey = os.path.normcase(filename) - if newkey == key: - return - if self.dict.has_key(newkey): - conflict = self.dict[newkey] - self.inversedict[conflict] = None - tkMessageBox.showerror( - "Name Conflict", - "You now have multiple edit windows open for %s" % `filename`, - master=self.root) - self.dict[newkey] = edit - self.inversedict[edit] = newkey - if key: - try: - del self.dict[key] - except KeyError: - pass - - def canonize(self, filename): - if not os.path.isabs(filename): - try: - pwd = os.getcwd() - except os.error: - pass - else: - filename = os.path.join(pwd, filename) - return os.path.normpath(filename) - - -def _test(): - from EditorWindow import fixwordbreaks - import sys - root = Tk() - fixwordbreaks(root) - root.withdraw() - flist = FileList(root) - if sys.argv[1:]: - for filename in sys.argv[1:]: - flist.open(filename) - else: - flist.new() - if flist.inversedict: - root.mainloop() - -if __name__ == '__main__': - _test() diff --git a/Lib/idlelib/FormatParagraph.py b/Lib/idlelib/FormatParagraph.py deleted file mode 100644 index 498e2ef..0000000 --- a/Lib/idlelib/FormatParagraph.py +++ /dev/null @@ -1,155 +0,0 @@ -# Extension to format a paragraph - -# Does basic, standard text formatting, and also understands Python -# comment blocks. Thus, for editing Python source code, this -# extension is really only suitable for reformatting these comment -# blocks or triple-quoted strings. - -# Known problems with comment reformatting: -# * If there is a selection marked, and the first line of the -# selection is not complete, the block will probably not be detected -# as comments, and will have the normal "text formatting" rules -# applied. -# * If a comment block has leading whitespace that mixes tabs and -# spaces, they will not be considered part of the same block. -# * Fancy comments, like this bulleted list, arent handled :-) - -import string -import re - -class FormatParagraph: - - menudefs = [ - ('format', [ # /s/edit/format dscherer@cmu.edu - ('Format Paragraph', '<>'), - ]) - ] - - keydefs = { - '<>': [''], - } - - unix_keydefs = { - '<>': [''], - } - - def __init__(self, editwin): - self.editwin = editwin - - def close(self): - self.editwin = None - - def format_paragraph_event(self, event): - text = self.editwin.text - first, last = self.editwin.get_selection_indices() - if first and last: - data = text.get(first, last) - comment_header = '' - else: - first, last, comment_header, data = \ - find_paragraph(text, text.index("insert")) - if comment_header: - # Reformat the comment lines - convert to text sans header. - lines = string.split(data, "\n") - lines = map(lambda st, l=len(comment_header): st[l:], lines) - data = string.join(lines, "\n") - # Reformat to 70 chars or a 20 char width, whichever is greater. - format_width = max(70-len(comment_header), 20) - newdata = reformat_paragraph(data, format_width) - # re-split and re-insert the comment header. - newdata = string.split(newdata, "\n") - # If the block ends in a \n, we dont want the comment - # prefix inserted after it. (Im not sure it makes sense to - # reformat a comment block that isnt made of complete - # lines, but whatever!) Can't think of a clean soltution, - # so we hack away - block_suffix = "" - if not newdata[-1]: - block_suffix = "\n" - newdata = newdata[:-1] - builder = lambda item, prefix=comment_header: prefix+item - newdata = string.join(map(builder, newdata), '\n') + block_suffix - else: - # Just a normal text format - newdata = reformat_paragraph(data) - text.tag_remove("sel", "1.0", "end") - if newdata != data: - text.mark_set("insert", first) - text.undo_block_start() - text.delete(first, last) - text.insert(first, newdata) - text.undo_block_stop() - else: - text.mark_set("insert", last) - text.see("insert") - -def find_paragraph(text, mark): - lineno, col = map(int, string.split(mark, ".")) - line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno) - while text.compare("%d.0" % lineno, "<", "end") and is_all_white(line): - lineno = lineno + 1 - line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno) - first_lineno = lineno - comment_header = get_comment_header(line) - comment_header_len = len(comment_header) - while get_comment_header(line)==comment_header and \ - not is_all_white(line[comment_header_len:]): - lineno = lineno + 1 - line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno) - last = "%d.0" % lineno - # Search back to beginning of paragraph - lineno = first_lineno - 1 - line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno) - while lineno > 0 and \ - get_comment_header(line)==comment_header and \ - not is_all_white(line[comment_header_len:]): - lineno = lineno - 1 - line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno) - first = "%d.0" % (lineno+1) - return first, last, comment_header, text.get(first, last) - -def reformat_paragraph(data, limit=70): - lines = string.split(data, "\n") - i = 0 - n = len(lines) - while i < n and is_all_white(lines[i]): - i = i+1 - if i >= n: - return data - indent1 = get_indent(lines[i]) - if i+1 < n and not is_all_white(lines[i+1]): - indent2 = get_indent(lines[i+1]) - else: - indent2 = indent1 - new = lines[:i] - partial = indent1 - while i < n and not is_all_white(lines[i]): - # XXX Should take double space after period (etc.) into account - words = re.split("(\s+)", lines[i]) - for j in range(0, len(words), 2): - word = words[j] - if not word: - continue # Can happen when line ends in whitespace - if len(string.expandtabs(partial + word)) > limit and \ - partial != indent1: - new.append(string.rstrip(partial)) - partial = indent2 - partial = partial + word + " " - if j+1 < len(words) and words[j+1] != " ": - partial = partial + " " - i = i+1 - new.append(string.rstrip(partial)) - # XXX Should reformat remaining paragraphs as well - new.extend(lines[i:]) - return string.join(new, "\n") - -def is_all_white(line): - return re.match(r"^\s*$", line) is not None - -def get_indent(line): - return re.match(r"^(\s*)", line).group() - -def get_comment_header(line): - m = re.match(r"^(\s*#*)", line) - if m is None: return "" - return m.group(1) diff --git a/Lib/idlelib/FrameViewer.py b/Lib/idlelib/FrameViewer.py deleted file mode 100644 index 2ce0935..0000000 --- a/Lib/idlelib/FrameViewer.py +++ /dev/null @@ -1,38 +0,0 @@ -from repr import Repr -from Tkinter import * - -class FrameViewer: - - def __init__(self, root, frame): - self.root = root - self.frame = frame - self.top = Toplevel(self.root) - self.repr = Repr() - self.repr.maxstring = 60 - self.load_variables() - - def load_variables(self): - row = 0 - if self.frame.f_locals is not self.frame.f_globals: - l = Label(self.top, text="Local Variables", - borderwidth=2, relief="raised") - l.grid(row=row, column=0, columnspan=2, sticky="ew") - row = self.load_names(self.frame.f_locals, row+1) - l = Label(self.top, text="Global Variables", - borderwidth=2, relief="raised") - l.grid(row=row, column=0, columnspan=2, sticky="ew") - row = self.load_names(self.frame.f_globals, row+1) - - def load_names(self, dict, row): - names = dict.keys() - names.sort() - for name in names: - value = dict[name] - svalue = self.repr.repr(value) - l = Label(self.top, text=name) - l.grid(row=row, column=0, sticky="w") - l = Entry(self.top, width=60, borderwidth=0) - l.insert(0, svalue) - l.grid(row=row, column=1, sticky="w") - row = row+1 - return row diff --git a/Lib/idlelib/GrepDialog.py b/Lib/idlelib/GrepDialog.py deleted file mode 100644 index 61c77c3..0000000 --- a/Lib/idlelib/GrepDialog.py +++ /dev/null @@ -1,135 +0,0 @@ -import string -import os -import re -import fnmatch -import sys -from Tkinter import * -import tkMessageBox -import SearchEngine -from SearchDialogBase import SearchDialogBase - -def grep(text, io=None, flist=None): - root = text._root() - engine = SearchEngine.get(root) - if not hasattr(engine, "_grepdialog"): - engine._grepdialog = GrepDialog(root, engine, flist) - dialog = engine._grepdialog - dialog.open(io) - -class GrepDialog(SearchDialogBase): - - title = "Find in Files Dialog" - icon = "Grep" - needwrapbutton = 0 - - def __init__(self, root, engine, flist): - SearchDialogBase.__init__(self, root, engine) - self.flist = flist - self.globvar = StringVar(root) - self.recvar = BooleanVar(root) - - def open(self, io=None): - SearchDialogBase.open(self, None) - if io: - path = io.filename or "" - else: - path = "" - dir, base = os.path.split(path) - head, tail = os.path.splitext(base) - if not tail: - tail = ".py" - self.globvar.set(os.path.join(dir, "*" + tail)) - - def create_entries(self): - SearchDialogBase.create_entries(self) - self.globent = self.make_entry("In files:", self.globvar) - - def create_other_buttons(self): - f = self.make_frame() - - btn = Checkbutton(f, anchor="w", - variable=self.recvar, - text="Recurse down subdirectories") - btn.pack(side="top", fill="both") - btn.select() - - def create_command_buttons(self): - SearchDialogBase.create_command_buttons(self) - self.make_button("Search Files", self.default_command, 1) - - def default_command(self, event=None): - prog = self.engine.getprog() - if not prog: - return - path = self.globvar.get() - if not path: - self.top.bell() - return - from OutputWindow import OutputWindow - save = sys.stdout - try: - sys.stdout = OutputWindow(self.flist) - self.grep_it(prog, path) - finally: - sys.stdout = save - - def grep_it(self, prog, path): - dir, base = os.path.split(path) - list = self.findfiles(dir, base, self.recvar.get()) - list.sort() - self.close() - pat = self.engine.getpat() - print "Searching %s in %s ..." % (`pat`, path) - hits = 0 - for fn in list: - try: - f = open(fn) - except IOError, msg: - print msg - continue - lineno = 0 - while 1: - block = f.readlines(100000) - if not block: - break - for line in block: - lineno = lineno + 1 - if line[-1:] == '\n': - line = line[:-1] - if prog.search(line): - sys.stdout.write("%s: %s: %s\n" % (fn, lineno, line)) - hits = hits + 1 - if hits: - if hits == 1: - s = "" - else: - s = "s" - print "Found", hits, "hit%s." % s - print "(Hint: right-click to open locations.)" - else: - print "No hits." - - def findfiles(self, dir, base, rec): - try: - names = os.listdir(dir or os.curdir) - except os.error, msg: - print msg - return [] - list = [] - subdirs = [] - for name in names: - fn = os.path.join(dir, name) - if os.path.isdir(fn): - subdirs.append(fn) - else: - if fnmatch.fnmatch(name, base): - list.append(fn) - if rec: - for subdir in subdirs: - list.extend(self.findfiles(subdir, base, rec)) - return list - - def close(self, event=None): - if self.top: - self.top.grab_release() - self.top.withdraw() diff --git a/Lib/idlelib/INSTALL.txt b/Lib/idlelib/INSTALL.txt deleted file mode 100644 index fcf42e1..0000000 --- a/Lib/idlelib/INSTALL.txt +++ /dev/null @@ -1,58 +0,0 @@ -IDLEfork INSTALL notes -====================== - -The emphasis in IDLEfork is now for the project to be able to be run -directly from the unpacked source directory. This is to enable easy testing -of (and hacking on) IDLEfork, and will also prevent interfering with the -stable Python IDLE set up in any way. - -To install IDLEfork just unpack the archive into its own directory wherever -you like. To run IDLEfork just go to the directory you unpacked IDLEfork -into and then run 'python idle.py' in an xterm under unix/linux, or -'idle.pyw' under windows 98/2000. Remember that IDLEfork 0.8.1 and greater -require python 2.1 or greater. - -See README.txt and NEWS.txt for more details on this version of IDLEfork. - - -INSTALLATION notes from IDLE fork 0.7.1 : -========================================= - -IDLE Fork Installation on Linux: - -Until the tarball is released, you must download a CVS copy. An excellent -place for it is - -/usr/local/src/PythonX.X/Tools/idlefork, assuming that's where your Python -source is located. Put the correct version in for X.X . - -# cd /usr/local/src/PythonX.X/Tools - -Now do the CVS login and checkout: - -# cvs -d:pserver:anonymous@cvs.idlefork.sourceforge.net:/cvsroot/idlefork login - -Type an for the password. - -# cvs -z3 -d:pserver:anonymous@cvs.idlefork.sourceforge.net:/cvsroot/idlefork \ - -d idlefork checkout idle - -The -d option to checkout puts the files in an idlefork directory, so you don't -step on "official" idle. - -# cd idlefork -# su to root - -# python setup.py install - -# echo "idle" > /usr/local/lib/pythonX.X/site-packages.pth - -This last is necessary so idle can find itself. I hope we can create/append -this file via setup.py at some point, but it needs to be done manually now, and -it only needs to be done once (unless you totally remove and reinstall python -itself). - -# exit from root - -NOTE that the above procedure will install idlefork IDLE on top of any -"official" IDLE that may be already installed. diff --git a/Lib/idlelib/IOBinding.py b/Lib/idlelib/IOBinding.py deleted file mode 100644 index 4875d11..0000000 --- a/Lib/idlelib/IOBinding.py +++ /dev/null @@ -1,254 +0,0 @@ -# changes by dscherer@cmu.edu -# - IOBinding.open() replaces the current window with the opened file, -# if the current window is both unmodified and unnamed -# - IOBinding.loadfile() interprets Windows, UNIX, and Macintosh -# end-of-line conventions, instead of relying on the standard library, -# which will only understand the local convention. - -import os -import tkFileDialog -import tkMessageBox -import re - -#$ event <> -#$ win -#$ unix - -#$ event <> -#$ win -#$ unix - -#$ event <> -#$ win -#$ unix - -#$ event <> -#$ win -#$ unix - - -class IOBinding: - - def __init__(self, editwin): - self.editwin = editwin - self.text = editwin.text - self.__id_open = self.text.bind("<>", self.open) - self.__id_save = self.text.bind("<>", self.save) - self.__id_saveas = self.text.bind("<>", - self.save_as) - self.__id_savecopy = self.text.bind("<>", - self.save_a_copy) - - def close(self): - # Undo command bindings - self.text.unbind("<>", self.__id_open) - self.text.unbind("<>", self.__id_save) - self.text.unbind("<>",self.__id_saveas) - self.text.unbind("<>", self.__id_savecopy) - # Break cycles - self.editwin = None - self.text = None - self.filename_change_hook = None - - def get_saved(self): - return self.editwin.get_saved() - - def set_saved(self, flag): - self.editwin.set_saved(flag) - - def reset_undo(self): - self.editwin.reset_undo() - - filename_change_hook = None - - def set_filename_change_hook(self, hook): - self.filename_change_hook = hook - - filename = None - - def set_filename(self, filename): - self.filename = filename - self.set_saved(1) - if self.filename_change_hook: - self.filename_change_hook() - - def open(self, event): - if self.editwin.flist: - filename = self.askopenfile() - if filename: - # if the current window has no filename and hasn't been - # modified, we replace it's contents (no loss). Otherwise - # we open a new window. - if not self.filename and self.get_saved(): - self.editwin.flist.open(filename, self.loadfile) - else: - self.editwin.flist.open(filename) - else: - self.text.focus_set() - - return "break" - # Code for use outside IDLE: - if self.get_saved(): - reply = self.maybesave() - if reply == "cancel": - self.text.focus_set() - return "break" - filename = self.askopenfile() - if filename: - self.loadfile(filename) - else: - self.text.focus_set() - return "break" - - def loadfile(self, filename): - try: - # open the file in binary mode so that we can handle - # end-of-line convention ourselves. - f = open(filename,'rb') - chars = f.read() - f.close() - except IOError, msg: - tkMessageBox.showerror("I/O Error", str(msg), master=self.text) - return 0 - - # We now convert all end-of-lines to '\n's - eol = r"(\r\n)|\n|\r" # \r\n (Windows), \n (UNIX), or \r (Mac) - chars = re.compile( eol ).sub( r"\n", chars ) - - self.text.delete("1.0", "end") - self.set_filename(None) - self.text.insert("1.0", chars) - self.reset_undo() - self.set_filename(filename) - self.text.mark_set("insert", "1.0") - self.text.see("insert") - return 1 - - def maybesave(self): - if self.get_saved(): - return "yes" - message = "Do you want to save %s before closing?" % ( - self.filename or "this untitled document") - m = tkMessageBox.Message( - title="Save On Close", - message=message, - icon=tkMessageBox.QUESTION, - type=tkMessageBox.YESNOCANCEL, - master=self.text) - reply = m.show() - if reply == "yes": - self.save(None) - if not self.get_saved(): - reply = "cancel" - self.text.focus_set() - return reply - - def save(self, event): - if not self.filename: - self.save_as(event) - else: - if self.writefile(self.filename): - self.set_saved(1) - self.text.focus_set() - return "break" - - def save_as(self, event): - filename = self.asksavefile() - if filename: - if self.writefile(filename): - self.set_filename(filename) - self.set_saved(1) - self.text.focus_set() - return "break" - - def save_a_copy(self, event): - filename = self.asksavefile() - if filename: - self.writefile(filename) - self.text.focus_set() - return "break" - - def writefile(self, filename): - self.fixlastline() - try: - f = open(filename, "w") - chars = self.text.get("1.0", "end-1c") - f.write(chars) - f.close() - ## print "saved to", `filename` - return 1 - except IOError, msg: - tkMessageBox.showerror("I/O Error", str(msg), - master=self.text) - return 0 - - def fixlastline(self): - c = self.text.get("end-2c") - if c != '\n': - self.text.insert("end-1c", "\n") - - opendialog = None - savedialog = None - - filetypes = [ - ("Python and text files", "*.py *.pyw *.txt", "TEXT"), - ("All text files", "*", "TEXT"), - ("All files", "*"), - ] - - def askopenfile(self): - dir, base = self.defaultfilename("open") - if not self.opendialog: - self.opendialog = tkFileDialog.Open(master=self.text, - filetypes=self.filetypes) - return self.opendialog.show(initialdir=dir, initialfile=base) - - def defaultfilename(self, mode="open"): - if self.filename: - return os.path.split(self.filename) - else: - try: - pwd = os.getcwd() - except os.error: - pwd = "" - return pwd, "" - - def asksavefile(self): - dir, base = self.defaultfilename("save") - if not self.savedialog: - self.savedialog = tkFileDialog.SaveAs(master=self.text, - filetypes=self.filetypes) - return self.savedialog.show(initialdir=dir, initialfile=base) - - -def test(): - root = Tk() - class MyEditWin: - def __init__(self, text): - self.text = text - self.flist = None - self.text.bind("", self.open) - self.text.bind("", self.save) - self.text.bind("", self.save_as) - self.text.bind("", self.save_a_copy) - def get_saved(self): return 0 - def set_saved(self, flag): pass - def reset_undo(self): pass - def open(self, event): - self.text.event_generate("<>") - def save(self, event): - self.text.event_generate("<>") - def save_as(self, event): - self.text.event_generate("<>") - def save_a_copy(self, event): - self.text.event_generate("<>") - text = Text(root) - text.pack() - text.focus_set() - editwin = MyEditWin(text) - io = IOBinding(editwin) - root.mainloop() - -if __name__ == "__main__": - from Tkinter import * - test() diff --git a/Lib/idlelib/Icons/folder.gif b/Lib/idlelib/Icons/folder.gif deleted file mode 100644 index effe8dc..0000000 Binary files a/Lib/idlelib/Icons/folder.gif and /dev/null differ diff --git a/Lib/idlelib/Icons/minusnode.gif b/Lib/idlelib/Icons/minusnode.gif deleted file mode 100644 index c72e46f..0000000 Binary files a/Lib/idlelib/Icons/minusnode.gif and /dev/null differ diff --git a/Lib/idlelib/Icons/openfolder.gif b/Lib/idlelib/Icons/openfolder.gif deleted file mode 100644 index 24aea1b..0000000 Binary files a/Lib/idlelib/Icons/openfolder.gif and /dev/null differ diff --git a/Lib/idlelib/Icons/plusnode.gif b/Lib/idlelib/Icons/plusnode.gif deleted file mode 100644 index 13ace90..0000000 Binary files a/Lib/idlelib/Icons/plusnode.gif and /dev/null differ diff --git a/Lib/idlelib/Icons/python.gif b/Lib/idlelib/Icons/python.gif deleted file mode 100644 index 58271ed..0000000 Binary files a/Lib/idlelib/Icons/python.gif and /dev/null differ diff --git a/Lib/idlelib/Icons/tk.gif b/Lib/idlelib/Icons/tk.gif deleted file mode 100644 index a603f5e..0000000 Binary files a/Lib/idlelib/Icons/tk.gif and /dev/null differ diff --git a/Lib/idlelib/IdleConf.py b/Lib/idlelib/IdleConf.py deleted file mode 100644 index 8eaa8e0..0000000 --- a/Lib/idlelib/IdleConf.py +++ /dev/null @@ -1,113 +0,0 @@ -"""Provides access to configuration information""" - -import os -import sys -from ConfigParser import ConfigParser, NoOptionError, NoSectionError - -class IdleConfParser(ConfigParser): - - # these conf sections do not define extensions! - builtin_sections = {} - for section in ('EditorWindow', 'Colors'): - builtin_sections[section] = section - - def getcolor(self, sec, name): - """Return a dictionary with foreground and background colors - - The return value is appropriate for passing to Tkinter in, e.g., - a tag_config call. - """ - fore = self.getdef(sec, name + "-foreground") - back = self.getdef(sec, name + "-background") - return {"foreground": fore, - "background": back} - - def getdef(self, sec, options, raw=0, vars=None, default=None): - """Get an option value for given section or return default""" - try: - return self.get(sec, options, raw, vars) - except (NoSectionError, NoOptionError): - return default - - def getsection(self, section): - """Return a SectionConfigParser object""" - return SectionConfigParser(section, self) - - def getextensions(self): - exts = [] - for sec in self.sections(): - if self.builtin_sections.has_key(sec): - continue - # enable is a bool, but it may not be defined - if self.getdef(sec, 'enable') != '0': - exts.append(sec) - return exts - - def reload(self): - global idleconf - idleconf = IdleConfParser() - load(_dir) # _dir is a global holding the last directory loaded - -class SectionConfigParser: - """A ConfigParser object specialized for one section - - This class has all the get methods that a regular ConfigParser does, - but without requiring a section argument. - """ - def __init__(self, section, config): - self.section = section - self.config = config - - def options(self): - return self.config.options(self.section) - - def get(self, options, raw=0, vars=None): - return self.config.get(self.section, options, raw, vars) - - def getdef(self, options, raw=0, vars=None, default=None): - return self.config.getdef(self.section, options, raw, vars, default) - - def getint(self, option): - return self.config.getint(self.section, option) - - def getfloat(self, option): - return self.config.getint(self.section, option) - - def getboolean(self, option): - return self.config.getint(self.section, option) - - def getcolor(self, option): - return self.config.getcolor(self.section, option) - -def load(dir): - """Load IDLE configuration files based on IDLE install in dir - - Attempts to load two config files: - dir/config.txt - dir/config-[win/mac/unix].txt - dir/config-%(sys.platform)s.txt - ~/.idle - """ - global _dir - _dir = dir - - if sys.platform[:3] == 'win': - genplatfile = os.path.join(dir, "config-win.txt") - # XXX don't know what the platform string is on a Mac - elif sys.platform[:3] == 'mac': - genplatfile = os.path.join(dir, "config-mac.txt") - else: - genplatfile = os.path.join(dir, "config-unix.txt") - - platfile = os.path.join(dir, "config-%s.txt" % sys.platform) - - try: - homedir = os.environ['HOME'] - except KeyError: - homedir = os.getcwd() - - idleconf.read((os.path.join(dir, "config.txt"), genplatfile, platfile, - os.path.join(homedir, ".idle"))) - -idleconf = IdleConfParser() -load(os.path.dirname(__file__)) diff --git a/Lib/idlelib/IdleHistory.py b/Lib/idlelib/IdleHistory.py deleted file mode 100644 index b882c92..0000000 --- a/Lib/idlelib/IdleHistory.py +++ /dev/null @@ -1,88 +0,0 @@ -import string - -class History: - - def __init__(self, text, output_sep = "\n"): - self.text = text - self.history = [] - self.history_prefix = None - self.history_pointer = None - self.output_sep = output_sep - text.bind("<>", self.history_prev) - text.bind("<>", self.history_next) - - def history_next(self, event): - self.history_do(0) - return "break" - - def history_prev(self, event): - self.history_do(1) - return "break" - - def _get_source(self, start, end): - # Get source code from start index to end index. Lines in the - # text control may be separated by sys.ps2 . - lines = string.split(self.text.get(start, end), self.output_sep) - return string.join(lines, "\n") - - def _put_source(self, where, source): - output = string.join(string.split(source, "\n"), self.output_sep) - self.text.insert(where, output) - - def history_do(self, reverse): - nhist = len(self.history) - pointer = self.history_pointer - prefix = self.history_prefix - if pointer is not None and prefix is not None: - if self.text.compare("insert", "!=", "end-1c") or \ - self._get_source("iomark", "end-1c") != self.history[pointer]: - pointer = prefix = None - if pointer is None or prefix is None: - prefix = self._get_source("iomark", "end-1c") - if reverse: - pointer = nhist - else: - pointer = -1 - nprefix = len(prefix) - while 1: - if reverse: - pointer = pointer - 1 - else: - pointer = pointer + 1 - if pointer < 0 or pointer >= nhist: - self.text.bell() - if self._get_source("iomark", "end-1c") != prefix: - self.text.delete("iomark", "end-1c") - self._put_source("iomark", prefix) - pointer = prefix = None - break - item = self.history[pointer] - if item[:nprefix] == prefix and len(item) > nprefix: - self.text.delete("iomark", "end-1c") - self._put_source("iomark", item) - break - self.text.mark_set("insert", "end-1c") - self.text.see("insert") - self.text.tag_remove("sel", "1.0", "end") - self.history_pointer = pointer - self.history_prefix = prefix - - def history_store(self, source): - source = string.strip(source) - if len(source) > 2: - # avoid duplicates - try: - self.history.remove(source) - except ValueError: - pass - self.history.append(source) - self.history_pointer = None - self.history_prefix = None - - def recall(self, s): - s = string.strip(s) - self.text.tag_remove("sel", "1.0", "end") - self.text.delete("iomark", "end-1c") - self.text.mark_set("insert", "end-1c") - self.text.insert("insert", s) - self.text.see("insert") diff --git a/Lib/idlelib/LICENSE.txt b/Lib/idlelib/LICENSE.txt deleted file mode 100644 index f7a8395..0000000 --- a/Lib/idlelib/LICENSE.txt +++ /dev/null @@ -1,50 +0,0 @@ -To apply this license to IDLE or IDLEfork, read 'IDLE' or 'IDLEfork' -for every occurence of 'Python 2.1.1' in the text below. - -PSF LICENSE AGREEMENT ---------------------- - -1. This LICENSE AGREEMENT is between the Python Software Foundation -("PSF"), and the Individual or Organization ("Licensee") accessing and -otherwise using Python 2.1.1 software in source or binary form and its -associated documentation. - -2. Subject to the terms and conditions of this License Agreement, PSF -hereby grants Licensee a nonexclusive, royalty-free, world-wide -license to reproduce, analyze, test, perform and/or display publicly, -prepare derivative works, distribute, and otherwise use Python 2.1.1 -alone or in any derivative version, provided, however, that PSF's -License Agreement and PSF's notice of copyright, i.e., "Copyright (c) -2001 Python Software Foundation; All Rights Reserved" are retained in -Python 2.1.1 alone or in any derivative version prepared by Licensee. - -3. In the event Licensee prepares a derivative work that is based on -or incorporates Python 2.1.1 or any part thereof, and wants to make -the derivative work available to others as provided herein, then -Licensee hereby agrees to include in any such work a brief summary of -the changes made to Python 2.1.1. - -4. PSF is making Python 2.1.1 available to Licensee on an "AS IS" -basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 2.1.1 WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON -2.1.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS -A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.1.1, -OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -6. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -7. Nothing in this License Agreement shall be deemed to create any -relationship of agency, partnership, or joint venture between PSF and -Licensee. This License Agreement does not grant permission to use PSF -trademarks or trade name in a trademark sense to endorse or promote -products or services of Licensee, or any third party. - -8. By copying, installing or otherwise using Python 2.1.1, Licensee -agrees to be bound by the terms and conditions of this License -Agreement. diff --git a/Lib/idlelib/MultiScrolledLists.py b/Lib/idlelib/MultiScrolledLists.py deleted file mode 100644 index 6c140df..0000000 --- a/Lib/idlelib/MultiScrolledLists.py +++ /dev/null @@ -1,138 +0,0 @@ -# One or more ScrolledLists with HSeparators between them. -# There is a hierarchical relationship between them: -# the right list displays the substructure of the selected item -# in the left list. - -import string -from Tkinter import * -from WindowList import ListedToplevel -from Separator import HSeparator -from ScrolledList import ScrolledList - -class MultiScrolledLists: - - def __init__(self, root, nlists=2): - assert nlists >= 1 - self.root = root - self.nlists = nlists - self.path = [] - # create top - self.top = top = ListedToplevel(root) - top.protocol("WM_DELETE_WINDOW", self.close) - top.bind("", self.close) - self.settitle() - # create frames and separators in between - self.frames = [] - self.separators = [] - last = top - for i in range(nlists-1): - sepa = HSeparator(last) - self.separators.append(sepa) - frame, last = sepa.parts() - self.frames.append(frame) - self.frames.append(last) - # create labels and lists - self.labels = [] - self.lists = [] - for i in range(nlists): - frame = self.frames[i] - label = Label(frame, text=self.subtitle(i), - relief="groove", borderwidth=2) - label.pack(fill="x") - self.labels.append(label) - list = ScrolledList(frame, width=self.width(i), - height=self.height(i)) - self.lists.append(list) - list.on_select = \ - lambda index, i=i, self=self: self.on_select(index, i) - list.on_double = \ - lambda index, i=i, self=self: self.on_double(index, i) - # fill leftmost list (rest get filled on demand) - self.fill(0) - # XXX one after_idle isn't enough; two are... - top.after_idle(self.call_pack_propagate_1) - - def call_pack_propagate_1(self): - self.top.after_idle(self.call_pack_propagate) - - def call_pack_propagate(self): - for frame in self.frames: - frame.pack_propagate(0) - - def close(self, event=None): - self.top.destroy() - - def settitle(self): - short = self.shorttitle() - long = self.longtitle() - if short and long: - title = short + " - " + long - elif short: - title = short - elif long: - title = long - else: - title = "Untitled" - icon = short or long or title - self.top.wm_title(title) - self.top.wm_iconname(icon) - - def longtitle(self): - # override this - return "Multi Scrolled Lists" - - def shorttitle(self): - # override this - return None - - def width(self, i): - # override this - return 20 - - def height(self, i): - # override this - return 10 - - def subtitle(self, i): - # override this - return "Column %d" % i - - def fill(self, i): - for k in range(i, self.nlists): - self.lists[k].clear() - self.labels[k].configure(text=self.subtitle(k)) - list = self.lists[i] - l = self.items(i) - for s in l: - list.append(s) - - def on_select(self, index, i): - item = self.lists[i].get(index) - del self.path[i:] - self.path.append(item) - if i+1 < self.nlists: - self.fill(i+1) - - def items(self, i): - # override this - l = [] - for k in range(10): - s = str(k) - if i > 0: - s = self.path[i-1] + "." + s - l.append(s) - return l - - def on_double(self, index, i): - pass - - -def main(): - root = Tk() - quit = Button(root, text="Exit", command=root.destroy) - quit.pack() - MultiScrolledLists(root, 4) - root.mainloop() - -if __name__ == "__main__": - main() diff --git a/Lib/idlelib/MultiStatusBar.py b/Lib/idlelib/MultiStatusBar.py deleted file mode 100644 index dd6d041..0000000 --- a/Lib/idlelib/MultiStatusBar.py +++ /dev/null @@ -1,32 +0,0 @@ -from Tkinter import * - -class MultiStatusBar(Frame): - - def __init__(self, master=None, **kw): - if master is None: - master = Tk() - apply(Frame.__init__, (self, master), kw) - self.labels = {} - - def set_label(self, name, text='', side=LEFT): - if not self.labels.has_key(name): - label = Label(self, bd=1, relief=SUNKEN, anchor=W) - label.pack(side=side) - self.labels[name] = label - else: - label = self.labels[name] - label.config(text=text) - -def _test(): - b = Frame() - c = Text(b) - c.pack(side=TOP) - a = MultiStatusBar(b) - a.set_label("one", "hello") - a.set_label("two", "world") - a.pack(side=BOTTOM, fill=X) - b.pack() - b.mainloop() - -if __name__ == '__main__': - _test() diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt deleted file mode 100644 index 3cff047..0000000 --- a/Lib/idlelib/NEWS.txt +++ /dev/null @@ -1,173 +0,0 @@ -IDLEfork NEWS -============= -(For a more detailed change log, see the file ChangeLog.) ---------------------------------------------------------- - - -IDLEfork 0.8.1 (22 JUL 2001) ----------------------------- -New tarball released as a result of the 'revitalisation' of the IDLEfork -project. - -This release requires python 2.1 or better. Compatability with earlier -versions of python (especially ancient ones like 1.5x) is no longer -a priority in IDLEfork development. - -This release is based on a merging of the earlier IDLE fork work with -current cvs IDLE (post IDLE version 0.8), with some minor additional -coding by Kurt B. Kaiser and Stephen M. Gava. - -This release is basically functional but also contains some known -breakages, particularly with running things from the shell window. Also -the debugger is not working, but I believe this was the case with the -previous IDLE fork release (0.7.1) as well. - -This release is being made now to mark the point at which IDLEfork is -launching into a new stage of development. - -IDLEfork CVS will now be branched to enable further development and -exploration of the two "execution in a remote process" patches submitted -by David Scherer (David's is currently in IDLEfork) and GvR, while -stabilisation and development of less heavyweight improvements (like -user customisation) can continue on the trunk. - - -IDLE fork 0.7.1 (15 AUG 2000) ------------------------------ -First project tarball released. - -This was the first release of IDLE fork, which at this stage was a -combination of IDLE 0.5 and the VPython idle fork, with additional -changes coded by David Scherer, Peter Schneider-Kamp and -Nicholas Riley. - - -original IDLE NEWS.txt : -======================== - -New in IDLE 0.5 (2/15/2000) -------------------------- - -Tons of stuff, much of it contributed by Tim Peters and Mark Hammond: - -- Status bar, displaying current line/column (Moshe Zadka). - -- Better stack viewer, using tree widget. (XXX Only used by Stack -Viewer menu, not by the debugger.) - -- Format paragraph now recognizes Python block comments and reformats -them correctly (MH) - -- New version of pyclbr.py parses top-level functions and understands -much more of Python's syntax; this is reflected in the class and path -browsers (TP) - -- Much better auto-indent; knows how to indent the insides of -multi-line statements (TP) - -- Call tip window pops up when you type the name of a known function -followed by an open parenthesis. Hit ESC or click elsewhere in the -window to close the tip window (MH) - -- Comment out region now inserts ## to make it stand out more (TP) - -- New path and class browsers based on a tree widget that looks -familiar to Windows users - -- Reworked script running commands to be more intuitive: I/O now -always goes to the *Python Shell* window, and raw_input() works -correctly. You use F5 to import/reload a module: this adds the module -name to the __main__ namespace. You use Control-F5 to run a script: -this runs the script *in* the __main__ namespace. The latter also -sets sys.argv[] to the script name - -New in IDLE 0.4 (4/7/99) ------------------------- - -Most important change: a new menu entry "File -> Path browser", shows -a 4-column hierarchical browser which lets you browse sys.path, -directories, modules, and classes. Yes, it's a superset of the Class -browser menu entry. There's also a new internal module, -MultiScrolledLists.py, which provides the framework for this dialog. - -New in IDLE 0.3 (2/17/99) -------------------------- - -Most important changes: - -- Enabled support for running a module, with or without the debugger. -Output goes to a new window. Pressing F5 in a module is effectively a -reload of that module; Control-F5 loads it under the debugger. - -- Re-enable tearing off the Windows menu, and make a torn-off Windows -menu update itself whenever a window is opened or closed. - -- Menu items can now be have a checkbox (when the menu label starts -with "!"); use this for the Debugger and "Auto-open stack viewer" -(was: JIT stack viewer) menu items. - -- Added a Quit button to the Debugger API. - -- The current directory is explicitly inserted into sys.path. - -- Fix the debugger (when using Python 1.5.2b2) to use canonical -filenames for breakpoints, so these actually work. (There's still a -lot of work to be done to the management of breakpoints in the -debugger though.) - -- Closing a window that is still colorizing now actually works. - -- Allow dragging of the separator between the two list boxes in the -class browser. - -- Bind ESC to "close window" of the debugger, stack viewer and class -browser. It removes the selection highlighting in regular text -windows. (These are standard Windows conventions.) - ----------------------------------------------------------------------- - -New in IDLE 0.2 (1/8/99) ------------------------- - -Lots of changes; here are the highlights: - -General: - -- You can now write and configure your own IDLE extension modules; see -extend.txt. - - -File menu: - -The command to open the Python shell window is now in the File menu. - - -Edit menu: - -New Find dialog with more options; replace dialog; find in files dialog. - -Commands to tabify or untabify a region. - -Command to format a paragraph. - - -Debug menu: - -JIT (Just-In-Time) stack viewer toggle -- if set, the stack viewer -automaticall pops up when you get a traceback. - -Windows menu: - -Zoom height -- make the window full height. - - -Help menu: - -The help text now show up in a regular window so you can search and -even edit it if you like. - ----------------------------------------------------------------------- - -IDLE 0.1 was distributed with the Python 1.5.2b1 release on 12/22/98. - -====================================================================== diff --git a/Lib/idlelib/ObjectBrowser.py b/Lib/idlelib/ObjectBrowser.py deleted file mode 100644 index c235a75..0000000 --- a/Lib/idlelib/ObjectBrowser.py +++ /dev/null @@ -1,151 +0,0 @@ -# XXX TO DO: -# - popup menu -# - support partial or total redisplay -# - more doc strings -# - tooltips - -# object browser - -# XXX TO DO: -# - for classes/modules, add "open source" to object browser - -from TreeWidget import TreeItem, TreeNode, ScrolledCanvas - -from repr import Repr - -myrepr = Repr() -myrepr.maxstring = 100 -myrepr.maxother = 100 - -class ObjectTreeItem(TreeItem): - def __init__(self, labeltext, object, setfunction=None): - self.labeltext = labeltext - self.object = object - self.setfunction = setfunction - def GetLabelText(self): - return self.labeltext - def GetText(self): - return myrepr.repr(self.object) - def GetIconName(self): - if not self.IsExpandable(): - return "python" - def IsEditable(self): - return self.setfunction is not None - def SetText(self, text): - try: - value = eval(text) - self.setfunction(value) - except: - pass - else: - self.object = value - def IsExpandable(self): - return not not dir(self.object) - def GetSubList(self): - keys = dir(self.object) - sublist = [] - for key in keys: - try: - value = getattr(self.object, key) - except AttributeError: - continue - item = make_objecttreeitem( - str(key) + " =", - value, - lambda value, key=key, object=self.object: - setattr(object, key, value)) - sublist.append(item) - return sublist - -class InstanceTreeItem(ObjectTreeItem): - def IsExpandable(self): - return 1 - def GetSubList(self): - sublist = ObjectTreeItem.GetSubList(self) - sublist.insert(0, - make_objecttreeitem("__class__ =", self.object.__class__)) - return sublist - -class ClassTreeItem(ObjectTreeItem): - def IsExpandable(self): - return 1 - def GetSubList(self): - sublist = ObjectTreeItem.GetSubList(self) - if len(self.object.__bases__) == 1: - item = make_objecttreeitem("__bases__[0] =", - self.object.__bases__[0]) - else: - item = make_objecttreeitem("__bases__ =", self.object.__bases__) - sublist.insert(0, item) - return sublist - -class AtomicObjectTreeItem(ObjectTreeItem): - def IsExpandable(self): - return 0 - -class SequenceTreeItem(ObjectTreeItem): - def IsExpandable(self): - return len(self.object) > 0 - def keys(self): - return range(len(self.object)) - def GetSubList(self): - sublist = [] - for key in self.keys(): - try: - value = self.object[key] - except KeyError: - continue - def setfunction(value, key=key, object=self.object): - object[key] = value - item = make_objecttreeitem(`key` + ":", value, setfunction) - sublist.append(item) - return sublist - -class DictTreeItem(SequenceTreeItem): - def keys(self): - keys = self.object.keys() - try: - keys.sort() - except: - pass - return keys - -from types import * - -dispatch = { - IntType: AtomicObjectTreeItem, - LongType: AtomicObjectTreeItem, - FloatType: AtomicObjectTreeItem, - StringType: AtomicObjectTreeItem, - TupleType: SequenceTreeItem, - ListType: SequenceTreeItem, - DictType: DictTreeItem, - InstanceType: InstanceTreeItem, - ClassType: ClassTreeItem, -} - -def make_objecttreeitem(labeltext, object, setfunction=None): - t = type(object) - if dispatch.has_key(t): - c = dispatch[t] - else: - c = ObjectTreeItem - return c(labeltext, object, setfunction) - -# Test script - -def _test(): - import sys - from Tkinter import Tk - root = Tk() - root.configure(bd=0, bg="yellow") - root.focus_set() - sc = ScrolledCanvas(root, bg="white", highlightthickness=0, takefocus=1) - sc.frame.pack(expand=1, fill="both") - item = make_objecttreeitem("sys", sys) - node = TreeNode(sc.canvas, None, item) - node.update() - root.mainloop() - -if __name__ == '__main__': - _test() diff --git a/Lib/idlelib/OldStackViewer.py b/Lib/idlelib/OldStackViewer.py deleted file mode 100644 index 2fa4127..0000000 --- a/Lib/idlelib/OldStackViewer.py +++ /dev/null @@ -1,276 +0,0 @@ -import string -import sys -import os -from Tkinter import * -import linecache -from repr import Repr -from WindowList import ListedToplevel - -from ScrolledList import ScrolledList - - -class StackBrowser: - - def __init__(self, root, flist, stack=None): - self.top = top = ListedToplevel(root) - top.protocol("WM_DELETE_WINDOW", self.close) - top.bind("", self.close) - top.wm_title("Stack viewer") - top.wm_iconname("Stack") - # Create help label - self.helplabel = Label(top, - text="Click once to view variables; twice for source", - borderwidth=2, relief="groove") - self.helplabel.pack(fill="x") - # - self.sv = StackViewer(top, flist, self) - if stack is None: - stack = get_stack() - self.sv.load_stack(stack) - - def close(self, event=None): - self.top.destroy() - - localsframe = None - localsviewer = None - localsdict = None - globalsframe = None - globalsviewer = None - globalsdict = None - curframe = None - - def show_frame(self, (frame, lineno)): - if frame is self.curframe: - return - self.curframe = None - if frame.f_globals is not self.globalsdict: - self.show_globals(frame) - self.show_locals(frame) - self.curframe = frame - - def show_globals(self, frame): - title = "Global Variables" - if frame.f_globals.has_key("__name__"): - try: - name = str(frame.f_globals["__name__"]) + "" - except: - name = "" - if name: - title = title + " in module " + name - self.globalsdict = None - if self.globalsviewer: - self.globalsviewer.close() - self.globalsviewer = None - if not self.globalsframe: - self.globalsframe = Frame(self.top) - self.globalsdict = frame.f_globals - self.globalsviewer = NamespaceViewer( - self.globalsframe, - title, - self.globalsdict) - self.globalsframe.pack(fill="both", side="bottom") - - def show_locals(self, frame): - self.localsdict = None - if self.localsviewer: - self.localsviewer.close() - self.localsviewer = None - if frame.f_locals is not frame.f_globals: - title = "Local Variables" - code = frame.f_code - funcname = code.co_name - if funcname not in ("?", "", None): - title = title + " in " + funcname - if not self.localsframe: - self.localsframe = Frame(self.top) - self.localsdict = frame.f_locals - self.localsviewer = NamespaceViewer( - self.localsframe, - title, - self.localsdict) - self.localsframe.pack(fill="both", side="top") - else: - if self.localsframe: - self.localsframe.forget() - - -class StackViewer(ScrolledList): - - def __init__(self, master, flist, browser): - ScrolledList.__init__(self, master, width=80) - self.flist = flist - self.browser = browser - self.stack = [] - - def load_stack(self, stack, index=None): - self.stack = stack - self.clear() -## if len(stack) > 10: -## l["height"] = 10 -## self.topframe.pack(expand=1) -## else: -## l["height"] = len(stack) -## self.topframe.pack(expand=0) - for i in range(len(stack)): - frame, lineno = stack[i] - try: - modname = frame.f_globals["__name__"] - except: - modname = "?" - code = frame.f_code - filename = code.co_filename - funcname = code.co_name - sourceline = linecache.getline(filename, lineno) - sourceline = string.strip(sourceline) - if funcname in ("?", "", None): - item = "%s, line %d: %s" % (modname, lineno, sourceline) - else: - item = "%s.%s(), line %d: %s" % (modname, funcname, - lineno, sourceline) - if i == index: - item = "> " + item - self.append(item) - if index is not None: - self.select(index) - - def popup_event(self, event): - if self.stack: - return ScrolledList.popup_event(self, event) - - def fill_menu(self): - menu = self.menu - menu.add_command(label="Go to source line", - command=self.goto_source_line) - menu.add_command(label="Show stack frame", - command=self.show_stack_frame) - - def on_select(self, index): - if 0 <= index < len(self.stack): - self.browser.show_frame(self.stack[index]) - - def on_double(self, index): - self.show_source(index) - - def goto_source_line(self): - index = self.listbox.index("active") - self.show_source(index) - - def show_stack_frame(self): - index = self.listbox.index("active") - if 0 <= index < len(self.stack): - self.browser.show_frame(self.stack[index]) - - def show_source(self, index): - if not (0 <= index < len(self.stack)): - return - frame, lineno = self.stack[index] - code = frame.f_code - filename = code.co_filename - if os.path.isfile(filename): - edit = self.flist.open(filename) - if edit: - edit.gotoline(lineno) - - -def get_stack(t=None, f=None): - if t is None: - t = sys.last_traceback - stack = [] - if t and t.tb_frame is f: - t = t.tb_next - while f is not None: - stack.append((f, f.f_lineno)) - if f is self.botframe: - break - f = f.f_back - stack.reverse() - while t is not None: - stack.append((t.tb_frame, t.tb_lineno)) - t = t.tb_next - return stack - - -def getexception(type=None, value=None): - if type is None: - type = sys.last_type - value = sys.last_value - if hasattr(type, "__name__"): - type = type.__name__ - s = str(type) - if value is not None: - s = s + ": " + str(value) - return s - - -class NamespaceViewer: - - def __init__(self, master, title, dict=None): - width = 0 - height = 40 - if dict: - height = 20*len(dict) # XXX 20 == observed height of Entry widget - self.master = master - self.title = title - self.repr = Repr() - self.repr.maxstring = 60 - self.repr.maxother = 60 - self.frame = frame = Frame(master) - self.frame.pack(expand=1, fill="both") - self.label = Label(frame, text=title, borderwidth=2, relief="groove") - self.label.pack(fill="x") - self.vbar = vbar = Scrollbar(frame, name="vbar") - vbar.pack(side="right", fill="y") - self.canvas = canvas = Canvas(frame, - height=min(300, max(40, height)), - scrollregion=(0, 0, width, height)) - canvas.pack(side="left", fill="both", expand=1) - vbar["command"] = canvas.yview - canvas["yscrollcommand"] = vbar.set - self.subframe = subframe = Frame(canvas) - self.sfid = canvas.create_window(0, 0, window=subframe, anchor="nw") - self.load_dict(dict) - - dict = -1 - - def load_dict(self, dict, force=0): - if dict is self.dict and not force: - return - subframe = self.subframe - frame = self.frame - for c in subframe.children.values(): - c.destroy() - self.dict = None - if not dict: - l = Label(subframe, text="None") - l.grid(row=0, column=0) - else: - names = dict.keys() - names.sort() - row = 0 - for name in names: - value = dict[name] - svalue = self.repr.repr(value) # repr(value) - l = Label(subframe, text=name) - l.grid(row=row, column=0, sticky="nw") - ## l = Label(subframe, text=svalue, justify="l", wraplength=300) - l = Entry(subframe, width=0, borderwidth=0) - l.insert(0, svalue) - ## l["state"] = "disabled" - l.grid(row=row, column=1, sticky="nw") - row = row+1 - self.dict = dict - # XXX Could we use a callback for the following? - subframe.update_idletasks() # Alas! - width = subframe.winfo_reqwidth() - height = subframe.winfo_reqheight() - canvas = self.canvas - self.canvas["scrollregion"] = (0, 0, width, height) - if height > 300: - canvas["height"] = 300 - frame.pack(expand=1) - else: - canvas["height"] = height - frame.pack(expand=0) - - def close(self): - self.frame.destroy() diff --git a/Lib/idlelib/OutputWindow.py b/Lib/idlelib/OutputWindow.py deleted file mode 100644 index 12280ad..0000000 --- a/Lib/idlelib/OutputWindow.py +++ /dev/null @@ -1,279 +0,0 @@ -# changes by dscherer@cmu.edu -# - OutputWindow and OnDemandOutputWindow have been hastily -# extended to provide readline() support, an "iomark" separate -# from the "insert" cursor, and scrolling to clear the window. -# These changes are used by the ExecBinding module to provide -# standard input and output for user programs. Many of the new -# features are very similar to features of PyShell, which is a -# subclass of OutputWindow. Someone should make some sense of -# this. - -from Tkinter import * -from EditorWindow import EditorWindow -import re -import tkMessageBox - -from UndoDelegator import UndoDelegator - -class OutputUndoDelegator(UndoDelegator): - reading = 0 - # Forbid insert/delete before the I/O mark, in the blank lines after - # the output, or *anywhere* if we are not presently doing user input - def insert(self, index, chars, tags=None): - try: - if (self.delegate.compare(index, "<", "iomark") or - self.delegate.compare(index, ">", "endmark") or - (index!="iomark" and not self.reading)): - self.delegate.bell() - return - except TclError: - pass - UndoDelegator.insert(self, index, chars, tags) - def delete(self, index1, index2=None): - try: - if (self.delegate.compare(index1, "<", "iomark") or - self.delegate.compare(index1, ">", "endmark") or - (index2 and self.delegate.compare(index2, ">=", "endmark")) or - not self.reading): - self.delegate.bell() - return - except TclError: - pass - UndoDelegator.delete(self, index1, index2) - -class OutputWindow(EditorWindow): - """An editor window that can serve as an input and output file. - The input support has been rather hastily hacked in, and should - not be trusted. - """ - - UndoDelegator = OutputUndoDelegator - source_window = None - - def __init__(self, *args, **keywords): - if keywords.has_key('source_window'): - self.source_window = keywords['source_window'] - apply(EditorWindow.__init__, (self,) + args) - self.text.bind("<>", self.goto_file_line) - self.text.bind("<>", self.enter_callback) - self.text.mark_set("iomark","1.0") - self.text.mark_gravity("iomark", LEFT) - self.text.mark_set("endmark","1.0") - - # Customize EditorWindow - - def ispythonsource(self, filename): - # No colorization needed - return 0 - - def short_title(self): - return "Output" - - def long_title(self): - return "" - - def maybesave(self): - # Override base class method -- don't ask any questions - if self.get_saved(): - return "yes" - else: - return "no" - - # Act as input file - incomplete - - def set_line_and_column(self, event=None): - index = self.text.index(INSERT) - if (self.text.compare(index, ">", "endmark")): - self.text.mark_set("insert", "endmark") - self.text.see("insert") - EditorWindow.set_line_and_column(self) - - reading = 0 - canceled = 0 - endoffile = 0 - - def readline(self): - save = self.reading - try: - self.reading = self.undo.reading = 1 - self.text.mark_set("insert", "iomark") - self.text.see("insert") - self.top.mainloop() - finally: - self.reading = self.undo.reading = save - line = self.text.get("input", "iomark") - if self.canceled: - self.canceled = 0 - raise KeyboardInterrupt - if self.endoffile: - self.endoffile = 0 - return "" - return line or '\n' - - def close(self): - self.interrupt() - return EditorWindow.close(self) - - def interrupt(self): - if self.reading: - self.endoffile = 1 - self.top.quit() - - def enter_callback(self, event): - if self.reading and self.text.compare("insert", ">=", "iomark"): - self.text.mark_set("input", "iomark") - self.text.mark_set("iomark", "insert") - self.write('\n',"iomark") - self.text.tag_add("stdin", "input", "iomark") - self.text.update_idletasks() - self.top.quit() # Break out of recursive mainloop() in raw_input() - - return "break" - - # Act as output file - - def write(self, s, tags=(), mark="iomark"): - self.text.mark_gravity(mark, RIGHT) - self.text.insert(mark, str(s), tags) - self.text.mark_gravity(mark, LEFT) - self.text.see(mark) - self.text.update() - - def writelines(self, l): - map(self.write, l) - - def flush(self): - pass - - # Our own right-button menu - - rmenu_specs = [ - ("Go to file/line", "<>"), - ] - - file_line_pats = [ - r'file "([^"]*)", line (\d+)', - r'([^\s]+)\((\d+)\)', - r'([^\s]+):\s*(\d+):', - ] - - file_line_progs = None - - def goto_file_line(self, event=None): - if self.file_line_progs is None: - l = [] - for pat in self.file_line_pats: - l.append(re.compile(pat, re.IGNORECASE)) - self.file_line_progs = l - # x, y = self.event.x, self.event.y - # self.text.mark_set("insert", "@%d,%d" % (x, y)) - line = self.text.get("insert linestart", "insert lineend") - result = self._file_line_helper(line) - if not result: - # Try the previous line. This is handy e.g. in tracebacks, - # where you tend to right-click on the displayed source line - line = self.text.get("insert -1line linestart", - "insert -1line lineend") - result = self._file_line_helper(line) - if not result: - tkMessageBox.showerror( - "No special line", - "The line you point at doesn't look like " - "a valid file name followed by a line number.", - master=self.text) - return - filename, lineno = result - edit = self.untitled(filename) or self.flist.open(filename) - edit.gotoline(lineno) - edit.wakeup() - - def untitled(self, filename): - if filename!='Untitled' or not self.source_window or self.source_window.io.filename: - return None - return self.source_window - - def _file_line_helper(self, line): - for prog in self.file_line_progs: - m = prog.search(line) - if m: - break - else: - return None - filename, lineno = m.group(1, 2) - if not self.untitled(filename): - try: - f = open(filename, "r") - f.close() - except IOError: - return None - try: - return filename, int(lineno) - except TypeError: - return None - -# This classes now used by ExecBinding.py: - -class OnDemandOutputWindow: - source_window = None - - tagdefs = { - # XXX Should use IdlePrefs.ColorPrefs - "stdin": {"foreground": "black"}, - "stdout": {"foreground": "blue"}, - "stderr": {"foreground": "red"}, - } - - def __init__(self, flist): - self.flist = flist - self.owin = None - self.title = "Output" - self.close_hook = None - self.old_close = None - - def owclose(self): - if self.close_hook: - self.close_hook() - if self.old_close: - self.old_close() - - def set_title(self, title): - self.title = title - if self.owin and self.owin.text: - self.owin.saved_change_hook() - - def write(self, s, tags=(), mark="iomark"): - if not self.owin or not self.owin.text: - self.setup() - self.owin.write(s, tags, mark) - - def readline(self): - if not self.owin or not self.owin.text: - self.setup() - return self.owin.readline() - - def scroll_clear(self): - if self.owin and self.owin.text: - lineno = self.owin.getlineno("endmark") - self.owin.text.mark_set("insert","endmark") - self.owin.text.yview(float(lineno)) - self.owin.wakeup() - - def setup(self): - self.owin = owin = OutputWindow(self.flist, source_window = self.source_window) - owin.short_title = lambda self=self: self.title - text = owin.text - - self.old_close = owin.close_hook - owin.close_hook = self.owclose - - # xxx Bad hack: 50 blank lines at the bottom so that - # we can scroll the top of the window to the output - # cursor in scroll_clear(). There must be a better way... - owin.text.mark_gravity('endmark', LEFT) - owin.text.insert('iomark', '\n'*50) - owin.text.mark_gravity('endmark', RIGHT) - - for tag, cnf in self.tagdefs.items(): - if cnf: - apply(text.tag_configure, (tag,), cnf) - text.tag_raise('sel') diff --git a/Lib/idlelib/ParenMatch.py b/Lib/idlelib/ParenMatch.py deleted file mode 100644 index 17d76c2..0000000 --- a/Lib/idlelib/ParenMatch.py +++ /dev/null @@ -1,191 +0,0 @@ -"""ParenMatch -- An IDLE extension for parenthesis matching. - -When you hit a right paren, the cursor should move briefly to the left -paren. Paren here is used generically; the matching applies to -parentheses, square brackets, and curly braces. - -WARNING: This extension will fight with the CallTips extension, -because they both are interested in the KeyRelease-parenright event. -We'll have to fix IDLE to do something reasonable when two or more -extensions what to capture the same event. -""" - -import string - -import PyParse -from AutoIndent import AutoIndent, index2line -from IdleConf import idleconf - -class ParenMatch: - """Highlight matching parentheses - - There are three supported style of paren matching, based loosely - on the Emacs options. The style is select based on the - HILITE_STYLE attribute; it can be changed used the set_style - method. - - The supported styles are: - - default -- When a right paren is typed, highlight the matching - left paren for 1/2 sec. - - expression -- When a right paren is typed, highlight the entire - expression from the left paren to the right paren. - - TODO: - - fix interaction with CallTips - - extend IDLE with configuration dialog to change options - - implement rest of Emacs highlight styles (see below) - - print mismatch warning in IDLE status window - - Note: In Emacs, there are several styles of highlight where the - matching paren is highlighted whenever the cursor is immediately - to the right of a right paren. I don't know how to do that in Tk, - so I haven't bothered. - """ - - menudefs = [] - - keydefs = { - '<>' : ('', - '', - ''), - '<>' : ('',), - } - - windows_keydefs = {} - unix_keydefs = {} - - iconf = idleconf.getsection('ParenMatch') - STYLE = iconf.getdef('style', 'default') - FLASH_DELAY = iconf.getint('flash-delay') - HILITE_CONFIG = iconf.getcolor('hilite') - BELL = iconf.getboolean('bell') - del iconf - - def __init__(self, editwin): - self.editwin = editwin - self.text = editwin.text - self.finder = LastOpenBracketFinder(editwin) - self.counter = 0 - self._restore = None - self.set_style(self.STYLE) - - def set_style(self, style): - self.STYLE = style - if style == "default": - self.create_tag = self.create_tag_default - self.set_timeout = self.set_timeout_last - elif style == "expression": - self.create_tag = self.create_tag_expression - self.set_timeout = self.set_timeout_none - - def flash_open_paren_event(self, event): - index = self.finder.find(keysym_type(event.keysym)) - if index is None: - self.warn_mismatched() - return - self._restore = 1 - self.create_tag(index) - self.set_timeout() - - def check_restore_event(self, event=None): - if self._restore: - self.text.tag_delete("paren") - self._restore = None - - def handle_restore_timer(self, timer_count): - if timer_count + 1 == self.counter: - self.check_restore_event() - - def warn_mismatched(self): - if self.BELL: - self.text.bell() - - # any one of the create_tag_XXX methods can be used depending on - # the style - - def create_tag_default(self, index): - """Highlight the single paren that matches""" - self.text.tag_add("paren", index) - self.text.tag_config("paren", self.HILITE_CONFIG) - - def create_tag_expression(self, index): - """Highlight the entire expression""" - self.text.tag_add("paren", index, "insert") - self.text.tag_config("paren", self.HILITE_CONFIG) - - # any one of the set_timeout_XXX methods can be used depending on - # the style - - def set_timeout_none(self): - """Highlight will remain until user input turns it off""" - pass - - def set_timeout_last(self): - """The last highlight created will be removed after .5 sec""" - # associate a counter with an event; only disable the "paren" - # tag if the event is for the most recent timer. - self.editwin.text_frame.after(self.FLASH_DELAY, - lambda self=self, c=self.counter: \ - self.handle_restore_timer(c)) - self.counter = self.counter + 1 - -def keysym_type(ks): - # Not all possible chars or keysyms are checked because of the - # limited context in which the function is used. - if ks == "parenright" or ks == "(": - return "paren" - if ks == "bracketright" or ks == "[": - return "bracket" - if ks == "braceright" or ks == "{": - return "brace" - -class LastOpenBracketFinder: - num_context_lines = AutoIndent.num_context_lines - indentwidth = AutoIndent.indentwidth - tabwidth = AutoIndent.tabwidth - context_use_ps1 = AutoIndent.context_use_ps1 - - def __init__(self, editwin): - self.editwin = editwin - self.text = editwin.text - - def _find_offset_in_buf(self, lno): - y = PyParse.Parser(self.indentwidth, self.tabwidth) - for context in self.num_context_lines: - startat = max(lno - context, 1) - startatindex = `startat` + ".0" - # rawtext needs to contain everything up to the last - # character, which was the close paren. the parser also - # requires that the last line ends with "\n" - rawtext = self.text.get(startatindex, "insert")[:-1] + "\n" - y.set_str(rawtext) - bod = y.find_good_parse_start( - self.context_use_ps1, - self._build_char_in_string_func(startatindex)) - if bod is not None or startat == 1: - break - y.set_lo(bod or 0) - i = y.get_last_open_bracket_pos() - return i, y.str - - def find(self, right_keysym_type): - """Return the location of the last open paren""" - lno = index2line(self.text.index("insert")) - i, buf = self._find_offset_in_buf(lno) - if i is None \ - or keysym_type(buf[i]) != right_keysym_type: - return None - lines_back = string.count(buf[i:], "\n") - 1 - # subtract one for the "\n" added to please the parser - upto_open = buf[:i] - j = string.rfind(upto_open, "\n") + 1 # offset of column 0 of line - offset = i - j - return "%d.%d" % (lno - lines_back, offset) - - def _build_char_in_string_func(self, startindex): - def inner(offset, startindex=startindex, - icis=self.editwin.is_char_in_string): - return icis(startindex + "%dc" % offset) - return inner diff --git a/Lib/idlelib/PathBrowser.py b/Lib/idlelib/PathBrowser.py deleted file mode 100644 index 86cd270..0000000 --- a/Lib/idlelib/PathBrowser.py +++ /dev/null @@ -1,95 +0,0 @@ -import os -import sys -import imp - -from TreeWidget import TreeItem -from ClassBrowser import ClassBrowser, ModuleBrowserTreeItem - -class PathBrowser(ClassBrowser): - - def __init__(self, flist): - self.init(flist) - - def settitle(self): - self.top.wm_title("Path Browser") - self.top.wm_iconname("Path Browser") - - def rootnode(self): - return PathBrowserTreeItem() - -class PathBrowserTreeItem(TreeItem): - - def GetText(self): - return "sys.path" - - def GetSubList(self): - sublist = [] - for dir in sys.path: - item = DirBrowserTreeItem(dir) - sublist.append(item) - return sublist - -class DirBrowserTreeItem(TreeItem): - - def __init__(self, dir, packages=[]): - self.dir = dir - self.packages = packages - - def GetText(self): - if not self.packages: - return self.dir - else: - return self.packages[-1] + ": package" - - def GetSubList(self): - try: - names = os.listdir(self.dir or os.curdir) - except os.error: - return [] - packages = [] - for name in names: - file = os.path.join(self.dir, name) - if self.ispackagedir(file): - nn = os.path.normcase(name) - packages.append((nn, name, file)) - packages.sort() - sublist = [] - for nn, name, file in packages: - item = DirBrowserTreeItem(file, self.packages + [name]) - sublist.append(item) - for nn, name in self.listmodules(names): - item = ModuleBrowserTreeItem(os.path.join(self.dir, name)) - sublist.append(item) - return sublist - - def ispackagedir(self, file): - if not os.path.isdir(file): - return 0 - init = os.path.join(file, "__init__.py") - return os.path.exists(init) - - def listmodules(self, allnames): - modules = {} - suffixes = imp.get_suffixes() - sorted = [] - for suff, mode, flag in suffixes: - i = -len(suff) - for name in allnames[:]: - normed_name = os.path.normcase(name) - if normed_name[i:] == suff: - mod_name = name[:i] - if not modules.has_key(mod_name): - modules[mod_name] = None - sorted.append((normed_name, name)) - allnames.remove(name) - sorted.sort() - return sorted - -def main(): - import PyShell - PathBrowser(PyShell.flist) - if sys.stdin is sys.__stdin__: - mainloop() - -if __name__ == "__main__": - main() diff --git a/Lib/idlelib/Percolator.py b/Lib/idlelib/Percolator.py deleted file mode 100644 index 5682111..0000000 --- a/Lib/idlelib/Percolator.py +++ /dev/null @@ -1,85 +0,0 @@ -from WidgetRedirector import WidgetRedirector -from Delegator import Delegator - -class Percolator: - - def __init__(self, text): - # XXX would be nice to inherit from Delegator - self.text = text - self.redir = WidgetRedirector(text) - self.top = self.bottom = Delegator(text) - self.bottom.insert = self.redir.register("insert", self.insert) - self.bottom.delete = self.redir.register("delete", self.delete) - self.filters = [] - - def close(self): - while self.top is not self.bottom: - self.removefilter(self.top) - self.top = None - self.bottom.setdelegate(None); self.bottom = None - self.redir.close(); self.redir = None - self.text = None - - def insert(self, index, chars, tags=None): - # Could go away if inheriting from Delegator - self.top.insert(index, chars, tags) - - def delete(self, index1, index2=None): - # Could go away if inheriting from Delegator - self.top.delete(index1, index2) - - def insertfilter(self, filter): - # Perhaps rename to pushfilter()? - assert isinstance(filter, Delegator) - assert filter.delegate is None - filter.setdelegate(self.top) - self.top = filter - - def removefilter(self, filter): - # XXX Perhaps should only support popfilter()? - assert isinstance(filter, Delegator) - assert filter.delegate is not None - f = self.top - if f is filter: - self.top = filter.delegate - filter.setdelegate(None) - else: - while f.delegate is not filter: - assert f is not self.bottom - f.resetcache() - f = f.delegate - f.setdelegate(filter.delegate) - filter.setdelegate(None) - - -def main(): - class Tracer(Delegator): - def __init__(self, name): - self.name = name - Delegator.__init__(self, None) - def insert(self, *args): - print self.name, ": insert", args - apply(self.delegate.insert, args) - def delete(self, *args): - print self.name, ": delete", args - apply(self.delegate.delete, args) - root = Tk() - root.wm_protocol("WM_DELETE_WINDOW", root.quit) - text = Text() - text.pack() - text.focus_set() - p = Percolator(text) - t1 = Tracer("t1") - t2 = Tracer("t2") - p.insertfilter(t1) - p.insertfilter(t2) - root.mainloop() - p.removefilter(t2) - root.mainloop() - p.insertfilter(t2) - p.removefilter(t1) - root.mainloop() - -if __name__ == "__main__": - from Tkinter import * - main() diff --git a/Lib/idlelib/PyParse.py b/Lib/idlelib/PyParse.py deleted file mode 100644 index c8212b2..0000000 --- a/Lib/idlelib/PyParse.py +++ /dev/null @@ -1,589 +0,0 @@ -import string -import re -import sys - -# Reason last stmt is continued (or C_NONE if it's not). -C_NONE, C_BACKSLASH, C_STRING, C_BRACKET = range(4) - -if 0: # for throwaway debugging output - def dump(*stuff): - sys.__stdout__.write(string.join(map(str, stuff), " ") + "\n") - -# Find what looks like the start of a popular stmt. - -_synchre = re.compile(r""" - ^ - [ \t]* - (?: if - | for - | while - | else - | def - | return - | assert - | break - | class - | continue - | elif - | try - | except - | raise - | import - | yield - ) - \b -""", re.VERBOSE | re.MULTILINE).search - -# Match blank line or non-indenting comment line. - -_junkre = re.compile(r""" - [ \t]* - (?: \# \S .* )? - \n -""", re.VERBOSE).match - -# Match any flavor of string; the terminating quote is optional -# so that we're robust in the face of incomplete program text. - -_match_stringre = re.compile(r""" - \""" [^"\\]* (?: - (?: \\. | "(?!"") ) - [^"\\]* - )* - (?: \""" )? - -| " [^"\\\n]* (?: \\. [^"\\\n]* )* "? - -| ''' [^'\\]* (?: - (?: \\. | '(?!'') ) - [^'\\]* - )* - (?: ''' )? - -| ' [^'\\\n]* (?: \\. [^'\\\n]* )* '? -""", re.VERBOSE | re.DOTALL).match - -# Match a line that starts with something interesting; -# used to find the first item of a bracket structure. - -_itemre = re.compile(r""" - [ \t]* - [^\s#\\] # if we match, m.end()-1 is the interesting char -""", re.VERBOSE).match - -# Match start of stmts that should be followed by a dedent. - -_closere = re.compile(r""" - \s* - (?: return - | break - | continue - | raise - | pass - ) - \b -""", re.VERBOSE).match - -# Chew up non-special chars as quickly as possible. If match is -# successful, m.end() less 1 is the index of the last boring char -# matched. If match is unsuccessful, the string starts with an -# interesting char. - -_chew_ordinaryre = re.compile(r""" - [^[\](){}#'"\\]+ -""", re.VERBOSE).match - -# Build translation table to map uninteresting chars to "x", open -# brackets to "(", and close brackets to ")". - -_tran = ['x'] * 256 -for ch in "({[": - _tran[ord(ch)] = '(' -for ch in ")}]": - _tran[ord(ch)] = ')' -for ch in "\"'\\\n#": - _tran[ord(ch)] = ch -_tran = string.join(_tran, '') -del ch - -try: - UnicodeType = type(unicode("")) -except NameError: - UnicodeType = None - -class Parser: - - def __init__(self, indentwidth, tabwidth): - self.indentwidth = indentwidth - self.tabwidth = tabwidth - - def set_str(self, str): - assert len(str) == 0 or str[-1] == '\n' - if type(str) is UnicodeType: - # The parse functions have no idea what to do with Unicode, so - # replace all Unicode characters with "x". This is "safe" - # so long as the only characters germane to parsing the structure - # of Python are 7-bit ASCII. It's *necessary* because Unicode - # strings don't have a .translate() method that supports - # deletechars. - uniphooey = str - str = [] - push = str.append - for raw in map(ord, uniphooey): - push(raw < 127 and chr(raw) or "x") - str = "".join(str) - self.str = str - self.study_level = 0 - - # Return index of a good place to begin parsing, as close to the - # end of the string as possible. This will be the start of some - # popular stmt like "if" or "def". Return None if none found: - # the caller should pass more prior context then, if possible, or - # if not (the entire program text up until the point of interest - # has already been tried) pass 0 to set_lo. - # - # This will be reliable iff given a reliable is_char_in_string - # function, meaning that when it says "no", it's absolutely - # guaranteed that the char is not in a string. - # - # Ack, hack: in the shell window this kills us, because there's - # no way to tell the differences between output, >>> etc and - # user input. Indeed, IDLE's first output line makes the rest - # look like it's in an unclosed paren!: - # Python 1.5.2 (#0, Apr 13 1999, ... - - def find_good_parse_start(self, use_ps1, is_char_in_string=None, - _rfind=string.rfind, - _synchre=_synchre): - str, pos = self.str, None - if use_ps1: - # shell window - ps1 = '\n' + sys.ps1 - i = _rfind(str, ps1) - if i >= 0: - pos = i + len(ps1) - # make it look like there's a newline instead - # of ps1 at the start -- hacking here once avoids - # repeated hackery later - self.str = str[:pos-1] + '\n' + str[pos:] - return pos - - # File window -- real work. - if not is_char_in_string: - # no clue -- make the caller pass everything - return None - - # Peek back from the end for a good place to start, - # but don't try too often; pos will be left None, or - # bumped to a legitimate synch point. - limit = len(str) - for tries in range(5): - i = _rfind(str, ":\n", 0, limit) - if i < 0: - break - i = _rfind(str, '\n', 0, i) + 1 # start of colon line - m = _synchre(str, i, limit) - if m and not is_char_in_string(m.start()): - pos = m.start() - break - limit = i - if pos is None: - # Nothing looks like a block-opener, or stuff does - # but is_char_in_string keeps returning true; most likely - # we're in or near a giant string, the colorizer hasn't - # caught up enough to be helpful, or there simply *aren't* - # any interesting stmts. In any of these cases we're - # going to have to parse the whole thing to be sure, so - # give it one last try from the start, but stop wasting - # time here regardless of the outcome. - m = _synchre(str) - if m and not is_char_in_string(m.start()): - pos = m.start() - return pos - - # Peeking back worked; look forward until _synchre no longer - # matches. - i = pos + 1 - while 1: - m = _synchre(str, i) - if m: - s, i = m.span() - if not is_char_in_string(s): - pos = s - else: - break - return pos - - # Throw away the start of the string. Intended to be called with - # find_good_parse_start's result. - - def set_lo(self, lo): - assert lo == 0 or self.str[lo-1] == '\n' - if lo > 0: - self.str = self.str[lo:] - - # As quickly as humanly possible , find the line numbers (0- - # based) of the non-continuation lines. - # Creates self.{goodlines, continuation}. - - def _study1(self, _replace=string.replace, _find=string.find): - if self.study_level >= 1: - return - self.study_level = 1 - - # Map all uninteresting characters to "x", all open brackets - # to "(", all close brackets to ")", then collapse runs of - # uninteresting characters. This can cut the number of chars - # by a factor of 10-40, and so greatly speed the following loop. - str = self.str - str = string.translate(str, _tran) - str = _replace(str, 'xxxxxxxx', 'x') - str = _replace(str, 'xxxx', 'x') - str = _replace(str, 'xx', 'x') - str = _replace(str, 'xx', 'x') - str = _replace(str, '\nx', '\n') - # note that replacing x\n with \n would be incorrect, because - # x may be preceded by a backslash - - # March over the squashed version of the program, accumulating - # the line numbers of non-continued stmts, and determining - # whether & why the last stmt is a continuation. - continuation = C_NONE - level = lno = 0 # level is nesting level; lno is line number - self.goodlines = goodlines = [0] - push_good = goodlines.append - i, n = 0, len(str) - while i < n: - ch = str[i] - i = i+1 - - # cases are checked in decreasing order of frequency - if ch == 'x': - continue - - if ch == '\n': - lno = lno + 1 - if level == 0: - push_good(lno) - # else we're in an unclosed bracket structure - continue - - if ch == '(': - level = level + 1 - continue - - if ch == ')': - if level: - level = level - 1 - # else the program is invalid, but we can't complain - continue - - if ch == '"' or ch == "'": - # consume the string - quote = ch - if str[i-1:i+2] == quote * 3: - quote = quote * 3 - w = len(quote) - 1 - i = i+w - while i < n: - ch = str[i] - i = i+1 - - if ch == 'x': - continue - - if str[i-1:i+w] == quote: - i = i+w - break - - if ch == '\n': - lno = lno + 1 - if w == 0: - # unterminated single-quoted string - if level == 0: - push_good(lno) - break - continue - - if ch == '\\': - assert i < n - if str[i] == '\n': - lno = lno + 1 - i = i+1 - continue - - # else comment char or paren inside string - - else: - # didn't break out of the loop, so we're still - # inside a string - continuation = C_STRING - continue # with outer loop - - if ch == '#': - # consume the comment - i = _find(str, '\n', i) - assert i >= 0 - continue - - assert ch == '\\' - assert i < n - if str[i] == '\n': - lno = lno + 1 - if i+1 == n: - continuation = C_BACKSLASH - i = i+1 - - # The last stmt may be continued for all 3 reasons. - # String continuation takes precedence over bracket - # continuation, which beats backslash continuation. - if continuation != C_STRING and level > 0: - continuation = C_BRACKET - self.continuation = continuation - - # Push the final line number as a sentinel value, regardless of - # whether it's continued. - assert (continuation == C_NONE) == (goodlines[-1] == lno) - if goodlines[-1] != lno: - push_good(lno) - - def get_continuation_type(self): - self._study1() - return self.continuation - - # study1 was sufficient to determine the continuation status, - # but doing more requires looking at every character. study2 - # does this for the last interesting statement in the block. - # Creates: - # self.stmt_start, stmt_end - # slice indices of last interesting stmt - # self.lastch - # last non-whitespace character before optional trailing - # comment - # self.lastopenbracketpos - # if continuation is C_BRACKET, index of last open bracket - - def _study2(self, _rfind=string.rfind, _find=string.find, - _ws=string.whitespace): - if self.study_level >= 2: - return - self._study1() - self.study_level = 2 - - # Set p and q to slice indices of last interesting stmt. - str, goodlines = self.str, self.goodlines - i = len(goodlines) - 1 - p = len(str) # index of newest line - while i: - assert p - # p is the index of the stmt at line number goodlines[i]. - # Move p back to the stmt at line number goodlines[i-1]. - q = p - for nothing in range(goodlines[i-1], goodlines[i]): - # tricky: sets p to 0 if no preceding newline - p = _rfind(str, '\n', 0, p-1) + 1 - # The stmt str[p:q] isn't a continuation, but may be blank - # or a non-indenting comment line. - if _junkre(str, p): - i = i-1 - else: - break - if i == 0: - # nothing but junk! - assert p == 0 - q = p - self.stmt_start, self.stmt_end = p, q - - # Analyze this stmt, to find the last open bracket (if any) - # and last interesting character (if any). - lastch = "" - stack = [] # stack of open bracket indices - push_stack = stack.append - while p < q: - # suck up all except ()[]{}'"#\\ - m = _chew_ordinaryre(str, p, q) - if m: - # we skipped at least one boring char - newp = m.end() - # back up over totally boring whitespace - i = newp - 1 # index of last boring char - while i >= p and str[i] in " \t\n": - i = i-1 - if i >= p: - lastch = str[i] - p = newp - if p >= q: - break - - ch = str[p] - - if ch in "([{": - push_stack(p) - lastch = ch - p = p+1 - continue - - if ch in ")]}": - if stack: - del stack[-1] - lastch = ch - p = p+1 - continue - - if ch == '"' or ch == "'": - # consume string - # Note that study1 did this with a Python loop, but - # we use a regexp here; the reason is speed in both - # cases; the string may be huge, but study1 pre-squashed - # strings to a couple of characters per line. study1 - # also needed to keep track of newlines, and we don't - # have to. - lastch = ch - p = _match_stringre(str, p, q).end() - continue - - if ch == '#': - # consume comment and trailing newline - p = _find(str, '\n', p, q) + 1 - assert p > 0 - continue - - assert ch == '\\' - p = p+1 # beyond backslash - assert p < q - if str[p] != '\n': - # the program is invalid, but can't complain - lastch = ch + str[p] - p = p+1 # beyond escaped char - - # end while p < q: - - self.lastch = lastch - if stack: - self.lastopenbracketpos = stack[-1] - - # Assuming continuation is C_BRACKET, return the number - # of spaces the next line should be indented. - - def compute_bracket_indent(self, _find=string.find): - self._study2() - assert self.continuation == C_BRACKET - j = self.lastopenbracketpos - str = self.str - n = len(str) - origi = i = string.rfind(str, '\n', 0, j) + 1 - j = j+1 # one beyond open bracket - # find first list item; set i to start of its line - while j < n: - m = _itemre(str, j) - if m: - j = m.end() - 1 # index of first interesting char - extra = 0 - break - else: - # this line is junk; advance to next line - i = j = _find(str, '\n', j) + 1 - else: - # nothing interesting follows the bracket; - # reproduce the bracket line's indentation + a level - j = i = origi - while str[j] in " \t": - j = j+1 - extra = self.indentwidth - return len(string.expandtabs(str[i:j], - self.tabwidth)) + extra - - # Return number of physical lines in last stmt (whether or not - # it's an interesting stmt! this is intended to be called when - # continuation is C_BACKSLASH). - - def get_num_lines_in_stmt(self): - self._study1() - goodlines = self.goodlines - return goodlines[-1] - goodlines[-2] - - # Assuming continuation is C_BACKSLASH, return the number of spaces - # the next line should be indented. Also assuming the new line is - # the first one following the initial line of the stmt. - - def compute_backslash_indent(self): - self._study2() - assert self.continuation == C_BACKSLASH - str = self.str - i = self.stmt_start - while str[i] in " \t": - i = i+1 - startpos = i - - # See whether the initial line starts an assignment stmt; i.e., - # look for an = operator - endpos = string.find(str, '\n', startpos) + 1 - found = level = 0 - while i < endpos: - ch = str[i] - if ch in "([{": - level = level + 1 - i = i+1 - elif ch in ")]}": - if level: - level = level - 1 - i = i+1 - elif ch == '"' or ch == "'": - i = _match_stringre(str, i, endpos).end() - elif ch == '#': - break - elif level == 0 and ch == '=' and \ - (i == 0 or str[i-1] not in "=<>!") and \ - str[i+1] != '=': - found = 1 - break - else: - i = i+1 - - if found: - # found a legit =, but it may be the last interesting - # thing on the line - i = i+1 # move beyond the = - found = re.match(r"\s*\\", str[i:endpos]) is None - - if not found: - # oh well ... settle for moving beyond the first chunk - # of non-whitespace chars - i = startpos - while str[i] not in " \t\n": - i = i+1 - - return len(string.expandtabs(str[self.stmt_start : - i], - self.tabwidth)) + 1 - - # Return the leading whitespace on the initial line of the last - # interesting stmt. - - def get_base_indent_string(self): - self._study2() - i, n = self.stmt_start, self.stmt_end - j = i - str = self.str - while j < n and str[j] in " \t": - j = j + 1 - return str[i:j] - - # Did the last interesting stmt open a block? - - def is_block_opener(self): - self._study2() - return self.lastch == ':' - - # Did the last interesting stmt close a block? - - def is_block_closer(self): - self._study2() - return _closere(self.str, self.stmt_start) is not None - - # index of last open bracket ({[, or None if none - lastopenbracketpos = None - - def get_last_open_bracket_pos(self): - self._study2() - return self.lastopenbracketpos diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py deleted file mode 100644 index 5037806..0000000 --- a/Lib/idlelib/PyShell.py +++ /dev/null @@ -1,903 +0,0 @@ -#! /usr/bin/env python - -# changes by dscherer@cmu.edu - -# The main() function has been replaced by a whole class, in order to -# address the constraint that only one process can sit on the port -# hard-coded into the loader. - -# It attempts to load the RPC protocol server and publish itself. If -# that fails, it assumes that some other copy of IDLE is already running -# on the port and attempts to contact it. It then uses the RPC mechanism -# to ask that copy to do whatever it was instructed (via the command -# line) to do. (Think netscape -remote). The handling of command line -# arguments for remotes is still very incomplete. - -# Default behavior (no command line options) is to open an editor window -# instead of starting the Python Shell. However, if called as -# Pyshell.main(0), the Shell will be started instead of the editor window. - -# In the default editor mode, if files are specified, they are opened. - -# If any command line options are specified, a shell does appear, and if -# the -e option is used, both a shell and an editor window open. - -import os -import spawn -import sys -import string -import getopt -import re -import protocol -import warnings - -import linecache -from code import InteractiveInterpreter - -from Tkinter import * -import tkMessageBox - -from EditorWindow import EditorWindow, fixwordbreaks -from FileList import FileList -from ColorDelegator import ColorDelegator -from UndoDelegator import UndoDelegator -from OutputWindow import OutputWindow, OnDemandOutputWindow -from IdleConf import idleconf -from configHandler import idleConf -import idlever - -# We need to patch linecache.checkcache, because we don't want it -# to throw away our entries. -# Rather than repeating its code here, we save those entries, -# then call the original function, and then restore the saved entries. -def linecache_checkcache(orig_checkcache=linecache.checkcache): - cache = linecache.cache - save = {} - for filename in cache.keys(): - if filename[:1] + filename[-1:] == '<>': - save[filename] = cache[filename] - orig_checkcache() - cache.update(save) -linecache.checkcache = linecache_checkcache - - -# Note: <> event is defined in AutoIndent.py - -#$ event <> -#$ win -#$ unix - -#$ event <> -#$ win -#$ win -#$ unix -#$ unix - -#$ event <> -#$ win -#$ unix - -#$ event <> -#$ win -#$ unix - -#$ event <> -#$ win -#$ unix - -#$ event <> -#$ win -#$ unix - -#$ event <> - -#$ event <> - - -class PyShellEditorWindow(EditorWindow): - - # Regular text edit window when a shell is present - # XXX ought to merge with regular editor window - - def __init__(self, *args): - apply(EditorWindow.__init__, (self,) + args) - self.text.bind("<>", self.set_breakpoint_here) - self.text.bind("<>", self.flist.open_shell) - - rmenu_specs = [ - ("Set breakpoint here", "<>"), - ] - - def set_breakpoint_here(self, event=None): - if not self.flist.pyshell or not self.flist.pyshell.interp.debugger: - self.text.bell() - return - self.flist.pyshell.interp.debugger.set_breakpoint_here(self) - - -class PyShellFileList(FileList): - - # File list when a shell is present - - EditorWindow = PyShellEditorWindow - - pyshell = None - - def open_shell(self, event=None): - if self.pyshell: - self.pyshell.wakeup() - else: - self.pyshell = PyShell(self) - self.pyshell.begin() - return self.pyshell - - -class ModifiedColorDelegator(ColorDelegator): - - # Colorizer for the shell window itself - - def recolorize_main(self): - self.tag_remove("TODO", "1.0", "iomark") - self.tag_add("SYNC", "1.0", "iomark") - ColorDelegator.recolorize_main(self) - - tagdefs = ColorDelegator.tagdefs.copy() - theme = idleConf.GetOption('main','Theme','name') - tagdefs.update({ - - "stdin": idleConf.GetHighlight(theme, "stdin"), - "stdout": idleConf.GetHighlight(theme, "stdout"), - "stderr": idleConf.GetHighlight(theme, "stderr"), - "console": idleConf.GetHighlight(theme, "console"), - "ERROR": idleConf.GetHighlight(theme, "error"), - None: idleConf.GetHighlight(theme, "normal"), - }) - - -class ModifiedUndoDelegator(UndoDelegator): - - # Forbid insert/delete before the I/O mark - - def insert(self, index, chars, tags=None): - try: - if self.delegate.compare(index, "<", "iomark"): - self.delegate.bell() - return - except TclError: - pass - UndoDelegator.insert(self, index, chars, tags) - - def delete(self, index1, index2=None): - try: - if self.delegate.compare(index1, "<", "iomark"): - self.delegate.bell() - return - except TclError: - pass - UndoDelegator.delete(self, index1, index2) - -class ModifiedInterpreter(InteractiveInterpreter): - - def __init__(self, tkconsole): - self.tkconsole = tkconsole - locals = sys.modules['__main__'].__dict__ - InteractiveInterpreter.__init__(self, locals=locals) - self.save_warnings_filters = None - - gid = 0 - - def execsource(self, source): - # Like runsource() but assumes complete exec source - filename = self.stuffsource(source) - self.execfile(filename, source) - - def execfile(self, filename, source=None): - # Execute an existing file - if source is None: - source = open(filename, "r").read() - try: - code = compile(source, filename, "exec") - except (OverflowError, SyntaxError): - self.tkconsole.resetoutput() - InteractiveInterpreter.showsyntaxerror(self, filename) - else: - self.runcode(code) - - def runsource(self, source): - # Extend base class to stuff the source in the line cache first - filename = self.stuffsource(source) - self.more = 0 - self.save_warnings_filters = warnings.filters[:] - warnings.filterwarnings(action="error", category=SyntaxWarning) - try: - return InteractiveInterpreter.runsource(self, source, filename) - finally: - if self.save_warnings_filters is not None: - warnings.filters[:] = self.save_warnings_filters - self.save_warnings_filters = None - - def stuffsource(self, source): - # Stuff source in the filename cache - filename = "" % self.gid - self.gid = self.gid + 1 - lines = string.split(source, "\n") - linecache.cache[filename] = len(source)+1, 0, lines, filename - return filename - - def showsyntaxerror(self, filename=None): - # Extend base class to color the offending position - # (instead of printing it and pointing at it with a caret) - text = self.tkconsole.text - stuff = self.unpackerror() - if not stuff: - self.tkconsole.resetoutput() - InteractiveInterpreter.showsyntaxerror(self, filename) - return - msg, lineno, offset, line = stuff - if lineno == 1: - pos = "iomark + %d chars" % (offset-1) - else: - pos = "iomark linestart + %d lines + %d chars" % (lineno-1, - offset-1) - text.tag_add("ERROR", pos) - text.see(pos) - char = text.get(pos) - if char and char in string.letters + string.digits + "_": - text.tag_add("ERROR", pos + " wordstart", pos) - self.tkconsole.resetoutput() - self.write("SyntaxError: %s\n" % str(msg)) - - def unpackerror(self): - type, value, tb = sys.exc_info() - ok = type is SyntaxError - if ok: - try: - msg, (dummy_filename, lineno, offset, line) = value - except: - ok = 0 - if ok: - return msg, lineno, offset, line - else: - return None - - def showtraceback(self): - # Extend base class method to reset output properly - text = self.tkconsole.text - self.tkconsole.resetoutput() - self.checklinecache() - InteractiveInterpreter.showtraceback(self) - - def checklinecache(self): - c = linecache.cache - for key in c.keys(): - if key[:1] + key[-1:] != "<>": - del c[key] - - debugger = None - - def setdebugger(self, debugger): - self.debugger = debugger - - def getdebugger(self): - return self.debugger - - def runcode(self, code): - # Override base class method - if self.save_warnings_filters is not None: - warnings.filters[:] = self.save_warnings_filters - self.save_warnings_filters = None - debugger = self.debugger - try: - self.tkconsole.beginexecuting() - try: - if debugger: - debugger.run(code, self.locals) - else: - exec code in self.locals - except SystemExit: - if tkMessageBox.askyesno( - "Exit?", - "Do you want to exit altogether?", - default="yes", - master=self.tkconsole.text): - raise - else: - self.showtraceback() - if self.tkconsole.getvar("<>"): - self.tkconsole.open_stack_viewer() - except: - self.showtraceback() - if self.tkconsole.getvar("<>"): - self.tkconsole.open_stack_viewer() - - finally: - self.tkconsole.endexecuting() - - def write(self, s): - # Override base class write - self.tkconsole.console.write(s) - - -class PyShell(OutputWindow): - - shell_title = "Python Shell" - - # Override classes - ColorDelegator = ModifiedColorDelegator - UndoDelegator = ModifiedUndoDelegator - - # Override menu bar specs - menu_specs = PyShellEditorWindow.menu_specs[:] - menu_specs.insert(len(menu_specs)-3, ("debug", "_Debug")) - - # New classes - from IdleHistory import History - - def __init__(self, flist=None): - self.interp = ModifiedInterpreter(self) - if flist is None: - root = Tk() - fixwordbreaks(root) - root.withdraw() - flist = PyShellFileList(root) - - OutputWindow.__init__(self, flist, None, None) - - import __builtin__ - __builtin__.quit = __builtin__.exit = "To exit, type Ctrl-D." - - self.auto = self.extensions["AutoIndent"] # Required extension - self.auto.config(usetabs=1, indentwidth=8, context_use_ps1=1) - - text = self.text - text.configure(wrap="char") - text.bind("<>", self.enter_callback) - text.bind("<>", self.linefeed_callback) - text.bind("<>", self.cancel_callback) - text.bind("<>", self.home_callback) - text.bind("<>", self.eof_callback) - text.bind("<>", self.open_stack_viewer) - text.bind("<>", self.toggle_debugger) - text.bind("<>", self.flist.open_shell) - text.bind("<>", self.toggle_jit_stack_viewer) - - self.save_stdout = sys.stdout - self.save_stderr = sys.stderr - self.save_stdin = sys.stdin - sys.stdout = PseudoFile(self, "stdout") - sys.stderr = PseudoFile(self, "stderr") - sys.stdin = self - self.console = PseudoFile(self, "console") - - self.history = self.History(self.text) - - reading = 0 - executing = 0 - canceled = 0 - endoffile = 0 - - def toggle_debugger(self, event=None): - if self.executing: - tkMessageBox.showerror("Don't debug now", - "You can only toggle the debugger when idle", - master=self.text) - self.set_debugger_indicator() - return "break" - else: - db = self.interp.getdebugger() - if db: - self.close_debugger() - else: - self.open_debugger() - - def set_debugger_indicator(self): - db = self.interp.getdebugger() - self.setvar("<>", not not db) - - def toggle_jit_stack_viewer( self, event=None): - pass # All we need is the variable - - def close_debugger(self): - db = self.interp.getdebugger() - if db: - self.interp.setdebugger(None) - db.close() - self.resetoutput() - self.console.write("[DEBUG OFF]\n") - sys.ps1 = ">>> " - self.showprompt() - self.set_debugger_indicator() - - def open_debugger(self): - import Debugger - self.interp.setdebugger(Debugger.Debugger(self)) - sys.ps1 = "[DEBUG ON]\n>>> " - self.showprompt() - self.set_debugger_indicator() - - def beginexecuting(self): - # Helper for ModifiedInterpreter - self.resetoutput() - self.executing = 1 - ##self._cancel_check = self.cancel_check - ##sys.settrace(self._cancel_check) - - def endexecuting(self): - # Helper for ModifiedInterpreter - ##sys.settrace(None) - ##self._cancel_check = None - self.executing = 0 - self.canceled = 0 - - def close(self): - # Extend base class method - if self.executing: - # XXX Need to ask a question here - if not tkMessageBox.askokcancel( - "Kill?", - "The program is still running; do you want to kill it?", - default="ok", - master=self.text): - return "cancel" - self.canceled = 1 - if self.reading: - self.top.quit() - return "cancel" - return OutputWindow.close(self) - - def _close(self): - self.close_debugger() - # Restore std streams - sys.stdout = self.save_stdout - sys.stderr = self.save_stderr - sys.stdin = self.save_stdin - # Break cycles - self.interp = None - self.console = None - self.auto = None - self.flist.pyshell = None - self.history = None - OutputWindow._close(self) # Really EditorWindow._close - - def ispythonsource(self, filename): - # Override this so EditorWindow never removes the colorizer - return 1 - - def short_title(self): - return self.shell_title - - COPYRIGHT = \ - 'Type "copyright", "credits" or "license" for more information.' - - def begin(self): - self.resetoutput() - self.write("Python %s on %s\n%s\nIDLE Fork %s -- press F1 for help\n" % - (sys.version, sys.platform, self.COPYRIGHT, - idlever.IDLE_VERSION)) - try: - sys.ps1 - except AttributeError: - sys.ps1 = ">>> " - self.showprompt() - import Tkinter - Tkinter._default_root = None - - def interact(self): - self.begin() - self.top.mainloop() - - def readline(self): - save = self.reading - try: - self.reading = 1 - self.top.mainloop() - finally: - self.reading = save - line = self.text.get("iomark", "end-1c") - self.resetoutput() - if self.canceled: - self.canceled = 0 - raise KeyboardInterrupt - if self.endoffile: - self.endoffile = 0 - return "" - return line - - def isatty(self): - return 1 - - def cancel_callback(self, event): - try: - if self.text.compare("sel.first", "!=", "sel.last"): - return # Active selection -- always use default binding - except: - pass - if not (self.executing or self.reading): - self.resetoutput() - self.write("KeyboardInterrupt\n") - self.showprompt() - return "break" - self.endoffile = 0 - self.canceled = 1 - if self.reading: - self.top.quit() - return "break" - - def eof_callback(self, event): - if self.executing and not self.reading: - return # Let the default binding (delete next char) take over - if not (self.text.compare("iomark", "==", "insert") and - self.text.compare("insert", "==", "end-1c")): - return # Let the default binding (delete next char) take over - if not self.executing: -## if not tkMessageBox.askokcancel( -## "Exit?", -## "Are you sure you want to exit?", -## default="ok", master=self.text): -## return "break" - self.resetoutput() - self.close() - else: - self.canceled = 0 - self.endoffile = 1 - self.top.quit() - return "break" - - def home_callback(self, event): - if event.state != 0 and event.keysym == "Home": - return # ; fall back to class binding - if self.text.compare("iomark", "<=", "insert") and \ - self.text.compare("insert linestart", "<=", "iomark"): - self.text.mark_set("insert", "iomark") - self.text.tag_remove("sel", "1.0", "end") - self.text.see("insert") - return "break" - - def linefeed_callback(self, event): - # Insert a linefeed without entering anything (still autoindented) - if self.reading: - self.text.insert("insert", "\n") - self.text.see("insert") - else: - self.auto.auto_indent(event) - return "break" - - def enter_callback(self, event): - if self.executing and not self.reading: - return # Let the default binding (insert '\n') take over - # If some text is selected, recall the selection - # (but only if this before the I/O mark) - try: - sel = self.text.get("sel.first", "sel.last") - if sel: - if self.text.compare("sel.last", "<=", "iomark"): - self.recall(sel) - return "break" - except: - pass - # If we're strictly before the line containing iomark, recall - # the current line, less a leading prompt, less leading or - # trailing whitespace - if self.text.compare("insert", "<", "iomark linestart"): - # Check if there's a relevant stdin range -- if so, use it - prev = self.text.tag_prevrange("stdin", "insert") - if prev and self.text.compare("insert", "<", prev[1]): - self.recall(self.text.get(prev[0], prev[1])) - return "break" - next = self.text.tag_nextrange("stdin", "insert") - if next and self.text.compare("insert lineend", ">=", next[0]): - self.recall(self.text.get(next[0], next[1])) - return "break" - # No stdin mark -- just get the current line - self.recall(self.text.get("insert linestart", "insert lineend")) - return "break" - # If we're in the current input and there's only whitespace - # beyond the cursor, erase that whitespace first - s = self.text.get("insert", "end-1c") - if s and not string.strip(s): - self.text.delete("insert", "end-1c") - # If we're in the current input before its last line, - # insert a newline right at the insert point - if self.text.compare("insert", "<", "end-1c linestart"): - self.auto.auto_indent(event) - return "break" - # We're in the last line; append a newline and submit it - self.text.mark_set("insert", "end-1c") - if self.reading: - self.text.insert("insert", "\n") - self.text.see("insert") - else: - self.auto.auto_indent(event) - self.text.tag_add("stdin", "iomark", "end-1c") - self.text.update_idletasks() - if self.reading: - self.top.quit() # Break out of recursive mainloop() in raw_input() - else: - self.runit() - return "break" - - def recall(self, s): - if self.history: - self.history.recall(s) - - def runit(self): - line = self.text.get("iomark", "end-1c") - # Strip off last newline and surrounding whitespace. - # (To allow you to hit return twice to end a statement.) - i = len(line) - while i > 0 and line[i-1] in " \t": - i = i-1 - if i > 0 and line[i-1] == "\n": - i = i-1 - while i > 0 and line[i-1] in " \t": - i = i-1 - line = line[:i] - more = self.interp.runsource(line) - if not more: - self.showprompt() - - def cancel_check(self, frame, what, args, - dooneevent=tkinter.dooneevent, - dontwait=tkinter.DONT_WAIT): - # Hack -- use the debugger hooks to be able to handle events - # and interrupt execution at any time. - # This slows execution down quite a bit, so you may want to - # disable this (by not calling settrace() in runcode() above) - # for full-bore (uninterruptable) speed. - # XXX This should become a user option. - if self.canceled: - return - dooneevent(dontwait) - if self.canceled: - self.canceled = 0 - raise KeyboardInterrupt - return self._cancel_check - - def open_stack_viewer(self, event=None): - try: - sys.last_traceback - except: - tkMessageBox.showerror("No stack trace", - "There is no stack trace yet.\n" - "(sys.last_traceback is not defined)", - master=self.text) - return - from StackViewer import StackBrowser - sv = StackBrowser(self.root, self.flist) - - def showprompt(self): - self.resetoutput() - try: - s = str(sys.ps1) - except: - s = "" - self.console.write(s) - self.text.mark_set("insert", "end-1c") - - def resetoutput(self): - source = self.text.get("iomark", "end-1c") - if self.history: - self.history.history_store(source) - if self.text.get("end-2c") != "\n": - self.text.insert("end-1c", "\n") - self.text.mark_set("iomark", "end-1c") - sys.stdout.softspace = 0 - - def write(self, s, tags=()): - self.text.mark_gravity("iomark", "right") - OutputWindow.write(self, s, tags, "iomark") - self.text.mark_gravity("iomark", "left") - if self.canceled: - self.canceled = 0 - raise KeyboardInterrupt - -class PseudoFile: - - def __init__(self, shell, tags): - self.shell = shell - self.tags = tags - - def write(self, s): - self.shell.write(s, self.tags) - - def writelines(self, l): - map(self.write, l) - - def flush(self): - pass - - def isatty(self): - return 1 - -usage_msg = """\ -usage: idle.py [-c command] [-d] [-i] [-r script] [-s] [-t title] [arg] ... - -idle file(s) (without options) edit the file(s) - --c cmd run the command in a shell --d enable the debugger --i open an interactive shell --i file(s) open a shell and also an editor window for each file --r script run a file as a script in a shell --s run $IDLESTARTUP or $PYTHONSTARTUP before anything else --t title set title of shell window - -Remaining arguments are applied to the command (-c) or script (-r). -""" - -class usageError: - def __init__(self, string): self.string = string - def __repr__(self): return self.string - -class main: - def __init__(self, noshell=1): - - global flist, root - root = Tk(className="Idle") - fixwordbreaks(root) - root.withdraw() - flist = PyShellFileList(root) - - dbg=OnDemandOutputWindow(flist) - dbg.set_title('IDLE Debugging Messages') - sys.stdout = PseudoFile(dbg,['stdout']) - sys.stderr = PseudoFile(dbg,['stderr']) - - try: - self.server = protocol.Server(connection_hook = self.address_ok) - protocol.publish( 'IDLE', self.connect ) - self.main(sys.argv[1:], noshell) - return - except protocol.connectionLost: - try: - client = protocol.Client() - IDLE = client.getobject('IDLE') - if IDLE: - try: - IDLE.remote( sys.argv[1:] ) - except usageError, msg: - sys.stderr.write("Error: %s\n" % str(msg)) - sys.stderr.write(usage_msg) - return - except protocol.connectionLost: - pass - - #maybe the following should be handled by a tkmessagebox for - #users who don't start idle from a console?? - print """\ -IDLE cannot run. - -IDLE needs to use a specific TCP/IP port (7454) in order to execute and -debug programs. IDLE is unable to bind to this port, and so cannot -start. Here are some possible causes of this problem: - - 1. TCP/IP networking is not installed or not working on this computer - 2. Another program is running that uses this port - 3. Another copy of IDLE stopped responding but is still bound to the port - 4. Personal firewall software is preventing IDLE from using this port - -IDLE makes and accepts connections only with this computer, and does not -communicate over the internet in any way. It's use of port 7454 should not -be a security risk on a single-user machine. -""" - dbg.owin.gotoline(1) - dbg.owin.remove_selection() - root.mainloop() # wait for user to read message - - def idle(self): - spawn.kill_zombies() - self.server.rpc_loop() - root.after(25, self.idle) - - # We permit connections from localhost only - def address_ok(self, addr): - return addr[0] == '127.0.0.1' - - def connect(self, client, addr): - return self - - def remote( self, argv ): - # xxx Should make this behavior match the behavior in main, or redo - # command line options entirely. - - try: - opts, args = getopt.getopt(argv, "c:deist:") - except getopt.error, msg: - raise usageError(msg) - - for filename in args: - flist.open(filename) - if not args: - flist.new() - - def main(self, argv, noshell): - cmd = None - edit = 0 - debug = 0 - interactive = 0 - script = None - startup = 0 - - try: - opts, args = getopt.getopt(argv, "c:dir:st:") - except getopt.error, msg: - sys.stderr.write("Error: %s\n" % str(msg)) - sys.stderr.write(usage_msg) - sys.exit(2) - - for o, a in opts: - noshell = 0 # There are options, bring up a shell - if o == '-c': - cmd = a - if o == '-d': - debug = 1 - if o == '-i': - interactive = 1 - if o == '-r': - script = a - if o == '-s': - startup = 1 - if o == '-t': - PyShell.shell_title = a - - if noshell: edit=1 - if interactive and args and args[0] != "-": edit = 1 - - for i in range(len(sys.path)): - sys.path[i] = os.path.abspath(sys.path[i]) - - pathx = [] - if edit: - for filename in args: - pathx.append(os.path.dirname(filename)) - elif args and args[0] != "-": - pathx.append(os.path.dirname(args[0])) - else: - pathx.append(os.curdir) - for dir in pathx: - dir = os.path.abspath(dir) - if not dir in sys.path: - sys.path.insert(0, dir) - - if edit: - for filename in args: - flist.open(filename) - if not args: - flist.new() - else: - if cmd: - sys.argv = ["-c"] + args - else: - sys.argv = args or [""] - - if noshell: - flist.pyshell = None - else: - shell = PyShell(flist) - interp = shell.interp - flist.pyshell = shell - - if startup: - filename = os.environ.get("IDLESTARTUP") or \ - os.environ.get("PYTHONSTARTUP") - if filename and os.path.isfile(filename): - interp.execfile(filename) - - if debug: - shell.open_debugger() - if cmd: - interp.execsource(cmd) - elif script: - if os.path.isfile(script): - interp.execfile(script) - else: - print "No script file: ", script - shell.begin() - - self.idle() - root.mainloop() - root.destroy() - - -if __name__ == "__main__": - main() diff --git a/Lib/idlelib/README.txt b/Lib/idlelib/README.txt deleted file mode 100644 index 152d497..0000000 --- a/Lib/idlelib/README.txt +++ /dev/null @@ -1,158 +0,0 @@ -IDLEfork README -=============== - -IDLEfork is an official experimental fork of Python's Integrated -DeveLopment Environment IDLE. Worthwhile and successful changes and -additions will go back into the Python distribution's IDLE at some -later stage. There is no spanish inquisition. - -As David Scherer aptly put it in the original IDLE fork README (below), -"It is alpha software and might be unstable. If it breaks, you get to -keep both pieces." One of the aims of IDLEfork now is for it to be able -to be uncompressed into its own directory and run from there, that way -you can play with (or hack on) IDLEfork without any further installation, -and entirely separately from your stable python IDLE distribution. - -If you find bugs or undesired behaviour please code nifty patches and -submit them to the IDLEfork SourceForge patch manager, 8^) or let us -know about it in one of the appropriate fora. See the IDLEfork home -page at - -http://idlefork.sourceforge.net - -for details on the various ways to give input to or contact the project. - -Please see the files NEWS.txt and ChangeLog for more up to date -information on changes in this release of IDLEfork. - - -Thanks for trying IDLEfork, -Stephen M. Gava. - - - - -README from IDLE fork 0.7.1 : -============================= - -EXPERIMENTAL LOADER IDLE 2000-05-29 ------------------------------------ - - David Scherer - -This is a modification of the CVS version of IDLE 0.5, updated as of -2000-03-09. It is alpha software and might be unstable. If it breaks, -you get to keep both pieces. - -If you have problems or suggestions, you should either contact me or -post to the list at http://www.python.org/mailman/listinfo/idle-dev -(making it clear that you are using this modified version of IDLE). - -Changes: - - The ExecBinding module, a replacement for ScriptBinding, executes - programs in a separate process, piping standard I/O through an RPC - mechanism to an OnDemandOutputWindow in IDLE. It supports executing - unnamed programs (through a temporary file). It does not yet support - debugging. - - When running programs with ExecBinding, tracebacks will be clipped - to exclude system modules. If, however, a system module calls back - into the user program, that part of the traceback will be shown. - - The OnDemandOutputWindow class has been improved. In particular, - it now supports a readline() function used to implement user input, - and a scroll_clear() operation which is used to hide the output of - a previous run by scrolling it out of the window. - - Startup behavior has been changed. By default IDLE starts up with - just a blank editor window, rather than an interactive window. Opening - a file in such a blank window replaces the (nonexistent) contents of - that window instead of creating another window. Because of the need to - have a well-known port for the ExecBinding protocol, only one copy of - IDLE can be running. Additional invocations use the RPC mechanism to - report their command line arguments to the copy already running. - - The menus have been reorganized. In particular, the excessively large - 'edit' menu has been split up into 'edit', 'format', and 'run'. - - 'Python Documentation' now works on Windows, if the win32api module is - present. - - A few key bindings have been changed: F1 now loads Python Documentation - instead of the IDLE help; shift-TAB is now a synonym for unindent. - -New modules: - ExecBinding.py Executes program through loader - loader.py Bootstraps user program - protocol.py RPC protocol - Remote.py User-process interpreter - spawn.py OS-specific code to start programs - -Files modified: - autoindent.py ( bindings tweaked ) - bindings.py ( menus reorganized ) - config.txt ( execbinding enabled ) - editorwindow.py ( new menus, fixed 'Python Documentation' ) - filelist.py ( hook for "open in same window" ) - formatparagraph.py ( bindings tweaked ) - idle.bat ( removed absolute pathname ) - idle.pyw ( weird bug due to import with same name? ) - iobinding.py ( open in same window, EOL convention ) - keydefs.py ( bindings tweaked ) - outputwindow.py ( readline, scroll_clear, etc ) - pyshell.py ( changed startup behavior ) - readme.txt ( ) - -IDLE 0.5 - February 2000 ------------------------- - -This is an early release of IDLE, my own attempt at a Tkinter-based -IDE for Python. - -For news about this release, see the file NEWS.txt. (For a more -detailed change log, see the file ChangeLog.) - -FEATURES - -IDLE has the following features: - -- coded in 100% pure Python, using the Tkinter GUI toolkit (i.e. Tcl/Tk) - -- cross-platform: works on Windows and Unix (on the Mac, there are -currently problems with Tcl/Tk) - -- multi-window text editor with multiple undo, Python colorizing -and many other features, e.g. smart indent and call tips - -- Python shell window (a.k.a. interactive interpreter) - -- debugger (not complete, but you can set breakpoints, view and step) - -USAGE - -The main program is in the file "idle.py"; on Unix, you should be able -to run it by typing "./idle.py" to your shell. On Windows, you can -run it by double-clicking it; you can use idle.pyw to avoid popping up -a DOS console. If you want to pass command line arguments on Windows, -use the batch file idle.bat. - -Command line arguments: files passed on the command line are executed, -not opened for editing, unless you give the -e command line option. -Try "./idle.py -h" to see other command line options. - -IDLE requires Python 1.5.2, so it is currently only usable with a -Python 1.5.2 distribution. (An older version of IDLE is distributed -with Python 1.5.2; you can drop this version on top of it.) - -COPYRIGHT - -IDLE is covered by the standard Python copyright notice -(http://www.python.org/doc/Copyright.html). - -FEEDBACK - -(removed, since Guido probably doesn't want complaints about my -changes) - ---Guido van Rossum (home page: http://www.python.org/~guido/) diff --git a/Lib/idlelib/Remote.py b/Lib/idlelib/Remote.py deleted file mode 100644 index facba78..0000000 --- a/Lib/idlelib/Remote.py +++ /dev/null @@ -1,101 +0,0 @@ -"""Remote - This module is imported by the loader and serves to control - the execution of the user program. It presently executes files - and reports exceptions to IDLE. It could be extended to provide - other services, such as interactive mode and debugging. To that - end, it could be a subclass of e.g. InteractiveInterpreter. - - Two other classes, pseudoIn and pseudoOut, are file emulators also - used by loader. -""" -import sys, os -import traceback - -class Remote: - def __init__(self, main, master): - self.main = main - self.master = master - self.this_file = self.canonic( self.__init__.im_func.func_code.co_filename ) - - def canonic(self, path): - return os.path.normcase(os.path.abspath(path)) - - def mainloop(self): - while 1: - args = self.master.get_command() - - try: - f = getattr(self,args[0]) - apply(f,args[1:]) - except: - if not self.report_exception(): raise - - def finish(self): - sys.exit() - - def run(self, *argv): - sys.argv = argv - - path = self.canonic( argv[0] ) - dir = self.dir = os.path.dirname(path) - os.chdir(dir) - - sys.path[0] = dir - - usercode = open(path) - exec usercode in self.main - - def report_exception(self): - try: - type, value, tb = sys.exc_info() - sys.last_type = type - sys.last_value = value - sys.last_traceback = tb - - tblist = traceback.extract_tb(tb) - - # Look through the traceback, canonicalizing filenames and - # eliminating leading and trailing system modules. - first = last = 1 - for i in range(len(tblist)): - filename, lineno, name, line = tblist[i] - filename = self.canonic(filename) - tblist[i] = filename, lineno, name, line - - dir = os.path.dirname(filename) - if filename == self.this_file: - first = i+1 - elif dir==self.dir: - last = i+1 - - # Canonicalize the filename in a syntax error, too: - if type is SyntaxError: - try: - msg, (filename, lineno, offset, line) = value - filename = self.canonic(filename) - value = msg, (filename, lineno, offset, line) - except: - pass - - return self.master.program_exception( type, value, tblist, first, last ) - finally: - # avoid any circular reference through the traceback - del tb - -class pseudoIn: - def __init__(self, readline): - self.readline = readline - def isatty(): - return 1 - -class pseudoOut: - def __init__(self, func, **kw): - self.func = func - self.kw = kw - def write(self, *args): - return apply( self.func, args, self.kw ) - def writelines(self, l): - map(self.write, l) - def flush(self): - pass - diff --git a/Lib/idlelib/RemoteInterp.py b/Lib/idlelib/RemoteInterp.py deleted file mode 100644 index 724997c..0000000 --- a/Lib/idlelib/RemoteInterp.py +++ /dev/null @@ -1,342 +0,0 @@ -import select -import socket -import struct -import sys -import types - -VERBOSE = None - -class SocketProtocol: - """A simple protocol for sending strings across a socket""" - BUF_SIZE = 8192 - - def __init__(self, sock): - self.sock = sock - self._buffer = '' - self._closed = 0 - - def close(self): - self._closed = 1 - self.sock.close() - - def send(self, buf): - """Encode buf and write it on the socket""" - if VERBOSE: - VERBOSE.write('send %d:%s\n' % (len(buf), `buf`)) - self.sock.send('%d:%s' % (len(buf), buf)) - - def receive(self, timeout=0): - """Get next complete string from socket or return None - - Raise EOFError on EOF - """ - buf = self._read_from_buffer() - if buf is not None: - return buf - recvbuf = self._read_from_socket(timeout) - if recvbuf is None: - return None - if recvbuf == '' and self._buffer == '': - raise EOFError - if VERBOSE: - VERBOSE.write('recv %s\n' % `recvbuf`) - self._buffer = self._buffer + recvbuf - r = self._read_from_buffer() - return r - - def _read_from_socket(self, timeout): - """Does not block""" - if self._closed: - return '' - if timeout is not None: - r, w, x = select.select([self.sock], [], [], timeout) - if timeout is None or r: - return self.sock.recv(self.BUF_SIZE) - else: - return None - - def _read_from_buffer(self): - buf = self._buffer - i = buf.find(':') - if i == -1: - return None - buflen = int(buf[:i]) - enclen = i + 1 + buflen - if len(buf) >= enclen: - s = buf[i+1:enclen] - self._buffer = buf[enclen:] - return s - else: - self._buffer = buf - return None - -# helpers for registerHandler method below - -def get_methods(obj): - methods = [] - for name in dir(obj): - attr = getattr(obj, name) - if callable(attr): - methods.append(name) - if type(obj) == types.InstanceType: - methods = methods + get_methods(obj.__class__) - if type(obj) == types.ClassType: - for super in obj.__bases__: - methods = methods + get_methods(super) - return methods - -class CommandProtocol: - def __init__(self, sockp): - self.sockp = sockp - self.seqno = 0 - self.handlers = {} - - def close(self): - self.sockp.close() - self.handlers.clear() - - def registerHandler(self, handler): - """A Handler is an object with handle_XXX methods""" - for methname in get_methods(handler): - if methname[:7] == "handle_": - name = methname[7:] - self.handlers[name] = getattr(handler, methname) - - def send(self, cmd, arg='', seqno=None): - if arg: - msg = "%s %s" % (cmd, arg) - else: - msg = cmd - if seqno is None: - seqno = self.get_seqno() - msgbuf = self.encode_seqno(seqno) + msg - self.sockp.send(msgbuf) - if cmd == "reply": - return - reply = self.sockp.receive(timeout=None) - r_cmd, r_arg, r_seqno = self._decode_msg(reply) - assert r_seqno == seqno and r_cmd == "reply", "bad reply" - return r_arg - - def _decode_msg(self, msg): - seqno = self.decode_seqno(msg[:self.SEQNO_ENC_LEN]) - msg = msg[self.SEQNO_ENC_LEN:] - parts = msg.split(" ", 2) - if len(parts) == 1: - cmd = msg - arg = '' - else: - cmd = parts[0] - arg = parts[1] - return cmd, arg, seqno - - def dispatch(self): - msg = self.sockp.receive() - if msg is None: - return - cmd, arg, seqno = self._decode_msg(msg) - self._current_reply = seqno - h = self.handlers.get(cmd, self.default_handler) - try: - r = h(arg) - except TypeError, msg: - raise TypeError, "handle_%s: %s" % (cmd, msg) - if self._current_reply is None: - if r is not None: - sys.stderr.write("ignoring %s return value type %s\n" % \ - (cmd, type(r).__name__)) - return - if r is None: - r = '' - if type(r) != types.StringType: - raise ValueError, "invalid return type for %s" % cmd - self.send("reply", r, seqno=seqno) - - def reply(self, arg=''): - """Send a reply immediately - - otherwise reply will be sent when handler returns - """ - self.send("reply", arg, self._current_reply) - self._current_reply = None - - def default_handler(self, arg): - sys.stderr.write("WARNING: unhandled message %s\n" % arg) - return '' - - SEQNO_ENC_LEN = 4 - - def get_seqno(self): - seqno = self.seqno - self.seqno = seqno + 1 - return seqno - - def encode_seqno(self, seqno): - return struct.pack("I", seqno) - - def decode_seqno(self, buf): - return struct.unpack("I", buf)[0] - - -class StdioRedirector: - """Redirect sys.std{in,out,err} to a set of file-like objects""" - - def __init__(self, stdin, stdout, stderr): - self.stdin = stdin - self.stdout = stdout - self.stderr = stderr - - def redirect(self): - self.save() - sys.stdin = self.stdin - sys.stdout = self.stdout - sys.stderr = self.stderr - - def save(self): - self._stdin = sys.stdin - self._stdout = sys.stdout - self._stderr = sys.stderr - - def restore(self): - sys.stdin = self._stdin - sys.stdout = self._stdout - sys.stderr = self._stderr - -class IOWrapper: - """Send output from a file-like object across a SocketProtocol - - XXX Should this be more tightly integrated with the CommandProtocol? - """ - - def __init__(self, name, cmdp): - self.name = name - self.cmdp = cmdp - self.buffer = [] - -class InputWrapper(IOWrapper): - def write(self, buf): - # XXX what should this do on Windows? - raise IOError, (9, '[Errno 9] Bad file descriptor') - - def read(self, arg=None): - if arg is not None: - if arg <= 0: - return '' - else: - arg = 0 - return self.cmdp.send(self.name, "read,%s" % arg) - - def readline(self): - return self.cmdp.send(self.name, "readline") - -class OutputWrapper(IOWrapper): - def write(self, buf): - self.cmdp.send(self.name, buf) - - def read(self, arg=None): - return '' - -class RemoteInterp: - def __init__(self, sock): - self._sock = SocketProtocol(sock) - self._cmd = CommandProtocol(self._sock) - self._cmd.registerHandler(self) - - def run(self): - try: - while 1: - self._cmd.dispatch() - except EOFError: - pass - - def handle_execfile(self, arg): - self._cmd.reply() - io = StdioRedirector(InputWrapper("stdin", self._cmd), - OutputWrapper("stdout", self._cmd), - OutputWrapper("stderr", self._cmd)) - io.redirect() - execfile(arg, {'__name__':'__main__'}) - io.restore() - self._cmd.send("terminated") - - def handle_quit(self, arg): - self._cmd.reply() - self._cmd.close() - -def startRemoteInterp(id): - import os - # UNIX domain sockets are simpler for starters - sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - sock.bind("/var/tmp/ri.%s" % id) - try: - sock.listen(1) - cli, addr = sock.accept() - rinterp = RemoteInterp(cli) - rinterp.run() - finally: - os.unlink("/var/tmp/ri.%s" % id) - -class RIClient: - """Client of the remote interpreter""" - def __init__(self, sock): - self._sock = SocketProtocol(sock) - self._cmd = CommandProtocol(self._sock) - self._cmd.registerHandler(self) - - def execfile(self, file): - self._cmd.send("execfile", file) - - def run(self): - try: - while 1: - self._cmd.dispatch() - except EOFError: - pass - - def handle_stdout(self, buf): - sys.stdout.write(buf) -## sys.stdout.flush() - - def handle_stderr(self, buf): - sys.stderr.write(buf) - - def handle_stdin(self, arg): - if arg == "readline": - return sys.stdin.readline() - i = arg.find(",") + 1 - bytes = int(arg[i:]) - if bytes == 0: - return sys.stdin.read() - else: - return sys.stdin.read(bytes) - - def handle_terminated(self, arg): - self._cmd.reply() - self._cmd.send("quit") - self._cmd.close() - -def riExec(id, file): - sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - sock.connect("/var/tmp/ri.%s" % id) - cli = RIClient(sock) - cli.execfile(file) - cli.run() - -if __name__ == "__main__": - import sys - import getopt - - SERVER = 1 - opts, args = getopt.getopt(sys.argv[1:], 'cv') - for o, v in opts: - if o == '-c': - SERVER = 0 - elif o == '-v': - VERBOSE = sys.stderr - id = args[0] - - if SERVER: - startRemoteInterp(id) - else: - file = args[1] - riExec(id, file) diff --git a/Lib/idlelib/ReplaceDialog.py b/Lib/idlelib/ReplaceDialog.py deleted file mode 100644 index 83462f9..0000000 --- a/Lib/idlelib/ReplaceDialog.py +++ /dev/null @@ -1,188 +0,0 @@ -import string -import os -import re -import fnmatch -from Tkinter import * -import tkMessageBox -import SearchEngine -from SearchDialogBase import SearchDialogBase - -def replace(text): - root = text._root() - engine = SearchEngine.get(root) - if not hasattr(engine, "_replacedialog"): - engine._replacedialog = ReplaceDialog(root, engine) - dialog = engine._replacedialog - dialog.open(text) - -class ReplaceDialog(SearchDialogBase): - - title = "Replace Dialog" - icon = "Replace" - - def __init__(self, root, engine): - SearchDialogBase.__init__(self, root, engine) - self.replvar = StringVar(root) - - def open(self, text): - SearchDialogBase.open(self, text) - try: - first = text.index("sel.first") - except TclError: - first = None - try: - last = text.index("sel.last") - except TclError: - last = None - first = first or text.index("insert") - last = last or first - self.show_hit(first, last) - self.ok = 1 - - def create_entries(self): - SearchDialogBase.create_entries(self) - self.replent = self.make_entry("Replace with:", self.replvar) - - def create_command_buttons(self): - SearchDialogBase.create_command_buttons(self) - self.make_button("Find", self.find_it) - self.make_button("Replace", self.replace_it) - self.make_button("Replace+Find", self.default_command, 1) - self.make_button("Replace All", self.replace_all) - - def find_it(self, event=None): - self.do_find(0) - - def replace_it(self, event=None): - if self.do_find(self.ok): - self.do_replace() - - def default_command(self, event=None): - if self.do_find(self.ok): - self.do_replace() - self.do_find(0) - - def replace_all(self, event=None): - prog = self.engine.getprog() - if not prog: - return - repl = self.replvar.get() - text = self.text - res = self.engine.search_text(text, prog) - if not res: - text.bell() - return - text.tag_remove("sel", "1.0", "end") - text.tag_remove("hit", "1.0", "end") - line = res[0] - col = res[1].start() - if self.engine.iswrap(): - line = 1 - col = 0 - ok = 1 - first = last = None - # XXX ought to replace circular instead of top-to-bottom when wrapping - text.undo_block_start() - while 1: - res = self.engine.search_forward(text, prog, line, col, 0, ok) - if not res: - break - line, m = res - chars = text.get("%d.0" % line, "%d.0" % (line+1)) - orig = m.group() - new = self._expand(m, repl) - i, j = m.span() - first = "%d.%d" % (line, i) - last = "%d.%d" % (line, j) - if new == orig: - text.mark_set("insert", last) - else: - text.mark_set("insert", first) - if first != last: - text.delete(first, last) - if new: - text.insert(first, new) - col = i + len(new) - ok = 0 - text.undo_block_stop() - if first and last: - self.show_hit(first, last) - self.close() - - def do_find(self, ok=0): - if not self.engine.getprog(): - return 0 - text = self.text - res = self.engine.search_text(text, None, ok) - if not res: - text.bell() - return 0 - line, m = res - i, j = m.span() - first = "%d.%d" % (line, i) - last = "%d.%d" % (line, j) - self.show_hit(first, last) - self.ok = 1 - return 1 - - def do_replace(self): - prog = self.engine.getprog() - if not prog: - return 0 - text = self.text - try: - first = pos = text.index("sel.first") - last = text.index("sel.last") - except TclError: - pos = None - if not pos: - first = last = pos = text.index("insert") - line, col = SearchEngine.get_line_col(pos) - chars = text.get("%d.0" % line, "%d.0" % (line+1)) - m = prog.match(chars, col) - if not prog: - return 0 - new = self._expand(m, self.replvar.get()) - text.mark_set("insert", first) - text.undo_block_start() - if m.group(): - text.delete(first, last) - if new: - text.insert(first, new) - text.undo_block_stop() - self.show_hit(first, text.index("insert")) - self.ok = 0 - return 1 - - def _expand(self, m, template): - # XXX This code depends on internals of the regular expression - # engine! There's no standard API to do a substitution when you - # have already found the match. One should be added. - # The solution here is designed to be backwards compatible - # with previous Python versions, e.g. 1.5.2. - # XXX This dynamic test should be done only once. - if getattr(re, "engine", "pre") == "pre": - return re.pcre_expand(m, template) - else: # sre - # XXX This import should be avoidable... - import sre_parse - # XXX This parses the template over and over... - ptemplate = sre_parse.parse_template(template, m.re) - return sre_parse.expand_template(ptemplate, m) - - def show_hit(self, first, last): - text = self.text - text.mark_set("insert", first) - text.tag_remove("sel", "1.0", "end") - text.tag_add("sel", first, last) - text.tag_remove("hit", "1.0", "end") - if first == last: - text.tag_add("hit", first) - else: - text.tag_add("hit", first, last) - text.see("insert") - text.update_idletasks() - - def close(self, event=None): - SearchDialogBase.close(self, event) - self.text.tag_remove("hit", "1.0", "end") diff --git a/Lib/idlelib/ScriptBinding.py b/Lib/idlelib/ScriptBinding.py deleted file mode 100644 index b54dfc4..0000000 --- a/Lib/idlelib/ScriptBinding.py +++ /dev/null @@ -1,173 +0,0 @@ -"""Extension to execute code outside the Python shell window. - -This adds the following commands (to the Edit menu, until there's a -separate Python menu): - -- Check module (Alt-F5) does a full syntax check of the current module. -It also runs the tabnanny to catch any inconsistent tabs. - -- Import module (F5) is equivalent to either import or reload of the -current module. The window must have been saved previously. The -module is added to sys.modules, and is also added to the __main__ -namespace. Output goes to the shell window. - -- Run module (Control-F5) does the same but executes the module's -code in the __main__ namespace. - -""" - -import sys -import os -import imp -import tkMessageBox - -indent_message = """Error: Inconsistent indentation detected! - -This means that either: - -(1) your indentation is outright incorrect (easy to fix), or - -(2) your indentation mixes tabs and spaces in a way that depends on \ -how many spaces a tab is worth. - -To fix case 2, change all tabs to spaces by using Select All followed \ -by Untabify Region (both in the Edit menu).""" - -class ScriptBinding: - - keydefs = { - '<>': ['', ''], - '<>': [''], - '<>': [''], - } - - menudefs = [ - ('edit', [None, - ('Check module', '<>'), - ('Import module', '<>'), - ('Run script', '<>'), - ] - ), - ] - - def __init__(self, editwin): - self.editwin = editwin - # Provide instance variables referenced by Debugger - # XXX This should be done differently - self.flist = self.editwin.flist - self.root = self.flist.root - - def check_module_event(self, event): - filename = self.getfilename() - if not filename: - return - if not self.tabnanny(filename): - return - if not self.checksyntax(filename): - return - - def tabnanny(self, filename): - import tabnanny - import tokenize - tabnanny.reset_globals() - f = open(filename, 'r') - try: - tokenize.tokenize(f.readline, tabnanny.tokeneater) - except tokenize.TokenError, msg: - self.errorbox("Token error", - "Token error:\n%s" % str(msg)) - return 0 - except tabnanny.NannyNag, nag: - # The error messages from tabnanny are too confusing... - self.editwin.gotoline(nag.get_lineno()) - self.errorbox("Tab/space error", indent_message) - return 0 - return 1 - - def checksyntax(self, filename): - f = open(filename, 'r') - source = f.read() - f.close() - if '\r' in source: - import re - source = re.sub(r"\r\n", "\n", source) - if source and source[-1] != '\n': - source = source + '\n' - try: - compile(source, filename, "exec") - except (SyntaxError, OverflowError), err: - try: - msg, (errorfilename, lineno, offset, line) = err - if not errorfilename: - err.args = msg, (filename, lineno, offset, line) - err.filename = filename - except: - lineno = None - msg = "*** " + str(err) - if lineno: - self.editwin.gotoline(lineno) - self.errorbox("Syntax error", - "There's an error in your program:\n" + msg) - return 1 - - def import_module_event(self, event): - filename = self.getfilename() - if not filename: - return - - modname, ext = os.path.splitext(os.path.basename(filename)) - if sys.modules.has_key(modname): - mod = sys.modules[modname] - else: - mod = imp.new_module(modname) - sys.modules[modname] = mod - mod.__file__ = filename - setattr(sys.modules['__main__'], modname, mod) - - dir = os.path.dirname(filename) - dir = os.path.normpath(os.path.abspath(dir)) - if dir not in sys.path: - sys.path.insert(0, dir) - - flist = self.editwin.flist - shell = flist.open_shell() - interp = shell.interp - interp.runcode("reload(%s)" % modname) - - def run_script_event(self, event): - filename = self.getfilename() - if not filename: - return - - flist = self.editwin.flist - shell = flist.open_shell() - interp = shell.interp - if (not sys.argv or - os.path.basename(sys.argv[0]) != os.path.basename(filename)): - # XXX Too often this discards arguments the user just set... - sys.argv = [filename] - interp.execfile(filename) - - def getfilename(self): - # Logic to make sure we have a saved filename - # XXX Better logic would offer to save! - if not self.editwin.get_saved(): - name = (self.editwin.short_title() or - self.editwin.long_title() or - "Untitled") - self.errorbox("Not saved", - "The buffer for %s is not saved.\n" % name + - "Please save it first!") - self.editwin.text.focus_set() - return - filename = self.editwin.io.filename - if not filename: - self.errorbox("No file name", - "This window has no file name") - return - return filename - - def errorbox(self, title, message): - # XXX This should really be a function of EditorWindow... - tkMessageBox.showerror(title, message, master=self.editwin.text) - self.editwin.text.focus_set() diff --git a/Lib/idlelib/ScrolledList.py b/Lib/idlelib/ScrolledList.py deleted file mode 100644 index 92119365..0000000 --- a/Lib/idlelib/ScrolledList.py +++ /dev/null @@ -1,139 +0,0 @@ -from Tkinter import * - -class ScrolledList: - - default = "(None)" - - def __init__(self, master, **options): - # Create top frame, with scrollbar and listbox - self.master = master - self.frame = frame = Frame(master) - self.frame.pack(fill="both", expand=1) - self.vbar = vbar = Scrollbar(frame, name="vbar") - self.vbar.pack(side="right", fill="y") - self.listbox = listbox = Listbox(frame, exportselection=0, - background="white") - if options: - listbox.configure(options) - listbox.pack(expand=1, fill="both") - # Tie listbox and scrollbar together - vbar["command"] = listbox.yview - listbox["yscrollcommand"] = vbar.set - # Bind events to the list box - listbox.bind("", self.click_event) - listbox.bind("", self.double_click_event) - listbox.bind("", self.popup_event) - listbox.bind("", self.up_event) - listbox.bind("", self.down_event) - # Mark as empty - self.clear() - - def close(self): - self.frame.destroy() - - def clear(self): - self.listbox.delete(0, "end") - self.empty = 1 - self.listbox.insert("end", self.default) - - def append(self, item): - if self.empty: - self.listbox.delete(0, "end") - self.empty = 0 - self.listbox.insert("end", str(item)) - - def get(self, index): - return self.listbox.get(index) - - def click_event(self, event): - self.listbox.activate("@%d,%d" % (event.x, event.y)) - index = self.listbox.index("active") - self.select(index) - self.on_select(index) - return "break" - - def double_click_event(self, event): - index = self.listbox.index("active") - self.select(index) - self.on_double(index) - return "break" - - menu = None - - def popup_event(self, event): - if not self.menu: - self.make_menu() - menu = self.menu - self.listbox.activate("@%d,%d" % (event.x, event.y)) - index = self.listbox.index("active") - self.select(index) - menu.tk_popup(event.x_root, event.y_root) - - def make_menu(self): - menu = Menu(self.listbox, tearoff=0) - self.menu = menu - self.fill_menu() - - def up_event(self, event): - index = self.listbox.index("active") - if self.listbox.selection_includes(index): - index = index - 1 - else: - index = self.listbox.size() - 1 - if index < 0: - self.listbox.bell() - else: - self.select(index) - self.on_select(index) - return "break" - - def down_event(self, event): - index = self.listbox.index("active") - if self.listbox.selection_includes(index): - index = index + 1 - else: - index = 0 - if index >= self.listbox.size(): - self.listbox.bell() - else: - self.select(index) - self.on_select(index) - return "break" - - def select(self, index): - self.listbox.focus_set() - self.listbox.activate(index) - self.listbox.selection_clear(0, "end") - self.listbox.selection_set(index) - self.listbox.see(index) - - # Methods to override for specific actions - - def fill_menu(self): - pass - - def on_select(self, index): - pass - - def on_double(self, index): - pass - - -def test(): - root = Tk() - root.protocol("WM_DELETE_WINDOW", root.destroy) - class MyScrolledList(ScrolledList): - def fill_menu(self): self.menu.add_command(label="pass") - def on_select(self, index): print "select", self.get(index) - def on_double(self, index): print "double", self.get(index) - s = MyScrolledList(root) - for i in range(30): - s.append("item %02d" % i) - return root - -def main(): - root = test() - root.mainloop() - -if __name__ == '__main__': - main() diff --git a/Lib/idlelib/SearchBinding.py b/Lib/idlelib/SearchBinding.py deleted file mode 100644 index 5943e3b..0000000 --- a/Lib/idlelib/SearchBinding.py +++ /dev/null @@ -1,97 +0,0 @@ -import tkSimpleDialog - -###$ event <> -###$ win -###$ unix - -###$ event <> -###$ win -###$ win -###$ unix - -###$ event <> -###$ win -###$ unix - -###$ event <> -###$ win - -###$ event <> -###$ win - -###$ event <> -###$ win -###$ unix - -class SearchBinding: - - windows_keydefs = { - '<>': ['', ''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - } - - unix_keydefs = { - '<>': [''], - '<>': ['', ''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': ['', ''], - } - - menudefs = [ - ('edit', [ - None, - ('_Find...', '<>'), - ('Find a_gain', '<>'), - ('Find _selection', '<>'), - ('Find in Files...', '<>'), - ('R_eplace...', '<>'), - ('Go to _line', '<>'), - ]), - ] - - def __init__(self, editwin): - self.editwin = editwin - - def find_event(self, event): - import SearchDialog - SearchDialog.find(self.editwin.text) - return "break" - - def find_again_event(self, event): - import SearchDialog - SearchDialog.find_again(self.editwin.text) - return "break" - - def find_selection_event(self, event): - import SearchDialog - SearchDialog.find_selection(self.editwin.text) - return "break" - - def find_in_files_event(self, event): - import GrepDialog - GrepDialog.grep(self.editwin.text, self.editwin.io, self.editwin.flist) - return "break" - - def replace_event(self, event): - import ReplaceDialog - ReplaceDialog.replace(self.editwin.text) - return "break" - - def goto_line_event(self, event): - text = self.editwin.text - lineno = tkSimpleDialog.askinteger("Goto", - "Go to line number:", - parent=text) - if lineno is None: - return "break" - if lineno <= 0: - text.bell() - return "break" - text.mark_set("insert", "%d.0" % lineno) - text.see("insert") diff --git a/Lib/idlelib/SearchDialog.py b/Lib/idlelib/SearchDialog.py deleted file mode 100644 index 0f0cb18..0000000 --- a/Lib/idlelib/SearchDialog.py +++ /dev/null @@ -1,67 +0,0 @@ -from Tkinter import * -import SearchEngine -from SearchDialogBase import SearchDialogBase - - -def _setup(text): - root = text._root() - engine = SearchEngine.get(root) - if not hasattr(engine, "_searchdialog"): - engine._searchdialog = SearchDialog(root, engine) - return engine._searchdialog - -def find(text): - return _setup(text).open(text) - -def find_again(text): - return _setup(text).find_again(text) - -def find_selection(text): - return _setup(text).find_selection(text) - -class SearchDialog(SearchDialogBase): - - def create_widgets(self): - f = SearchDialogBase.create_widgets(self) - self.make_button("Find", self.default_command, 1) - - def default_command(self, event=None): - if not self.engine.getprog(): - return - if self.find_again(self.text): - self.close() - - def find_again(self, text): - if not self.engine.getpat(): - self.open(text) - return 0 - if not self.engine.getprog(): - return 0 - res = self.engine.search_text(text) - if res: - line, m = res - i, j = m.span() - first = "%d.%d" % (line, i) - last = "%d.%d" % (line, j) - try: - selfirst = text.index("sel.first") - sellast = text.index("sel.last") - if selfirst == first and sellast == last: - text.bell() - return 0 - except TclError: - pass - text.tag_remove("sel", "1.0", "end") - text.tag_add("sel", first, last) - text.mark_set("insert", self.engine.isback() and first or last) - text.see("insert") - return 1 - else: - text.bell() - return 0 - - def find_selection(self, text): - pat = text.get("sel.first", "sel.last") - if pat: - self.engine.setcookedpat(pat) - return self.find_again(text) diff --git a/Lib/idlelib/SearchDialogBase.py b/Lib/idlelib/SearchDialogBase.py deleted file mode 100644 index faf5269..0000000 --- a/Lib/idlelib/SearchDialogBase.py +++ /dev/null @@ -1,129 +0,0 @@ -import string -from Tkinter import * - -class SearchDialogBase: - - title = "Search Dialog" - icon = "Search" - needwrapbutton = 1 - - def __init__(self, root, engine): - self.root = root - self.engine = engine - self.top = None - - def open(self, text): - self.text = text - if not self.top: - self.create_widgets() - else: - self.top.deiconify() - self.top.tkraise() - self.ent.focus_set() - self.ent.selection_range(0, "end") - self.ent.icursor(0) - self.top.grab_set() - - def close(self, event=None): - if self.top: - self.top.grab_release() - self.top.withdraw() - - def create_widgets(self): - top = Toplevel(self.root) - top.bind("", self.default_command) - top.bind("", self.close) - top.protocol("WM_DELETE_WINDOW", self.close) - top.wm_title(self.title) - top.wm_iconname(self.icon) - self.top = top - - self.row = 0 - self.top.grid_columnconfigure(0, weight=0) - self.top.grid_columnconfigure(1, weight=100) - - self.create_entries() - self.create_option_buttons() - self.create_other_buttons() - return self.create_command_buttons() - - def make_entry(self, label, var): - l = Label(self.top, text=label) - l.grid(row=self.row, col=0, sticky="w") - e = Entry(self.top, textvariable=var, exportselection=0) - e.grid(row=self.row, col=1, sticky="we") - self.row = self.row + 1 - return e - - def make_frame(self): - f = Frame(self.top) - f.grid(row=self.row, col=0, columnspan=2, sticky="we") - self.row = self.row + 1 - return f - - def make_button(self, label, command, isdef=0, side="left"): - b = Button(self.buttonframe, - text=label, command=command, - default=isdef and "active" or "normal") - b.pack(side=side) - return b - - def create_entries(self): - self.ent = self.make_entry("Find:", self.engine.patvar) - - def create_option_buttons(self): - f = self.make_frame() - - btn = Checkbutton(f, anchor="w", - variable=self.engine.revar, - text="Regular expression") - btn.pack(side="left", fill="both") - if self.engine.isre(): - btn.select() - - btn = Checkbutton(f, anchor="w", - variable=self.engine.casevar, - text="Match case") - btn.pack(side="left", fill="both") - if self.engine.iscase(): - btn.select() - - btn = Checkbutton(f, anchor="w", - variable=self.engine.wordvar, - text="Whole word") - btn.pack(side="left", fill="both") - if self.engine.isword(): - btn.select() - - if self.needwrapbutton: - btn = Checkbutton(f, anchor="w", - variable=self.engine.wrapvar, - text="Wrap around") - btn.pack(side="left", fill="both") - if self.engine.iswrap(): - btn.select() - - def create_other_buttons(self): - f = self.make_frame() - - lbl = Label(f, text="Direction: ") - lbl.pack(side="left") - - btn = Radiobutton(f, anchor="w", - variable=self.engine.backvar, value=1, - text="Up") - btn.pack(side="left", fill="both") - if self.engine.isback(): - btn.select() - - btn = Radiobutton(f, anchor="w", - variable=self.engine.backvar, value=0, - text="Down") - btn.pack(side="left", fill="both") - if not self.engine.isback(): - btn.select() - - def create_command_buttons(self): - f = self.buttonframe = self.make_frame() - b = self.make_button("close", self.close, side="right") - b.lower() diff --git a/Lib/idlelib/SearchEngine.py b/Lib/idlelib/SearchEngine.py deleted file mode 100644 index e379751..0000000 --- a/Lib/idlelib/SearchEngine.py +++ /dev/null @@ -1,221 +0,0 @@ -import string -import re -from Tkinter import * -import tkMessageBox - -def get(root): - if not hasattr(root, "_searchengine"): - root._searchengine = SearchEngine(root) - # XXX This will never garbage-collect -- who cares - return root._searchengine - -class SearchEngine: - - def __init__(self, root): - self.root = root - # State shared by search, replace, and grep; - # the search dialogs bind these to UI elements. - self.patvar = StringVar(root) # search pattern - self.revar = BooleanVar(root) # regular expression? - self.casevar = BooleanVar(root) # match case? - self.wordvar = BooleanVar(root) # match whole word? - self.wrapvar = BooleanVar(root) # wrap around buffer? - self.wrapvar.set(1) # (on by default) - self.backvar = BooleanVar(root) # search backwards? - - # Access methods - - def getpat(self): - return self.patvar.get() - - def setpat(self, pat): - self.patvar.set(pat) - - def isre(self): - return self.revar.get() - - def iscase(self): - return self.casevar.get() - - def isword(self): - return self.wordvar.get() - - def iswrap(self): - return self.wrapvar.get() - - def isback(self): - return self.backvar.get() - - # Higher level access methods - - def getcookedpat(self): - pat = self.getpat() - if not self.isre(): - pat = re.escape(pat) - if self.isword(): - pat = r"\b%s\b" % pat - return pat - - def getprog(self): - pat = self.getpat() - if not pat: - self.report_error(pat, "Empty regular expression") - return None - pat = self.getcookedpat() - flags = 0 - if not self.iscase(): - flags = flags | re.IGNORECASE - try: - prog = re.compile(pat, flags) - except re.error, what: - try: - msg, col = what - except: - msg = str(what) - col = -1 - self.report_error(pat, msg, col) - return None - return prog - - def report_error(self, pat, msg, col=-1): - # Derived class could overrid this with something fancier - msg = "Error: " + str(msg) - if pat: - msg = msg + "\np\Pattern: " + str(pat) - if col >= 0: - msg = msg + "\nOffset: " + str(col) - tkMessageBox.showerror("Regular expression error", - msg, master=self.root) - - def setcookedpat(self, pat): - if self.isre(): - pat = re.escape(pat) - self.setpat(pat) - - def search_text(self, text, prog=None, ok=0): - """Search a text widget for the pattern. - - If prog is given, it should be the precompiled pattern. - Return a tuple (lineno, matchobj); None if not found. - - This obeys the wrap and direction (back) settings. - - The search starts at the selection (if there is one) or - at the insert mark (otherwise). If the search is forward, - it starts at the right of the selection; for a backward - search, it starts at the left end. An empty match exactly - at either end of the selection (or at the insert mark if - there is no selection) is ignored unless the ok flag is true - -- this is done to guarantee progress. - - If the search is allowed to wrap around, it will return the - original selection if (and only if) it is the only match. - - """ - if not prog: - prog = self.getprog() - if not prog: - return None # Compilation failed -- stop - wrap = self.wrapvar.get() - first, last = get_selection(text) - if self.isback(): - if ok: - start = last - else: - start = first - line, col = get_line_col(start) - res = self.search_backward(text, prog, line, col, wrap, ok) - else: - if ok: - start = first - else: - start = last - line, col = get_line_col(start) - res = self.search_forward(text, prog, line, col, wrap, ok) - return res - - def search_forward(self, text, prog, line, col, wrap, ok=0): - wrapped = 0 - startline = line - chars = text.get("%d.0" % line, "%d.0" % (line+1)) - while chars: - m = prog.search(chars[:-1], col) - if m: - if ok or m.end() > col: - return line, m - line = line + 1 - if wrapped and line > startline: - break - col = 0 - ok = 1 - chars = text.get("%d.0" % line, "%d.0" % (line+1)) - if not chars and wrap: - wrapped = 1 - wrap = 0 - line = 1 - chars = text.get("1.0", "2.0") - return None - - def search_backward(self, text, prog, line, col, wrap, ok=0): - wrapped = 0 - startline = line - chars = text.get("%d.0" % line, "%d.0" % (line+1)) - while 1: - m = search_reverse(prog, chars[:-1], col) - if m: - if ok or m.start() < col: - return line, m - line = line - 1 - if wrapped and line < startline: - break - ok = 1 - if line <= 0: - if not wrap: - break - wrapped = 1 - wrap = 0 - pos = text.index("end-1c") - line, col = map(int, string.split(pos, ".")) - chars = text.get("%d.0" % line, "%d.0" % (line+1)) - col = len(chars) - 1 - return None - -# Helper to search backwards in a string. -# (Optimized for the case where the pattern isn't found.) - -def search_reverse(prog, chars, col): - m = prog.search(chars) - if not m: - return None - found = None - i, j = m.span() - while i < col and j <= col: - found = m - if i == j: - j = j+1 - m = prog.search(chars, j) - if not m: - break - i, j = m.span() - return found - -# Helper to get selection end points, defaulting to insert mark. -# Return a tuple of indices ("line.col" strings). - -def get_selection(text): - try: - first = text.index("sel.first") - last = text.index("sel.last") - except TclError: - first = last = None - if not first: - first = text.index("insert") - if not last: - last = first - return first, last - -# Helper to parse a text index into a (line, col) tuple. - -def get_line_col(index): - line, col = map(int, string.split(index, ".")) # Fails on invalid index - return line, col diff --git a/Lib/idlelib/Separator.py b/Lib/idlelib/Separator.py deleted file mode 100644 index 7145559..0000000 --- a/Lib/idlelib/Separator.py +++ /dev/null @@ -1,92 +0,0 @@ -from Tkinter import * - -class Separator: - - def __init__(self, master, orient, min=10, thickness=5, bg=None): - self.min = max(1, min) - self.thickness = max(1, thickness) - if orient in ("h", "horizontal"): - self.side = "left" - self.dim = "width" - self.dir = "x" - self.cursor = "sb_h_double_arrow" - elif orient in ("v", "vertical"): - self.side = "top" - self.dim = "height" - self.dir = "y" - self.cursor = "sb_v_double_arrow" - else: - raise ValueError, "Separator: orient should be h or v" - self.winfo_dim = "winfo_" + self.dim - self.master = master = Frame(master) - master.pack(expand=1, fill="both") - self.f1 = Frame(master) - self.f1.pack(expand=1, fill="both", side=self.side) - self.div = Frame(master, cursor=self.cursor) - self.div[self.dim] = self.thickness - self.div.pack(fill="both", side=self.side) - self.f2 = Frame(master) - self.f2.pack(expand=1, fill="both", side=self.side) - self.div.bind("", self.divider_press) - if bg: - ##self.f1["bg"] = bg - ##self.f2["bg"] = bg - self.div["bg"] = bg - - def parts(self): - return self.f1, self.f2 - - def divider_press(self, event): - self.press_event = event - self.f1.pack_propagate(0) - self.f2.pack_propagate(0) - for f in self.f1, self.f2: - for dim in "width", "height": - f[dim] = getattr(f, "winfo_"+dim)() - self.div.bind("", self.div_motion) - self.div.bind("", self.div_release) - self.div.grab_set() - - def div_motion(self, event): - delta = getattr(event, self.dir) - getattr(self.press_event, self.dir) - if delta: - dim1 = getattr(self.f1, self.winfo_dim)() - dim2 = getattr(self.f2, self.winfo_dim)() - delta = max(delta, self.min-dim1) - delta = min(delta, dim2-self.min) - dim1 = dim1 + delta - dim2 = dim2 - delta - self.f1[self.dim] = dim1 - self.f2[self.dim] = dim2 - - def div_release(self, event): - self.div_motion(event) - self.div.unbind("") - self.div.grab_release() - -class VSeparator(Separator): - - def __init__(self, master, min=10, thickness=5, bg=None): - Separator.__init__(self, master, "v", min, thickness, bg) - -class HSeparator(Separator): - - def __init__(self, master, min=10, thickness=5, bg=None): - Separator.__init__(self, master, "h", min, thickness, bg) - -def main(): - root = Tk() - tlist = [] - outer = HSeparator(root, bg="red") - for part in outer.parts(): - inner = VSeparator(part, bg="blue") - for f in inner.parts(): - t = Text(f, width=40, height=10, borderwidth=0) - t.pack(fill="both", expand=1) - tlist.append(t) - tlist[0].insert("1.0", "Make your own Mondrian!") - tlist[1].insert("1.0", "Move the colored dividers...") - root.mainloop() - -if __name__ == '__main__': - main() diff --git a/Lib/idlelib/StackViewer.py b/Lib/idlelib/StackViewer.py deleted file mode 100644 index d70658b..0000000 --- a/Lib/idlelib/StackViewer.py +++ /dev/null @@ -1,147 +0,0 @@ -import os -import sys -import string -import linecache - -from TreeWidget import TreeNode, TreeItem, ScrolledCanvas -from ObjectBrowser import ObjectTreeItem, make_objecttreeitem -from OldStackViewer import StackViewer, NamespaceViewer - -def StackBrowser(root, flist=None, tb=None, top=None): - if top is None: - from Tkinter import Toplevel - top = Toplevel(root) - sc = ScrolledCanvas(top, bg="white", highlightthickness=0) - sc.frame.pack(expand=1, fill="both") - item = StackTreeItem(flist, tb) - node = TreeNode(sc.canvas, None, item) - node.expand() - -class StackTreeItem(TreeItem): - - def __init__(self, flist=None, tb=None): - self.flist = flist - self.stack = get_stack(tb) - self.text = get_exception() - - def GetText(self): - return self.text - - def GetSubList(self): - sublist = [] - for info in self.stack: - item = FrameTreeItem(info, self.flist) - sublist.append(item) - return sublist - -class FrameTreeItem(TreeItem): - - def __init__(self, info, flist): - self.info = info - self.flist = flist - - def GetText(self): - frame, lineno = self.info - try: - modname = frame.f_globals["__name__"] - except: - modname = "?" - code = frame.f_code - filename = code.co_filename - funcname = code.co_name - sourceline = linecache.getline(filename, lineno) - sourceline = string.strip(sourceline) - if funcname in ("?", "", None): - item = "%s, line %d: %s" % (modname, lineno, sourceline) - else: - item = "%s.%s(...), line %d: %s" % (modname, funcname, - lineno, sourceline) -## if i == index: -## item = "> " + item - return item - - def GetSubList(self): - frame, lineno = self.info - sublist = [] - if frame.f_globals is not frame.f_locals: - item = VariablesTreeItem("", frame.f_locals, self.flist) - sublist.append(item) - item = VariablesTreeItem("", frame.f_globals, self.flist) - sublist.append(item) - return sublist - - def OnDoubleClick(self): - if self.flist: - frame, lineno = self.info - filename = frame.f_code.co_filename - if os.path.isfile(filename): - self.flist.gotofileline(filename, lineno) - -class VariablesTreeItem(ObjectTreeItem): - - def GetText(self): - return self.labeltext - - def GetLabelText(self): - return None - - def IsExpandable(self): - return len(self.object) > 0 - - def keys(self): - return self.object.keys() - - def GetSubList(self): - sublist = [] - for key in self.keys(): - try: - value = self.object[key] - except KeyError: - continue - def setfunction(value, key=key, object=self.object): - object[key] = value - item = make_objecttreeitem(key + " =", value, setfunction) - sublist.append(item) - return sublist - -def get_stack(t=None, f=None): - if t is None: - t = sys.last_traceback - stack = [] - if t and t.tb_frame is f: - t = t.tb_next - while f is not None: - stack.append((f, f.f_lineno)) - if f is self.botframe: - break - f = f.f_back - stack.reverse() - while t is not None: - stack.append((t.tb_frame, t.tb_lineno)) - t = t.tb_next - return stack - -def get_exception(type=None, value=None): - if type is None: - type = sys.last_type - value = sys.last_value - if hasattr(type, "__name__"): - type = type.__name__ - s = str(type) - if value is not None: - s = s + ": " + str(value) - return s - -def _test(): - try: - import testcode - reload(testcode) - except: - sys.last_type, sys.last_value, sys.last_traceback = sys.exc_info() - from Tkinter import Tk - root = Tk() - StackBrowser(None, top=root) - root.mainloop() - -if __name__ == "__main__": - _test() diff --git a/Lib/idlelib/TODO.txt b/Lib/idlelib/TODO.txt deleted file mode 100644 index 96b0450..0000000 --- a/Lib/idlelib/TODO.txt +++ /dev/null @@ -1,212 +0,0 @@ -Original IDLE todo, much of it now outdated: -============================================ -TO DO: - -- improve debugger: - - manage breakpoints globally, allow bp deletion, tbreak, cbreak etc. - - real object browser - - help on how to use it (a simple help button will do wonders) - - performance? (updates of large sets of locals are slow) - - better integration of "debug module" - - debugger should be global resource (attached to flist, not to shell) - - fix the stupid bug where you need to step twice - - display class name in stack viewer entries for methods - - suppress tracing through IDLE internals (e.g. print) - - add a button to suppress through a specific module or class or method - - more object inspection to stack viewer, e.g. to view all array items -- insert the initial current directory into sys.path -- default directory attribute for each window instead of only for windows - that have an associated filename -- command expansion from keywords, module contents, other buffers, etc. -- "Recent documents" menu item -- Filter region command -- Optional horizontal scroll bar -- more Emacsisms: - - ^K should cut to buffer - - M-[, M-] to move by paragraphs - - incremental search? -- search should indicate wrap-around in some way -- restructure state sensitive code to avoid testing flags all the time -- persistent user state (e.g. window and cursor positions, bindings) -- make backups when saving -- check file mtimes at various points -- Pluggable interface with RCS/CVS/Perforce/Clearcase -- better help? -- don't open second class browser on same module (nor second path browser) -- unify class and path browsers -- Need to define a standard way whereby one can determine one is running - inside IDLE (needed for Tk mainloop, also handy for $PYTHONSTARTUP) -- Add more utility methods for use by extensions (a la get_selection) -- Way to run command in totally separate interpreter (fork+os.system?) -- Way to find definition of fully-qualified name: - In other words, select "UserDict.UserDict", hit some magic key and - it loads up UserDict.py and finds the first def or class for UserDict. -- need a way to force colorization on/off -- need a way to force auto-indent on/off - -Details: - -- when there's a selection, left/right arrow should go to either - end of the selection -- ^O (on Unix -- open-line) should honor autoindent -- after paste, show end of pasted text -- on Windows, should turn short filename to long filename (not only in argv!) - (shouldn't this be done -- or undone -- by ntpath.normpath?) -- new autoindent after colon even indents when the colon is in a comment! -- sometimes forward slashes in pathname remain -- sometimes star in window name remains in Windows menu -- With unix bindings, ESC by itself is ignored -- Sometimes for no apparent reason a selection from the cursor to the - end of the command buffer appears, which is hard to get rid of - because it stays when you are typing! -- The Line/Col in the status bar can be wrong initially in PyShell - -Structural problems: - -- too much knowledge in FileList about EditorWindow (for example) -- should add some primitives for accessing the selection etc. - to repeat cumbersome code over and over - -====================================================================== - -Jeff Bauer suggests: - -- Open Module doesn't appear to handle hierarchical packages. -- Class browser should also allow hierarchical packages. -- Open and Open Module could benefit from a history, - either command line style, or Microsoft recent-file - style. -- Add a Smalltalk-style inspector (i.e. Tkinspect) - -The last suggestion is already a reality, but not yet -integrated into IDLE. I use a module called inspector.py, -that used to be available from python.org(?) It no longer -appears to be in the contributed section, and the source -has no author attribution. - -In any case, the code is useful for visually navigating -an object's attributes, including its container hierarchy. - - >>> from inspector import Tkinspect - >>> Tkinspect(None, myObject) - -Tkinspect could probably be extended and refined to -integrate better into IDLE. - -====================================================================== - -Comparison to PTUI ------------------- - -+ PTUI's help is better (HTML!) - -+ PTUI can attach a shell to any module - -+ PTUI has some more I/O commands: - open multiple - append - examine (what's that?) - -====================================================================== - -Notes after trying to run Grail -------------------------------- - -- Grail does stuff to sys.path based on sys.argv[0]; you must set -sys.argv[0] to something decent first (it is normally set to the path of -the idle script). - -- Grail must be exec'ed in __main__ because that's imported by some -other parts of Grail. - -- Grail uses a module called History and so does idle :-( - -====================================================================== - -Robin Friedrich's items: - -Things I'd like to see: - - I'd like support for shift-click extending the selection. There's a - bug now that it doesn't work the first time you try it. - - Printing is needed. How hard can that be on Windows? - - The python-mode trick of autoindenting a line with is neat and - very handy. - - (someday) a spellchecker for docstrings and comments. - - a pagedown/up command key which moves to next class/def statement (top - level) - - split window capability - - DnD text relocation/copying - -Things I don't want to see. - - line numbers... will probably slow things down way too much. - - Please use another icon for the tree browser leaf. The small snake - isn't cutting it. - ----------------------------------------------------------------------- - -- Customizable views (multi-window or multi-pane). (Markus Gritsch) - -- Being able to double click (maybe double right click) on a callable -object in the editor which shows the source of the object, if -possible. (Gerrit Holl) - -- Hooks into the guts, like in Emacs. (Mike Romberg) - -- Sharing the editor with a remote tutor. (Martijn Faassen) - -- Multiple views on the same file. (Tony J Ibbs) - -- Store breakpoints in a global (per-project) database (GvR); Dirk -Heise adds: save some space-trimmed context and search around when -reopening a file that might have been edited by someone else. - -- Capture menu events in extensions without changing the IDLE source. -(Matthias Barmeier) - -- Use overlapping panels (a "notebook" in MFC terms I think) for info -that doesn't need to be accessible simultaneously (e.g. HTML source -and output). Use multi-pane windows for info that does need to be -shown together (e.g. class browser and source). (Albert Brandl) - -- A project should invisibly track all symbols, for instant search, -replace and cross-ref. Projects should be allowed to span multiple -directories, hosts, etc. Project management files are placed in a -directory you specify. A global mapping between project names and -project directories should exist [not so sure --GvR]. (Tim Peters) - -- Merge attr-tips and auto-expand. (Mark Hammond, Tim Peters) - -- Python Shell should behave more like a "shell window" as users know -it -- i.e. you can only edit the current command, and the cursor can't -escape from the command area. (Albert Brandl) - -- Set X11 class to "idle/Idle", set icon and title to something -beginning with "idle" -- for window manangers. (Randall Hopper) - -- Config files editable through a preferences dialog. (me) - -- Config files still editable outside the preferences dialog. -(Randall Hopper) - -- When you're editing a command in PyShell, and there are only blank -lines below the cursor, hitting Return should ignore or delete those -blank lines rather than deciding you're not on the last line. (me) - -- Run command (F5 c.s.) should be more like Pythonwin's Run -- a -dialog with options to give command line arguments, run the debugger, -etc. (me) - -- Shouldn't be able to delete part of the prompt (or any text before -it) in the PyShell. (Martijn Faassen) - -- Emacs style auto-fill (also smart about comments and strings). -(Jeremy Hylton) - -- Output of Run Script should go to a separate output window, not to -the shell window. Output of separate runs should all go to the same -window but clearly delimited. (David Scherer) - -- GUI form designer to kick VB's butt. (Robert Geiger) - -- Printing! Possibly via generation of PDF files which the user must -then send to the printer separately. (Dinu Gherman) diff --git a/Lib/idlelib/ToolTip.py b/Lib/idlelib/ToolTip.py deleted file mode 100644 index eadcdea..0000000 --- a/Lib/idlelib/ToolTip.py +++ /dev/null @@ -1,87 +0,0 @@ -# Ideas gleaned from PySol - -import os -from Tkinter import * - -class ToolTipBase: - - def __init__(self, button): - self.button = button - self.tipwindow = None - self.id = None - self.x = self.y = 0 - self._id1 = self.button.bind("", self.enter) - self._id2 = self.button.bind("", self.leave) - self._id3 = self.button.bind("", self.leave) - - def enter(self, event=None): - self.schedule() - - def leave(self, event=None): - self.unschedule() - self.hidetip() - - def schedule(self): - self.unschedule() - self.id = self.button.after(1500, self.showtip) - - def unschedule(self): - id = self.id - self.id = None - if id: - self.button.after_cancel(id) - - def showtip(self): - if self.tipwindow: - return - # The tip window must be completely outside the button; - # otherwise when the mouse enters the tip window we get - # a leave event and it disappears, and then we get an enter - # event and it reappears, and so on forever :-( - x = self.button.winfo_rootx() + 20 - y = self.button.winfo_rooty() + self.button.winfo_height() + 1 - self.tipwindow = tw = Toplevel(self.button) - tw.wm_overrideredirect(1) - tw.wm_geometry("+%d+%d" % (x, y)) - self.showcontents() - - def showcontents(self, text="Your text here"): - # Override this in derived class - label = Label(self.tipwindow, text=text, justify=LEFT, - background="#ffffe0", relief=SOLID, borderwidth=1) - label.pack() - - def hidetip(self): - tw = self.tipwindow - self.tipwindow = None - if tw: - tw.destroy() - -class ToolTip(ToolTipBase): - def __init__(self, button, text): - ToolTipBase.__init__(self, button) - self.text = text - def showcontents(self): - ToolTipBase.showcontents(self, self.text) - -class ListboxToolTip(ToolTipBase): - def __init__(self, button, items): - ToolTipBase.__init__(self, button) - self.items = items - def showcontents(self): - listbox = Listbox(self.tipwindow, background="#ffffe0") - listbox.pack() - for item in self.items: - listbox.insert(END, item) - -def main(): - # Test code - root = Tk() - b = Button(root, text="Hello", command=root.destroy) - b.pack() - root.update() - tip = ListboxToolTip(b, ["Hello", "world"]) - - # root.mainloop() # not in idle - -main() diff --git a/Lib/idlelib/TreeWidget.py b/Lib/idlelib/TreeWidget.py deleted file mode 100644 index 60eefdc..0000000 --- a/Lib/idlelib/TreeWidget.py +++ /dev/null @@ -1,471 +0,0 @@ -# XXX TO DO: -# - popup menu -# - support partial or total redisplay -# - key bindings (instead of quick-n-dirty bindings on Canvas): -# - up/down arrow keys to move focus around -# - ditto for page up/down, home/end -# - left/right arrows to expand/collapse & move out/in -# - more doc strings -# - add icons for "file", "module", "class", "method"; better "python" icon -# - callback for selection??? -# - multiple-item selection -# - tooltips -# - redo geometry without magic numbers -# - keep track of object ids to allow more careful cleaning -# - optimize tree redraw after expand of subnode - -import os -import sys -import string -from Tkinter import * -import imp - -import ZoomHeight - -ICONDIR = "Icons" - -# Look for Icons subdirectory in the same directory as this module -try: - _icondir = os.path.join(os.path.dirname(__file__), ICONDIR) -except NameError: - _icondir = ICONDIR -if os.path.isdir(_icondir): - ICONDIR = _icondir -elif not os.path.isdir(ICONDIR): - raise RuntimeError, "can't find icon directory (%s)" % `ICONDIR` - -def listicons(icondir=ICONDIR): - """Utility to display the available icons.""" - root = Tk() - import glob - list = glob.glob(os.path.join(icondir, "*.gif")) - list.sort() - images = [] - row = column = 0 - for file in list: - name = os.path.splitext(os.path.basename(file))[0] - image = PhotoImage(file=file, master=root) - images.append(image) - label = Label(root, image=image, bd=1, relief="raised") - label.grid(row=row, column=column) - label = Label(root, text=name) - label.grid(row=row+1, column=column) - column = column + 1 - if column >= 10: - row = row+2 - column = 0 - root.images = images - - -class TreeNode: - - def __init__(self, canvas, parent, item): - self.canvas = canvas - self.parent = parent - self.item = item - self.state = 'collapsed' - self.selected = 0 - self.children = [] - self.x = self.y = None - self.iconimages = {} # cache of PhotoImage instances for icons - - def destroy(self): - for c in self.children[:]: - self.children.remove(c) - c.destroy() - self.parent = None - - def geticonimage(self, name): - try: - return self.iconimages[name] - except KeyError: - pass - file, ext = os.path.splitext(name) - ext = ext or ".gif" - fullname = os.path.join(ICONDIR, file + ext) - image = PhotoImage(master=self.canvas, file=fullname) - self.iconimages[name] = image - return image - - def select(self, event=None): - if self.selected: - return - self.deselectall() - self.selected = 1 - self.canvas.delete(self.image_id) - self.drawicon() - self.drawtext() - - def deselect(self, event=None): - if not self.selected: - return - self.selected = 0 - self.canvas.delete(self.image_id) - self.drawicon() - self.drawtext() - - def deselectall(self): - if self.parent: - self.parent.deselectall() - else: - self.deselecttree() - - def deselecttree(self): - if self.selected: - self.deselect() - for child in self.children: - child.deselecttree() - - def flip(self, event=None): - if self.state == 'expanded': - self.collapse() - else: - self.expand() - self.item.OnDoubleClick() - return "break" - - def expand(self, event=None): - if not self.item._IsExpandable(): - return - if self.state != 'expanded': - self.state = 'expanded' - self.update() - self.view() - - def collapse(self, event=None): - if self.state != 'collapsed': - self.state = 'collapsed' - self.update() - - def view(self): - top = self.y - 2 - bottom = self.lastvisiblechild().y + 17 - height = bottom - top - visible_top = self.canvas.canvasy(0) - visible_height = self.canvas.winfo_height() - visible_bottom = self.canvas.canvasy(visible_height) - if visible_top <= top and bottom <= visible_bottom: - return - x0, y0, x1, y1 = self.canvas._getints(self.canvas['scrollregion']) - if top >= visible_top and height <= visible_height: - fraction = top + height - visible_height - else: - fraction = top - fraction = float(fraction) / y1 - self.canvas.yview_moveto(fraction) - - def lastvisiblechild(self): - if self.children and self.state == 'expanded': - return self.children[-1].lastvisiblechild() - else: - return self - - def update(self): - if self.parent: - self.parent.update() - else: - oldcursor = self.canvas['cursor'] - self.canvas['cursor'] = "watch" - self.canvas.update() - self.canvas.delete(ALL) # XXX could be more subtle - self.draw(7, 2) - x0, y0, x1, y1 = self.canvas.bbox(ALL) - self.canvas.configure(scrollregion=(0, 0, x1, y1)) - self.canvas['cursor'] = oldcursor - - def draw(self, x, y): - # XXX This hard-codes too many geometry constants! - self.x, self.y = x, y - self.drawicon() - self.drawtext() - if self.state != 'expanded': - return y+17 - # draw children - if not self.children: - sublist = self.item._GetSubList() - if not sublist: - # _IsExpandable() was mistaken; that's allowed - return y+17 - for item in sublist: - child = TreeNode(self.canvas, self, item) - self.children.append(child) - cx = x+20 - cy = y+17 - cylast = 0 - for child in self.children: - cylast = cy - self.canvas.create_line(x+9, cy+7, cx, cy+7, fill="gray50") - cy = child.draw(cx, cy) - if child.item._IsExpandable(): - if child.state == 'expanded': - iconname = "minusnode" - callback = child.collapse - else: - iconname = "plusnode" - callback = child.expand - image = self.geticonimage(iconname) - id = self.canvas.create_image(x+9, cylast+7, image=image) - # XXX This leaks bindings until canvas is deleted: - self.canvas.tag_bind(id, "<1>", callback) - self.canvas.tag_bind(id, "", lambda x: None) - id = self.canvas.create_line(x+9, y+10, x+9, cylast+7, - ##stipple="gray50", # XXX Seems broken in Tk 8.0.x - fill="gray50") - self.canvas.tag_lower(id) # XXX .lower(id) before Python 1.5.2 - return cy - - def drawicon(self): - if self.selected: - imagename = (self.item.GetSelectedIconName() or - self.item.GetIconName() or - "openfolder") - else: - imagename = self.item.GetIconName() or "folder" - image = self.geticonimage(imagename) - id = self.canvas.create_image(self.x, self.y, anchor="nw", image=image) - self.image_id = id - self.canvas.tag_bind(id, "<1>", self.select) - self.canvas.tag_bind(id, "", self.flip) - - def drawtext(self): - textx = self.x+20-1 - texty = self.y-1 - labeltext = self.item.GetLabelText() - if labeltext: - id = self.canvas.create_text(textx, texty, anchor="nw", - text=labeltext) - self.canvas.tag_bind(id, "<1>", self.select) - self.canvas.tag_bind(id, "", self.flip) - x0, y0, x1, y1 = self.canvas.bbox(id) - textx = max(x1, 200) + 10 - text = self.item.GetText() or "" - try: - self.entry - except AttributeError: - pass - else: - self.edit_finish() - try: - label = self.label - except AttributeError: - # padding carefully selected (on Windows) to match Entry widget: - self.label = Label(self.canvas, text=text, bd=0, padx=2, pady=2) - if self.selected: - self.label.configure(fg="white", bg="darkblue") - else: - self.label.configure(fg="black", bg="white") - id = self.canvas.create_window(textx, texty, - anchor="nw", window=self.label) - self.label.bind("<1>", self.select_or_edit) - self.label.bind("", self.flip) - self.text_id = id - - def select_or_edit(self, event=None): - if self.selected and self.item.IsEditable(): - self.edit(event) - else: - self.select(event) - - def edit(self, event=None): - self.entry = Entry(self.label, bd=0, highlightthickness=1, width=0) - self.entry.insert(0, self.label['text']) - self.entry.selection_range(0, END) - self.entry.pack(ipadx=5) - self.entry.focus_set() - self.entry.bind("", self.edit_finish) - self.entry.bind("", self.edit_cancel) - - def edit_finish(self, event=None): - try: - entry = self.entry - del self.entry - except AttributeError: - return - text = entry.get() - entry.destroy() - if text and text != self.item.GetText(): - self.item.SetText(text) - text = self.item.GetText() - self.label['text'] = text - self.drawtext() - self.canvas.focus_set() - - def edit_cancel(self, event=None): - self.drawtext() - self.canvas.focus_set() - - -class TreeItem: - - """Abstract class representing tree items. - - Methods should typically be overridden, otherwise a default action - is used. - - """ - - def __init__(self): - """Constructor. Do whatever you need to do.""" - - def GetText(self): - """Return text string to display.""" - - def GetLabelText(self): - """Return label text string to display in front of text (if any).""" - - expandable = None - - def _IsExpandable(self): - """Do not override! Called by TreeNode.""" - if self.expandable is None: - self.expandable = self.IsExpandable() - return self.expandable - - def IsExpandable(self): - """Return whether there are subitems.""" - return 1 - - def _GetSubList(self): - """Do not override! Called by TreeNode.""" - if not self.IsExpandable(): - return [] - sublist = self.GetSubList() - if not sublist: - self.expandable = 0 - return sublist - - def IsEditable(self): - """Return whether the item's text may be edited.""" - - def SetText(self, text): - """Change the item's text (if it is editable).""" - - def GetIconName(self): - """Return name of icon to be displayed normally.""" - - def GetSelectedIconName(self): - """Return name of icon to be displayed when selected.""" - - def GetSubList(self): - """Return list of items forming sublist.""" - - def OnDoubleClick(self): - """Called on a double-click on the item.""" - - -# Example application - -class FileTreeItem(TreeItem): - - """Example TreeItem subclass -- browse the file system.""" - - def __init__(self, path): - self.path = path - - def GetText(self): - return os.path.basename(self.path) or self.path - - def IsEditable(self): - return os.path.basename(self.path) != "" - - def SetText(self, text): - newpath = os.path.dirname(self.path) - newpath = os.path.join(newpath, text) - if os.path.dirname(newpath) != os.path.dirname(self.path): - return - try: - os.rename(self.path, newpath) - self.path = newpath - except os.error: - pass - - def GetIconName(self): - if not self.IsExpandable(): - return "python" # XXX wish there was a "file" icon - - def IsExpandable(self): - return os.path.isdir(self.path) - - def GetSubList(self): - try: - names = os.listdir(self.path) - except os.error: - return [] - names.sort(lambda a, b: cmp(os.path.normcase(a), os.path.normcase(b))) - sublist = [] - for name in names: - item = FileTreeItem(os.path.join(self.path, name)) - sublist.append(item) - return sublist - - -# A canvas widget with scroll bars and some useful bindings - -class ScrolledCanvas: - def __init__(self, master, **opts): - if not opts.has_key('yscrollincrement'): - opts['yscrollincrement'] = 17 - self.master = master - self.frame = Frame(master) - self.frame.rowconfigure(0, weight=1) - self.frame.columnconfigure(0, weight=1) - self.canvas = apply(Canvas, (self.frame,), opts) - self.canvas.grid(row=0, column=0, sticky="nsew") - self.vbar = Scrollbar(self.frame, name="vbar") - self.vbar.grid(row=0, column=1, sticky="nse") - self.hbar = Scrollbar(self.frame, name="hbar", orient="horizontal") - self.hbar.grid(row=1, column=0, sticky="ews") - self.canvas['yscrollcommand'] = self.vbar.set - self.vbar['command'] = self.canvas.yview - self.canvas['xscrollcommand'] = self.hbar.set - self.hbar['command'] = self.canvas.xview - self.canvas.bind("", self.page_up) - self.canvas.bind("", self.page_down) - self.canvas.bind("", self.unit_up) - self.canvas.bind("", self.unit_down) - if isinstance(master, Toplevel) or isinstance(master, Tk): - self.canvas.bind("", self.zoom_height) - self.canvas.focus_set() - def page_up(self, event): - self.canvas.yview_scroll(-1, "page") - return "break" - def page_down(self, event): - self.canvas.yview_scroll(1, "page") - return "break" - def unit_up(self, event): - self.canvas.yview_scroll(-1, "unit") - return "break" - def unit_down(self, event): - self.canvas.yview_scroll(1, "unit") - return "break" - def zoom_height(self, event): - ZoomHeight.zoom_height(self.master) - return "break" - - -# Testing functions - -def test(): - import PyShell - root = Toplevel(PyShell.root) - root.configure(bd=0, bg="yellow") - root.focus_set() - sc = ScrolledCanvas(root, bg="white", highlightthickness=0, takefocus=1) - sc.frame.pack(expand=1, fill="both") - item = FileTreeItem("C:/windows/desktop") - node = TreeNode(sc.canvas, None, item) - node.expand() - -def test2(): - # test w/o scrolling canvas - root = Tk() - root.configure(bd=0) - canvas = Canvas(root, bg="white", highlightthickness=0) - canvas.pack(expand=1, fill="both") - item = FileTreeItem(os.curdir) - node = TreeNode(canvas, None, item) - node.update() - canvas.focus_set() - -if __name__ == '__main__': - test() diff --git a/Lib/idlelib/UndoDelegator.py b/Lib/idlelib/UndoDelegator.py deleted file mode 100644 index ec7af81..0000000 --- a/Lib/idlelib/UndoDelegator.py +++ /dev/null @@ -1,352 +0,0 @@ -import sys -import string -from Tkinter import * -from Delegator import Delegator - -#$ event <> -#$ win -#$ unix - -#$ event <> -#$ win -#$ unix - -#$ event <> -#$ win -#$ unix - - -class UndoDelegator(Delegator): - - max_undo = 1000 - - def __init__(self): - Delegator.__init__(self) - self.reset_undo() - - def setdelegate(self, delegate): - if self.delegate is not None: - self.unbind("<>") - self.unbind("<>") - self.unbind("<>") - Delegator.setdelegate(self, delegate) - if delegate is not None: - self.bind("<>", self.undo_event) - self.bind("<>", self.redo_event) - self.bind("<>", self.dump_event) - - def dump_event(self, event): - from pprint import pprint - pprint(self.undolist[:self.pointer]) - print "pointer:", self.pointer, - print "saved:", self.saved, - print "can_merge:", self.can_merge, - print "get_saved():", self.get_saved() - pprint(self.undolist[self.pointer:]) - return "break" - - def reset_undo(self): - self.was_saved = -1 - self.pointer = 0 - self.undolist = [] - self.undoblock = 0 # or a CommandSequence instance - self.set_saved(1) - - def set_saved(self, flag): - if flag: - self.saved = self.pointer - else: - self.saved = -1 - self.can_merge = 0 - self.check_saved() - - def get_saved(self): - return self.saved == self.pointer - - saved_change_hook = None - - def set_saved_change_hook(self, hook): - self.saved_change_hook = hook - - was_saved = -1 - - def check_saved(self): - is_saved = self.get_saved() - if is_saved != self.was_saved: - self.was_saved = is_saved - if self.saved_change_hook: - self.saved_change_hook() - - def insert(self, index, chars, tags=None): - self.addcmd(InsertCommand(index, chars, tags)) - - def delete(self, index1, index2=None): - self.addcmd(DeleteCommand(index1, index2)) - - # Clients should call undo_block_start() and undo_block_stop() - # around a sequence of editing cmds to be treated as a unit by - # undo & redo. Nested matching calls are OK, and the inner calls - # then act like nops. OK too if no editing cmds, or only one - # editing cmd, is issued in between: if no cmds, the whole - # sequence has no effect; and if only one cmd, that cmd is entered - # directly into the undo list, as if undo_block_xxx hadn't been - # called. The intent of all that is to make this scheme easy - # to use: all the client has to worry about is making sure each - # _start() call is matched by a _stop() call. - - def undo_block_start(self): - if self.undoblock == 0: - self.undoblock = CommandSequence() - self.undoblock.bump_depth() - - def undo_block_stop(self): - if self.undoblock.bump_depth(-1) == 0: - cmd = self.undoblock - self.undoblock = 0 - if len(cmd) > 0: - if len(cmd) == 1: - # no need to wrap a single cmd - cmd = cmd.getcmd(0) - # this blk of cmds, or single cmd, has already - # been done, so don't execute it again - self.addcmd(cmd, 0) - - def addcmd(self, cmd, execute=1): - if execute: - cmd.do(self.delegate) - if self.undoblock != 0: - self.undoblock.append(cmd) - return - if self.can_merge and self.pointer > 0: - lastcmd = self.undolist[self.pointer-1] - if lastcmd.merge(cmd): - return - self.undolist[self.pointer:] = [cmd] - if self.saved > self.pointer: - self.saved = -1 - self.pointer = self.pointer + 1 - if len(self.undolist) > self.max_undo: - ##print "truncating undo list" - del self.undolist[0] - self.pointer = self.pointer - 1 - if self.saved >= 0: - self.saved = self.saved - 1 - self.can_merge = 1 - self.check_saved() - - def undo_event(self, event): - if self.pointer == 0: - self.bell() - return "break" - cmd = self.undolist[self.pointer - 1] - cmd.undo(self.delegate) - self.pointer = self.pointer - 1 - self.can_merge = 0 - self.check_saved() - return "break" - - def redo_event(self, event): - if self.pointer >= len(self.undolist): - self.bell() - return "break" - cmd = self.undolist[self.pointer] - cmd.redo(self.delegate) - self.pointer = self.pointer + 1 - self.can_merge = 0 - self.check_saved() - return "break" - - -class Command: - - # Base class for Undoable commands - - tags = None - - def __init__(self, index1, index2, chars, tags=None): - self.marks_before = {} - self.marks_after = {} - self.index1 = index1 - self.index2 = index2 - self.chars = chars - if tags: - self.tags = tags - - def __repr__(self): - s = self.__class__.__name__ - t = (self.index1, self.index2, self.chars, self.tags) - if self.tags is None: - t = t[:-1] - return s + `t` - - def do(self, text): - pass - - def redo(self, text): - pass - - def undo(self, text): - pass - - def merge(self, cmd): - return 0 - - def save_marks(self, text): - marks = {} - for name in text.mark_names(): - if name != "insert" and name != "current": - marks[name] = text.index(name) - return marks - - def set_marks(self, text, marks): - for name, index in marks.items(): - text.mark_set(name, index) - - -class InsertCommand(Command): - - # Undoable insert command - - def __init__(self, index1, chars, tags=None): - Command.__init__(self, index1, None, chars, tags) - - def do(self, text): - self.marks_before = self.save_marks(text) - self.index1 = text.index(self.index1) - if text.compare(self.index1, ">", "end-1c"): - # Insert before the final newline - self.index1 = text.index("end-1c") - text.insert(self.index1, self.chars, self.tags) - self.index2 = text.index("%s+%dc" % (self.index1, len(self.chars))) - self.marks_after = self.save_marks(text) - ##sys.__stderr__.write("do: %s\n" % self) - - def redo(self, text): - text.mark_set('insert', self.index1) - text.insert(self.index1, self.chars, self.tags) - self.set_marks(text, self.marks_after) - text.see('insert') - ##sys.__stderr__.write("redo: %s\n" % self) - - def undo(self, text): - text.mark_set('insert', self.index1) - text.delete(self.index1, self.index2) - self.set_marks(text, self.marks_before) - text.see('insert') - ##sys.__stderr__.write("undo: %s\n" % self) - - def merge(self, cmd): - if self.__class__ is not cmd.__class__: - return 0 - if self.index2 != cmd.index1: - return 0 - if self.tags != cmd.tags: - return 0 - if len(cmd.chars) != 1: - return 0 - if self.chars and \ - self.classify(self.chars[-1]) != self.classify(cmd.chars): - return 0 - self.index2 = cmd.index2 - self.chars = self.chars + cmd.chars - return 1 - - alphanumeric = string.letters + string.digits + "_" - - def classify(self, c): - if c in self.alphanumeric: - return "alphanumeric" - if c == "\n": - return "newline" - return "punctuation" - - -class DeleteCommand(Command): - - # Undoable delete command - - def __init__(self, index1, index2=None): - Command.__init__(self, index1, index2, None, None) - - def do(self, text): - self.marks_before = self.save_marks(text) - self.index1 = text.index(self.index1) - if self.index2: - self.index2 = text.index(self.index2) - else: - self.index2 = text.index(self.index1 + " +1c") - if text.compare(self.index2, ">", "end-1c"): - # Don't delete the final newline - self.index2 = text.index("end-1c") - self.chars = text.get(self.index1, self.index2) - text.delete(self.index1, self.index2) - self.marks_after = self.save_marks(text) - ##sys.__stderr__.write("do: %s\n" % self) - - def redo(self, text): - text.mark_set('insert', self.index1) - text.delete(self.index1, self.index2) - self.set_marks(text, self.marks_after) - text.see('insert') - ##sys.__stderr__.write("redo: %s\n" % self) - - def undo(self, text): - text.mark_set('insert', self.index1) - text.insert(self.index1, self.chars) - self.set_marks(text, self.marks_before) - text.see('insert') - ##sys.__stderr__.write("undo: %s\n" % self) - -class CommandSequence(Command): - - # Wrapper for a sequence of undoable cmds to be undone/redone - # as a unit - - def __init__(self): - self.cmds = [] - self.depth = 0 - - def __repr__(self): - s = self.__class__.__name__ - strs = [] - for cmd in self.cmds: - strs.append(" " + `cmd`) - return s + "(\n" + string.join(strs, ",\n") + "\n)" - - def __len__(self): - return len(self.cmds) - - def append(self, cmd): - self.cmds.append(cmd) - - def getcmd(self, i): - return self.cmds[i] - - def redo(self, text): - for cmd in self.cmds: - cmd.redo(text) - - def undo(self, text): - cmds = self.cmds[:] - cmds.reverse() - for cmd in cmds: - cmd.undo(text) - - def bump_depth(self, incr=1): - self.depth = self.depth + incr - return self.depth - -def main(): - from Percolator import Percolator - root = Tk() - root.wm_protocol("WM_DELETE_WINDOW", root.quit) - text = Text() - text.pack() - text.focus_set() - p = Percolator(text) - d = UndoDelegator() - p.insertfilter(d) - root.mainloop() - -if __name__ == "__main__": - main() diff --git a/Lib/idlelib/WidgetRedirector.py b/Lib/idlelib/WidgetRedirector.py deleted file mode 100644 index b49ccf1..0000000 --- a/Lib/idlelib/WidgetRedirector.py +++ /dev/null @@ -1,92 +0,0 @@ -from Tkinter import * - - -class WidgetRedirector: - - """Support for redirecting arbitrary widget subcommands.""" - - def __init__(self, widget): - self.dict = {} - self.widget = widget - self.tk = tk = widget.tk - w = widget._w - self.orig = w + "_orig" - tk.call("rename", w, self.orig) - tk.createcommand(w, self.dispatch) - - def __repr__(self): - return "WidgetRedirector(%s<%s>)" % (self.widget.__class__.__name__, - self.widget._w) - - def close(self): - for name in self.dict.keys(): - self.unregister(name) - widget = self.widget; del self.widget - orig = self.orig; del self.orig - tk = widget.tk - w = widget._w - tk.deletecommand(w) - tk.call("rename", orig, w) - - def register(self, name, function): - if self.dict.has_key(name): - previous = dict[name] - else: - previous = OriginalCommand(self, name) - self.dict[name] = function - setattr(self.widget, name, function) - return previous - - def unregister(self, name): - if self.dict.has_key(name): - function = self.dict[name] - del self.dict[name] - if hasattr(self.widget, name): - delattr(self.widget, name) - return function - else: - return None - - def dispatch(self, cmd, *args): - m = self.dict.get(cmd) - try: - if m: - return apply(m, args) - else: - return self.tk.call((self.orig, cmd) + args) - except TclError: - return "" - - -class OriginalCommand: - - def __init__(self, redir, name): - self.redir = redir - self.name = name - self.tk = redir.tk - self.orig = redir.orig - self.tk_call = self.tk.call - self.orig_and_name = (self.orig, self.name) - - def __repr__(self): - return "OriginalCommand(%s, %s)" % (`self.redir`, `self.name`) - - def __call__(self, *args): - return self.tk_call(self.orig_and_name + args) - - -def main(): - root = Tk() - text = Text() - text.pack() - text.focus_set() - redir = WidgetRedirector(text) - global orig_insert - def my_insert(*args): - print "insert", args - apply(orig_insert, args) - orig_insert = redir.register("insert", my_insert) - root.mainloop() - -if __name__ == "__main__": - main() diff --git a/Lib/idlelib/WindowList.py b/Lib/idlelib/WindowList.py deleted file mode 100644 index 7e05a57..0000000 --- a/Lib/idlelib/WindowList.py +++ /dev/null @@ -1,85 +0,0 @@ -from Tkinter import * - -class WindowList: - - def __init__(self): - self.dict = {} - self.callbacks = [] - - def add(self, window): - window.after_idle(self.call_callbacks) - self.dict[str(window)] = window - - def delete(self, window): - try: - del self.dict[str(window)] - except KeyError: - # Sometimes, destroy() is called twice - pass - self.call_callbacks() - - def add_windows_to_menu(self, menu): - list = [] - for key in self.dict.keys(): - window = self.dict[key] - try: - title = window.get_title() - except TclError: - continue - list.append((title, window)) - list.sort() - for title, window in list: - if title == "Python Shell": - # Hack -- until we have a better way to this - continue - menu.add_command(label=title, command=window.wakeup) - - def register_callback(self, callback): - self.callbacks.append(callback) - - def unregister_callback(self, callback): - try: - self.callbacks.remove(callback) - except ValueError: - pass - - def call_callbacks(self): - for callback in self.callbacks: - try: - callback() - except: - print "warning: callback failed in WindowList", \ - sys.exc_type, ":", sys.exc_value - -registry = WindowList() - -add_windows_to_menu = registry.add_windows_to_menu -register_callback = registry.register_callback -unregister_callback = registry.unregister_callback - - -class ListedToplevel(Toplevel): - - def __init__(self, master, **kw): - Toplevel.__init__(self, master, kw) - registry.add(self) - - def destroy(self): - registry.delete(self) - Toplevel.destroy(self) - - def get_title(self): - # Subclass can override - return self.wm_title() - - def wakeup(self): - try: - if self.wm_state() == "iconic": - self.wm_deiconify() - else: - self.tkraise() - self.focus_set() - except TclError: - # This can happen when the window menu was torn off. - # Simply ignore it. - pass diff --git a/Lib/idlelib/ZoomHeight.py b/Lib/idlelib/ZoomHeight.py deleted file mode 100644 index ecc306a..0000000 --- a/Lib/idlelib/ZoomHeight.py +++ /dev/null @@ -1,46 +0,0 @@ -# Sample extension: zoom a window to maximum height - -import re -import sys - -class ZoomHeight: - - menudefs = [ - ('windows', [ - ('_Zoom Height', '<>'), - ]) - ] - - windows_keydefs = { - '<>': [''], - } - unix_keydefs = { - '<>': [''], - } - - def __init__(self, editwin): - self.editwin = editwin - - def zoom_height_event(self, event): - top = self.editwin.top - zoom_height(top) - -def zoom_height(top): - geom = top.wm_geometry() - m = re.match(r"(\d+)x(\d+)\+(-?\d+)\+(-?\d+)", geom) - if not m: - top.bell() - return - width, height, x, y = map(int, m.groups()) - newheight = top.winfo_screenheight() - if sys.platform == 'win32': - newy = 0 - newheight = newheight - 72 - else: - newy = 24 - newheight = newheight - 96 - if height >= newheight: - newgeom = "" - else: - newgeom = "%dx%d+%d+%d" % (width, newheight, x, newy) - top.wm_geometry(newgeom) diff --git a/Lib/idlelib/__init__.py b/Lib/idlelib/__init__.py deleted file mode 100644 index 4c5b567..0000000 --- a/Lib/idlelib/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Dummy file to make this a potential package. diff --git a/Lib/idlelib/aboutDialog.py b/Lib/idlelib/aboutDialog.py deleted file mode 100644 index 25443ae..0000000 --- a/Lib/idlelib/aboutDialog.py +++ /dev/null @@ -1,135 +0,0 @@ -##---------------------------------------------------------------------------## -## -## idle - about box -## elguavas -## -##---------------------------------------------------------------------------## -""" -about box for idle -""" -from Tkinter import * -import tkFont -import string, os -import textView -import idlever -class AboutDialog(Toplevel): - """ - modal about dialog for idle - """ - def __init__(self,parent,title): - Toplevel.__init__(self, parent) - self.configure(borderwidth=5) - self.geometry("+%d+%d" % (parent.winfo_rootx()+30, - parent.winfo_rooty()+30)) - self.bg="#777777" - self.fg="#ffffff" - #no ugly bold default font on *nix - font=tkFont.Font(self,Label(self).cget('font')) - if os.name=='posix': font.config(weight=NORMAL) - self.textFont=font - - self.CreateWidgets() - self.resizable(height=FALSE,width=FALSE) - self.title(title) - self.transient(parent) - self.grab_set() - self.protocol("WM_DELETE_WINDOW", self.Ok) - self.parent = parent - self.buttonOk.focus_set() - #key bindings for this dialog - self.bind('',self.CreditsButtonBinding) #credits button - self.bind('',self.LicenseButtonBinding) #license button - self.bind('',self.Ok) #dismiss dialog - self.bind('',self.Ok) #dismiss dialog - self.wait_window() - - def CreateWidgets(self): - frameMain = Frame(self,borderwidth=2,relief=SUNKEN) - frameButtons = Frame(self) - frameButtons.pack(side=BOTTOM,fill=X) - frameMain.pack(side=TOP,expand=TRUE,fill=BOTH) - self.buttonOk = Button(frameButtons,text='Ok', - command=self.Ok)#,default=ACTIVE - self.buttonOk.pack(padx=5,pady=5) - #self.picture = Image('photo',data=self.pictureData) - frameBg = Frame(frameMain,bg=self.bg) - frameBg.pack(expand=TRUE,fill=BOTH) - labelTitle = Label(frameBg,text='IDLEfork',fg=self.fg,bg=self.bg, - font=('courier', 24, 'bold')) - labelTitle.grid(row=0,column=0,sticky=W,padx=10,pady=10) - #labelPicture = Label(frameBg,text='[picture]') - #image=self.picture,bg=self.bg) - #labelPicture.grid(row=0,column=1,sticky=W,rowspan=2,padx=0,pady=3) - labelVersion = Label(frameBg,text='version '+idlever.IDLE_VERSION, - fg=self.fg,bg=self.bg,font=self.textFont) - labelVersion.grid(row=1,column=0,sticky=W,padx=10,pady=5) - labelDesc = Label(frameBg, - text="A development version of Python's lightweight\n"+ - 'Integrated DeveLopment Environment, IDLE.', - justify=LEFT,fg=self.fg,bg=self.bg,font=self.textFont) - labelDesc.grid(row=2,column=0,sticky=W,columnspan=3,padx=10,pady=5) - labelCopyright = Label(frameBg, - text="Copyright (c) 2001 Python Software Foundation;\nAll Rights Reserved", - justify=LEFT,fg=self.fg,bg=self.bg,font=self.textFont) - labelCopyright.grid(row=3,column=0,sticky=W,columnspan=3,padx=10,pady=5) - labelLicense = Label(frameBg, - text='Released under the Python 2.1.1 PSF Licence', - justify=LEFT,fg=self.fg,bg=self.bg,font=self.textFont) - labelLicense.grid(row=4,column=0,sticky=W,columnspan=3,padx=10,pady=5) - framePad = Frame(frameBg,height=5,bg=self.bg).grid(row=5,column=0) - labelEmail = Label(frameBg,text='email: idle-dev@python.org', - justify=LEFT,fg=self.fg,bg=self.bg,font=self.textFont) - labelEmail.grid(row=6,column=0,columnspan=2,sticky=W,padx=10,pady=0) - labelWWW = Label(frameBg,text='www: http://idlefork.sourceforge.net', - justify=LEFT,fg=self.fg,bg=self.bg,font=self.textFont) - labelWWW.grid(row=7,column=0,columnspan=2,sticky=W,padx=10,pady=0) - frameDivider = Frame(frameBg,borderwidth=1,relief=SUNKEN, - height=2,bg=self.bg).grid(row=8,column=0,sticky=(E,W),columnspan=3, - padx=5,pady=5) - labelPythonVer = Label(frameBg,text='Python version: '+ - sys.version.split()[0],fg=self.fg,bg=self.bg,font=self.textFont) - labelPythonVer.grid(row=9,column=0,sticky=W,padx=10,pady=0) - #handle weird tk version num in windoze python >= 1.6 (?!?) - tkVer = `TkVersion`.split('.') - tkVer[len(tkVer)-1] = str('%.3g' % (float('.'+tkVer[len(tkVer)-1])))[2:] - if tkVer[len(tkVer)-1] == '': - tkVer[len(tkVer)-1] = '0' - tkVer = string.join(tkVer,'.') - labelTkVer = Label(frameBg,text='Tk version: '+tkVer,fg=self.fg,bg=self.bg, - font=self.textFont) - labelTkVer.grid(row=9,column=1,sticky=W,padx=2,pady=0) - - self.buttonLicense = Button(frameBg,text='View License',underline=5, - width=14,highlightbackground=self.bg,command=self.ShowLicense)#takefocus=FALSE - self.buttonLicense.grid(row=10,column=0,sticky=W,padx=10,pady=10) - self.buttonCredits = Button(frameBg,text='View Credits',underline=5, - width=14,highlightbackground=self.bg,command=self.ShowCredits)#takefocus=FALSE - self.buttonCredits.grid(row=10,column=1,columnspan=2,sticky=E,padx=10,pady=10) - - def CreditsButtonBinding(self,event): - self.buttonCredits.invoke() - - def LicenseButtonBinding(self,event): - self.buttonLicense.invoke() - - def ShowLicense(self): - self.ViewFile('About - License','LICENSE.txt') - - def ShowCredits(self): - self.ViewFile('About - Credits','CREDITS.txt') - - def ViewFile(self,viewTitle,viewFile): - fn=os.path.join(os.path.abspath(os.path.dirname(__file__)),viewFile) - textView.TextViewer(self,viewTitle,fn) - - def Ok(self, event=None): - self.destroy() - -if __name__ == '__main__': - #test the dialog - root=Tk() - def run(): - import aboutDialog - aboutDialog.AboutDialog(root,'About') - Button(root,text='Dialog',command=run).pack() - root.mainloop() diff --git a/Lib/idlelib/config-extensions.def b/Lib/idlelib/config-extensions.def deleted file mode 100644 index d1c1ee2..0000000 --- a/Lib/idlelib/config-extensions.def +++ /dev/null @@ -1,34 +0,0 @@ -# IDLE reads several config files to determine user preferences. This -# file is the default config file for idle extensions settings. - -[SearchBinding] -enable=1 - -[AutoIndent] -enable=1 - -[AutoExpand] -enable=1 - -[FormatParagraph] -enable=1 - -[ZoomHeight] -enable=1 - -#[ScriptBinding] # disabled in favor of ExecBinding -#enable=0 - -[ExecBinding] -enable=1 - -[CallTips] -enable=1 - -[ParenMatch] -enable=0 -style= expression -flash-delay= 500 -bell= 1 -hilite-foreground= black -hilite-background= #43cd80 diff --git a/Lib/idlelib/config-highlight.def b/Lib/idlelib/config-highlight.def deleted file mode 100644 index 83c9807..0000000 --- a/Lib/idlelib/config-highlight.def +++ /dev/null @@ -1,56 +0,0 @@ -# IDLE reads several config files to determine user preferences. This -# file is the default config file for idle highlight theme settings. - -[IDLE Classic Old - plain fonts] -normal-foreground= black -normal-background= white -normal-fontStyle= normal -keyword-foreground= #ff7700 -keyword-fontStyle= normal -comment-foreground= #dd0000 -comment-fontStyle= normal -string-foreground= #00aa00 -string-fontStyle= normal -definition-foreground= #0000ff -definition-fontStyle= normal -hilite-foreground= #000068 -hilite-background= #006868 -hilite-fontStyle= normal -break-foreground= #ff7777 -break-fontStyle= normal -hit-background= #000000 -hit-foreground= #ffffff -hit-fontStyle= normal -cursor-foreround= black -error-background= #ff7777 -#shell window -stdout-foreground= blue -stdout-fontStyle= normal -stderr-foreground= red -stderr-fontStyle= normal -console-foreground= #770000 -console-fontStyle= normal - -[IDLE Classic New] -normal-foreground= black -normal-background= white -normal-fontStyle= normal -keyword-foreground= #ff7700 -keyword-fontStyle= bold -comment-foreground= #dd0000 -comment-fontStyle= italic -string-foreground= #00aa00 -string-fontStyle= normal -definition-foreground= #0000ff -definition-fontStyle= bold -hilite-foreground= #000068 -hilite-background= #006868 -break-foreground= #ff7777 -hit-background= #000000 -hit-foreground= #ffffff -cursor-foreground= black -error-background= #ff7777 -#shell window -stdout-foreground= blue -stderr-foreground= red -console-foreground= #770000 diff --git a/Lib/idlelib/config-keys.def b/Lib/idlelib/config-keys.def deleted file mode 100644 index feec31c..0000000 --- a/Lib/idlelib/config-keys.def +++ /dev/null @@ -1,64 +0,0 @@ -# IDLE reads several config files to determine user preferences. This -# file is the default config file for idle key binding settings. -# Where multiple keys are specified for an action: if they are separated -# by a space (eg. action= ) then the keys are altenatives, if -# there is no space (eg. action=key2>) then the keys comprise a -# single 'emacs style' multi-keystoke binding. - -[IDLE CUA-ish] -Copy= -Cut= -Paste= -beginning-of-line= -center-insert= -close-all-windows= -close-window= -dump-undo-state= -end-of-file= -python-docs= -python-context-help= -history-next= -history-previous= -interrupt-execution= -open-class-browser= -open-module= -open-new-window= -open-window-from-file= -plain-newline-and-indent= -redo= -remove-selection= -save-copy-of-window-as-file= -save-window-as-file= -save-window= -select-all= -toggle-auto-coloring= -undo= - -[IDLE Emacs-ish] -Copy= -Cut= -Paste= -beginning-of-line= -center-insert= -close-all-windows= -close-window= -do-nothing= -dump-undo-state= -end-of-file= -history-next= -history-previous= -interrupt-execution= -open-class-browser= -open-module= -open-new-window= -open-window-from-file= -plain-newline-and-indent= -python-docs= -python-context-help= -redo= -save-copy-of-window-as-file= -save-window-as-file= -save-window= -select-all= -toggle-auto-coloring= -undo= diff --git a/Lib/idlelib/config-main.def b/Lib/idlelib/config-main.def deleted file mode 100644 index dca0e54..0000000 --- a/Lib/idlelib/config-main.def +++ /dev/null @@ -1,79 +0,0 @@ -# IDLE reads several config files to determine user preferences. This -# file is the default config file for general idle settings. -# -# When IDLE starts, it will look in -# the following two sets of files, in order: -# -# default configuration -# --------------------- -# config-main.def the default general config file -# config-extensions.def the default extension config file -# config-highlight.def the default highlighting config file -# config-keys.def the default keybinding config file -# -# user configuration -# ------------------- -# ~/.idlerc/idle-main.cfg the user general config file -# ~/.idlerc/idle-extensions.cfg the user extension config file -# ~/.idlerc/idle-highlight.cfg the user highlighting config file -# ~/.idlerc/idle-keys.cfg the user keybinding config file -# -# Any options the user saves through the config dialog will be saved to -# the relevant user config file. Reverting any general setting to the -# default causes that entry to be wiped from the user file and re-read -# from the default file. User highlighting themes or keybinding sets are -# retained unless specifically deleted within the config dialog. Choosing -# one of the default themes or keysets just applies the relevant settings -# from the default file. - -[General] -run-in-separate-process= 1 -help-browser= "" - -[HelpFiles] -idle="IDLE _Help","" -python="_Python Documentation","" -#additional help sources -1= -2= -3= -4= -5= -6= -7= -8= -9= -10= - -[EditorWindow] -editor-on-startup= 0 -width= 80 -height= 24 -font= courier -font-size= 12 - -[Indent] -use-spaces= 1 -num-spaces= 4 -tab-cols= 4 - -[Theme] -default= 1 -name= IDLE Classic New - -[Keys] -default= 1 -name= IDLE Classic - windows - -[RecentFiles] -1= -2= -3= -4= -5= -6= -7= -8= -9= -10= - diff --git a/Lib/idlelib/config-unix.txt b/Lib/idlelib/config-unix.txt deleted file mode 100644 index be9fa81..0000000 --- a/Lib/idlelib/config-unix.txt +++ /dev/null @@ -1,3 +0,0 @@ -[EditorWindow] -font-name= courier -font-size= 10 diff --git a/Lib/idlelib/config-win.txt b/Lib/idlelib/config-win.txt deleted file mode 100644 index 9faa635..0000000 --- a/Lib/idlelib/config-win.txt +++ /dev/null @@ -1,3 +0,0 @@ -[EditorWindow] -font-name: courier new -font-size: 10 diff --git a/Lib/idlelib/config.txt b/Lib/idlelib/config.txt deleted file mode 100644 index 223b302..0000000 --- a/Lib/idlelib/config.txt +++ /dev/null @@ -1,66 +0,0 @@ -# IDLE reads several config files to determine user preferences. This -# file is the default config file. When IDLE starts, it will look in -# the following four files in order: -# config.txt the default config file -# config-[win/unix/mac].txt the generic platform config file -# config-[sys.platform].txt the specific platform config file -# ~/.idle the user config file -# XXX what about Windows? -# -# The last definition of each option is used. For example, you can -# override the default window size (80x24) by defining width and -# height options in the EditorWindow section of your ~/.idle file -# -# IDLE extensions can be enabled and disabled by adding them to one of -# the config files. To enable an extension, create a section with the -# same name as the extension, e.g. the [ParenMatch] section below. To -# disable an extension, either remove the section or add the 'enable' -# option with the value 0. - -[EditorWindow] -width= 80 -height= 24 -# fonts defined in config-[win/unix].txt - -[Colors] -normal-foreground= black -normal-background= white -# These color types are not explicitly defined= sync, todo, stdin -keyword-foreground= #ff7700 -comment-foreground= #dd0000 -string-foreground= #00aa00 -definition-foreground= #0000ff -hilite-foreground= #000068 -hilite-background= #006868 -break-foreground= #ff7777 -hit-foreground= #ffffff -hit-background= #000000 -stdout-foreground= blue -stderr-foreground= red -console-foreground= #770000 -error-background= #ff7777 -cursor-background= black - -[SearchBinding] - -[AutoIndent] - -[AutoExpand] - -[FormatParagraph] - -[ZoomHeight] - -#[ScriptBinding] # disabled in favor of ExecBinding - -[ExecBinding] - -[CallTips] - -[ParenMatch] -enable= 0 -style= expression -flash-delay= 500 -bell= 1 -hilite-foreground= black -hilite-background= #43cd80 diff --git a/Lib/idlelib/configDialog.py b/Lib/idlelib/configDialog.py deleted file mode 100644 index b131eeb..0000000 --- a/Lib/idlelib/configDialog.py +++ /dev/null @@ -1,623 +0,0 @@ -""" -configuration dialog -""" -from Tkinter import * -import tkMessageBox, tkColorChooser, tkFont - -from configHandler import idleConf -from dynOptionMenuWidget import DynOptionMenu -from tabpage import TabPageSet - -class ConfigDialog(Toplevel): - """ - configuration dialog for idle - """ - def __init__(self,parent,title): - Toplevel.__init__(self, parent) - self.configure(borderwidth=5) - self.geometry("+%d+%d" % (parent.winfo_rootx()+20, - parent.winfo_rooty()+30)) - #Theme Elements. Each theme element key is it's display name. - #The first value of the tuple is the sample area tag name. - #The second value is the display name list sort index. - #The third value indicates whether the element can have a foreground - #or background colour or both. - self.themeElements={'Normal Text':('normal','00','both'), - 'Python Keywords':('keyword','01','both'), - 'Python Definitions':('definition','02','both'), - 'Python Comments':('comment','03','both'), - 'Python Strings':('string','04','both'), - 'Selected Text':('hilite','05','both'), - 'Found Text':('hit','06','both'), - 'Cursor':('cursor','07','fg'), - 'Error Background':('error','08','bg'), - 'Shell Foreground':('console','09','fg'), - 'Shell Stdout Foreground':('stdout','10','fg'), - 'Shell Stderr Foreground':('stderr','11','fg')} - self.CreateWidgets() - self.resizable(height=FALSE,width=FALSE) - self.transient(parent) - self.grab_set() - self.protocol("WM_DELETE_WINDOW", self.Cancel) - self.parent = parent - self.tabPages.focus_set() - #key bindings for this dialog - self.bind('',self.CancelBinding) #dismiss dialog, no save - self.bind('',self.ApplyBinding) #apply changes, save - self.bind('',self.HelpBinding) #context help - self.LoadConfigs() - self.wait_window() - - def Cancel(self): - self.destroy() - - def Ok(self): - pass - - def Apply(self): - pass - - def Help(self): - pass - - def CancelBinding(self,event): - self.Cancel() - - def OkBinding(self,event): - self.Ok() - - def ApplyBinding(self,event): - self.Apply() - - def HelpBinding(self,event): - self.Help() - - def SetThemeType(self): - if self.themeIsBuiltin.get(): - self.optMenuThemeBuiltin.config(state=NORMAL) - self.optMenuThemeCustom.config(state=DISABLED) - self.buttonDeleteCustomTheme.config(state=DISABLED) - else: - self.optMenuThemeBuiltin.config(state=DISABLED) - self.optMenuThemeCustom.config(state=NORMAL) - self.buttonDeleteCustomTheme.config(state=NORMAL) - - def SetKeysType(self): - if self.keysAreDefault.get(): - self.optMenuKeysBuiltin.config(state=NORMAL) - self.optMenuKeysCustom.config(state=DISABLED) - self.buttonDeleteCustomKeys.config(state=DISABLED) - else: - self.optMenuKeysBuiltin.config(state=DISABLED) - self.optMenuKeysCustom.config(state=NORMAL) - self.buttonDeleteCustomKeys.config(state=NORMAL) - - def GetColour(self): - target=self.highlightTarget.get() - rgbTuplet, colourString = tkColorChooser.askcolor(parent=self, - title='Pick new colour for : '+target, - initialcolor=self.frameColourSet.cget('bg')) - if colourString: #user didn't cancel - self.frameColourSet.config(bg=colourString)#set sample - if self.fgHilite.get(): plane='foreground' - else: plane='background' - apply(self.textHighlightSample.tag_config, - (self.themeElements[target][0],),{plane:colourString}) - - def SetFontSampleBinding(self,event): - self.SetFontSample() - - def SetFontSample(self): - self.editFont.config(size=self.fontSize.get(),weight=NORMAL, - family=self.listFontName.get(self.listFontName.curselection()[0])) - - def SetHighlightTargetBinding(self,*args): - self.SetHighlightTarget() - - def SetHighlightTarget(self): - colourPlane=self.themeElements[self.highlightTarget.get()][2] - if colourPlane == 'bg': - self.radioFg.config(state=DISABLED) - self.radioBg.config(state=DISABLED) - self.fgHilite.set(0) - elif colourPlane == 'fg': - self.radioFg.config(state=DISABLED) - self.radioBg.config(state=DISABLED) - self.fgHilite.set(1) - elif colourPlane == 'both': - self.radioFg.config(state=NORMAL) - self.radioBg.config(state=NORMAL) - self.fgHilite.set(1) #default to setting foreground attribute - self.SetColourSample() - - def SetColourSampleBinding(self,*args): - self.SetColourSample() - - def SetColourSample(self): - #set the colour smaple area - tag=self.themeElements[self.highlightTarget.get()][0] - if self.fgHilite.get(): plane='foreground' - else: plane='background' - colour=self.textHighlightSample.tag_cget(tag,plane) - self.frameColourSet.config(bg=colour) - - def CreateWidgets(self): - self.tabPages = TabPageSet(self, - pageNames=['Fonts/Tabs','Highlighting','Keys','General']) - frameActionButtons = Frame(self) - #action buttons - self.buttonHelp = Button(frameActionButtons,text='Help', - command=self.Help,takefocus=FALSE) - self.buttonOk = Button(frameActionButtons,text='Ok', - command=self.Ok,takefocus=FALSE) - self.buttonApply = Button(frameActionButtons,text='Apply', - command=self.Apply,underline=0,takefocus=FALSE) - self.buttonCancel = Button(frameActionButtons,text='Cancel', - command=self.Cancel,takefocus=FALSE) - self.CreatePageFontTab() - self.CreatePageHighlight() - self.CreatePageKeys() - self.CreatePageGeneral() - self.buttonHelp.pack(side=RIGHT,padx=5,pady=5) - self.buttonOk.pack(side=LEFT,padx=5,pady=5) - self.buttonApply.pack(side=LEFT,padx=5,pady=5) - self.buttonCancel.pack(side=LEFT,padx=5,pady=5) - frameActionButtons.pack(side=BOTTOM) - self.tabPages.pack(side=TOP,expand=TRUE,fill=BOTH) - - - def CreatePageFontTab(self): - #tkVars - self.fontSize=StringVar(self) - self.fontBold=StringVar(self) - self.spaceNum=IntVar(self) - self.tabCols=IntVar(self) - self.indentType=IntVar(self) - self.editFont=tkFont.Font(self,('courier',12,'normal')) - ##widget creation - #body frame - frame=self.tabPages.pages['Fonts/Tabs']['page'] - #body section frames - frameFont=Frame(frame,borderwidth=2,relief=GROOVE) - frameIndent=Frame(frame,borderwidth=2,relief=GROOVE) - #frameFont - labelFontTitle=Label(frameFont,text='Set Base Editor Font') - frameFontName=Frame(frameFont) - frameFontParam=Frame(frameFont) - labelFontNameTitle=Label(frameFontName,justify=LEFT, - text='Font :') - self.listFontName=Listbox(frameFontName,height=5,takefocus=FALSE, - exportselection=FALSE) - self.listFontName.bind('<>',self.SetFontSampleBinding) - scrollFont=Scrollbar(frameFontName) - scrollFont.config(command=self.listFontName.yview) - self.listFontName.config(yscrollcommand=scrollFont.set) - labelFontSizeTitle=Label(frameFontParam,text='Size :') - self.optMenuFontSize=DynOptionMenu(frameFontParam,self.fontSize,None, - command=self.SetFontSampleBinding) - checkFontBold=Checkbutton(frameFontParam,variable=self.fontBold, - onvalue='Bold',offvalue='',text='Bold') - frameFontSample=Frame(frameFont,relief=SOLID,borderwidth=1) - self.labelFontSample=Label(frameFontSample, - text='AaBbCcDdEe\nFfGgHhIiJjK\n1234567890\n#:+=(){}[]', - justify=LEFT,font=self.editFont) - #frameIndent - labelIndentTitle=Label(frameIndent,text='Set Indentation Defaults') - frameIndentType=Frame(frameIndent) - frameIndentSize=Frame(frameIndent) - labelIndentTypeTitle=Label(frameIndentType, - text='Choose indentation type :') - radioUseSpaces=Radiobutton(frameIndentType,variable=self.indentType, - value=1,text='Tab key inserts spaces') - radioUseTabs=Radiobutton(frameIndentType,variable=self.indentType, - value=0,text='Tab key inserts tabs') - labelIndentSizeTitle=Label(frameIndentSize, - text='Choose indentation size :') - labelSpaceNumTitle=Label(frameIndentSize,justify=LEFT, - text='when tab key inserts spaces,\nspaces per tab') - self.scaleSpaceNum=Scale(frameIndentSize,variable=self.spaceNum, - orient='horizontal',tickinterval=2,from_=2,to=8) - labeltabColsTitle=Label(frameIndentSize,justify=LEFT, - text='when tab key inserts tabs,\ncolumns per tab') - self.scaleTabCols=Scale(frameIndentSize,variable=self.tabCols, - orient='horizontal',tickinterval=2,from_=2,to=8) - #widget packing - #body - frameFont.pack(side=LEFT,padx=5,pady=10,expand=TRUE,fill=BOTH) - frameIndent.pack(side=LEFT,padx=5,pady=10,fill=Y) - #frameFont - labelFontTitle.pack(side=TOP,anchor=W,padx=5,pady=5) - frameFontName.pack(side=TOP,padx=5,pady=5,fill=X) - frameFontParam.pack(side=TOP,padx=5,pady=5,fill=X) - labelFontNameTitle.pack(side=TOP,anchor=W) - self.listFontName.pack(side=LEFT,expand=TRUE,fill=X) - scrollFont.pack(side=LEFT,fill=Y) - labelFontSizeTitle.pack(side=LEFT,anchor=W) - self.optMenuFontSize.pack(side=LEFT,anchor=W) - checkFontBold.pack(side=LEFT,anchor=W,padx=20) - frameFontSample.pack(side=TOP,padx=5,pady=5,expand=TRUE,fill=BOTH) - self.labelFontSample.pack(expand=TRUE,fill=BOTH) - #frameIndent - labelIndentTitle.pack(side=TOP,anchor=W,padx=5,pady=5) - frameIndentType.pack(side=TOP,padx=5,fill=X) - frameIndentSize.pack(side=TOP,padx=5,pady=5,fill=BOTH) - labelIndentTypeTitle.pack(side=TOP,anchor=W,padx=5,pady=5) - radioUseSpaces.pack(side=TOP,anchor=W,padx=5) - radioUseTabs.pack(side=TOP,anchor=W,padx=5) - labelIndentSizeTitle.pack(side=TOP,anchor=W,padx=5,pady=5) - labelSpaceNumTitle.pack(side=TOP,anchor=W,padx=5) - self.scaleSpaceNum.pack(side=TOP,padx=5,fill=X) - labeltabColsTitle.pack(side=TOP,anchor=W,padx=5) - self.scaleTabCols.pack(side=TOP,padx=5,fill=X) - return frame - - def CreatePageHighlight(self): - self.builtinTheme=StringVar(self) - self.customTheme=StringVar(self) - self.fgHilite=IntVar(self) - self.colour=StringVar(self) - self.fontName=StringVar(self) - self.themeIsBuiltin=IntVar(self) - self.highlightTarget=StringVar(self) - self.highlightTarget.trace_variable('w',self.SetHighlightTargetBinding) - ##widget creation - #body frame - frame=self.tabPages.pages['Highlighting']['page'] - #body section frames - frameCustom=Frame(frame,borderwidth=2,relief=GROOVE) - frameTheme=Frame(frame,borderwidth=2,relief=GROOVE) - #frameCustom - self.textHighlightSample=Text(frameCustom,relief=SOLID,borderwidth=1, - font=('courier',12,''),cursor='hand2',width=10,height=10, - takefocus=FALSE,highlightthickness=0) - text=self.textHighlightSample - text.bind('',lambda e: 'break') - text.bind('',lambda e: 'break') - textAndTags=(('#you can click in here','comment'),('\n','normal'), - ('#to choose items','comment'),('\n','normal'),('def','keyword'), - (' ','normal'),('func','definition'),('(param):','normal'), - ('\n ','normal'),('"""string"""','string'),('\n var0 = ','normal'), - ("'string'",'string'),('\n var1 = ','normal'),("'selected'",'hilite'), - ('\n var2 = ','normal'),("'found'",'hit'),('\n\n','normal'), - (' error ','error'),(' ','normal'),('cursor |','cursor'), - ('\n ','normal'),('shell','console'),(' ','normal'),('stdout','stdout'), - (' ','normal'),('stderr','stderr'),('\n','normal')) - for txTa in textAndTags: - text.insert(END,txTa[0],txTa[1]) - for element in self.themeElements.keys(): - text.tag_bind(self.themeElements[element][0],'', - lambda event,elem=element: event.widget.winfo_toplevel() - .highlightTarget.set(elem)) - text.config(state=DISABLED) - self.frameColourSet=Frame(frameCustom,relief=SOLID,borderwidth=1) - frameFgBg=Frame(frameCustom) - labelCustomTitle=Label(frameCustom,text='Set Custom Highlighting') - buttonSetColour=Button(self.frameColourSet,text='Choose Colour for :', - command=self.GetColour,highlightthickness=0) - self.optMenuHighlightTarget=DynOptionMenu(self.frameColourSet, - self.highlightTarget,None,highlightthickness=0)#,command=self.SetHighlightTargetBinding - self.radioFg=Radiobutton(frameFgBg,variable=self.fgHilite, - value=1,text='Foreground',command=self.SetColourSampleBinding) - self.radioBg=Radiobutton(frameFgBg,variable=self.fgHilite, - value=0,text='Background',command=self.SetColourSampleBinding) - self.fgHilite.set(1) - buttonSaveCustomTheme=Button(frameCustom, - text='Save as a Custom Theme') - #frameTheme - labelThemeTitle=Label(frameTheme,text='Select a Highlighting Theme') - labelTypeTitle=Label(frameTheme,text='Select : ') - self.radioThemeBuiltin=Radiobutton(frameTheme,variable=self.themeIsBuiltin, - value=1,command=self.SetThemeType,text='a Built-in Theme') - self.radioThemeCustom=Radiobutton(frameTheme,variable=self.themeIsBuiltin, - value=0,command=self.SetThemeType,text='a Custom Theme') - self.optMenuThemeBuiltin=DynOptionMenu(frameTheme, - self.builtinTheme,None,command=None) - self.optMenuThemeCustom=DynOptionMenu(frameTheme, - self.customTheme,None,command=None) - self.buttonDeleteCustomTheme=Button(frameTheme,text='Delete Custom Theme') - ##widget packing - #body - frameCustom.pack(side=LEFT,padx=5,pady=10,expand=TRUE,fill=BOTH) - frameTheme.pack(side=LEFT,padx=5,pady=10,fill=Y) - #frameCustom - labelCustomTitle.pack(side=TOP,anchor=W,padx=5,pady=5) - self.frameColourSet.pack(side=TOP,padx=5,pady=5,expand=TRUE,fill=X) - frameFgBg.pack(side=TOP,padx=5,pady=0) - self.textHighlightSample.pack(side=TOP,padx=5,pady=5,expand=TRUE, - fill=BOTH) - buttonSetColour.pack(side=TOP,expand=TRUE,fill=X,padx=8,pady=4) - self.optMenuHighlightTarget.pack(side=TOP,expand=TRUE,fill=X,padx=8,pady=3) - self.radioFg.pack(side=LEFT,anchor=E) - self.radioBg.pack(side=RIGHT,anchor=W) - buttonSaveCustomTheme.pack(side=BOTTOM,fill=X,padx=5,pady=5) - #frameTheme - labelThemeTitle.pack(side=TOP,anchor=W,padx=5,pady=5) - labelTypeTitle.pack(side=TOP,anchor=W,padx=5,pady=5) - self.radioThemeBuiltin.pack(side=TOP,anchor=W,padx=5) - self.radioThemeCustom.pack(side=TOP,anchor=W,padx=5,pady=2) - self.optMenuThemeBuiltin.pack(side=TOP,fill=X,padx=5,pady=5) - self.optMenuThemeCustom.pack(side=TOP,fill=X,anchor=W,padx=5,pady=5) - self.buttonDeleteCustomTheme.pack(side=TOP,fill=X,padx=5,pady=5) - return frame - - def CreatePageKeys(self): - #tkVars - self.bindingTarget=StringVar(self) - self.builtinKeys=StringVar(self) - self.customKeys=StringVar(self) - self.keyChars=StringVar(self) - self.keyCtrl=StringVar(self) - self.keyAlt=StringVar(self) - self.keyShift=StringVar(self) - self.keysAreDefault=IntVar(self) - ##widget creation - #body frame - frame=self.tabPages.pages['Keys']['page'] - #body section frames - frameCustom=Frame(frame,borderwidth=2,relief=GROOVE) - frameKeySets=Frame(frame,borderwidth=2,relief=GROOVE) - #frameCustom - frameTarget=Frame(frameCustom) - frameSet=Frame(frameCustom) - labelCustomTitle=Label(frameCustom,text='Set Custom Key Bindings') - labelTargetTitle=Label(frameTarget,text='Action') - scrollTarget=Scrollbar(frameTarget) - listTarget=Listbox(frameTarget) - scrollTarget.config(command=listTarget.yview) - listTarget.config(yscrollcommand=scrollTarget.set) - labelKeyBindTitle=Label(frameSet,text='Binding') - labelModifierTitle=Label(frameSet,text='Modifier:') - checkCtrl=Checkbutton(frameSet,text='Ctrl') - checkAlt=Checkbutton(frameSet,text='Alt') - checkShift=Checkbutton(frameSet,text='Shift') - labelKeyEntryTitle=Label(frameSet,text='Key:') - entryKey=Entry(frameSet,width=4) - buttonSaveCustomKeys=Button(frameCustom,text='Save as a Custom Key Set') - #frameKeySets - labelKeysTitle=Label(frameKeySets,text='Select a Key Set') - labelTypeTitle=Label(frameKeySets,text='Select : ') - self.radioKeysBuiltin=Radiobutton(frameKeySets,variable=self.keysAreDefault, - value=1,command=self.SetKeysType,text='a Built-in Key Set') - self.radioKeysCustom=Radiobutton(frameKeySets,variable=self.keysAreDefault, - value=0,command=self.SetKeysType,text='a Custom Key Set') - self.optMenuKeysBuiltin=DynOptionMenu(frameKeySets, - self.builtinKeys,None,command=None) - self.optMenuKeysCustom=DynOptionMenu(frameKeySets, - self.customKeys,None,command=None) - self.buttonDeleteCustomKeys=Button(frameKeySets,text='Delete Custom Key Set') - ##widget packing - #body - frameCustom.pack(side=LEFT,padx=5,pady=5,expand=TRUE,fill=BOTH) - frameKeySets.pack(side=LEFT,padx=5,pady=5,fill=Y) - #frameCustom - labelCustomTitle.pack(side=TOP,anchor=W,padx=5,pady=5) - buttonSaveCustomKeys.pack(side=BOTTOM,fill=X,padx=5,pady=5) - frameTarget.pack(side=LEFT,padx=5,pady=5,fill=Y) - frameSet.pack(side=LEFT,padx=5,pady=5,fill=Y) - labelTargetTitle.pack(side=TOP,anchor=W) - scrollTarget.pack(side=RIGHT,anchor=W,fill=Y) - listTarget.pack(side=TOP,anchor=W,expand=TRUE,fill=BOTH) - labelKeyBindTitle.pack(side=TOP,anchor=W) - labelModifierTitle.pack(side=TOP,anchor=W,pady=5) - checkCtrl.pack(side=TOP,anchor=W) - checkAlt.pack(side=TOP,anchor=W,pady=2) - checkShift.pack(side=TOP,anchor=W) - labelKeyEntryTitle.pack(side=TOP,anchor=W,pady=5) - entryKey.pack(side=TOP,anchor=W) - #frameKeySets - labelKeysTitle.pack(side=TOP,anchor=W,padx=5,pady=5) - labelTypeTitle.pack(side=TOP,anchor=W,padx=5,pady=5) - self.radioKeysBuiltin.pack(side=TOP,anchor=W,padx=5) - self.radioKeysCustom.pack(side=TOP,anchor=W,padx=5,pady=2) - self.optMenuKeysBuiltin.pack(side=TOP,fill=X,padx=5,pady=5) - self.optMenuKeysCustom.pack(side=TOP,fill=X,anchor=W,padx=5,pady=5) - self.buttonDeleteCustomKeys.pack(side=TOP,fill=X,padx=5,pady=5) - return frame - - def CreatePageGeneral(self): - #tkVars - self.runType=IntVar(self) - self.winWidth=StringVar(self) - self.winHeight=StringVar(self) - self.extState=IntVar(self) - #widget creation - #body - frame=self.tabPages.pages['General']['page'] - #body section frames - frameRun=Frame(frame,borderwidth=2,relief=GROOVE) - frameWinSize=Frame(frame,borderwidth=2,relief=GROOVE) - frameExt=Frame(frame,borderwidth=2,relief=GROOVE) - #frameRun - labelRunTitle=Label(frameRun,text='Run Preferences') - labelRunChoiceTitle=Label(frameRun,text='Run code : ') - radioRunInternal=Radiobutton(frameRun,variable=self.runType, - value=0,command=self.SetKeysType,text="in IDLE's Process") - radioRunSeparate=Radiobutton(frameRun,variable=self.runType, - value=1,command=self.SetKeysType,text='in a Separate Process') - #frameWinSize - labelWinSizeTitle=Label(frameWinSize,text='Initial Window Size') - buttonWinSizeSet=Button(frameWinSize,text='Set to current window size') - labelWinWidthTitle=Label(frameWinSize,text='Width') - entryWinWidth=Entry(frameWinSize,textvariable=self.winWidth, - width=3) - labelWinHeightTitle=Label(frameWinSize,text='Height') - entryWinHeight=Entry(frameWinSize,textvariable=self.winHeight, - width=3) - #frameExt - frameExtList=Frame(frameExt) - frameExtSet=Frame(frameExt) - labelExtTitle=Label(frameExt,text='Configure IDLE Extensions') - labelExtListTitle=Label(frameExtList,text='Extension') - scrollExtList=Scrollbar(frameExtList) - listExt=Listbox(frameExtList,height=5) - scrollExtList.config(command=listExt.yview) - listExt.config(yscrollcommand=scrollExtList.set) - labelExtSetTitle=Label(frameExtSet,text='Settings') - radioEnableExt=Radiobutton(frameExtSet,variable=self.extState, - value=1,text="enable") - radioDisableExt=Radiobutton(frameExtSet,variable=self.extState, - value=0,text="disable") - self.extState.set(1) - buttonExtConfig=Button(frameExtSet,text='Configure') - - #widget packing - #body - frameRun.pack(side=TOP,padx=5,pady=5,fill=X) - frameWinSize.pack(side=TOP,padx=5,pady=5,fill=X) - frameExt.pack(side=TOP,padx=5,pady=5,expand=TRUE,fill=BOTH) - #frameRun - labelRunTitle.pack(side=TOP,anchor=W,padx=5,pady=5) - labelRunChoiceTitle.pack(side=LEFT,anchor=W,padx=5,pady=5) - radioRunInternal.pack(side=LEFT,anchor=W,padx=5,pady=5) - radioRunSeparate.pack(side=LEFT,anchor=W,padx=5,pady=5) - #frameWinSize - labelWinSizeTitle.pack(side=TOP,anchor=W,padx=5,pady=5) - buttonWinSizeSet.pack(side=LEFT,anchor=W,padx=5,pady=5) - labelWinWidthTitle.pack(side=LEFT,anchor=W,padx=5,pady=5) - entryWinWidth.pack(side=LEFT,anchor=W,padx=5,pady=5) - labelWinHeightTitle.pack(side=LEFT,anchor=W,padx=5,pady=5) - entryWinHeight.pack(side=LEFT,anchor=W,padx=5,pady=5) - #frameExt - labelExtTitle.pack(side=TOP,anchor=W,padx=5,pady=5) - frameExtSet.pack(side=RIGHT,padx=5,pady=5,fill=Y) - frameExtList.pack(side=RIGHT,padx=5,pady=5,expand=TRUE,fill=BOTH) - labelExtListTitle.pack(side=TOP,anchor=W) - scrollExtList.pack(side=RIGHT,anchor=W,fill=Y) - listExt.pack(side=LEFT,anchor=E,expand=TRUE,fill=BOTH) - labelExtSetTitle.pack(side=TOP,anchor=W) - radioEnableExt.pack(side=TOP,anchor=W) - radioDisableExt.pack(side=TOP,anchor=W) - buttonExtConfig.pack(side=TOP,anchor=W,pady=5) - - return frame - - def PaintThemeSample(self): - if self.themeIsBuiltin.get(): #a default theme - theme=self.builtinTheme.get() - else: #a user theme - theme=self.customTheme.get() - for element in self.themeElements.keys(): - colours=idleConf.GetHighlight(theme, self.themeElements[element][0]) - apply(self.textHighlightSample.tag_config, - (self.themeElements[element][0],),colours) - - def LoadFontCfg(self): - ##base editor font selection list - fonts=list(tkFont.families(self)) - fonts.sort() - for font in fonts: - self.listFontName.insert(END,font) - configuredFont=idleConf.GetOption('main','EditorWindow','font', - default='courier') - if configuredFont in fonts: - currentFontIndex=fonts.index(configuredFont) - self.listFontName.see(currentFontIndex) - self.listFontName.select_set(currentFontIndex) - ##font size dropdown - fontSize=idleConf.GetOption('main','EditorWindow','font-size',default='12') - self.optMenuFontSize.SetMenu(('10','11','12','13','14', - '16','18','20','22'),fontSize ) - ##font sample - self.SetFontSample() - - def LoadTabCfg(self): - ##indent type radibuttons - spaceIndent=idleConf.GetOption('main','Indent','use-spaces', - default=1,type='bool') - self.indentType.set(spaceIndent) - ##indent sizes - spaceNum=idleConf.GetOption('main','Indent','num-spaces', - default=4,type='int') - tabCols=idleConf.GetOption('main','Indent','tab-cols', - default=4,type='int') - self.spaceNum.set(spaceNum) - self.tabCols.set(tabCols) - - def LoadThemeCfg(self): - ##current theme type radiobutton - self.themeIsBuiltin.set(idleConf.GetOption('main','Theme','default', - type='int',default=1)) - ##currently set theme - currentOption=idleConf.GetOption('main','Theme','name') - ##load available theme option menus - if self.themeIsBuiltin.get(): #default theme selected - itemList=idleConf.GetSectionList('default','highlight') - self.optMenuThemeBuiltin.SetMenu(itemList,currentOption) - itemList=idleConf.GetSectionList('user','highlight') - if not itemList: - self.radioThemeCustom.config(state=DISABLED) - self.customTheme.set('- no custom themes -') - else: - self.optMenuThemeCustom.SetMenu(itemList,itemList[0]) - else: #user theme selected - itemList=idleConf.GetSectionList('user','highlight') - self.optMenuThemeCustom.SetMenu(itemList,currentOption) - itemList=idleConf.GetSectionList('default','highlight') - self.optMenuThemeBuiltin.SetMenu(itemList,itemList[0]) - self.SetThemeType() - ##load theme element option menu - themeNames=self.themeElements.keys() - themeNames.sort(self.__ThemeNameIndexCompare) - self.optMenuHighlightTarget.SetMenu(themeNames,themeNames[0]) - sampleBg=idleConf.GetHighlight(currentOption, - self.highlightTarget.get())['background'] - self.fgHilite.set(0) - self.frameColourSet.config(bg=sampleBg) - self.PaintThemeSample() - - def __ThemeNameIndexCompare(self,a,b): - if self.themeElements[a][1]>': ['', ''], - '<>': ['', ''], - '<>': ['', ''], - '<>': ['', ''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': ['']} - if keySetName: - pass - - return keyBindings - - - def LoadCfgFiles(self): - """ - load all configuration files. - """ - for key in self.defaultCfg.keys(): - self.defaultCfg[key].Load() - self.userCfg[key].Load() #same keys - - def SaveUserCfgFiles(self): - """ - write all loaded user configuration files back to disk - """ - for key in self.userCfg.keys(): - self.userCfg[key].Save() - -idleConf=IdleConf() - -### module test -if __name__ == '__main__': - def dumpCfg(cfg): - print '\n',cfg,'\n' - for key in cfg.keys(): - sections=cfg[key].sections() - print key - print sections - for section in sections: - options=cfg[key].options(section) - print section - print options - for option in options: - print option, '=', cfg[key].Get(section,option) - dumpCfg(idleConf.defaultCfg) - dumpCfg(idleConf.userCfg) - print idleConf.userCfg['main'].Get('Theme','name') - #print idleConf.userCfg['highlight'].GetDefHighlight('Foo','normal') diff --git a/Lib/idlelib/dynOptionMenuWidget.py b/Lib/idlelib/dynOptionMenuWidget.py deleted file mode 100644 index bc716ed..0000000 --- a/Lib/idlelib/dynOptionMenuWidget.py +++ /dev/null @@ -1,41 +0,0 @@ -##---------------------------------------------------------------------------## -## -## idle - modified OptionMenu widget -## elguavas -## -##---------------------------------------------------------------------------## -""" -OptionMenu widget modified to allow dynamic menu reconfiguration -and setting of highlightthickness -""" -from Tkinter import OptionMenu -from Tkinter import _setit -import copy - -class DynOptionMenu(OptionMenu): - """ - unlike OptionMenu, our kwargs can include highlightthickness - """ - def __init__(self, master, variable, value, *values, **kwargs): - #get a copy of kwargs before OptionMenu.__init__ munges them - kwargsCopy=copy.copy(kwargs) - if 'highlightthickness' in kwargs.keys(): - del(kwargs['highlightthickness']) - OptionMenu.__init__(self, master, variable, value, *values, **kwargs) - self.config(highlightthickness=kwargsCopy.get('highlightthickness')) - #self.menu=self['menu'] - self.variable=variable - self.command=kwargs.get('command') - - def SetMenu(self,valueList,value=None): - """ - clear and reload the menu with a new set of options. - valueList - list of new options - value - initial value to set the optionmenu's menubutton to - """ - self['menu'].delete(0,'end') - for item in valueList: - self['menu'].add_command(label=item, - command=_setit(self.variable,item,self.command)) - if value: - self.variable.set(value) diff --git a/Lib/idlelib/eventparse.py b/Lib/idlelib/eventparse.py deleted file mode 100644 index cb2028d..0000000 --- a/Lib/idlelib/eventparse.py +++ /dev/null @@ -1,93 +0,0 @@ -#! /usr/bin/env python - -"""Parse event definitions out of comments in source files.""" - -import re -import sys -import os -import string -import getopt -import glob -import fileinput -import pprint - -def main(): - hits = [] - sublist = [] - args = sys.argv[1:] - if not args: - args = filter(lambda s: 'A' <= s[0] <= 'Z', glob.glob("*.py")) - if not args: - print "No arguments, no [A-Z]*.py files." - return 1 - for line in fileinput.input(args): - if line[:2] == '#$': - if not sublist: - sublist.append('file %s' % fileinput.filename()) - sublist.append('line %d' % fileinput.lineno()) - sublist.append(string.strip(line[2:-1])) - else: - if sublist: - hits.append(sublist) - sublist = [] - if sublist: - hits.append(sublist) - sublist = [] - dd = {} - for sublist in hits: - d = {} - for line in sublist: - words = string.split(line, None, 1) - if len(words) != 2: - continue - tag = words[0] - l = d.get(tag, []) - l.append(words[1]) - d[tag] = l - if d.has_key('event'): - keys = d['event'] - if len(keys) != 1: - print "Multiple event keys in", d - print 'File "%s", line %d' % (d['file'], d['line']) - key = keys[0] - if dd.has_key(key): - print "Duplicate event in", d - print 'File "%s", line %d' % (d['file'], d['line']) - return - dd[key] = d - else: - print "No event key in", d - print 'File "%s", line %d' % (d['file'], d['line']) - winevents = getevents(dd, "win") - unixevents = getevents(dd, "unix") - save = sys.stdout - f = open("keydefs.py", "w") - try: - sys.stdout = f - print "windows_keydefs = \\" - pprint.pprint(winevents) - print - print "unix_keydefs = \\" - pprint.pprint(unixevents) - finally: - sys.stdout = save - f.close() - -def getevents(dd, key): - res = {} - events = dd.keys() - events.sort() - for e in events: - d = dd[e] - if d.has_key(key) or d.has_key("all"): - list = [] - for x in d.get(key, []) + d.get("all", []): - list.append(x) - if key == "unix" and x[:5] == ">, and corresponding -methods, e.g. zoom_height_event(), and have one or more class (or instance) -variables that define mappings between virtual events and key sequences, -e.g. . When the extension is loaded, these key sequences will -be bound to the corresponding virtual events, and the virtual events -will be bound to the corresponding methods. (This indirection is done -so that the key bindings can easily be changed, and so that other -sources of virtual events can exist, such as menu entries.) - -The following class or instance variables are used to define key -bindings for virtual events: - - keydefs for all platforms - mac_keydefs for Macintosh - windows_keydefs for Windows - unix_keydefs for Unix (and other platforms) - -Each of these variables, if it exists, must be a dictionary whose -keys are virtual events, and whose values are lists of key sequences. - -An extension can define menu entries in a similar fashion. This is done -with a class or instance variable named menudefs; it should be a list of -pair, where each pair is a menu name (lowercase) and a list of menu -entries. Each menu entry is either None (to insert a separator entry) or -a pair of strings (menu_label, virtual_event). Here, menu_label is the -label of the menu entry, and virtual_event is the virtual event to be -generated when the entry is selected. An underscore in the menu label -is removed; the character following the underscore is displayed -underlined, to indicate the shortcut character (for Windows). - -At the moment, extensions cannot define whole new menus; they must -define entries in existing menus. Some menus are not present on some -windows; such entry definitions are then ignored, but the key bindings -are still applied. (This should probably be refined in the future.) - -Here is a complete example example: - -class ZoomHeight: - - menudefs = [ - ('edit', [ - None, # Separator - ('_Zoom Height', '<>'), - ]) - ] - - windows_keydefs = { - '<>': [''], - } - unix_keydefs = { - '<>': [''], - } - - def __init__(self, editwin): - self.editwin = editwin - - def zoom_height_event(self, event): - "...Do what you want here..." - -The final piece of the puzzle is the file "config.txt", which is used -to to configure the loading of extensions. For each extension, -you must include a section in config.txt (or in any of the other -configuration files that are consulted at startup: config-unix.txt, -config-win.txt, or ~/.idle). A section is headed by the module name -in square brackets, e.g. - - [ZoomHeight] - -The section may be empty, or it may define configuration options for -the extension. (See ParenMatch.py for an example.) A special option -is 'enable': including - - enable = 0 - -in a section disables that extension. More than one configuration -file may specify options for the same extension, so a user may disable -an extension that is loaded by default, or enable an extension that is -disabled by default. - -Extensions can define key bindings and menu entries that reference -events they don't implement (including standard events); however this is -not recommended (and may be forbidden in the future). - -Extensions are not required to define menu entries for all events they -implement. - -Note: in order to change key bindings, you must currently edit the file -keydefs. It contains two dictionaries named and formatted like the -keydefs dictionaries described above, one for the Unix bindings and one -for the Windows bindings. In the future, a better mechanism will be -provided. diff --git a/Lib/idlelib/help.txt b/Lib/idlelib/help.txt deleted file mode 100644 index 67e6e71..0000000 --- a/Lib/idlelib/help.txt +++ /dev/null @@ -1,165 +0,0 @@ -[See end for tips.] - -Click on the dotted line at the top of a menu to "tear it off": a -separate window containing the menu is created. - -File menu: - - New window -- create a new editing window - Open... -- open an existing file - Open module... -- open an existing module (searches sys.path) - Class browser -- show classes and methods in current file - Path browser -- show sys.path directories, modules, classes - and methods - --- - Save -- save current window to the associated file (unsaved - windows have a * before and after the window title) - - Save As... -- save current window to new file, which becomes - the associated file - Save Copy As... -- save current window to different file - without changing the associated file - --- - Close -- close current window (asks to save if unsaved) - Exit -- close all windows and quit IDLE (asks to save if unsaved) - -Edit menu: - - Undo -- Undo last change to current window (max 1000 changes) - Redo -- Redo last undone change to current window - --- - Cut -- Copy selection into system-wide clipboard; then delete selection - Copy -- Copy selection into system-wide clipboard - Paste -- Insert system-wide clipboard into window - Select All -- Select the entire contents of the edit buffer - --- - Find... -- Open a search dialog box with many options - Find again -- Repeat last search - Find selection -- Search for the string in the selection - Find in Files... -- Open a search dialog box for searching files - Replace... -- Open a search-and-replace dialog box - Go to line -- Ask for a line number and show that line - --- - Indent region -- Shift selected lines right 4 spaces - Dedent region -- Shift selected lines left 4 spaces - Comment out region -- Insert ## in front of selected lines - Uncomment region -- Remove leading # or ## from selected lines - Tabify region -- Turns *leading* stretches of spaces into tabs - Untabify region -- Turn *all* tabs into the right number of spaces - Expand word -- Expand the word you have typed to match another - word in the same buffer; repeat to get a different expansion - Format Paragraph -- Reformat the current blank-line-separated paragraph - --- - Import module -- Import or reload the current module - Run script -- Execute the current file in the __main__ namespace - -Windows menu: - - Zoom Height -- toggles the window between normal size (24x80) - and maximum height. - --- - The rest of this menu lists the names of all open windows; - select one to bring it to the foreground (deiconifying it if - necessary). - -Debug menu (in the Python Shell window only): - - Go to file/line -- look around the insert point for a filename - and linenumber, open the file, and show the line - Open stack viewer -- show the stack traceback of the last exception - Debugger toggle -- Run commands in the shell under the debugger - JIT Stack viewer toggle -- Open stack viewer on traceback - -Basic editing and navigation: - - Backspace deletes to the left; DEL deletes to the right - Arrow keys and Page Up/Down to move around - Home/End go to begin/end of line - Control-Home/End go to begin/end of file - Some Emacs bindings may also work, e.g. ^B/^P/^A/^E/^D/^L - -Automatic indentation: - - After a block-opening statement, the next line is indented by - 4 spaces (in the Python Shell window by one tab). After - certain keywords (break, return etc.) the next line is - dedented. In leading indentation, Backspace deletes up to 4 - spaces if they are there. Tab inserts 1-4 spaces (in the - Python Shell window one tab). See also the indent/dedent - region commands in the edit menu. - -Python Shell window: - - ^C interrupts executing command - ^D sends end-of-file; closes window if typed at >>> prompt - - Command history: - - Alt-p retrieves previous command matching what you have typed - Alt-n retrieves next - Return while on any previous command retrieves that command - Alt-/ (Expand word) is also useful here - -Syntax colors: - - The coloring is applied in a background "thread", so you may - occasionally see uncolorized text. To change the color - scheme, edit the [Colors] section in config.txt (or add a - [Colors] section to ~/.idle). - - Python syntax colors: - - Keywords orange - Strings green - Comments red - Definitions blue - - Shell colors: - - Console output brown - stdout blue - stderr dark green - stdin black - -Other preferences: - - To change the font open config-[win/unix/mac].txt and - change - - font-name: courier new - font-size: 10 - - to, for example: - - font-name: courier new bold - font-size: 14 - - Note: a GUI based configuration screen will be provided - in the future. - - To change keyboard bindings, edit Bindings.py - -Command line usage: - - idle.py [-c command] [-d] [-e] [-s] [-t title] [arg] ... - - -c command run this command - -d enable debugger - -e edit mode; arguments are files to be edited - -s run $IDLESTARTUP or $PYTHONSTARTUP first - -t title set title of shell window - - If there are arguments: - - If -e is used, arguments are files opened for editing and - sys.argv reflects the arguments passed to IDLE itself. - - Otherwise, if -c is used, all arguments are placed in - sys.argv[1:...], with sys.argv[0] set to '-c'. - - Otherwise, if neither -e nor -c is used, the first - argument is a script which is executed with the remaining - arguments in sys.argv[1:...] and sys.argv[0] set to the - script name. If the script name is '-', no script is - executed but an interactive Python session is started; the - arguments are still available in sys.argv. diff --git a/Lib/idlelib/idle b/Lib/idlelib/idle deleted file mode 100755 index 8638a16..0000000 --- a/Lib/idlelib/idle +++ /dev/null @@ -1,4 +0,0 @@ -#! /usr/bin/env python - -import PyShell -PyShell.main() diff --git a/Lib/idlelib/idle.bat b/Lib/idlelib/idle.bat deleted file mode 100755 index c1b5fd2..0000000 --- a/Lib/idlelib/idle.bat +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -rem Working IDLE bat for Windows - uses start instead of absolute pathname -start idle.pyw %1 %2 %3 %4 %5 %6 %7 %8 %9 diff --git a/Lib/idlelib/idle.py b/Lib/idlelib/idle.py deleted file mode 100644 index 8638a16..0000000 --- a/Lib/idlelib/idle.py +++ /dev/null @@ -1,4 +0,0 @@ -#! /usr/bin/env python - -import PyShell -PyShell.main() diff --git a/Lib/idlelib/idle.pyw b/Lib/idlelib/idle.pyw deleted file mode 100644 index 71fdce5..0000000 --- a/Lib/idlelib/idle.pyw +++ /dev/null @@ -1,12 +0,0 @@ -#! /usr/bin/env python - -import os -import sys -import IdleConf - -idle_dir = os.path.split(sys.argv[0])[0] -IdleConf.load(idle_dir) - -# defer importing Pyshell until IdleConf is loaded -import PyShell -PyShell.main() diff --git a/Lib/idlelib/idlever.py b/Lib/idlelib/idlever.py deleted file mode 100644 index b5d70a7..0000000 --- a/Lib/idlelib/idlever.py +++ /dev/null @@ -1 +0,0 @@ -IDLE_VERSION = "0.8.2" diff --git a/Lib/idlelib/keydefs.py b/Lib/idlelib/keydefs.py deleted file mode 100644 index 455253a..0000000 --- a/Lib/idlelib/keydefs.py +++ /dev/null @@ -1,55 +0,0 @@ -windows_keydefs = \ -{'<>': ['', ''], - '<>': ['', ''], - '<>': ['', ''], - '<>': ['', ''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': ['']} - -unix_keydefs = \ -{'<>': ['', ''], - '<>': [''], - '<>': [''], - '<>': ['', ''], - '<>': [''], - '<>': [''], - '<>': ['', ''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': ['', ''], - '<>': ['', ''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': ['', ''], - '<>': [''], - '<>': [''], - '<>': [''], - '<>': ['', ''], - '<>': [''], - '<>': ['']} diff --git a/Lib/idlelib/loader.py b/Lib/idlelib/loader.py deleted file mode 100644 index 6a438c3..0000000 --- a/Lib/idlelib/loader.py +++ /dev/null @@ -1,64 +0,0 @@ -# Everything is done inside the loader function so that no other names -# are placed in the global namespace. Before user code is executed, -# even this name is unbound. -def loader(): - import sys, os, protocol, threading, time - import Remote - -## Use to debug the loading process itself: -## sys.stdout = open('c:\\windows\\desktop\\stdout.txt','a') -## sys.stderr = open('c:\\windows\\desktop\\stderr.txt','a') - - # Ensure that there is absolutely no pollution of the global - # namespace by deleting the global name of this function. - global loader - del loader - - # Connect to IDLE - try: - client = protocol.Client() - except protocol.connectionLost, cL: - print 'loader: Unable to connect to IDLE', cL - return - - # Connect to an ExecBinding object that needs our help. If - # the user is starting multiple programs right now, we might get a - # different one than the one that started us. Proving that's okay is - # left as an exercise to the reader. (HINT: Twelve, by the pigeonhole - # principle) - ExecBinding = client.getobject('ExecBinding') - if not ExecBinding: - print "loader: IDLE does not need me." - return - - # All of our input and output goes through ExecBinding. - sys.stdin = Remote.pseudoIn( ExecBinding.readline ) - sys.stdout = Remote.pseudoOut( ExecBinding.write.void, tag="stdout" ) - sys.stderr = Remote.pseudoOut( ExecBinding.write.void, tag="stderr" ) - - # Create a Remote object and start it running. - remote = Remote.Remote(globals(), ExecBinding) - rthread = threading.Thread(target=remote.mainloop) - rthread.setDaemon(1) - rthread.start() - - # Block until either the client or the user program stops - user = rthread.isAlive - while user and client.isAlive(): - time.sleep(0.025) - - if not user(): - user = hasattr(sys, "ready_to_exit") and sys.ready_to_exit - for t in threading.enumerate(): - if not t.isDaemon() and t.isAlive() and t!=threading.currentThread(): - user = t.isAlive - break - - # We need to make sure we actually exit, so that the user doesn't get - # stuck with an invisible process. We want to finalize C modules, so - # we don't use os._exit(), but we don't call sys.exitfunc, which might - # block forever. - del sys.exitfunc - sys.exit() - -loader() diff --git a/Lib/idlelib/protocol.py b/Lib/idlelib/protocol.py deleted file mode 100644 index f3f6382..0000000 --- a/Lib/idlelib/protocol.py +++ /dev/null @@ -1,369 +0,0 @@ -"""protocol (David Scherer ) - - This module implements a simple RPC or "distributed object" protocol. - I am probably the 100,000th person to write this in Python, but, hey, - it was fun. - - Contents: - - connectionLost is an exception that will be thrown by functions in - the protocol module or calls to remote methods that fail because - the remote program has closed the socket or because no connection - could be established in the first place. - - Server( port=None, connection_hook=None ) creates a server on a - well-known port, to which clients can connect. When a client - connects, a Connection is created for it. If connection_hook - is defined, then connection_hook( socket.getpeername() ) is called - before a Connection is created, and if it returns false then the - connection is refused. connection_hook must be prepared to be - called from any thread. - - Client( ip='127.0.0.1', port=None ) returns a Connection to a Server - object at a well-known address and port. - - Connection( socket ) creates an RPC connection on an arbitrary socket, - which must already be connected to another program. You do not - need to use this directly if you are using Client() or Server(). - - publish( name, connect_function ) provides an object with the - specified name to some or all Connections. When another program - calls Connection.getobject() with the specified name, the - specified connect_function is called with the arguments - - connect_function( conn, addr ) - - where conn is the Connection object to the requesting client and - addr is the address returned by socket.getpeername(). If that - function returns an object, that object becomes accessible to - the caller. If it returns None, the caller's request fails. - - Connection objects: - - .close() refuses additional RPC messages from the peer, and notifies - the peer that the connection has been closed. All pending remote - method calls in either program will fail with a connectionLost - exception. Further remote method calls on this connection will - also result in errors. - - .getobject(name) returns a proxy for the remote object with the - specified name, if it exists and the peer permits us access. - Otherwise, it returns None. It may throw a connectionLost - exception. The returned proxy supports basic attribute access - and method calls, and its methods have an extra attribute, - .void, which is a function that has the same effect but always - returns None. This last capability is provided as a performance - hack: object.method.void(params) can return without waiting for - the remote process to respond, but object.method(params) needs - to wait for a return value or exception. - - .rpc_loop(block=0) processes *incoming* messages for this connection. - If block=1, it continues processing until an exception or return - value is received, which is normally forever. Otherwise it - returns when all currently pending messages have been delivered. - It may throw a connectionLost exception. - - .set_close_hook(f) specifies a function to be called when the remote - object closes the connection during a call to rpc_loop(). This - is a good way for servers to be notified when clients disconnect. - - .set_shutdown_hook(f) specifies a function called *immediately* when - the receive loop detects that the connection has been lost. The - provided function must be prepared to run in any thread. - - Server objects: - - .rpc_loop() processes incoming messages on all connections, and - returns when all pending messages have been processed. It will - *not* throw connectionLost exceptions; the - Connection.set_close_hook() mechanism is much better for servers. -""" - -import sys, os, string, types -import socket -from threading import Thread -from Queue import Queue, Empty -from cPickle import Pickler, Unpickler, PicklingError - -class connectionLost: - def __init__(self, what=""): self.what = what - def __repr__(self): return self.what - def __str__(self): return self.what - -def getmethods(cls): - "Returns a list of the names of the methods of a class." - methods = [] - for b in cls.__bases__: - methods = methods + getmethods(b) - d = cls.__dict__ - for k in d.keys(): - if type(d[k])==types.FunctionType: - methods.append(k) - return methods - -class methodproxy: - "Proxy for a method of a remote object." - def __init__(self, classp, name): - self.classp=classp - self.name=name - self.client = classp.client - def __call__(self, *args, **keywords): - return self.client.call( 'm', self.classp.name, self.name, args, keywords ) - - def void(self, *args, **keywords): - self.client.call_void( 'm', self.classp.name,self.name,args,keywords) - -class classproxy: - "Proxy for a remote object." - def __init__(self, client, name, methods): - self.__dict__['client'] = client - self.__dict__['name'] = name - - for m in methods: - prox = methodproxy( self, m ) - self.__dict__[m] = prox - - def __getattr__(self, attr): - return self.client.call( 'g', self.name, attr ) - - def __setattr__(self, attr, value): - self.client.call_void( 's', self.name, attr, value ) - -local_connect = {} -def publish(name, connect_function): - local_connect[name]=connect_function - -class socketFile: - "File emulator based on a socket. Provides only blocking semantics for now." - - def __init__(self, socket): - self.socket = socket - self.buffer = '' - - def _recv(self,bytes): - try: - r=self.socket.recv(bytes) - except: - raise connectionLost() - if not r: - raise connectionLost() - return r - - def write(self, string): - try: - self.socket.send( string ) - except: - raise connectionLost() - - def read(self,bytes): - x = bytes-len(self.buffer) - while x>0: - self.buffer=self.buffer+self._recv(x) - x = bytes-len(self.buffer) - s = self.buffer[:bytes] - self.buffer=self.buffer[bytes:] - return s - - def readline(self): - while 1: - f = string.find(self.buffer,'\n') - if f>=0: - s = self.buffer[:f+1] - self.buffer=self.buffer[f+1:] - return s - self.buffer = self.buffer + self._recv(1024) - - -class Connection (Thread): - debug = 0 - def __init__(self, socket): - self.local_objects = {} - self.socket = socket - self.name = socket.getpeername() - self.socketfile = socketFile(socket) - self.queue = Queue(-1) - self.refuse_messages = 0 - self.cmds = { 'm': self.r_meth, - 'g': self.r_get, - 's': self.r_set, - 'o': self.r_geto, - 'e': self.r_exc, - #'r' handled by rpc_loop - } - - Thread.__init__(self) - self.setDaemon(1) - self.start() - - def getobject(self, name): - methods = self.call( 'o', name ) - if methods is None: return None - return classproxy(self, name, methods) - - # close_hook is called from rpc_loop(), like a normal remote method - # invocation - def set_close_hook(self,hook): self.close_hook = hook - - # shutdown_hook is called directly from the run() thread, and needs - # to be "thread safe" - def set_shutdown_hook(self,hook): self.shutdown_hook = hook - - close_hook = None - shutdown_hook = None - - def close(self): - self._shutdown() - self.refuse_messages = 1 - - def call(self, c, *args): - self.send( (c, args, 1 ) ) - return self.rpc_loop( block = 1 ) - - def call_void(self, c, *args): - try: - self.send( (c, args, 0 ) ) - except: - pass - - # the following methods handle individual RPC calls: - - def r_geto(self, obj): - c = local_connect.get(obj) - if not c: return None - o = c(self, self.name) - if not o: return None - self.local_objects[obj] = o - return getmethods(o.__class__) - - def r_meth(self, obj, name, args, keywords): - return apply( getattr(self.local_objects[obj],name), args, keywords) - - def r_get(self, obj, name): - return getattr(self.local_objects[obj],name) - - def r_set(self, obj, name, value): - setattr(self.local_objects[obj],name,value) - - def r_exc(self, e, v): - raise e, v - - def rpc_exec(self, cmd, arg, ret): - if self.refuse_messages: return - if self.debug: print cmd,arg,ret - if ret: - try: - r=apply(self.cmds.get(cmd), arg) - self.send( ('r', r, 0) ) - except: - try: - self.send( ('e', sys.exc_info()[:2], 0) ) - except PicklingError: - self.send( ('e', (TypeError, 'Unpicklable exception.'), 0 ) ) - else: - # we cannot report exceptions to the caller, so - # we report them in this process. - r=apply(self.cmds.get(cmd), arg) - - # the following methods implement the RPC and message loops: - - def rpc_loop(self, block=0): - if self.refuse_messages: raise connectionLost('(already closed)') - try: - while 1: - try: - cmd, arg, ret = self.queue.get( block ) - except Empty: - return None - if cmd=='r': return arg - self.rpc_exec(cmd,arg,ret) - except connectionLost: - if self.close_hook: - self.close_hook() - self.close_hook = None - raise - - def run(self): - try: - while 1: - data = self.recv() - self.queue.put( data ) - except: - self.queue.put( ('e', sys.exc_info()[:2], 0) ) - - # The following send raw pickled data to the peer - - def send(self, data): - try: - Pickler(self.socketfile,1).dump( data ) - except connectionLost: - self._shutdown() - if self.shutdown_hook: self.shutdown_hook() - raise - - def recv(self): - try: - return Unpickler(self.socketfile).load() - except connectionLost: - self._shutdown() - if self.shutdown_hook: self.shutdown_hook() - raise - except: - raise - - def _shutdown(self): - try: - self.socket.shutdown(1) - self.socket.close() - except: - pass - - -class Server (Thread): - default_port = 0x1D1E # "IDlE" - - def __init__(self, port=None, connection_hook=None): - self.connections = [] - self.port = port or self.default_port - self.connection_hook = connection_hook - - try: - self.wellknown = s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.bind(('', self.port)) - s.listen(3) - except: - raise connectionLost - - Thread.__init__(self) - self.setDaemon(1) - self.start() - - def run(self): - s = self.wellknown - while 1: - conn, addr = s.accept() - if self.connection_hook and not self.connection_hook(addr): - try: - conn.shutdown(1) - except: - pass - continue - self.connections.append( Connection(conn) ) - - def rpc_loop(self): - cns = self.connections[:] - for c in cns: - try: - c.rpc_loop(block = 0) - except connectionLost: - if c in self.connections: - self.connections.remove(c) - -def Client(ip='127.0.0.1', port=None): - try: - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.connect((ip,port or Server.default_port)) - except socket.error, what: - raise connectionLost(str(what)) - except: - raise connectionLost() - return Connection(s) diff --git a/Lib/idlelib/setup.py b/Lib/idlelib/setup.py deleted file mode 100644 index e683512..0000000 --- a/Lib/idlelib/setup.py +++ /dev/null @@ -1,86 +0,0 @@ -import os,glob -from distutils.core import setup -from distutils.command.build_py import build_py -from distutils.command.install_lib import install_lib -import idlever - -# name of idle package -idlelib = "idlelib" - -# the normal build_py would not incorporate the .txt files -txt_files = ['config-unix.txt','config-win.txt','config.txt', 'help.txt'] -Icons = glob.glob1("Icons","*.gif") -class idle_build_py(build_py): - def get_plain_outfile(self, build_dir, package, file): - # like get_module_outfile, but does not append .py - outfile_path = [build_dir] + list(package) + [file] - return apply(os.path.join, outfile_path) - - def run(self): - # Copies all .py files, then also copies the txt and gif files - build_py.run(self) - assert self.packages == [idlelib] - for name in txt_files: - outfile = self.get_plain_outfile(self.build_lib, [idlelib], name) - dir = os.path.dirname(outfile) - self.mkpath(dir) - self.copy_file(name, outfile, preserve_mode = 0) - for name in Icons: - outfile = self.get_plain_outfile(self.build_lib, - [idlelib,"Icons"], name) - dir = os.path.dirname(outfile) - self.mkpath(dir) - self.copy_file(os.path.join("Icons",name), - outfile, preserve_mode = 0) - - def get_source_files(self): - # returns the .py files, the .txt files, and the icons - icons = [os.path.join("Icons",name) for name in Icons] - return build_py.get_source_files(self)+txt_files+icons - - def get_outputs(self, include_bytecode=1): - # returns the built files - outputs = build_py.get_outputs(self, include_bytecode) - if not include_bytecode: - return outputs - for name in txt_files: - filename = self.get_plain_outfile(self.build_lib, - [idlelib], name) - outputs.append(filename) - for name in Icons: - filename = self.get_plain_outfile(self.build_lib, - [idlelib,"Icons"], name) - outputs.append(filename) - return outputs - -# Arghhh. install_lib thinks that all files returned from build_py's -# get_outputs are bytecode files - -class idle_install_lib(install_lib): - def _bytecode_filenames(self, files): - files = [n for n in files if n.endswith('.py')] - return install_lib._bytecode_filenames(self,files) - -setup(name="IDLE", - version = idlever.IDLE_VERSION, - description = "IDLE Fork, the Forked Python IDE", - author = "Guido van Rossum", - author_email = "guido@python.org", - #url = - long_description = -"""IDLE is a Tkinter based IDE for Python. It is written in 100% pure -Python and works both on Windows and Unix. It features a multi-window -text editor with multiple undo, Python colorizing, and many other things, -as well as a Python shell window and a debugger. - -IDLE Fork is a separate line of development which was initiated by D. Scherer -at CMU as part of Visual Python. It features execution in a separate -process, with a fresh environment for each run. For further details, -refer to idlefork.sourceforge.net.""", - - cmdclass = {'build_py':idle_build_py, - 'install_lib':idle_install_lib}, - package_dir = {idlelib:'.'}, - packages = [idlelib], - scripts = ['idle'] - ) diff --git a/Lib/idlelib/spawn.py b/Lib/idlelib/spawn.py deleted file mode 100644 index be8fdf7..0000000 --- a/Lib/idlelib/spawn.py +++ /dev/null @@ -1,58 +0,0 @@ -# spawn - This is ugly, OS-specific code to spawn a separate process. It -# also defines a function for getting the version of a path most -# likely to work with cranky API functions. - -import os - -def hardpath(path): - path = os.path.normcase(os.path.abspath(path)) - try: - import win32api - path = win32api.GetShortPathName( path ) - except: - pass - return path - -if hasattr(os, 'fork'): - - # UNIX-ish operating system: we fork() and exec(), and we have to track - # the pids of our children and call waitpid() on them to avoid leaving - # zombies in the process table. kill_zombies() does the dirty work, and - # should be called periodically. - - zombies = [] - - def spawn(bin, *args): - pid = os.fork() - if pid: - zombies.append(pid) - else: - os.execv( bin, (bin, ) + args ) - - def kill_zombies(): - for z in zombies[:]: - stat = os.waitpid(z, os.WNOHANG) - if stat[0]==z: - zombies.remove(z) -elif hasattr(os, 'spawnv'): - - # Windows-ish OS: we use spawnv(), and stick quotes around arguments - # in case they contains spaces, since Windows will jam all the - # arguments to spawn() or exec() together into one string. The - # kill_zombies function is a noop. - - def spawn(bin, *args): - nargs = ['"'+bin+'"'] - for arg in args: - nargs.append( '"'+arg+'"' ) - os.spawnv( os.P_NOWAIT, bin, nargs ) - - def kill_zombies(): pass - -else: - # If you get here, you may be able to write an alternative implementation - # of these functions for your OS. - - def kill_zombies(): pass - - raise OSError, 'This OS does not support fork() or spawnv().' diff --git a/Lib/idlelib/tabpage.py b/Lib/idlelib/tabpage.py deleted file mode 100644 index fcd074c..0000000 --- a/Lib/idlelib/tabpage.py +++ /dev/null @@ -1,110 +0,0 @@ -""" -a couple of classes for implementing partial tabbed-page like behaviour -""" - -from Tkinter import * - -class PageTab(Frame): - """ - a 'page tab' like framed button - """ - def __init__(self,parent): - Frame.__init__(self, parent,borderwidth=2,relief=RIDGE) - self.button=Radiobutton(self,padx=5,pady=5,takefocus=FALSE, - underline=0,indicatoron=FALSE,highlightthickness=0, - borderwidth=0,selectcolor=self.cget('bg')) - self.button.pack() - -class TabPageSet(Frame): - """ - a set of 'pages' with TabButtons for controlling their display - """ - def __init__(self,parent,pageNames,**kw): - """ - pageNames - a list of strings, each string will be the dictionary key - to a page's data, and the name displayed on the page's tab. Should be - specified in desired page order. The first page will be the default - and first active page. - """ - Frame.__init__(self, parent, kw) - self.grid_location(0,0) - self.columnconfigure(0,weight=1) - self.rowconfigure(1,weight=1) - self.tabBar=Frame(self) - self.tabBar.grid(row=0,column=0,sticky=EW) - self.activePage=StringVar(self) - self.defaultPage='' - self.pages={} - for name in pageNames: - self.AddPage(name) - - def ChangePage(self,pageName=None): - if pageName: - if pageName in self.pages.keys(): - self.activePage.set(pageName) - else: - raise 'Invalid TabPage Name' - ## pop up the active 'tab' only - for page in self.pages.keys(): - self.pages[page]['tab'].config(relief=RIDGE) - self.pages[self.GetActivePage()]['tab'].config(relief=RAISED) - ## switch page - self.pages[self.GetActivePage()]['page'].lift() - - def GetActivePage(self): - return self.activePage.get() - - def AddPage(self,pageName): - if pageName in self.pages.keys(): - raise 'TabPage Name Already Exists' - self.pages[pageName]={'tab':PageTab(self.tabBar), - 'page':Frame(self,borderwidth=2,relief=RAISED)} - self.pages[pageName]['tab'].button.config(text=pageName, - command=self.ChangePage,variable=self.activePage, - value=pageName) - self.pages[pageName]['tab'].pack(side=LEFT) - self.pages[pageName]['page'].grid(row=1,column=0,sticky=NSEW) - if len(self.pages)==1: # adding first page - self.defaultPage=pageName - self.activePage.set(self.defaultPage) - self.ChangePage() - - def RemovePage(self,pageName): - if not pageName in self.pages.keys(): - raise 'Invalid TabPage Name' - self.pages[pageName]['tab'].pack_forget() - self.pages[pageName]['page'].grid_forget() - self.pages[pageName]['tab'].destroy() - self.pages[pageName]['page'].destroy() - del(self.pages[pageName]) - # handle removing last remaining, or default, or active page - if not self.pages: # removed last remaining page - self.defaultPage='' - return - if pageName==self.defaultPage: # set a new default page - self.defaultPage=\ - self.tabBar.winfo_children()[0].button.cget('text') - if pageName==self.GetActivePage(): # set a new active page - self.activePage.set(self.defaultPage) - self.ChangePage() - -if __name__ == '__main__': - #test dialog - root=Tk() - tabPage=TabPageSet(root,pageNames=['Foobar','Baz']) - tabPage.pack(expand=TRUE,fill=BOTH) - Label(tabPage.pages['Foobar']['page'],text='Foo',pady=20).pack() - Label(tabPage.pages['Foobar']['page'],text='Bar',pady=20).pack() - Label(tabPage.pages['Baz']['page'],text='Baz').pack() - entryPgName=Entry(root) - buttonAdd=Button(root,text='Add Page', - command=lambda:tabPage.AddPage(entryPgName.get())) - buttonRemove=Button(root,text='Remove Page', - command=lambda:tabPage.RemovePage(entryPgName.get())) - labelPgName=Label(root,text='name of page to add/remove:') - buttonAdd.pack(padx=5,pady=5) - buttonRemove.pack(padx=5,pady=5) - labelPgName.pack(padx=5) - entryPgName.pack(padx=5) - root.mainloop() - diff --git a/Lib/idlelib/testcode.py b/Lib/idlelib/testcode.py deleted file mode 100644 index 05eaa56..0000000 --- a/Lib/idlelib/testcode.py +++ /dev/null @@ -1,31 +0,0 @@ -import string - -def f(): - a = 0 - b = 1 - c = 2 - d = 3 - e = 4 - g() - -def g(): - h() - -def h(): - i() - -def i(): - j() - -def j(): - k() - -def k(): - l() - -l = lambda: test() - -def test(): - string.capwords(1) - -f() diff --git a/Lib/idlelib/textView.py b/Lib/idlelib/textView.py deleted file mode 100644 index 9b3fb97..0000000 --- a/Lib/idlelib/textView.py +++ /dev/null @@ -1,77 +0,0 @@ -##---------------------------------------------------------------------------## -## -## idle - simple text view dialog -## elguavas -## -##---------------------------------------------------------------------------## -""" -simple text browser for idle -""" -from Tkinter import * -import tkMessageBox - -class TextViewer(Toplevel): - """ - simple text viewer dialog for idle - """ - def __init__(self,parent,title,fileName): - """ - fileName - string,should be an absoulute filename - """ - Toplevel.__init__(self, parent) - self.configure(borderwidth=5) - self.geometry("+%d+%d" % (parent.winfo_rootx()+10, - parent.winfo_rooty()+10)) - #elguavas - config placeholders til config stuff completed - self.bg=None - self.fg=None - - self.CreateWidgets() - self.title(title) - self.transient(parent) - self.grab_set() - self.protocol("WM_DELETE_WINDOW", self.Ok) - self.parent = parent - self.textView.focus_set() - #key bindings for this dialog - self.bind('',self.Ok) #dismiss dialog - self.bind('',self.Ok) #dismiss dialog - self.LoadTextFile(fileName) - self.textView.config(state=DISABLED) - self.wait_window() - - def LoadTextFile(self, fileName): - textFile = None - try: - textFile = open(fileName, 'r') - except IOError: - tkMessageBox.showerror(title='File Load Error', - message='Unable to load file '+`fileName`+' .') - else: - self.textView.insert(0.0,textFile.read()) - - def CreateWidgets(self): - frameText = Frame(self) - frameButtons = Frame(self) - self.buttonOk = Button(frameButtons,text='Ok', - command=self.Ok,takefocus=FALSE,default=ACTIVE) - self.scrollbarView = Scrollbar(frameText,orient=VERTICAL, - takefocus=FALSE,highlightthickness=0) - self.textView = Text(frameText,wrap=WORD,highlightthickness=0) - self.scrollbarView.config(command=self.textView.yview) - self.textView.config(yscrollcommand=self.scrollbarView.set) - self.buttonOk.pack(padx=5,pady=5) - self.scrollbarView.pack(side=RIGHT,fill=Y) - self.textView.pack(side=LEFT,expand=TRUE,fill=BOTH) - frameButtons.pack(side=BOTTOM,fill=X) - frameText.pack(side=TOP,expand=TRUE,fill=BOTH) - - def Ok(self, event=None): - self.destroy() - -if __name__ == '__main__': - #test the dialog - root=Tk() - Button(root,text='View', - command=lambda:TextViewer(root,'Text','./textView.py')).pack() - root.mainloop() diff --git a/Lib/test/test_cpickle.py b/Lib/test/test_cpickle.py index dda606f..874735b 100644 --- a/Lib/test/test_cpickle.py +++ b/Lib/test/test_cpickle.py @@ -80,6 +80,13 @@ class cPickleFastPicklerTests(AbstractPickleTests): AbstractPickleTests.test_recursive_multi, self) + def test_nonrecursive_deep(self): + a = [] + for i in range(100): + a = [a] + b = self.loads(self.dumps(a)) + self.assertEqual(a, b) + def test_main(): loader = unittest.TestLoader() suite = unittest.TestSuite() diff --git a/Mac/Build/PythonCore.mcp b/Mac/Build/PythonCore.mcp index 03e46e1..140ce15 100644 Binary files a/Mac/Build/PythonCore.mcp and b/Mac/Build/PythonCore.mcp differ diff --git a/Mac/Distributions/(vise)/Python 2.2.vct b/Mac/Distributions/(vise)/Python 2.2.vct index e53f6f4..18e625c 100644 Binary files a/Mac/Distributions/(vise)/Python 2.2.vct and b/Mac/Distributions/(vise)/Python 2.2.vct differ diff --git a/Mac/Distributions/binary.exclude b/Mac/Distributions/binary.exclude index e0b3b92..e61b9a4 100644 --- a/Mac/Distributions/binary.exclude +++ b/Mac/Distributions/binary.exclude @@ -34,3 +34,4 @@ CVS Makefile* Setup.in [(]*[)] +*~[0-9] diff --git a/Mac/Distributions/binary.include b/Mac/Distributions/binary.include index 1c6f417..73279a2 100644 --- a/Mac/Distributions/binary.include +++ b/Mac/Distributions/binary.include @@ -127,6 +127,7 @@ (':Mac:Contrib:PythonScript', '') (':Mac:Contrib:Sherlock', '') (':Mac:Contrib:Tabcleaner', '') +(':Mac:Contrib:mpwsystem', '') (':Mac:Contrib:osam:OSAm.carbon.slb', '') (':Mac:Contrib:osam:OSAm.exp', None) (':Mac:Contrib:osam:OSAm.ppc.slb', '') @@ -149,6 +150,7 @@ (':Mac:ReadMe', ':ReadMe') (':Mac:ReadMe-dev', None) (':Mac:ReadMe-src', None) +(':Mac:ReadMe~0', None) (':Mac:ReadmeSource', None) (':Mac:Relnotes', ':Relnotes:') (':Mac:Resources', None) @@ -219,5 +221,3 @@ (':pystone.py', None) (':setup.py', None) (':site-packages', None) -(':Mac:ReadMe~0', None) -(':Mac:Contrib:mpwsystem', '') diff --git a/Mac/Distributions/dev.exclude b/Mac/Distributions/dev.exclude index 2babfd6..42ad004 100644 --- a/Mac/Distributions/dev.exclude +++ b/Mac/Distributions/dev.exclude @@ -17,3 +17,4 @@ @* CVS [(]*[)] +*~[0-9] diff --git a/Mac/Distributions/dev.include b/Mac/Distributions/dev.include index e7476e6..70c75cb 100644 --- a/Mac/Distributions/dev.include +++ b/Mac/Distributions/dev.include @@ -63,13 +63,16 @@ (':Mac:Build:Printing.mcp', None) (':Mac:Build:Printing.mcp.exp', None) (':Mac:Build:Printing.mcp.xml', None) +(':Mac:Build:PythonCore.axp', None) (':Mac:Build:PythonCore.exp', None) (':Mac:Build:PythonCore.mcp', None) (':Mac:Build:PythonCoreCarbon.exp', None) (':Mac:Build:PythonInterpreter.mcp', None) +(':Mac:Build:PythonInterpreter.old.mcp', None) (':Mac:Build:PythonStandSmall.mcp', None) (':Mac:Build:PythonStandSmall.mcp~0', None) (':Mac:Build:PythonStandSmall.mcp~1', None) +(':Mac:Build:PythonStandSmall.old.mcp', None) (':Mac:Build:PythonStandalone.mcp', None) (':Mac:Build:PythonStandalone.mcp~0', None) (':Mac:Build:PythonStandalone.mcp~1', None) @@ -104,6 +107,12 @@ (':Mac:Build:_CF.carbon.mcp', None) (':Mac:Build:_CF.carbon.mcp.exp', None) (':Mac:Build:_CF.carbon.mcp.xml', None) +(':Mac:Build:_CG.carbon.mcp', None) +(':Mac:Build:_CG.carbon.mcp.exp', None) +(':Mac:Build:_CG.carbon.old.mcp', None) +(':Mac:Build:_CarbonEvt.carbon.mcp', None) +(':Mac:Build:_CarbonEvt.carbon.mcp.exp', None) +(':Mac:Build:_CarbonEvt.carbon.mcp.xml', None) (':Mac:Build:_Cm.carbon.mcp', None) (':Mac:Build:_Cm.carbon.mcp.exp', None) (':Mac:Build:_Cm.carbon.mcp.xml', None) @@ -223,6 +232,7 @@ (':Mac:Build:_Win.mcp.xml', None) (':Mac:Build:_dummy_tkinter.mcp', None) (':Mac:Build:_dummy_tkinter.mcp.exp', None) +(':Mac:Build:_dummy_tkinter.old.mcp', None) (':Mac:Build:_hotshot.carbon.mcp', None) (':Mac:Build:_hotshot.carbon.mcp.exp', None) (':Mac:Build:_hotshot.carbon.mcp.xml', None) @@ -373,6 +383,7 @@ (':Mac:ReadMe', None) (':Mac:ReadMe-dev', ':') (':Mac:ReadMe-src', None) +(':Mac:ReadMe~0', None) (':Mac:Relnotes', None) (':Mac:Relnotes-source', None) (':Mac:Resources:Carbon.r', None) @@ -529,6 +540,8 @@ (':Modules:testcapi_long.h', None) (':Modules:threadmodule.c', None) (':Modules:timemodule.c', None) +(':Modules:timemodule.c~0', None) +(':Modules:timemodule.c~1', None) (':Modules:timing.h', None) (':Modules:timingmodule.c', None) (':Modules:tkappinit.c', None) @@ -600,16 +613,3 @@ (':readmefiles', None) (':setup.py', None) (':site-packages', None) -(':Mac:Build:_CG.carbon.old.mcp', None) -(':Mac:Build:_CG.carbon.mcp.exp', None) -(':Mac:Build:_CG.carbon.mcp', None) -(':Mac:Build:_CarbonEvt.carbon.mcp.xml', None) -(':Mac:Build:_CarbonEvt.carbon.mcp.exp', None) -(':Mac:Build:_CarbonEvt.carbon.mcp', None) -(':Mac:ReadMe~0', None) -(':Modules:timemodule.c~1', None) -(':Modules:timemodule.c~0', None) -(':Mac:Build:PythonStandSmall.old.mcp', None) -(':Mac:Build:PythonInterpreter.old.mcp', None) -(':Mac:Build:PythonCore.axp', None) -(':Mac:Build:_dummy_tkinter.old.mcp', None) diff --git a/Mac/Include/macbuildno.h b/Mac/Include/macbuildno.h index ae377c1..d2179af 100644 --- a/Mac/Include/macbuildno.h +++ b/Mac/Include/macbuildno.h @@ -1 +1 @@ -#define BUILD 121 +#define BUILD 124 diff --git a/Mac/Python/macglue.c b/Mac/Python/macglue.c index e66ab83..f78f97f 100644 --- a/Mac/Python/macglue.c +++ b/Mac/Python/macglue.c @@ -392,6 +392,17 @@ Pstring(char *str) } #if TARGET_API_MAC_OS8 +Point +LMGetMouse(void) +{ + return LMGetMouseLocation(); +} + +long LMGetExpandMem(void) +{ + return 0; +} + void c2pstrcpy(unsigned char *dst, const char *src) { diff --git a/Mac/ReadMe b/Mac/ReadMe index 9745090..17e781f 100644 --- a/Mac/ReadMe +++ b/Mac/ReadMe @@ -1,9 +1,6 @@ -How to install Python 2.2c1 on your Macintosh +How to install Python 2.2 on your Macintosh --------------------------------------------- -This is a release candidate for MacPython 2.2, please report any problems as -soon as possible, by email to pythonmac-sig@python.org. - This is a MacPython that can run on classic MacOS (from 8.1 onwards) and natively on MacOSX. The installer tries to work out whether you can use the Carbon version or not. For Mac OS X users: this version of Python @@ -32,19 +29,19 @@ Mac:Demo. The documentation is sparse, but it will have to serve for now. The documentation is in HTML format, start with index.html. This installer installs MacPython for classic PPC MacOS, MacPython for Carbon -(OS X, OS 9 or OS8 with CarbonLib installed) or both, depending on your +(OS X, OS 9 or OS 8 with CarbonLib installed) or both, depending on your configuration. By selecting custom install you can bypass these tests and install what you want. -If you want 68k support you will have to stay with MacPython 1.5.2. +If you want 68k support you will have get MacPython 1.5.2. Toolbox module reorganization and more -------------------------------------- You can safely skip this section if this is your first encounter with MacPython. -I am working on a new organization of the mac-specific modules, and in -general bringing the MacPython folder structure more in line with +This release has a new organization of the mac-specific modules, and in +general brings the MacPython folder structure more in line with unix-Python. This is not only a good idea, it will also immensely facilitate moving MacPython functionality to an OSX Python that is based on Mach-O and the unix-Python distribution. But don't worry: MacPython @@ -92,6 +89,8 @@ But: - this works only for input, and there's no way to find out what the original linefeed convention of the file was. - Windows \r\n linefeeds are not supported and get turned into \n\n. +- in 2.3 this feature will be replaced by a more general, platform independent + way of handling files with foreign newline conventions. What to install --------------- @@ -169,20 +168,18 @@ ways. Uninstalling ------------ -Two items are installed in the system folder: the interpreter shared -libraries PythonCore and PythonCoreCarbon lives in the Extensions -folder and the "Python 2.2c1 Preferences" file in the Python subfolder +Up to three items are installed in the system folder: the interpreter shared +libraries PythonCore and PythonCoreCarbon live in the Extensions +folder and the "Python 2.2 Preferences" file in the Python subfolder in the Preferences folder. All the rest of Python lives in the folder you installed in. -On OSX the libraries are installed in /Library/CFMSupport. There is a -nasty bug in OSX that is triggered by Python: if any orphaned aliases -are left in /Library/CFMSupport your machine will start to behave very -badly. 2.1 beta installers triggered this problem if you simply threw -away your Python folder, so if you installed a 2.1beta you should -clean out the aliases in /Library/CFMSupport too. The final 2.1 and -2.1.1 installers always copied the shared libraries on OSX, so it does -not have the problem anymore. +On OSX the libraries are installed in /Library/CFMSupport. The ConfigurePython +applets will complain if you have no right to create the libraries there +(you need Admin privileges). This has one consequence: you will not be able to +run applets unless they reside in the MacPython folder (such as the IDE or +EditPythonPrefs). If you try to run an applet stored elsewhere you will +get a "Cannot locate PythonCore" error message. Things to see ------------- @@ -221,9 +218,9 @@ this means you can keep your older version around if you are unsure whether to upgrade. The bad news is that your old preference settings are lost and you have to set them again. -After you are satisfied that 2.2c1 works as expected you can trash +After you are satisfied that 2.2 works as expected you can trash anything in the system folder that has "python" in the name and not -"2.2c1". +"2.2". The ConfigurePython... applets will try to detect incompatible preferences files and offer to remove them. This means that re-running @@ -278,9 +275,9 @@ this purpose. Jack Jansen -Oratrix Development BV -Valeriusplein 30 -Amsterdam +CWI +Kruislaan 413 +1098 SJ Amsterdam the Netherlands , http://www.cwi.nl/~jack diff --git a/Mac/Relnotes b/Mac/Relnotes index 3d99c13..ce67bdb 100644 --- a/Mac/Relnotes +++ b/Mac/Relnotes @@ -1,8 +1,8 @@ -Changes in 2.2c1 since 2.1.1 +Changes in 2.2 since 2.1.1 ---------------------------- These release notes refer to Mac-specific changes only. See NEWS (in the Misc folder) -for machine-independent changes. Changes that are new in 2.2c1 are flagged as such. +for machine-independent changes. - The main change is that all toolbox modules have moved to a package called Carbon. @@ -11,27 +11,27 @@ for machine-independent changes. Changes that are new in 2.2c1 are flagged as su some open questions and join the discussions on pythonmac-sig if you have anything to contribute. Aside from reducing clutter this change will also benefit the port to Mach-O/OSX Python later. -- All toolbox modules have been updated to Universal Headers 3.4. [2.2c1] +- All toolbox modules have been updated to Universal Headers 3.4. - Toolbox modules are weaklinked against InterfaceLib (for PPC builds) and raise - an exception when you call an unimplemented one on an old MacOS. [2.2c1] + an exception when you call an unimplemented one on an old MacOS. - On input MacPython now accepts either \n (unix style) or \r (mac style) newlines for text files. This behaviour can be turned off with a preference. This is an experimental feature; again: feedback is requested. -- The IDE looks better on OS X, but still not as good as on OS9. [2.2c1] +- The IDE looks better on OS X, but still not as good as on OS9. - Command-dot handling has been improved a lot: scripts are now much easier to interrupt, and they only scan for cmd-. while in the foreground. - "Copy" from the MacPython console window was always disabled. Fixed. - This release should run on MacOS 8.1 again. - A new, rather different GUSI I/O library is used. -- time.time() returns positive values again. [2.2c1] +- time.time() returns positive values again. - There is a new module macresource which makes it easier to open a resource file accompanying your script when the script is not (yet) converted to an applet. This module will later also do the right thing in Mach-O/OSX Python. - (Carbon only) experimental modules Carbon.CG (CoreGraphics) and CarbonEvt have - been added. [2.2c1] + been added. - A new, experimental module hfsplus is included, which gives access to some of the functionality of the HFS+ API. -- A new, experimental module gives access to Carbon Events. [2.2c1] +- A new, experimental module gives access to Carbon Events. - Threads had a stack that was too small for many serious Python applications (20K). They now get 64K. There is still no overflow check, though. - Garbage collection and the gc module have (finally) been enabled. @@ -52,11 +52,6 @@ for machine-independent changes. Changes that are new in 2.2c1 are flagged as su - Contrib:morefindertools is gone, the functionality has been integrated into the standard module findertools.py. -What is not in this distribution --------------------------------- - -- The toolbox modules have not all been updated to Universal Header 3.4 or CarbonLib 1.4 yet. - Known problems -------------- @@ -65,7 +60,8 @@ http://www.cwi.nl/~jack/macpython.html. - MacPython 2.2 (and MacPython 2.1) will not run correctly on a multiprocessor MacOS X machine, it will quickly deadlock during I/O operations. The GUSI I/O library is suspected, - hints/clues/workarounds are solicited. + hints/clues/workarounds are solicited. This problem also occurs intermittently on fast + OS X single-processor machines. - Tkinter does not work under Carbon. - The IDE and Tkinter do not work together. Run tkinter programs under PythonInterpreter. - Tkinter file events do not work, unless you have opened the file through Tcl (but then diff --git a/Mac/Unsupported/mactcp/dnrglue.c b/Mac/Unsupported/mactcp/dnrglue.c deleted file mode 100644 index 5474b73..0000000 --- a/Mac/Unsupported/mactcp/dnrglue.c +++ /dev/null @@ -1,301 +0,0 @@ -/* DNR.c - DNR library for MPW - - (c) Copyright 1988 by Apple Computer. All rights reserved - - Modifications by Jim Matthews, Dartmouth College, 5/91 - Again modified for use with python by Jack Jansen, CWI, October 1994. - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "AddressXlation.h" - -TrapType GetTrapType(unsigned long theTrap); -Boolean TrapAvailable(unsigned long trap); -void GetSystemFolder(short *vRefNumP, long *dirIDP); -void GetCPanelFolder(short *vRefNumP, long *dirIDP); -short SearchFolderForDNRP(long targetType, long targetCreator, short vRefNum, long dirID); -short OpenOurRF(void); - -#define OPENRESOLVER 1L -#define CLOSERESOLVER 2L -#define STRTOADDR 3L -#define ADDRTOSTR 4L -#define ENUMCACHE 5L -#define ADDRTONAME 6L -#define HINFO 7L -#define MXINFO 8L - -Handle codeHndl = nil; - -OSErrProcPtr dnr = nil; - -TrapType GetTrapType(theTrap) -unsigned long theTrap; -{ - if (BitAnd(theTrap, 0x0800) > 0) - return(ToolTrap); - else - return(OSTrap); - } - -Boolean TrapAvailable(trap) -unsigned long trap; -{ -TrapType trapType = ToolTrap; -unsigned long numToolBoxTraps; - - if (NGetTrapAddress(_InitGraf, ToolTrap) == NGetTrapAddress(0xAA6E, ToolTrap)) - numToolBoxTraps = 0x200; - else - numToolBoxTraps = 0x400; - - trapType = GetTrapType(trap); - if (trapType == ToolTrap) { - trap = BitAnd(trap, 0x07FF); - if (trap >= numToolBoxTraps) - trap = _Unimplemented; - } - return(NGetTrapAddress(trap, trapType) != NGetTrapAddress(_Unimplemented, ToolTrap)); - -} - -void GetSystemFolder(short *vRefNumP, long *dirIDP) -{ - SysEnvRec info; - long wdProcID; - - SysEnvirons(1, &info); - if (GetWDInfo(info.sysVRefNum, vRefNumP, dirIDP, &wdProcID) != noErr) { - *vRefNumP = 0; - *dirIDP = 0; - } - } - -void GetCPanelFolder(short *vRefNumP, long *dirIDP) -{ - Boolean hasFolderMgr = false; - long feature; - - if (Gestalt(gestaltFindFolderAttr, &feature) == noErr) hasFolderMgr = true; - if (!hasFolderMgr) { - GetSystemFolder(vRefNumP, dirIDP); - return; - } - else { - if (FindFolder(kOnSystemDisk, kControlPanelFolderType, kDontCreateFolder, vRefNumP, dirIDP) != noErr) { - *vRefNumP = 0; - *dirIDP = 0; - } - } - } - -/* SearchFolderForDNRP is called to search a folder for files that might - contain the 'dnrp' resource */ -short SearchFolderForDNRP(long targetType, long targetCreator, short vRefNum, long dirID) -{ - HParamBlockRec fi; - Str255 filename; - short refnum; - - fi.fileParam.ioCompletion = nil; - fi.fileParam.ioNamePtr = filename; - fi.fileParam.ioVRefNum = vRefNum; - fi.fileParam.ioDirID = dirID; - fi.fileParam.ioFDirIndex = 1; - - while (PBHGetFInfo(&fi, false) == noErr) { - /* scan system folder for driver resource files of specific type & creator */ - if (fi.fileParam.ioFlFndrInfo.fdType == targetType && - fi.fileParam.ioFlFndrInfo.fdCreator == targetCreator) { - /* found the MacTCP driver file? */ - refnum = HOpenResFile(vRefNum, dirID, filename, fsRdPerm); - if (GetIndResource('dnrp', 1) == NULL) - CloseResFile(refnum); - else - return refnum; - } - /* check next file in system folder */ - fi.fileParam.ioFDirIndex++; - fi.fileParam.ioDirID = dirID; /* PBHGetFInfo() clobbers ioDirID */ - } - return(-1); - } - -/* OpenOurRF is called to open the MacTCP driver resources */ - -short OpenOurRF() -{ - short refnum; - short vRefNum; - long dirID; - - /* first search Control Panels for MacTCP 1.1 */ - GetCPanelFolder(&vRefNum, &dirID); - refnum = SearchFolderForDNRP('cdev', 'ztcp', vRefNum, dirID); - if (refnum != -1) return(refnum); - - /* next search System Folder for MacTCP 1.0.x */ - GetSystemFolder(&vRefNum, &dirID); - refnum = SearchFolderForDNRP('cdev', 'mtcp', vRefNum, dirID); - if (refnum != -1) return(refnum); - - /* finally, search Control Panels for MacTCP 1.0.x */ - GetCPanelFolder(&vRefNum, &dirID); - refnum = SearchFolderForDNRP('cdev', 'mtcp', vRefNum, dirID); - if (refnum != -1) return(refnum); - - return -1; - } - - -OSErr OpenResolver(fileName) -char *fileName; -{ - short refnum; - OSErr rc; - - if (dnr != nil) - /* resolver already loaded in */ - return(noErr); - - /* open the MacTCP driver to get DNR resources. Search for it based on - creator & type rather than simply file name */ - refnum = OpenOurRF(); - - /* ignore failures since the resource may have been installed in the - System file if running on a Mac 512Ke */ - - /* load in the DNR resource package */ - codeHndl = GetIndResource('dnrp', 1); - if (codeHndl == nil) { - /* can't open DNR */ - return(ResError()); - } - - DetachResource(codeHndl); - if (refnum != -1) { - CloseWD(refnum); - CloseResFile(refnum); - } - - /* lock the DNR resource since it cannot be reloated while opened */ - HLock(codeHndl); - dnr = (OSErrProcPtr) *codeHndl; - - /* call open resolver */ - rc = (*dnr)(OPENRESOLVER, fileName); - if (rc != noErr) { - /* problem with open resolver, flush it */ - HUnlock(codeHndl); - DisposHandle(codeHndl); - dnr = nil; - } - return(rc); - } - - -OSErr CloseResolver() -{ - if (dnr == nil) - /* resolver not loaded error */ - return(notOpenErr); - - /* call close resolver */ - (void) (*dnr)(CLOSERESOLVER); - - /* release the DNR resource package */ - HUnlock(codeHndl); - DisposHandle(codeHndl); - dnr = nil; - return(noErr); - } - -OSErr StrToAddr(hostName, rtnStruct, resultproc, userDataPtr) -char *hostName; -struct hostInfo *rtnStruct; -ResultProcPtr resultproc; -char *userDataPtr; -{ - if (dnr == nil) - /* resolver not loaded error */ - return(notOpenErr); - - return((*dnr)(STRTOADDR, hostName, rtnStruct, resultproc, userDataPtr)); - } - -OSErr AddrToStr(addr, addrStr) -unsigned long addr; -char *addrStr; -{ - if (dnr == nil) - /* resolver not loaded error */ - return(notOpenErr); - - (*dnr)(ADDRTOSTR, addr, addrStr); - return(noErr); - } - -OSErr EnumCache(resultproc, userDataPtr) -EnumResultProcPtr resultproc; -char *userDataPtr; -{ - if (dnr == nil) - /* resolver not loaded error */ - return(notOpenErr); - - return((*dnr)(ENUMCACHE, resultproc, userDataPtr)); - } - - -OSErr AddrToName(addr, rtnStruct, resultproc, userDataPtr) -unsigned long addr; -struct hostInfo *rtnStruct; -ResultProcPtr resultproc; -char *userDataPtr; -{ - if (dnr == nil) - /* resolver not loaded error */ - return(notOpenErr); - - return((*dnr)(ADDRTONAME, addr, rtnStruct, resultproc, userDataPtr)); - } - - -extern OSErr HInfo(hostName, returnRecPtr, resultProc, userDataPtr) -char *hostName; -struct returnRec *returnRecPtr; -ResultProc2Ptr resultProc; -char *userDataPtr; -{ - if (dnr == nil) - /* resolver not loaded error */ - return(notOpenErr); - - return((*dnr)(HINFO, hostName, returnRecPtr, resultProc, userDataPtr)); - - } - -extern OSErr MXInfo(hostName, returnRecPtr, resultProc, userDataPtr) -char *hostName; -struct returnRec *returnRecPtr; -ResultProc2Ptr resultProc; -char *userDataPtr; -{ - if (dnr == nil) - /* resolver not loaded error */ - return(notOpenErr); - - return((*dnr)(MXINFO, hostName, returnRecPtr, resultProc, userDataPtr)); - - } \ No newline at end of file diff --git a/Mac/_checkversion.py b/Mac/_checkversion.py index 443b9b5..79cc591 100644 --- a/Mac/_checkversion.py +++ b/Mac/_checkversion.py @@ -5,7 +5,7 @@ _checkversion.py file""" import pyversioncheck _PACKAGE="MacPython" -_VERSION="2.2b1" +_VERSION="2.2" _URL="http://www.cwi.nl/~jack/macpythonversion.txt" try: diff --git a/Misc/NEWS b/Misc/NEWS index eafe10e..323aae7 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -4,12 +4,38 @@ Release date: 21-Dec-2001 Type/class unification and new-style classes +- pickle.py, cPickle: allow pickling instances of new-style classes + with a custom metaclass. + Core and builtins +- weakref proxy object: when comparing, unwrap both arguments if both + are proxies. + Extension modules +- binascii.b2a_base64(): fix a potential buffer overrun when encoding + very short strings. + +- cPickle: the obscure "fast" mode was suspected of causing stack + overflows on the Mac. Hopefully fixed this by setting the recursion + limit much smaller. If the limit is too low (it only affects + performance), you can change it by defining PY_CPICKLE_FAST_LIMIT + when compiling cPickle.c (or in pyconfig.h). + Library +- dumbdbm.py: fixed a dumb old bug (the file didn't get synched at + close or delete time). + +- rfc822.py: fixed a bug where the address '<>' was converted to None + instead of an empty string (also fixes the email.Utils module). + +- xmlrpclib.py: version 1.0.0; uses precision for doubles. + +- test suite: the pickle and cPickle tests were not executing any code + when run from the standard regresssion test. + Tools/Demos Build @@ -22,8 +48,23 @@ Tests Windows +- distutils package: fixed broken Windows installers (bdist_wininst). + +- tempfile.py: prevent mysterious warnings when TemporaryFileWrapper + instances are deleted at process exit time. + +- socket.py: prevent mysterious warnings when socket instances are + deleted at process exit time. + +- posixmodule.c: fix a Windows crash with stat() of a filename ending + in backslash. + Mac +- The Carbon toolbox modules have been upgraded to Universal Headers + 3.4, and experimental CoreGraphics and CarbonEvents modules have + been added. All only for framework-enabled MacOSX. + What's New in Python 2.2c1? Release date: 14-Dec-2001 diff --git a/Modules/cPickle.c b/Modules/cPickle.c index a4943ce..adf7e44 100644 --- a/Modules/cPickle.c +++ b/Modules/cPickle.c @@ -321,7 +321,9 @@ typedef struct Picklerobject { PyObject *fast_memo; } Picklerobject; -#define FAST_LIMIT 2000 +#ifndef PY_CPICKLE_FAST_LIMIT +#define PY_CPICKLE_FAST_LIMIT 50 +#endif staticforward PyTypeObject Picklertype; @@ -891,7 +893,7 @@ static int fast_save_enter(Picklerobject *self, PyObject *obj) { /* if fast_container < 0, we're doing an error exit. */ - if (++self->fast_container >= FAST_LIMIT) { + if (++self->fast_container >= PY_CPICKLE_FAST_LIMIT) { PyObject *key = NULL; if (self->fast_memo == NULL) { self->fast_memo = PyDict_New(); @@ -921,7 +923,7 @@ fast_save_enter(Picklerobject *self, PyObject *obj) int fast_save_leave(Picklerobject *self, PyObject *obj) { - if (self->fast_container-- >= FAST_LIMIT) { + if (self->fast_container-- >= PY_CPICKLE_FAST_LIMIT) { PyObject *key = PyLong_FromVoidPtr(obj); if (key == NULL) return 0; diff --git a/Python/mysnprintf.c b/Python/mysnprintf.c index e3b72de..4d3770d 100644 --- a/Python/mysnprintf.c +++ b/Python/mysnprintf.c @@ -65,7 +65,7 @@ PyOS_vsnprintf(char *str, size_t size, const char *format, va_list va) len = vsnprintf(str, size, format, va); #else /* Emulate it. */ - buffer = PyMem_Malloc(size + 512); + buffer = PyMem_MALLOC(size + 512); if (buffer == NULL) { len = -666; goto Done; @@ -85,7 +85,7 @@ PyOS_vsnprintf(char *str, size_t size, const char *format, va_list va) memcpy(str, buffer, to_copy); str[to_copy] = '\0'; } - PyMem_Free(buffer); + PyMem_FREE(buffer); Done: #endif str[size-1] = '\0'; -- cgit v0.12