[Idle-dev] CVS: idle IOBinding.py,1.7,1.8
Kurt B. Kaiser
kbk@users.sourceforge.net
Mon, 16 Sep 2002 15:03:40 -0700
Update of /cvsroot/idlefork/idle
In directory usw-pr-cvs1:/tmp/cvs-serv19218
Modified Files:
IOBinding.py
Log Message:
Merge Py Idle changes:
Rev 1.5 tim_one
Convert a pile of obvious "yes/no" functions to return bool.
Rev 1.6 gvanrossum
(partially merged previously, move line outside try: block)
Provisional fix for writefile() [SF bug # 541730].
The problem was that an exception can occur in the text.get() call or
in the write() call, when the text buffer contains non-ASCII
characters. This causes the previous contents of the file to be lost.
The provisional fix is to call str(self.text.get(...)) *before*
opening the file, so that if the exception occurs, we never open the
file.
Two orthogonal better solutions have to wait for policy decisions:
1. We could try to encode the data as Latin-1 or as UTF-8; but that
would require IDLE to grow a notion of file encoding which requires
more thought.
2. We could make backups before overwriting a file. This requires
more thought because it needs to be fast and cross-platform and
configurable.
Rev 1.7 gvanrossum
(previously merged with modifications by Stephen M. Gava)
Add primitive printing support for Unix and Windows.
Rev 1.8 loewis
Patch #590913: PEP 263 support.
Rev 1.9 gvanrossum
(tempfile.py interface -- deferred)
Rev 1.10 tim_one
whitespace normalization
Rev 1.11 nnorwitz
(deferred pending 1.9 integration)
Index: IOBinding.py
===================================================================
RCS file: /cvsroot/idlefork/idle/IOBinding.py,v
retrieving revision 1.7
retrieving revision 1.8
diff -C2 -r1.7 -r1.8
*** IOBinding.py 21 Jul 2002 01:24:28 -0000 1.7
--- IOBinding.py 16 Sep 2002 22:03:37 -0000 1.8
***************
*** 7,10 ****
--- 7,13 ----
import os
+ import types
+ import sys
+ import codecs
import tempfile
import tkFileDialog
***************
*** 33,36 ****
--- 36,104 ----
#$ unix <Control-x><w>
+ try:
+ from codecs import BOM_UTF8
+ except ImportError:
+ # only available since Python 2.3
+ BOM_UTF8 = '\xef\xbb\xbf'
+
+ # Try setting the locale, so that we can find out
+ # what encoding to use
+ try:
+ import locale
+ locale.setlocale(locale.LC_CTYPE, "")
+ except ImportError:
+ pass
+
+ encoding = "ascii"
+ if sys.platform == 'win32':
+ # On Windows, we could use "mbcs". However, to give the user
+ # a portable encoding name, we need to find the code page
+ try:
+ encoding = locale.getdefaultlocale()[1]
+ codecs.lookup(encoding)
+ except LookupError:
+ pass
+ else:
+ try:
+ # Different things can fail here: the locale module may not be
+ # loaded, it may not offer nl_langinfo, or CODESET, or the
+ # resulting codeset may be unknown to Python. We ignore all
+ # these problems, falling back to ASCII
+ encoding = locale.nl_langinfo(locale.CODESET)
+ codecs.lookup(encoding)
+ except (NameError, AttributeError, LookupError):
+ # Try getdefaultlocale well: it parses environment variables,
+ # which may give a clue. Unfortunately, getdefaultlocale has
+ # bugs that can cause ValueError.
+ try:
+ encoding = locale.getdefaultlocale()[1]
+ codecs.lookup(encoding)
+ except (ValueError, LookupError):
+ pass
+
+ encoding = encoding.lower()
+
+ coding_re = re.compile("coding[:=]\s*([-\w_.]+)")
+ def coding_spec(str):
+
+ """Return the encoding declaration according to PEP 263.
+ Raise LookupError if the encoding is declared but unknown."""
+
+ # Only consider the first two lines
+ str = str.split("\n")[:2]
+ str = "\n".join(str)
+
+ match = coding_re.search(str)
+ if not match:
+ return None
+ name = match.group(1)
+ # Check whether the encoding is known
+ import codecs
+ try:
+ codecs.lookup(name)
+ except LookupError:
+ # The standard encoding error does not indicate the encoding
+ raise LookupError, "Unknown encoding "+name
+ return name
class IOBinding:
***************
*** 45,48 ****
--- 113,117 ----
self.__id_savecopy = self.text.bind("<<save-copy-of-window-as-file>>",
self.save_a_copy)
+ self.fileencoding = None
self.__id_print = self.text.bind("<<print-window>>", self.print_window)
***************
*** 130,135 ****
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)
--- 199,205 ----
except IOError, msg:
tkMessageBox.showerror("I/O Error", str(msg), master=self.text)
! return False
+ chars = self.decode(chars)
# We now convert all end-of-lines to '\n's
eol = r"(\r\n)|\n|\r" # \r\n (Windows), \n (UNIX), or \r (Mac)
***************
*** 143,147 ****
self.text.mark_set("insert", "1.0")
self.text.see("insert")
! return 1
def maybesave(self):
--- 213,265 ----
self.text.mark_set("insert", "1.0")
self.text.see("insert")
! return True
!
! def decode(self, chars):
! # Try to create a Unicode string. If that fails, let Tcl try
! # its best
!
! # Check presence of a UTF-8 signature first
! if chars.startswith(BOM_UTF8):
! try:
! chars = chars[3:].decode("utf-8")
! except UnicodeError:
! # has UTF-8 signature, but fails to decode...
! return chars
! else:
! # Indicates that this file originally had a BOM
! self.fileencoding = BOM_UTF8
! return chars
!
! # Next look for coding specification
! try:
! enc = coding_spec(chars)
! except LookupError, name:
! tkMessageBox.showerror(
! title="Error loading the file",
! message="The encoding '%s' is not known to this Python "\
! "installation. The file may not display correctly" % name,
! master = self.text)
! enc = None
!
! if enc:
! try:
! return unicode(chars, enc)
! except UnicodeError:
! pass
!
! # If it is ASCII, we need not to record anything
! try:
! return unicode(chars, 'ascii')
! except UnicodeError:
! pass
!
! # Finally, try the locale's encoding. This is deprecated;
! # the user should declare a non-ASCII encoding
! try:
! chars = unicode(chars, encoding)
! self.fileencoding = encoding
! except UnicodeError:
! pass
! return chars
def maybesave(self):
***************
*** 191,206 ****
def writefile(self, filename):
self.fixlastline()
try:
f = open(filename, "w")
- chars = str(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 print_window(self, event):
tempfilename = None
--- 309,392 ----
def writefile(self, filename):
self.fixlastline()
+ chars = self.encode(self.text.get("1.0", "end-1c"))
try:
f = open(filename, "w")
f.write(chars)
f.close()
## print "saved to", `filename`
! return True
except IOError, msg:
tkMessageBox.showerror("I/O Error", str(msg),
master=self.text)
! return False
!
! def encode(self, chars):
! if isinstance(chars, types.StringType):
! # This is either plain ASCII, or Tk was returning mixed-encoding
! # text to us. Don't try to guess further.
! return chars
!
! # See whether there is anything non-ASCII in it.
! # If not, no need to figure out the encoding.
! try:
! return chars.encode('ascii')
! except UnicodeError:
! pass
!
! # If there is an encoding declared, try this first.
! try:
! enc = coding_spec(chars)
! failed = None
! except LookupError, msg:
! failed = msg
! enc = None
! if enc:
! try:
! return chars.encode(enc)
! except UnicodeError:
! failed = "Invalid encoding '%s'" % enc
!
! if failed:
! tkMessageBox.showerror(
! "I/O Error",
! "%s. Saving as UTF-8" % failed,
! master = self.text)
!
! # If there was a UTF-8 signature, use that. This should not fail
! if self.fileencoding == BOM_UTF8 or failed:
! return BOM_UTF8 + chars.encode("utf-8")
!
! # Try the original file encoding next, if any
! if self.fileencoding:
! try:
! return chars.encode(self.fileencoding)
! except UnicodeError:
! tkMessageBox.showerror(
! "I/O Error",
! "Cannot save this as '%s' anymore. Saving as UTF-8" \
! % self.fileencoding,
! master = self.text)
! return BOM_UTF8 + chars.encode("utf-8")
!
! # Nothing was declared, and we had not determined an encoding
! # on loading. Recommend an encoding line.
! try:
! chars = chars.encode(encoding)
! enc = encoding
! except UnicodeError:
! chars = BOM_UTF8 + chars.encode("utf-8")
! enc = "utf-8"
! tkMessageBox.showerror(
! "I/O Error",
! "Non-ASCII found, yet no encoding declared. Add a line like\n"
! "# -*- coding: %s -*- \nto your file" % enc,
! master = self.text)
! return chars
+ def fixlastline(self):
+ c = self.text.get("end-2c")
+ if c != '\n':
+ self.text.insert("end-1c", "\n")
+
def print_window(self, event):
tempfilename = None
***************
*** 215,219 ****
printPlatform=1
if platform == 'posix': #posix platform
! command = idleConf.GetOption('main','General','print-command-posix')
command = command + " 2>&1"
elif platform == 'nt': #win32 platform
--- 401,406 ----
printPlatform=1
if platform == 'posix': #posix platform
! command = idleConf.GetOption('main','General',
! 'print-command-posix')
command = command + " 2>&1"
elif platform == 'nt': #win32 platform
***************
*** 227,231 ****
status = pipe.close()
if status:
! output = "Printing failed (exit status 0x%x)\n" % status + output
if output:
output = "Printing command: %s\n" % repr(command) + output
--- 414,419 ----
status = pipe.close()
if status:
! output = "Printing failed (exit status 0x%x)\n" % \
! status + output
if output:
output = "Printing command: %s\n" % repr(command) + output
***************
*** 236,244 ****
return "break"
- def fixlastline(self):
- c = self.text.get("end-2c")
- if c != '\n':
- self.text.insert("end-1c", "\n")
-
opendialog = None
savedialog = None
--- 424,427 ----