summaryrefslogtreecommitdiff
path: root/Lib/idlelib
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/idlelib')
-rw-r--r--Lib/idlelib/AutoComplete.py6
-rw-r--r--Lib/idlelib/Bindings.py8
-rw-r--r--Lib/idlelib/CREDITS.txt4
-rw-r--r--Lib/idlelib/EditorWindow.py162
-rw-r--r--Lib/idlelib/FileList.py6
-rw-r--r--Lib/idlelib/FormatParagraph.py2
-rw-r--r--Lib/idlelib/HISTORY.txt2
-rw-r--r--Lib/idlelib/IOBinding.py50
-rw-r--r--Lib/idlelib/MultiCall.py2
-rw-r--r--Lib/idlelib/MultiStatusBar.py2
-rw-r--r--Lib/idlelib/NEWS.txt45
-rw-r--r--Lib/idlelib/ObjectBrowser.py2
-rw-r--r--Lib/idlelib/PathBrowser.py2
-rw-r--r--Lib/idlelib/PyShell.py143
-rw-r--r--Lib/idlelib/RemoteDebugger.py2
-rw-r--r--Lib/idlelib/RstripExtension.py29
-rw-r--r--Lib/idlelib/ScriptBinding.py40
-rw-r--r--Lib/idlelib/TreeWidget.py2
-rw-r--r--Lib/idlelib/config-extensions.def6
-rw-r--r--Lib/idlelib/config-keys.def4
-rw-r--r--Lib/idlelib/configDialog.py11
-rw-r--r--Lib/idlelib/configHandler.py2
-rw-r--r--Lib/idlelib/extend.txt2
-rwxr-xr-xLib/idlelib/idle.bat5
-rw-r--r--Lib/idlelib/idle.py32
-rw-r--r--Lib/idlelib/idlever.py2
-rw-r--r--Lib/idlelib/macosxSupport.py107
-rw-r--r--Lib/idlelib/rpc.py14
-rw-r--r--Lib/idlelib/run.py16
-rw-r--r--Lib/idlelib/textView.py24
30 files changed, 468 insertions, 266 deletions
diff --git a/Lib/idlelib/AutoComplete.py b/Lib/idlelib/AutoComplete.py
index fa1733f9a6..4e173252d6 100644
--- a/Lib/idlelib/AutoComplete.py
+++ b/Lib/idlelib/AutoComplete.py
@@ -190,8 +190,7 @@ class AutoComplete:
bigl = eval("dir()", namespace)
bigl.sort()
if "__all__" in bigl:
- smalll = eval("__all__", namespace)
- smalll.sort()
+ smalll = sorted(eval("__all__", namespace))
else:
smalll = [s for s in bigl if s[:1] != '_']
else:
@@ -200,8 +199,7 @@ class AutoComplete:
bigl = dir(entity)
bigl.sort()
if "__all__" in bigl:
- smalll = entity.__all__
- smalll.sort()
+ smalll = sorted(entity.__all__)
else:
smalll = [s for s in bigl if s[:1] != '_']
except:
diff --git a/Lib/idlelib/Bindings.py b/Lib/idlelib/Bindings.py
index 74a93d3b14..ec2720b0d0 100644
--- a/Lib/idlelib/Bindings.py
+++ b/Lib/idlelib/Bindings.py
@@ -98,14 +98,6 @@ if macosxSupport.runningAsOSXApp():
# menu
del menudefs[-1][1][0:2]
- menudefs.insert(0,
- ('application', [
- ('About IDLE', '<<about-idle>>'),
- None,
- ('_Preferences....', '<<open-config-dialog>>'),
- ]))
-
-
default_keydefs = idleConf.GetCurrentKeySet()
del sys
diff --git a/Lib/idlelib/CREDITS.txt b/Lib/idlelib/CREDITS.txt
index 456079b8ca..5ff599dee1 100644
--- a/Lib/idlelib/CREDITS.txt
+++ b/Lib/idlelib/CREDITS.txt
@@ -25,8 +25,8 @@ integration, debugger integration and persistent breakpoints).
Scott David Daniels, Tal Einat, Hernan Foffani, Christos Georgiou,
Jim Jewett, Martin v. Löwis, Jason Orendorff, Guilherme Polo, Josh Robb,
-Nigel Rowe, Bruce Sherwood, and Jeff Shute have submitted useful patches.
-Thanks, guys!
+Nigel Rowe, Bruce Sherwood, Jeff Shute, and Weeble have submitted useful
+patches. Thanks, guys!
For additional details refer to NEWS.txt and Changelog.
diff --git a/Lib/idlelib/EditorWindow.py b/Lib/idlelib/EditorWindow.py
index 7cc69cbf00..fb05245dc3 100644
--- a/Lib/idlelib/EditorWindow.py
+++ b/Lib/idlelib/EditorWindow.py
@@ -2,7 +2,6 @@ import sys
import os
import re
import imp
-from itertools import count
from Tkinter import *
import tkSimpleDialog
import tkMessageBox
@@ -27,8 +26,10 @@ def _sphinx_version():
major, minor, micro, level, serial = sys.version_info
release = '%s%s' % (major, minor)
if micro:
- release += '%s' % micro
- if level != 'final':
+ release += '%s' % (micro,)
+ if level == 'candidate':
+ release += 'rc%s' % (serial,)
+ elif level != 'final':
release += '%s%s' % (level[0], serial)
return release
@@ -47,8 +48,67 @@ def _find_module(fullname, path=None):
path = module.__path__
except AttributeError:
raise ImportError, 'No source for module ' + module.__name__
+ if descr[2] != imp.PY_SOURCE:
+ # If all of the above fails and didn't raise an exception,fallback
+ # to a straight import which can find __init__.py in a package.
+ m = __import__(fullname)
+ try:
+ filename = m.__file__
+ except AttributeError:
+ pass
+ else:
+ file = None
+ base, ext = os.path.splitext(filename)
+ if ext == '.pyc':
+ ext = '.py'
+ filename = base + ext
+ descr = filename, None, imp.PY_SOURCE
return file, filename, descr
+
+class HelpDialog(object):
+
+ def __init__(self):
+ self.parent = None # parent of help window
+ self.dlg = None # the help window iteself
+
+ def display(self, parent, near=None):
+ """ Display the help dialog.
+
+ parent - parent widget for the help window
+
+ near - a Toplevel widget (e.g. EditorWindow or PyShell)
+ to use as a reference for placing the help window
+ """
+ if self.dlg is None:
+ self.show_dialog(parent)
+ if near:
+ self.nearwindow(near)
+
+ def show_dialog(self, parent):
+ self.parent = parent
+ fn=os.path.join(os.path.abspath(os.path.dirname(__file__)),'help.txt')
+ self.dlg = dlg = textView.view_file(parent,'Help',fn, modal=False)
+ dlg.bind('<Destroy>', self.destroy, '+')
+
+ def nearwindow(self, near):
+ # Place the help dialog near the window specified by parent.
+ # Note - this may not reposition the window in Metacity
+ # if "/apps/metacity/general/disable_workarounds" is enabled
+ dlg = self.dlg
+ geom = (near.winfo_rootx() + 10, near.winfo_rooty() + 10)
+ dlg.withdraw()
+ dlg.geometry("=+%d+%d" % geom)
+ dlg.deiconify()
+ dlg.lift()
+
+ def destroy(self, ev=None):
+ self.dlg = None
+ self.parent = None
+
+helpDialog = HelpDialog() # singleton instance
+
+
class EditorWindow(object):
from idlelib.Percolator import Percolator
from idlelib.ColorDelegator import ColorDelegator
@@ -101,8 +161,8 @@ class EditorWindow(object):
self.top = top = WindowList.ListedToplevel(root, menu=self.menubar)
if flist:
self.tkinter_vars = flist.vars
- #self.top.instance_dict makes flist.inversedict avalable to
- #configDialog.py so it can access all EditorWindow instaces
+ #self.top.instance_dict makes flist.inversedict available to
+ #configDialog.py so it can access all EditorWindow instances
self.top.instance_dict = flist.inversedict
else:
self.tkinter_vars = {} # keys: Tkinter event names
@@ -135,6 +195,14 @@ class EditorWindow(object):
if macosxSupport.runningAsOSXApp():
# Command-W on editorwindows doesn't work without this.
text.bind('<<close-window>>', self.close_event)
+ # Some OS X systems have only one mouse button,
+ # so use control-click for pulldown menus there.
+ # (Note, AquaTk defines <2> as the right button if
+ # present and the Tk Text widget already binds <2>.)
+ text.bind("<Control-Button-1>",self.right_menu_event)
+ else:
+ # Elsewhere, use right-click for pulldown menus.
+ text.bind("<3>",self.right_menu_event)
text.bind("<<cut>>", self.cut)
text.bind("<<copy>>", self.copy)
text.bind("<<paste>>", self.paste)
@@ -153,7 +221,6 @@ class EditorWindow(object):
text.bind("<<find-selection>>", self.find_selection_event)
text.bind("<<replace>>", self.replace_event)
text.bind("<<goto-line>>", self.goto_line_event)
- text.bind("<3>", self.right_menu_event)
text.bind("<<smart-backspace>>",self.smart_backspace_event)
text.bind("<<newline-and-indent>>",self.newline_and_indent_event)
text.bind("<<smart-indent>>",self.smart_indent_event)
@@ -299,13 +366,13 @@ class EditorWindow(object):
return "break"
def home_callback(self, event):
- if (event.state & 12) != 0 and event.keysym == "Home":
- # state&1==shift, state&4==control, state&8==alt
- return # <Modifier-Home>; fall back to class binding
-
+ if (event.state & 4) != 0 and event.keysym == "Home":
+ # state&4==Control. If <Control-Home>, use the Tk binding.
+ return
if self.text.index("iomark") and \
self.text.compare("iomark", "<=", "insert lineend") and \
self.text.compare("insert linestart", "<=", "iomark"):
+ # In Shell on input line, go to just after prompt
insertpt = int(self.text.index("iomark").split(".")[1])
else:
line = self.text.get("insert linestart", "insert lineend")
@@ -314,30 +381,27 @@ class EditorWindow(object):
break
else:
insertpt=len(line)
-
lineat = int(self.text.index("insert").split('.')[1])
-
if insertpt == lineat:
insertpt = 0
-
dest = "insert linestart+"+str(insertpt)+"c"
-
if (event.state&1) == 0:
- # shift not pressed
+ # shift was not pressed
self.text.tag_remove("sel", "1.0", "end")
else:
if not self.text.index("sel.first"):
- self.text.mark_set("anchor","insert")
-
+ self.text.mark_set("my_anchor", "insert") # there was no previous selection
+ else:
+ if self.text.compare(self.text.index("sel.first"), "<", self.text.index("insert")):
+ self.text.mark_set("my_anchor", "sel.first") # extend back
+ else:
+ self.text.mark_set("my_anchor", "sel.last") # extend forward
first = self.text.index(dest)
- last = self.text.index("anchor")
-
+ last = self.text.index("my_anchor")
if self.text.compare(first,">",last):
first,last = last,first
-
self.text.tag_remove("sel", "1.0", "end")
self.text.tag_add("sel", first, last)
-
self.text.mark_set("insert", dest)
self.text.see("insert")
return "break"
@@ -384,7 +448,7 @@ class EditorWindow(object):
menudict[name] = menu = Menu(mbar, name=name)
mbar.add_cascade(label=label, menu=menu, underline=underline)
- if macosxSupport.runningAsOSXApp():
+ if macosxSupport.isCarbonAquaTk(self.root):
# Insert the application menu
menudict['application'] = menu = Menu(mbar, name='apple')
mbar.add_cascade(label='IDLE', menu=menu)
@@ -439,12 +503,19 @@ class EditorWindow(object):
configDialog.ConfigDialog(self.top,'Settings')
def help_dialog(self, event=None):
- fn=os.path.join(os.path.abspath(os.path.dirname(__file__)),'help.txt')
- textView.view_file(self.top,'Help',fn)
+ if self.root:
+ parent = self.root
+ else:
+ parent = self.top
+ helpDialog.display(parent, near=self.top)
def python_docs(self, event=None):
if sys.platform[:3] == 'win':
- os.startfile(self.help_url)
+ try:
+ os.startfile(self.help_url)
+ except WindowsError as why:
+ tkMessageBox.showerror(title='Document Start Failure',
+ message=str(why), parent=self.text)
else:
webbrowser.open(self.help_url)
return "break"
@@ -704,8 +775,8 @@ class EditorWindow(object):
if accel:
itemName = menu.entrycget(index, 'label')
event = ''
- if menuEventDict.has_key(menubarItem):
- if menuEventDict[menubarItem].has_key(itemName):
+ if menubarItem in menuEventDict:
+ if itemName in menuEventDict[menubarItem]:
event = menuEventDict[menubarItem][itemName]
if event:
accel = get_accelerator(keydefs, event)
@@ -739,9 +810,13 @@ class EditorWindow(object):
"Create a callback with the helpfile value frozen at definition time"
def display_extra_help(helpfile=helpfile):
if not helpfile.startswith(('www', 'http')):
- url = os.path.normpath(helpfile)
+ helpfile = os.path.normpath(helpfile)
if sys.platform[:3] == 'win':
- os.startfile(helpfile)
+ try:
+ os.startfile(helpfile)
+ except WindowsError as why:
+ tkMessageBox.showerror(title='Document Start Failure',
+ message=str(why), parent=self.text)
else:
webbrowser.open(helpfile)
return display_extra_help
@@ -768,17 +843,22 @@ class EditorWindow(object):
rf_list = [path for path in rf_list if path not in bad_paths]
ulchars = "1234567890ABCDEFGHIJK"
rf_list = rf_list[0:len(ulchars)]
- rf_file = open(self.recent_files_path, 'w')
try:
- rf_file.writelines(rf_list)
- finally:
- rf_file.close()
+ with open(self.recent_files_path, 'w') as rf_file:
+ rf_file.writelines(rf_list)
+ except IOError as err:
+ if not getattr(self.root, "recentfilelist_error_displayed", False):
+ self.root.recentfilelist_error_displayed = True
+ tkMessageBox.showerror(title='IDLE Error',
+ message='Unable to update Recent Files list:\n%s'
+ % str(err),
+ parent=self.text)
# for each edit window instance, construct the recent files menu
for instance in self.top.instance_dict.keys():
menu = instance.recent_files_menu
menu.delete(1, END) # clear, and rebuild:
- for i, file in zip(count(), rf_list):
- file_name = file[0:-1] # zap \n
+ for i, file_name in enumerate(rf_list):
+ file_name = file_name.rstrip() # zap \n
# make unicode string to display non-ASCII chars correctly
ufile_name = self._filename_to_unicode(file_name)
callback = instance.__recent_file_callback(file_name)
@@ -1102,7 +1182,10 @@ class EditorWindow(object):
assert have > 0
want = ((have - 1) // self.indentwidth) * self.indentwidth
# Debug prompt is multilined....
- last_line_of_prompt = sys.ps1.split('\n')[-1]
+ if self.context_use_ps1:
+ last_line_of_prompt = sys.ps1.split('\n')[-1]
+ else:
+ last_line_of_prompt = ''
ncharsdeleted = 0
while 1:
if chars == last_line_of_prompt:
@@ -1525,7 +1608,12 @@ keynames = {
def get_accelerator(keydefs, eventname):
keylist = keydefs.get(eventname)
- if not keylist:
+ # issue10940: temporary workaround to prevent hang with OS X Cocoa Tk 8.5
+ # if not keylist:
+ if (not keylist) or (macosxSupport.runningAsOSXApp() and eventname in {
+ "<<open-module>>",
+ "<<goto-line>>",
+ "<<change-indentwidth>>"}):
return ""
s = keylist[0]
s = re.sub(r"-[a-z]\b", lambda m: m.group().upper(), s)
diff --git a/Lib/idlelib/FileList.py b/Lib/idlelib/FileList.py
index 5622805524..8318ff17b2 100644
--- a/Lib/idlelib/FileList.py
+++ b/Lib/idlelib/FileList.py
@@ -25,7 +25,7 @@ class FileList:
master=self.root)
return None
key = os.path.normcase(filename)
- if self.dict.has_key(key):
+ if key in self.dict:
edit = self.dict[key]
edit.top.wakeup()
return edit
@@ -43,7 +43,7 @@ class FileList:
def new(self, filename=None):
return self.EditorWindow(self, filename)
- def close_all_callback(self, event):
+ def close_all_callback(self, *args, **kwds):
for edit in self.inversedict.keys():
reply = edit.close()
if reply == "cancel":
@@ -79,7 +79,7 @@ class FileList:
newkey = os.path.normcase(filename)
if newkey == key:
return
- if self.dict.has_key(newkey):
+ if newkey in self.dict:
conflict = self.dict[newkey]
self.inversedict[conflict] = None
tkMessageBox.showerror(
diff --git a/Lib/idlelib/FormatParagraph.py b/Lib/idlelib/FormatParagraph.py
index 02f96d493a..6a5f9b5dd5 100644
--- a/Lib/idlelib/FormatParagraph.py
+++ b/Lib/idlelib/FormatParagraph.py
@@ -54,7 +54,7 @@ class FormatParagraph:
# 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,
+ # lines, but whatever!) Can't think of a clean solution,
# so we hack away
block_suffix = ""
if not newdata[-1]:
diff --git a/Lib/idlelib/HISTORY.txt b/Lib/idlelib/HISTORY.txt
index c0faaad872..01d73ed2ba 100644
--- a/Lib/idlelib/HISTORY.txt
+++ b/Lib/idlelib/HISTORY.txt
@@ -13,7 +13,7 @@ What's New in IDLEfork 0.8.1?
- New tarball released as a result of the 'revitalisation' of the IDLEfork
project.
-- This release requires python 2.1 or better. Compatability with earlier
+- This release requires python 2.1 or better. Compatibility with earlier
versions of python (especially ancient ones like 1.5x) is no longer a
priority in IDLEfork development.
diff --git a/Lib/idlelib/IOBinding.py b/Lib/idlelib/IOBinding.py
index cbc1c3343e..c515432ddc 100644
--- a/Lib/idlelib/IOBinding.py
+++ b/Lib/idlelib/IOBinding.py
@@ -266,7 +266,7 @@ class IOBinding:
self.reset_undo()
self.set_filename(filename)
self.text.mark_set("insert", "1.0")
- self.text.see("insert")
+ self.text.yview("insert")
self.updaterecentfileslist(filename)
return True
@@ -320,17 +320,20 @@ class IOBinding:
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":
+ confirm = tkMessageBox.askyesnocancel(
+ title="Save On Close",
+ message=message,
+ default=tkMessageBox.YES,
+ master=self.text)
+ if confirm:
+ reply = "yes"
self.save(None)
if not self.get_saved():
reply = "cancel"
+ elif confirm is None:
+ reply = "cancel"
+ else:
+ reply = "no"
self.text.focus_set()
return reply
@@ -339,7 +342,7 @@ class IOBinding:
self.save_as(event)
else:
if self.writefile(self.filename):
- self.set_saved(1)
+ self.set_saved(True)
try:
self.editwin.store_file_breaks()
except AttributeError: # may be a PyShell
@@ -465,15 +468,12 @@ class IOBinding:
self.text.insert("end-1c", "\n")
def print_window(self, event):
- m = tkMessageBox.Message(
- title="Print",
- message="Print to Default Printer",
- icon=tkMessageBox.QUESTION,
- type=tkMessageBox.OKCANCEL,
- default=tkMessageBox.OK,
- master=self.text)
- reply = m.show()
- if reply != tkMessageBox.OK:
+ confirm = tkMessageBox.askokcancel(
+ title="Print",
+ message="Print to Default Printer",
+ default=tkMessageBox.OK,
+ master=self.text)
+ if not confirm:
self.text.focus_set()
return "break"
tempfilename = None
@@ -488,8 +488,8 @@ class IOBinding:
if not self.writefile(tempfilename):
os.unlink(tempfilename)
return "break"
- platform=os.name
- printPlatform=1
+ platform = os.name
+ printPlatform = True
if platform == 'posix': #posix platform
command = idleConf.GetOption('main','General',
'print-command-posix')
@@ -497,7 +497,7 @@ class IOBinding:
elif platform == 'nt': #win32 platform
command = idleConf.GetOption('main','General','print-command-win')
else: #no printing for this platform
- printPlatform=0
+ printPlatform = False
if printPlatform: #we can try to print for this platform
command = command % filename
pipe = os.popen(command, "r")
@@ -511,7 +511,7 @@ class IOBinding:
output = "Printing command: %s\n" % repr(command) + output
tkMessageBox.showerror("Print status", output, master=self.text)
else: #no printing for this platform
- message="Printing is not enabled for this platform: %s" % platform
+ message = "Printing is not enabled for this platform: %s" % platform
tkMessageBox.showinfo("Print status", message, master=self.text)
if tempfilename:
os.unlink(tempfilename)
@@ -521,8 +521,8 @@ class IOBinding:
savedialog = None
filetypes = [
- ("Python and text files", "*.py *.pyw *.txt", "TEXT"),
- ("All text files", "*", "TEXT"),
+ ("Python files", "*.py *.pyw", "TEXT"),
+ ("Text files", "*.txt", "TEXT"),
("All files", "*"),
]
diff --git a/Lib/idlelib/MultiCall.py b/Lib/idlelib/MultiCall.py
index 5b73481535..b81c5ed7d0 100644
--- a/Lib/idlelib/MultiCall.py
+++ b/Lib/idlelib/MultiCall.py
@@ -201,7 +201,7 @@ class _ComplexBinder:
seq, handler)))
def bind(self, triplet, func):
- if not self.bindedfuncs.has_key(triplet[2]):
+ if triplet[2] not in self.bindedfuncs:
self.bindedfuncs[triplet[2]] = [[] for s in _states]
for s in _states:
lists = [ self.bindedfuncs[detail][i]
diff --git a/Lib/idlelib/MultiStatusBar.py b/Lib/idlelib/MultiStatusBar.py
index 2d4c5473d4..8ee2d03d04 100644
--- a/Lib/idlelib/MultiStatusBar.py
+++ b/Lib/idlelib/MultiStatusBar.py
@@ -9,7 +9,7 @@ class MultiStatusBar(Frame):
self.labels = {}
def set_label(self, name, text='', side=LEFT):
- if not self.labels.has_key(name):
+ if name not in self.labels:
label = Label(self, bd=1, relief=SUNKEN, anchor=W)
label.pack(side=side)
self.labels[name] = label
diff --git a/Lib/idlelib/NEWS.txt b/Lib/idlelib/NEWS.txt
index bb4c1431fe..46ef3cb658 100644
--- a/Lib/idlelib/NEWS.txt
+++ b/Lib/idlelib/NEWS.txt
@@ -1,36 +1,45 @@
-What's New in Python 2.6.4rc1
-=============================
+What's New in IDLE 2.7.2?
+=======================
-*Release date: 07-Oct-2009*
+*Release date: 29-May-2011*
-- OutputWindow/PyShell right click menu "Go to file/line" wasn't working with
- file paths containing spaces. Bug 5559.
+- Issue #6378: Further adjust idle.bat to start associated Python
-What's New in Python 2.6.3
-==========================
+- Issue #11896: Save on Close failed despite selecting "Yes" in dialog.
-*Release date: 02-Oct-2009*
+- <Home> toggle failing on Tk 8.5, causing IDLE exits and strange selection
+ behavior. Issue 4676. Improve selection extension behaviour.
-What's New in IDLE 2.6.3rc1?
-============================
+- <Home> toggle non-functional when NumLock set on Windows. Issue 3851.
-*Release date: 28-Sep-2009*
-- On OS X IDLE 2.6 shows two Preference menu items. Issue6951.
+What's New in IDLE 2.7?
+=======================
+
+*Release date: 07-03-2010*
+
+- idle.py modified and simplified to better support developing experimental
+ versions of IDLE which are not installed in the standard location.
+
+- OutputWindow/PyShell right click menu "Go to file/line" wasn't working with
+ file paths containing spaces. Bug 5559.
- Windows: Version string for the .chm help file changed, file not being
accessed Patch 5783 Guilherme Polo
-- Tk 8.5 Text widget requires 'wordprocessor' tabstyle attr to handle
- mixed space/tab properly. Issue 5129, patch by Guilherme Polo.
+- Allow multiple IDLE GUI/subprocess pairs to exist simultaneously. Thanks to
+ David Scherer for suggesting the use of an ephemeral port for the GUI.
+ Patch 1529142 Weeble.
-What's New in IDLE 2.6.2rc1?
-============================
+- Remove port spec from run.py and fix bug where subprocess fails to
+ extract port from command line when warnings are present.
-*Release date: 06-Apr-2009*
+- Tk 8.5 Text widget requires 'wordprocessor' tabstyle attr to handle
+ mixed space/tab properly. Issue 5129, patch by Guilherme Polo.
- Issue #3549: On MacOS the preferences menu was not present
+
What's New in IDLE 2.6?
=======================
@@ -56,7 +65,7 @@ What's New in IDLE 2.6a1?
in the config dialog would cause non-Python files to be colored as if they
were Python source; improve use of ColorDelagator. Patch 1334. Tal Einat.
-- ScriptBinding event handlers weren't returning 'break'. Patch 2050, Tal Einat
+- ScriptBinding event handlers weren't returning 'break'. Patch 2050, Tal Einat.
- There was an error on exit if no sys.exitfunc was defined. Issue 1647.
diff --git a/Lib/idlelib/ObjectBrowser.py b/Lib/idlelib/ObjectBrowser.py
index 83830812a2..7de698816f 100644
--- a/Lib/idlelib/ObjectBrowser.py
+++ b/Lib/idlelib/ObjectBrowser.py
@@ -126,7 +126,7 @@ dispatch = {
def make_objecttreeitem(labeltext, object, setfunction=None):
t = type(object)
- if dispatch.has_key(t):
+ if t in dispatch:
c = dispatch[t]
else:
c = ObjectTreeItem
diff --git a/Lib/idlelib/PathBrowser.py b/Lib/idlelib/PathBrowser.py
index 6b2c0712e6..d88a48e344 100644
--- a/Lib/idlelib/PathBrowser.py
+++ b/Lib/idlelib/PathBrowser.py
@@ -78,7 +78,7 @@ class DirBrowserTreeItem(TreeItem):
normed_name = os.path.normcase(name)
if normed_name[i:] == suff:
mod_name = name[:i]
- if not modules.has_key(mod_name):
+ if mod_name not in modules:
modules[mod_name] = None
sorted.append((normed_name, name))
allnames.remove(name)
diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py
index 6524dffa12..895d7dac09 100644
--- a/Lib/idlelib/PyShell.py
+++ b/Lib/idlelib/PyShell.py
@@ -36,7 +36,8 @@ from idlelib import RemoteDebugger
from idlelib import macosxSupport
IDENTCHARS = string.ascii_letters + string.digits + "_"
-LOCALHOST = '127.0.0.1'
+HOST = '127.0.0.1' # python execution server on localhost loopback
+PORT = 0 # someday pass in host, port for remote debug capability
try:
from signal import SIGTERM
@@ -56,20 +57,21 @@ except ImportError:
else:
def idle_showwarning(message, category, filename, lineno,
file=None, line=None):
- file = warning_stream
+ if file is None:
+ file = warning_stream
try:
- file.write(warnings.formatwarning(message, category, filename,\
- lineno, file=file, line=line))
+ file.write(warnings.formatwarning(message, category, filename,
+ lineno, line=line))
except IOError:
pass ## file (probably __stderr__) is invalid, warning dropped.
warnings.showwarning = idle_showwarning
- def idle_formatwarning(message, category, filename, lineno,
- file=None, line=None):
+ def idle_formatwarning(message, category, filename, lineno, line=None):
"""Format warnings the IDLE way"""
s = "\nWarning (from warnings module):\n"
s += ' File \"%s\", line %s\n' % (filename, lineno)
- line = linecache.getline(filename, lineno).strip() \
- if line is None else line
+ if line is None:
+ line = linecache.getline(filename, lineno)
+ line = line.strip()
if line:
s += " %s\n" % line
s += "%s: %s\n>>> " % (category.__name__, message)
@@ -82,18 +84,17 @@ def extended_linecache_checkcache(filename=None,
Rather than repeating the linecache code, patch it to save the
<pyshell#...> entries, call the original linecache.checkcache()
- (which destroys them), and then restore the saved entries.
+ (skipping them), and then restore the saved entries.
orig_checkcache is bound at definition time to the original
method, allowing it to be patched.
-
"""
cache = linecache.cache
save = {}
- for filename in cache.keys():
- if filename[:1] + filename[-1:] == '<>':
- save[filename] = cache[filename]
- orig_checkcache()
+ for key in list(cache):
+ if key[:1] + key[-1:] == '<>':
+ save[key] = cache.pop(key)
+ orig_checkcache(filename)
cache.update(save)
# Patch linecache.checkcache():
@@ -206,18 +207,26 @@ class PyShellEditorWindow(EditorWindow):
breaks = self.breakpoints
filename = self.io.filename
try:
- lines = open(self.breakpointPath,"r").readlines()
+ with open(self.breakpointPath,"r") as old_file:
+ lines = old_file.readlines()
except IOError:
lines = []
- new_file = open(self.breakpointPath,"w")
- for line in lines:
- if not line.startswith(filename + '='):
- new_file.write(line)
- self.update_breakpoints()
- breaks = self.breakpoints
- if breaks:
- new_file.write(filename + '=' + str(breaks) + '\n')
- new_file.close()
+ try:
+ with open(self.breakpointPath,"w") as new_file:
+ for line in lines:
+ if not line.startswith(filename + '='):
+ new_file.write(line)
+ self.update_breakpoints()
+ breaks = self.breakpoints
+ if breaks:
+ new_file.write(filename + '=' + str(breaks) + '\n')
+ except IOError as err:
+ if not getattr(self.root, "breakpoint_error_displayed", False):
+ self.root.breakpoint_error_displayed = True
+ tkMessageBox.showerror(title='IDLE Error',
+ message='Unable to update breakpoint list:\n%s'
+ % str(err),
+ parent=self.text)
def restore_file_breaks(self):
self.text.update() # this enables setting "BREAK" tags to be visible
@@ -341,17 +350,22 @@ class ModifiedInterpreter(InteractiveInterpreter):
InteractiveInterpreter.__init__(self, locals=locals)
self.save_warnings_filters = None
self.restarting = False
- self.subprocess_arglist = self.build_subprocess_arglist()
+ self.subprocess_arglist = None
+ self.port = PORT
+ self.original_compiler_flags = self.compile.compiler.flags
- port = 8833
rpcclt = None
rpcpid = None
def spawn_subprocess(self):
+ if self.subprocess_arglist is None:
+ self.subprocess_arglist = self.build_subprocess_arglist()
args = self.subprocess_arglist
self.rpcpid = os.spawnv(os.P_NOWAIT, sys.executable, args)
def build_subprocess_arglist(self):
+ assert (self.port!=0), (
+ "Socket should have been assigned a port number.")
w = ['-W' + s for s in sys.warnoptions]
if 1/2 > 0: # account for new division
w.append('-Qnew')
@@ -372,11 +386,8 @@ class ModifiedInterpreter(InteractiveInterpreter):
return [decorated_exec] + w + ["-c", command, str(self.port)]
def start_subprocess(self):
- # spawning first avoids passing a listening socket to the subprocess
- self.spawn_subprocess()
- #time.sleep(20) # test to simulate GUI not accepting connection
- addr = (LOCALHOST, self.port)
- # Idle starts listening for connection on localhost
+ addr = (HOST, self.port)
+ # GUI makes several attempts to acquire socket, listens for connection
for i in range(3):
time.sleep(i)
try:
@@ -387,6 +398,18 @@ class ModifiedInterpreter(InteractiveInterpreter):
else:
self.display_port_binding_error()
return None
+ # if PORT was 0, system will assign an 'ephemeral' port. Find it out:
+ self.port = self.rpcclt.listening_sock.getsockname()[1]
+ # if PORT was not 0, probably working with a remote execution server
+ if PORT != 0:
+ # To allow reconnection within the 2MSL wait (cf. Stevens TCP
+ # V1, 18.6), set SO_REUSEADDR. Note that this can be problematic
+ # on Windows since the implementation allows two active sockets on
+ # the same address!
+ self.rpcclt.listening_sock.setsockopt(socket.SOL_SOCKET,
+ socket.SO_REUSEADDR, 1)
+ self.spawn_subprocess()
+ #time.sleep(20) # test to simulate GUI not accepting connection
# Accept the connection from the Python execution server
self.rpcclt.listening_sock.settimeout(10)
try:
@@ -400,11 +423,11 @@ class ModifiedInterpreter(InteractiveInterpreter):
self.rpcclt.register("flist", self.tkconsole.flist)
self.rpcclt.register("linecache", linecache)
self.rpcclt.register("interp", self)
- self.transfer_path()
+ self.transfer_path(with_cwd=True)
self.poll_subprocess()
return self.rpcclt
- def restart_subprocess(self):
+ def restart_subprocess(self, with_cwd=False):
if self.restarting:
return self.rpcclt
self.restarting = True
@@ -428,7 +451,7 @@ class ModifiedInterpreter(InteractiveInterpreter):
except socket.timeout, err:
self.display_no_subprocess_error()
return None
- self.transfer_path()
+ self.transfer_path(with_cwd=with_cwd)
# annotate restart in shell window and mark it
console.text.delete("iomark", "end-1c")
if was_executing:
@@ -445,6 +468,7 @@ class ModifiedInterpreter(InteractiveInterpreter):
gui = RemoteDebugger.restart_subprocess_debugger(self.rpcclt)
# reload remote debugger breakpoints for all PyShellEditWindows
debug.load_breakpoints()
+ self.compile.compiler.flags = self.original_compiler_flags
self.restarting = False
return self.rpcclt
@@ -477,12 +501,18 @@ class ModifiedInterpreter(InteractiveInterpreter):
except OSError:
return
- def transfer_path(self):
+ def transfer_path(self, with_cwd=False):
+ if with_cwd: # Issue 13506
+ path = [''] # include Current Working Directory
+ path.extend(sys.path)
+ else:
+ path = sys.path
+
self.runcommand("""if 1:
import sys as _sys
_sys.path = %r
del _sys
- \n""" % (sys.path,))
+ \n""" % (path,))
active_seq = None
@@ -753,13 +783,12 @@ class ModifiedInterpreter(InteractiveInterpreter):
def display_port_binding_error(self):
tkMessageBox.showerror(
"Port Binding Error",
- "IDLE can't bind TCP/IP port 8833, which is necessary to "
- "communicate with its Python execution server. Either "
- "no networking is installed on this computer or another "
- "process (another IDLE?) is using the port. Run IDLE with the -n "
- "command line switch to start without a subprocess and refer to "
- "Help/IDLE Help 'Running without a subprocess' for further "
- "details.",
+ "IDLE can't bind to a TCP/IP port, which is necessary to "
+ "communicate with its Python execution server. This might be "
+ "because no networking is installed on this computer. "
+ "Run IDLE with the -n command line switch to start without a "
+ "subprocess and refer to Help/IDLE Help 'Running without a "
+ "subprocess' for further details.",
master=self.tkconsole.text)
def display_no_subprocess_error(self):
@@ -972,15 +1001,6 @@ class PyShell(OutputWindow):
COPYRIGHT = \
'Type "copyright", "credits" or "license()" for more information.'
- firewallmessage = """
- ****************************************************************
- Personal firewall software may warn about the connection IDLE
- makes to its subprocess using this computer's internal loopback
- interface. This connection is not visible on any external
- interface and no data is sent to or received from the Internet.
- ****************************************************************
- """
-
def begin(self):
self.resetoutput()
if use_subprocess:
@@ -991,9 +1011,8 @@ class PyShell(OutputWindow):
return False
else:
nosub = "==== No Subprocess ===="
- self.write("Python %s on %s\n%s\n%s\nIDLE %s %s\n" %
- (sys.version, sys.platform, self.COPYRIGHT,
- self.firewallmessage, idlever.IDLE_VERSION, nosub))
+ self.write("Python %s on %s\n%s\n%s" %
+ (sys.version, sys.platform, self.COPYRIGHT, nosub))
self.showprompt()
import Tkinter
Tkinter._default_root = None # 03Jan04 KBK What's this?
@@ -1196,7 +1215,8 @@ class PyShell(OutputWindow):
self.text.see("restart")
def restart_shell(self, event=None):
- self.interp.restart_subprocess()
+ "Callback for Run/Restart Shell Cntl-F6"
+ self.interp.restart_subprocess(with_cwd=True)
def showprompt(self):
self.resetoutput()
@@ -1310,7 +1330,7 @@ def main():
global flist, root, use_subprocess
use_subprocess = True
- enable_shell = False
+ enable_shell = True
enable_edit = False
debug = False
cmd = None
@@ -1331,6 +1351,7 @@ def main():
enable_shell = True
if o == '-e':
enable_edit = True
+ enable_shell = False
if o == '-h':
sys.stdout.write(usage_msg)
sys.exit()
@@ -1381,7 +1402,6 @@ def main():
edit_start = idleConf.GetOption('main', 'General',
'editor-on-startup', type='bool')
enable_edit = enable_edit or edit_start
- enable_shell = enable_shell or not edit_start
# start editor and/or shell windows:
root = Tk(className="Idle")
@@ -1429,6 +1449,13 @@ def main():
shell.interp.prepend_syspath(script)
shell.interp.execfile(script)
+ # Check for problematic OS X Tk versions and print a warning message
+ # in the IDLE shell window; this is less intrusive than always opening
+ # a separate window.
+ tkversionwarning = macosxSupport.tkVersionWarning(root)
+ if tkversionwarning:
+ shell.interp.runcommand(''.join(("print('", tkversionwarning, "')")))
+
root.mainloop()
root.destroy()
diff --git a/Lib/idlelib/RemoteDebugger.py b/Lib/idlelib/RemoteDebugger.py
index ffeffcedc1..647285fe4e 100644
--- a/Lib/idlelib/RemoteDebugger.py
+++ b/Lib/idlelib/RemoteDebugger.py
@@ -230,7 +230,7 @@ class FrameProxy:
return self._get_dict_proxy(did)
def _get_dict_proxy(self, did):
- if self._dictcache.has_key(did):
+ if did in self._dictcache:
return self._dictcache[did]
dp = DictProxy(self._conn, self._oid, did)
self._dictcache[did] = dp
diff --git a/Lib/idlelib/RstripExtension.py b/Lib/idlelib/RstripExtension.py
new file mode 100644
index 0000000000..19e35d4d48
--- /dev/null
+++ b/Lib/idlelib/RstripExtension.py
@@ -0,0 +1,29 @@
+'Provides "Strip trailing whitespace" under the "Format" menu.'
+
+__author__ = "Roger D. Serwy <roger.serwy at gmail.com>"
+
+class RstripExtension:
+
+ menudefs = [
+ ('format', [None,
+ ('Strip trailing whitespace', '<<do-rstrip>>'),
+ ]),]
+
+ def __init__(self, editwin):
+ self.editwin = editwin
+ self.editwin.text.bind("<<do-rstrip>>", self.do_rstrip)
+
+ def do_rstrip(self, event=None):
+
+ text = self.editwin.text
+ undo = self.editwin.undo
+
+ undo.undo_block_start()
+
+ end_line = int(float(text.index('end'))) + 1
+ for cur in range(1, end_line):
+ txt = text.get('%i.0' % cur, '%i.0 lineend' % cur)
+ cut = len(txt.rstrip())
+ text.delete('%i.%i' % (cur, cut), '%i.0 lineend' % cur)
+
+ undo.undo_block_stop()
diff --git a/Lib/idlelib/ScriptBinding.py b/Lib/idlelib/ScriptBinding.py
index 3a441650a9..01ac474658 100644
--- a/Lib/idlelib/ScriptBinding.py
+++ b/Lib/idlelib/ScriptBinding.py
@@ -26,6 +26,7 @@ import tkMessageBox
from idlelib import PyShell
from idlelib.configHandler import idleConf
+from idlelib import macosxSupport
IDENTCHARS = string.ascii_letters + string.digits + "_"
@@ -53,6 +54,9 @@ class ScriptBinding:
self.flist = self.editwin.flist
self.root = self.editwin.root
+ if macosxSupport.runningAsOSXApp():
+ self.editwin.text_frame.bind('<<run-module-event-2>>', self._run_module_event)
+
def check_module_event(self, event):
filename = self.getfilename()
if not filename:
@@ -97,7 +101,7 @@ class ScriptBinding:
try:
# If successful, return the compiled code
return compile(source, filename, "exec")
- except (SyntaxError, OverflowError), err:
+ except (SyntaxError, OverflowError, ValueError), err:
try:
msg, (errorfilename, lineno, offset, line) = err
if not errorfilename:
@@ -142,10 +146,9 @@ class ScriptBinding:
return 'break'
if not self.tabnanny(filename):
return 'break'
- shell = self.shell
- interp = shell.interp
+ interp = self.shell.interp
if PyShell.use_subprocess:
- shell.restart_shell()
+ interp.restart_subprocess(with_cwd=False)
dirname = os.path.dirname(filename)
# XXX Too often this discards arguments the user just set...
interp.runcommand("""if 1:
@@ -166,6 +169,19 @@ class ScriptBinding:
interp.runcode(code)
return 'break'
+ if macosxSupport.runningAsOSXApp():
+ # Tk-Cocoa in MacOSX is broken until at least
+ # Tk 8.5.9, and without this rather
+ # crude workaround IDLE would hang when a user
+ # tries to run a module using the keyboard shortcut
+ # (the menu item works fine).
+ _run_module_event = run_module_event
+
+ def run_module_event(self, event):
+ self.editwin.text_frame.after(200,
+ lambda: self.editwin.text_frame.event_generate('<<run-module-event-2>>'))
+ return 'break'
+
def getfilename(self):
"""Get source filename. If not saved, offer to save (or create) file
@@ -184,9 +200,9 @@ class ScriptBinding:
if autosave and filename:
self.editwin.io.save(None)
else:
- reply = self.ask_save_dialog()
+ confirm = self.ask_save_dialog()
self.editwin.text.focus_set()
- if reply == "ok":
+ if confirm:
self.editwin.io.save(None)
filename = self.editwin.io.filename
else:
@@ -195,13 +211,11 @@ class ScriptBinding:
def ask_save_dialog(self):
msg = "Source Must Be Saved\n" + 5*' ' + "OK to Save?"
- mb = tkMessageBox.Message(title="Save Before Run or Check",
- message=msg,
- icon=tkMessageBox.QUESTION,
- type=tkMessageBox.OKCANCEL,
- default=tkMessageBox.OK,
- master=self.editwin.text)
- return mb.show()
+ confirm = tkMessageBox.askokcancel(title="Save Before Run or Check",
+ message=msg,
+ default=tkMessageBox.OK,
+ master=self.editwin.text)
+ return confirm
def errorbox(self, title, message):
# XXX This should really be a function of EditorWindow...
diff --git a/Lib/idlelib/TreeWidget.py b/Lib/idlelib/TreeWidget.py
index 7d962feb32..0feca0196d 100644
--- a/Lib/idlelib/TreeWidget.py
+++ b/Lib/idlelib/TreeWidget.py
@@ -409,7 +409,7 @@ class FileTreeItem(TreeItem):
class ScrolledCanvas:
def __init__(self, master, **opts):
- if not opts.has_key('yscrollincrement'):
+ if 'yscrollincrement' not in opts:
opts['yscrollincrement'] = 17
self.master = master
self.frame = Frame(master)
diff --git a/Lib/idlelib/config-extensions.def b/Lib/idlelib/config-extensions.def
index 2d5cf6822e..78b68f6b56 100644
--- a/Lib/idlelib/config-extensions.def
+++ b/Lib/idlelib/config-extensions.def
@@ -86,3 +86,9 @@ bgcolor=LightGray
fgcolor=Black
[CodeContext_bindings]
toggle-code-context=
+
+[RstripExtension]
+enable=1
+enable_shell=0
+enable_editor=1
+
diff --git a/Lib/idlelib/config-keys.def b/Lib/idlelib/config-keys.def
index fb0aaf4dc1..fdc35ba7b5 100644
--- a/Lib/idlelib/config-keys.def
+++ b/Lib/idlelib/config-keys.def
@@ -176,7 +176,7 @@ comment-region = <Control-Key-3>
redo = <Shift-Command-Key-Z>
close-window = <Command-Key-w>
restart-shell = <Control-Key-F6>
-save-window-as-file = <Command-Key-S>
+save-window-as-file = <Shift-Command-Key-S>
close-all-windows = <Command-Key-q>
view-restart = <Key-F6>
tabify-region = <Control-Key-5>
@@ -208,7 +208,7 @@ open-new-window = <Command-Key-n>
open-module = <Command-Key-m>
find-selection = <Shift-Command-Key-F3>
python-context-help = <Shift-Key-F1>
-save-copy-of-window-as-file = <Shift-Command-Key-s>
+save-copy-of-window-as-file = <Option-Command-Key-s>
open-window-from-file = <Command-Key-o>
python-docs = <Key-F1>
diff --git a/Lib/idlelib/configDialog.py b/Lib/idlelib/configDialog.py
index 8d3a49dff7..dbaedc76c3 100644
--- a/Lib/idlelib/configDialog.py
+++ b/Lib/idlelib/configDialog.py
@@ -28,6 +28,7 @@ class ConfigDialog(Toplevel):
self.wm_withdraw()
self.configure(borderwidth=5)
+ self.title('IDLE Preferences')
self.geometry("+%d+%d" % (parent.winfo_rootx()+20,
parent.winfo_rooty()+30))
#Theme Elements. Each theme element key is its display name.
@@ -561,7 +562,7 @@ class ConfigDialog(Toplevel):
def AddChangedItem(self,type,section,item,value):
value=str(value) #make sure we use a string
- if not self.changedItems[type].has_key(section):
+ if section not in self.changedItems[type]:
self.changedItems[type][section]={}
self.changedItems[type][section][item]=value
@@ -708,7 +709,7 @@ class ConfigDialog(Toplevel):
return
#remove key set from config
idleConf.userCfg['keys'].remove_section(keySetName)
- if self.changedItems['keys'].has_key(keySetName):
+ if keySetName in self.changedItems['keys']:
del(self.changedItems['keys'][keySetName])
#write changes
idleConf.userCfg['keys'].Save()
@@ -735,7 +736,7 @@ class ConfigDialog(Toplevel):
return
#remove theme from config
idleConf.userCfg['highlight'].remove_section(themeName)
- if self.changedItems['highlight'].has_key(themeName):
+ if themeName in self.changedItems['highlight']:
del(self.changedItems['highlight'][themeName])
#write changes
idleConf.userCfg['highlight'].Save()
@@ -870,9 +871,9 @@ class ConfigDialog(Toplevel):
#handle any unsaved changes to this theme
if theme in self.changedItems['highlight'].keys():
themeDict=self.changedItems['highlight'][theme]
- if themeDict.has_key(element+'-foreground'):
+ if element+'-foreground' in themeDict:
colours['foreground']=themeDict[element+'-foreground']
- if themeDict.has_key(element+'-background'):
+ if element+'-background' in themeDict:
colours['background']=themeDict[element+'-background']
self.textHighlightSample.tag_config(element, **colours)
self.SetColourSample()
diff --git a/Lib/idlelib/configHandler.py b/Lib/idlelib/configHandler.py
index b00bdcf39d..73487d56f3 100644
--- a/Lib/idlelib/configHandler.py
+++ b/Lib/idlelib/configHandler.py
@@ -246,7 +246,7 @@ class IdleConf:
else: #returning default, print warning
if warn_on_default:
warning = ('\n Warning: configHandler.py - IdleConf.GetOption -\n'
- ' problem retrieving configration option %r\n'
+ ' problem retrieving configuration option %r\n'
' from section %r.\n'
' returning default value: %r\n' %
(option, section, default))
diff --git a/Lib/idlelib/extend.txt b/Lib/idlelib/extend.txt
index f5fb3e0409..165e044b5d 100644
--- a/Lib/idlelib/extend.txt
+++ b/Lib/idlelib/extend.txt
@@ -18,7 +18,7 @@ window.
An IDLE extension class is instantiated with a single argument,
`editwin', an EditorWindow instance. The extension cannot assume much
-about this argument, but it is guarateed to have the following instance
+about this argument, but it is guaranteed to have the following instance
variables:
text a Text instance (a widget)
diff --git a/Lib/idlelib/idle.bat b/Lib/idlelib/idle.bat
index c1b5fd28ac..e77b96e9b5 100755
--- a/Lib/idlelib/idle.bat
+++ b/Lib/idlelib/idle.bat
@@ -1,3 +1,4 @@
@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
+rem Start IDLE using the appropriate Python interpreter
+set CURRDIR=%~dp0
+start "IDLE" "%CURRDIR%..\..\pythonw.exe" "%CURRDIR%idle.pyw" %1 %2 %3 %4 %5 %6 %7 %8 %9
diff --git a/Lib/idlelib/idle.py b/Lib/idlelib/idle.py
index 537dd5a9a7..a249557dd1 100644
--- a/Lib/idlelib/idle.py
+++ b/Lib/idlelib/idle.py
@@ -1,21 +1,11 @@
-try:
- import idlelib.PyShell
-except ImportError:
- # IDLE is not installed, but maybe PyShell is on sys.path:
- try:
- import PyShell
- except ImportError:
- raise
- else:
- import os
- idledir = os.path.dirname(os.path.abspath(PyShell.__file__))
- if idledir != os.getcwd():
- # We're not in the IDLE directory, help the subprocess find run.py
- pypath = os.environ.get('PYTHONPATH', '')
- if pypath:
- os.environ['PYTHONPATH'] = pypath + ':' + idledir
- else:
- os.environ['PYTHONPATH'] = idledir
- PyShell.main()
-else:
- idlelib.PyShell.main()
+import os.path
+import sys
+
+# If we are working on a development version of IDLE, we need to prepend the
+# parent of this idlelib dir to sys.path. Otherwise, importing idlelib gets
+# the version installed with the Python used to call this module:
+idlelib_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+sys.path.insert(0, idlelib_dir)
+
+import idlelib.PyShell
+idlelib.PyShell.main()
diff --git a/Lib/idlelib/idlever.py b/Lib/idlelib/idlever.py
index 89352d7d3b..3f8bcffe99 100644
--- a/Lib/idlelib/idlever.py
+++ b/Lib/idlelib/idlever.py
@@ -1 +1 @@
-IDLE_VERSION = "2.6.7"
+IDLE_VERSION = "2.7.2"
diff --git a/Lib/idlelib/macosxSupport.py b/Lib/idlelib/macosxSupport.py
index 7ef56f3440..4be60a3601 100644
--- a/Lib/idlelib/macosxSupport.py
+++ b/Lib/idlelib/macosxSupport.py
@@ -4,19 +4,57 @@ GUI application (as opposed to an X11 application).
"""
import sys
import Tkinter
+from os import path
+
+
+_appbundle = None
def runningAsOSXApp():
"""
Returns True if Python is running from within an app on OSX.
If so, assume that Python was built with Aqua Tcl/Tk rather than
- X11 Tck/Tk.
+ X11 Tcl/Tk.
+ """
+ global _appbundle
+ if _appbundle is None:
+ _appbundle = (sys.platform == 'darwin' and '.app' in sys.executable)
+ return _appbundle
+
+_carbonaquatk = None
+
+def isCarbonAquaTk(root):
+ """
+ Returns True if IDLE is using a Carbon Aqua Tk (instead of the
+ newer Cocoa Aqua Tk).
"""
- return (sys.platform == 'darwin' and '.app' in sys.executable)
+ global _carbonaquatk
+ if _carbonaquatk is None:
+ _carbonaquatk = (runningAsOSXApp() and
+ 'aqua' in root.tk.call('tk', 'windowingsystem') and
+ 'AppKit' not in root.tk.call('winfo', 'server', '.'))
+ return _carbonaquatk
+
+def tkVersionWarning(root):
+ """
+ Returns a string warning message if the Tk version in use appears to
+ be one known to cause problems with IDLE. The Apple Cocoa-based Tk 8.5
+ that was shipped with Mac OS X 10.6.
+ """
+
+ if (runningAsOSXApp() and
+ ('AppKit' in root.tk.call('winfo', 'server', '.')) and
+ (root.tk.call('info', 'patchlevel') == '8.5.7') ):
+ return (r"WARNING: The version of Tcl/Tk (8.5.7) in use may"
+ r" be unstable.\n"
+ r"Visit http://www.python.org/download/mac/tcltk/"
+ r" for current information.")
+ else:
+ return False
def addOpenEventSupport(root, flist):
"""
- This ensures that the application will respont to open AppleEvents, which
- makes is feaseable to use IDLE as the default application for python files.
+ This ensures that the application will respond to open AppleEvents, which
+ makes is feasible to use IDLE as the default application for python files.
"""
def doOpenFile(*args):
for fn in args:
@@ -73,9 +111,6 @@ def overrideRootMenu(root, flist):
WindowList.add_windows_to_menu(menu)
WindowList.register_callback(postwindowsmenu)
- menudict['application'] = menu = Menu(menubar, name='apple')
- menubar.add_cascade(label='IDLE', menu=menu)
-
def about_dialog(event=None):
from idlelib import aboutDialog
aboutDialog.AboutDialog(root, 'About IDLE')
@@ -85,41 +120,45 @@ def overrideRootMenu(root, flist):
root.instance_dict = flist.inversedict
configDialog.ConfigDialog(root, 'Settings')
+ def help_dialog(event=None):
+ from idlelib import textView
+ fn = path.join(path.abspath(path.dirname(__file__)), 'help.txt')
+ textView.view_file(root, 'Help', fn)
root.bind('<<about-idle>>', about_dialog)
root.bind('<<open-config-dialog>>', config_dialog)
+ root.createcommand('::tk::mac::ShowPreferences', config_dialog)
if flist:
root.bind('<<close-all-windows>>', flist.close_all_callback)
-
- ###check if Tk version >= 8.4.14; if so, use hard-coded showprefs binding
- tkversion = root.tk.eval('info patchlevel')
- # Note: we cannot check if the string tkversion >= '8.4.14', because
- # the string '8.4.7' is greater than the string '8.4.14'.
- if tuple(map(int, tkversion.split('.'))) >= (8, 4, 14):
- Bindings.menudefs[0] = ('application', [
+ # The binding above doesn't reliably work on all versions of Tk
+ # on MacOSX. Adding command definition below does seem to do the
+ # right thing for now.
+ root.createcommand('exit', flist.close_all_callback)
+
+ if isCarbonAquaTk(root):
+ # for Carbon AquaTk, replace the default Tk apple menu
+ menudict['application'] = menu = Menu(menubar, name='apple')
+ menubar.add_cascade(label='IDLE', menu=menu)
+ Bindings.menudefs.insert(0,
+ ('application', [
('About IDLE', '<<about-idle>>'),
- None,
- ])
- root.createcommand('::tk::mac::ShowPreferences', config_dialog)
+ None,
+ ]))
+ tkversion = root.tk.eval('info patchlevel')
+ if tuple(map(int, tkversion.split('.'))) < (8, 4, 14):
+ # for earlier AquaTk versions, supply a Preferences menu item
+ Bindings.menudefs[0][1].append(
+ ('_Preferences....', '<<open-config-dialog>>'),
+ )
else:
- for mname, entrylist in Bindings.menudefs:
- menu = menudict.get(mname)
- if not menu:
- continue
- else:
- for entry in entrylist:
- if not entry:
- menu.add_separator()
- else:
- label, eventname = entry
- underline, label = prepstr(label)
- accelerator = get_accelerator(Bindings.default_keydefs,
- eventname)
- def command(text=root, eventname=eventname):
- text.event_generate(eventname)
- menu.add_command(label=label, underline=underline,
- command=command, accelerator=accelerator)
+ # assume Cocoa AquaTk
+ # replace default About dialog with About IDLE one
+ root.createcommand('tkAboutDialog', about_dialog)
+ # replace default "Help" item in Help menu
+ root.createcommand('::tk::mac::ShowHelp', help_dialog)
+ # remove redundant "IDLE Help" from menu
+ del Bindings.menudefs[-1][1][0]
def setupApp(root, flist):
"""
diff --git a/Lib/idlelib/rpc.py b/Lib/idlelib/rpc.py
index 3bac6a30b3..13950589a0 100644
--- a/Lib/idlelib/rpc.py
+++ b/Lib/idlelib/rpc.py
@@ -169,7 +169,7 @@ class SocketIO(object):
how, (oid, methodname, args, kwargs) = request
except TypeError:
return ("ERROR", "Bad request format")
- if not self.objtable.has_key(oid):
+ if oid not in self.objtable:
return ("ERROR", "Unknown object id: %r" % (oid,))
obj = self.objtable[oid]
if methodname == "__methods__":
@@ -304,7 +304,7 @@ class SocketIO(object):
# wait for notification from socket handling thread
cvar = self.cvars[myseq]
cvar.acquire()
- while not self.responses.has_key(myseq):
+ while myseq not in self.responses:
cvar.wait()
response = self.responses[myseq]
self.debug("_getresponse:%s: thread woke up: response: %s" %
@@ -518,8 +518,6 @@ class RPCClient(SocketIO):
def __init__(self, address, family=socket.AF_INET, type=socket.SOCK_STREAM):
self.listening_sock = socket.socket(family, type)
- self.listening_sock.setsockopt(socket.SOL_SOCKET,
- socket.SO_REUSEADDR, 1)
self.listening_sock.bind(address)
self.listening_sock.listen(1)
@@ -552,7 +550,7 @@ class RPCProxy(object):
return MethodProxy(self.sockio, self.oid, name)
if self.__attributes is None:
self.__getattributes()
- if self.__attributes.has_key(name):
+ if name in self.__attributes:
value = self.sockio.remotecall(self.oid, '__getattribute__',
(name,), {})
return value
@@ -572,7 +570,7 @@ def _getmethods(obj, methods):
# Adds names to dictionary argument 'methods'
for name in dir(obj):
attr = getattr(obj, name)
- if callable(attr):
+ if hasattr(attr, '__call__'):
methods[name] = 1
if type(obj) == types.InstanceType:
_getmethods(obj.__class__, methods)
@@ -583,7 +581,7 @@ def _getmethods(obj, methods):
def _getattributes(obj, attributes):
for name in dir(obj):
attr = getattr(obj, name)
- if not callable(attr):
+ if not hasattr(attr, '__call__'):
attributes[name] = 1
class MethodProxy(object):
@@ -599,4 +597,4 @@ class MethodProxy(object):
# XXX KBK 09Sep03 We need a proper unit test for this module. Previously
-# existing test code was removed at Rev 1.27.
+# existing test code was removed at Rev 1.27 (r34098).
diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py
index 270ea15d6d..642b979d8b 100644
--- a/Lib/idlelib/run.py
+++ b/Lib/idlelib/run.py
@@ -25,12 +25,13 @@ except ImportError:
pass
else:
def idle_formatwarning_subproc(message, category, filename, lineno,
- file=None, line=None):
+ line=None):
"""Format warnings the IDLE way"""
s = "\nWarning (from warnings module):\n"
s += ' File \"%s\", line %s\n' % (filename, lineno)
- line = linecache.getline(filename, lineno).strip() \
- if line is None else line
+ if line is None:
+ line = linecache.getline(filename, lineno)
+ line = line.strip()
if line:
s += " %s\n" % line
s += "%s: %s\n" % (category.__name__, message)
@@ -67,10 +68,13 @@ def main(del_exitfunc=False):
global quitting
global no_exitfunc
no_exitfunc = del_exitfunc
- port = 8833
#time.sleep(15) # test subprocess not responding
- if sys.argv[1:]:
- port = int(sys.argv[1])
+ try:
+ assert(len(sys.argv) > 1)
+ port = int(sys.argv[-1])
+ except:
+ print>>sys.stderr, "IDLE Subprocess: no IP port passed in sys.argv."
+ return
sys.argv[:] = [""]
sockthread = threading.Thread(target=manage_socket,
name='SockThread',
diff --git a/Lib/idlelib/textView.py b/Lib/idlelib/textView.py
index 0e7e663185..8937c17b6c 100644
--- a/Lib/idlelib/textView.py
+++ b/Lib/idlelib/textView.py
@@ -9,7 +9,7 @@ class TextViewer(Toplevel):
"""A simple text viewer dialog for IDLE
"""
- def __init__(self, parent, title, text):
+ def __init__(self, parent, title, text, modal=True):
"""Show the given text in a scrollable window with a 'close' button
"""
@@ -24,8 +24,6 @@ class TextViewer(Toplevel):
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()
@@ -34,7 +32,11 @@ class TextViewer(Toplevel):
self.bind('<Escape>',self.Ok) #dismiss dialog
self.textView.insert(0.0, text)
self.textView.config(state=DISABLED)
- self.wait_window()
+
+ if modal:
+ self.transient(parent)
+ self.grab_set()
+ self.wait_window()
def CreateWidgets(self):
frameText = Frame(self, relief=SUNKEN, height=700)
@@ -57,10 +59,10 @@ class TextViewer(Toplevel):
self.destroy()
-def view_text(parent, title, text):
- TextViewer(parent, title, text)
+def view_text(parent, title, text, modal=True):
+ return TextViewer(parent, title, text, modal)
-def view_file(parent, title, filename, encoding=None):
+def view_file(parent, title, filename, encoding=None, modal=True):
try:
if encoding:
import codecs
@@ -73,7 +75,7 @@ def view_file(parent, title, filename, encoding=None):
message='Unable to load file %r .' % filename,
parent=parent)
else:
- return view_text(parent, title, textFile.read())
+ return view_text(parent, title, textFile.read(), modal)
if __name__ == '__main__':
@@ -83,11 +85,15 @@ if __name__ == '__main__':
filename = './textView.py'
text = file(filename, 'r').read()
btn1 = Button(root, text='view_text',
- command=lambda:view_text(root, 'view_text', text))
+ command=lambda:view_text(root, 'view_text', text))
btn1.pack(side=LEFT)
btn2 = Button(root, text='view_file',
command=lambda:view_file(root, 'view_file', filename))
btn2.pack(side=LEFT)
+ btn3 = Button(root, text='nonmodal view_text',
+ command=lambda:view_text(root, 'nonmodal view_text', text,
+ modal=False))
+ btn3.pack(side=LEFT)
close = Button(root, text='Close', command=root.destroy)
close.pack(side=RIGHT)
root.mainloop()