merge heads

This commit is contained in:
Benjamin Peterson 2011-06-19 09:38:02 -05:00
commit 12f2bffce1
11 changed files with 118 additions and 96 deletions

View File

@ -41,10 +41,6 @@ Linux and the BSD variants of Unix.
Module :mod:`curses.textpad`
Editable text widget for curses supporting :program:`Emacs`\ -like bindings.
Module :mod:`curses.wrapper`
Convenience function to ensure proper terminal setup and resetting on
application entry and exit.
:ref:`curses-howto`
Tutorial material on using curses with Python, by Andrew Kuchling and Eric
Raymond.
@ -592,6 +588,19 @@ The module :mod:`curses` defines the following functions:
foreground color on the default background.
.. function:: wrapper(func, ...)
Initialize curses and call another callable object, *func*, which should be the
rest of your curses-using application. If the application raises an exception,
this function will restore the terminal to a sane state before re-raising the
exception and generating a traceback. The callable object *func* is then passed
the main window 'stdscr' as its first argument, followed by any other arguments
passed to :func:`wrapper`. Before calling *func*, :func:`wrapper` turns on
cbreak mode, turns off echo, enables the terminal keypad, and initializes colors
if the terminal has color support. On exit (whether normally or by exception)
it restores cooked mode, turns on echo, and disables the terminal keypad.
.. _curses-window-objects:
Window Objects
@ -1659,32 +1668,3 @@ You can instantiate a :class:`Textbox` object as follows:
cursor motion that would land the cursor on a trailing blank goes to the
end of that line instead, and trailing blanks are stripped when the window
contents are gathered.
:mod:`curses.wrapper` --- Terminal handler for curses programs
==============================================================
.. module:: curses.wrapper
:synopsis: Terminal configuration wrapper for curses programs.
.. moduleauthor:: Eric Raymond <esr@thyrsus.com>
.. sectionauthor:: Eric Raymond <esr@thyrsus.com>
This module supplies one function, :func:`wrapper`, which runs another function
which should be the rest of your curses-using application. If the application
raises an exception, :func:`wrapper` will restore the terminal to a sane state
before re-raising the exception and generating a traceback.
.. function:: wrapper(func, ...)
Wrapper function that initializes curses and calls another function, *func*,
restoring normal keyboard/screen behavior on error. The callable object *func*
is then passed the main window 'stdscr' as its first argument, followed by any
other arguments passed to :func:`wrapper`.
Before calling the hook function, :func:`wrapper` turns on cbreak mode, turns
off echo, enables the terminal keypad, and initializes colors if the terminal
has color support. On exit (whether normally or by exception) it restores
cooked mode, turns on echo, and disables the terminal keypad.

View File

@ -24,7 +24,7 @@ tracebacks:
* Only ASCII is supported. The ``backslashreplace`` error handler is used on
encoding.
* Each string is limited to 100 characters.
* Only the the filename, the function name and the line number are
* Only the filename, the function name and the line number are
displayed. (no source code)
* It is limited to 100 frames and 100 threads.

View File

@ -13,7 +13,6 @@ the package, and perhaps a particular module inside it.
__revision__ = "$Id$"
from _curses import *
from curses.wrapper import wrapper
import os as _os
import sys as _sys
@ -57,3 +56,48 @@ try:
has_key
except NameError:
from has_key import has_key
# Wrapper for the entire curses-based application. Runs a function which
# should be the rest of your curses-based application. If the application
# raises an exception, wrapper() will restore the terminal to a sane state so
# you can read the resulting traceback.
def wrapper(func, *args, **kwds):
"""Wrapper function that initializes curses and calls another function,
restoring normal keyboard/screen behavior on error.
The callable object 'func' is then passed the main window 'stdscr'
as its first argument, followed by any other arguments passed to
wrapper().
"""
try:
# Initialize curses
stdscr = initscr()
# Turn off echoing of keys, and enter cbreak mode,
# where no buffering is performed on keyboard input
noecho()
cbreak()
# In keypad mode, escape sequences for special keys
# (like the cursor keys) will be interpreted and
# a special value like curses.KEY_LEFT will be returned
stdscr.keypad(1)
# Start color, too. Harmless if the terminal doesn't have
# color; user can test with has_color() later on. The try/catch
# works around a minor bit of over-conscientiousness in the curses
# module -- the error return from C start_color() is ignorable.
try:
start_color()
except:
pass
return func(stdscr, *args, **kwds)
finally:
# Set everything back to normal
if 'stdscr' in locals():
stdscr.keypad(0)
echo()
nocbreak()
endwin()

View File

@ -1,50 +0,0 @@
"""curses.wrapper
Contains one function, wrapper(), which runs another function which
should be the rest of your curses-based application. If the
application raises an exception, wrapper() will restore the terminal
to a sane state so you can read the resulting traceback.
"""
import curses
def wrapper(func, *args, **kwds):
"""Wrapper function that initializes curses and calls another function,
restoring normal keyboard/screen behavior on error.
The callable object 'func' is then passed the main window 'stdscr'
as its first argument, followed by any other arguments passed to
wrapper().
"""
try:
# Initialize curses
stdscr = curses.initscr()
# Turn off echoing of keys, and enter cbreak mode,
# where no buffering is performed on keyboard input
curses.noecho()
curses.cbreak()
# In keypad mode, escape sequences for special keys
# (like the cursor keys) will be interpreted and
# a special value like curses.KEY_LEFT will be returned
stdscr.keypad(1)
# Start color, too. Harmless if the terminal doesn't have
# color; user can test with has_color() later on. The try/catch
# works around a minor bit of over-conscientiousness in the curses
# module -- the error return from C start_color() is ignorable.
try:
curses.start_color()
except:
pass
return func(stdscr, *args, **kwds)
finally:
# Set everything back to normal
if 'stdscr' in locals():
stdscr.keypad(0)
curses.echo()
curses.nocbreak()
curses.endwin()

View File

@ -73,9 +73,10 @@ def decode_header(header):
An email.errors.HeaderParseError may be raised when certain decoding error
occurs (e.g. a base64 decoding exception).
"""
# If it is a Header object, we can just return the chunks.
# If it is a Header object, we can just return the encoded chunks.
if hasattr(header, '_chunks'):
return list(header._chunks)
return [(_charset._encode(string, str(charset)), str(charset))
for string, charset in header._chunks]
# If no encoding, just return the header with no charset.
if not ecre.search(header):
return [(header, None)]
@ -274,7 +275,10 @@ class Header:
charset = Charset(charset)
if not isinstance(s, str):
input_charset = charset.input_codec or 'us-ascii'
s = s.decode(input_charset, errors)
if input_charset == _charset.UNKNOWN8BIT:
s = s.decode('us-ascii', 'surrogateescape')
else:
s = s.decode(input_charset, errors)
# Ensure that the bytes we're storing can be decoded to the output
# character set, otherwise an early error is thrown.
output_charset = charset.output_codec or 'us-ascii'

View File

@ -1923,9 +1923,10 @@ class _ProxyFile:
def close(self):
"""Close the file."""
if hasattr(self._file, 'close'):
self._file.close()
del self._file
if hasattr(self, '_file'):
if hasattr(self._file, 'close'):
self._file.close()
del self._file
def _read(self, size, read_method):
"""Read size bytes using read_method."""
@ -1957,6 +1958,10 @@ class _ProxyFile:
@property
def closed(self):
if not hasattr(self, '_file'):
return True
if not hasattr(self._file, 'closed'):
return False
return self._file.closed
@ -1995,7 +2000,8 @@ class _PartialFile(_ProxyFile):
def close(self):
# do *not* close the underlying file object for partial files,
# since it's global to the mailbox object
del self._file
if hasattr(self, '_file'):
del self._file
def _lock_file(f, dotlock=True):

View File

@ -4324,12 +4324,27 @@ A very long line that must get split to something other than at the
def test_escaped_8bit_header(self):
x = b'Ynwp4dUEbay Auction Semiar- No Charge \x96 Earn Big'
x = x.decode('ascii', 'surrogateescape')
e = x.decode('ascii', 'surrogateescape')
h = Header(e, charset=email.charset.UNKNOWN8BIT)
self.assertEqual(str(h),
'Ynwp4dUEbay Auction Semiar- No Charge \uFFFD Earn Big')
self.assertEqual(email.header.decode_header(h), [(x, 'unknown-8bit')])
def test_header_handles_binary_unknown8bit(self):
x = b'Ynwp4dUEbay Auction Semiar- No Charge \x96 Earn Big'
h = Header(x, charset=email.charset.UNKNOWN8BIT)
self.assertEqual(str(h),
'Ynwp4dUEbay Auction Semiar- No Charge \uFFFD Earn Big')
self.assertEqual(email.header.decode_header(h), [(x, 'unknown-8bit')])
def test_make_header_handles_binary_unknown8bit(self):
x = b'Ynwp4dUEbay Auction Semiar- No Charge \x96 Earn Big'
h = Header(x, charset=email.charset.UNKNOWN8BIT)
h2 = email.header.make_header(email.header.decode_header(h))
self.assertEqual(str(h2),
'Ynwp4dUEbay Auction Semiar- No Charge \uFFFD Earn Big')
self.assertEqual(email.header.decode_header(h2), [(x, 'unknown-8bit')])
def test_modify_returned_list_does_not_change_header(self):
h = Header('test')
chunks = email.header.decode_header(h)

View File

@ -297,6 +297,13 @@ class TestMailbox(TestBase):
self.assertEqual(data1.decode('ascii').replace(os.linesep, '\n'),
_sample_message)
def test_get_file_can_be_closed_twice(self):
# Issue 11700
key = self._box.add(_sample_message)
f = self._box.get_file(key)
f.close()
f.close()
def test_iterkeys(self):
# Get keys using iterkeys()
self._check_iteration(self._box.keys, do_keys=True, do_values=False)
@ -1862,8 +1869,12 @@ class TestProxyFileBase(TestBase):
def _test_close(self, proxy):
# Close a file
self.assertFalse(proxy.closed)
proxy.close()
self.assertRaises(AttributeError, lambda: proxy.close())
self.assertTrue(proxy.closed)
# Issue 11700 subsequent closes should be a no-op.
proxy.close()
self.assertTrue(proxy.closed)
class TestProxyFile(TestProxyFileBase):

View File

@ -1013,6 +1013,7 @@ David Wolever
Klaus-Juergen Wolf
Dan Wolfe
Richard Wolff
Adam Woodbeck
Darren Worrall
Gordon Worley
Thomas Wouters

View File

@ -193,6 +193,17 @@ Core and Builtins
Library
-------
- Issue #6771: moved the curses.wrapper function from the single-function
wrapper module into __init__, eliminating the module. Since __init__ was
already importing the function to curses.wrapper, there is no API change.
- Issue #11584: email.header.decode_header no longer fails if the header
passed to it is a Header object, and Header/make_header no longer fail
if given binary unknown-8bit input.
- Issue #11700: mailbox proxy object close methods can now be called multiple
times without error.
- Issue #11767: Correct file descriptor leak in mailbox's __getitem__ method.
- Issue #12133: AbstractHTTPHandler.do_open() of urllib.request closes the HTTP

View File

@ -1057,14 +1057,14 @@ def add_files(db):
lib.add_file("turtle.cfg")
if dir=="pydoc_data":
lib.add_file("_pydoc.css")
if dir=="data" and parent.physical=="test" and parent.basedir.physical=="email":
if dir=="data" and parent.physical=="test_email":
# This should contain all non-.svn files listed in subversion
for f in os.listdir(lib.absolute):
if f.endswith(".txt") or f==".svn":continue
if f.endswith(".au") or f.endswith(".gif"):
lib.add_file(f)
else:
print("WARNING: New file %s in email/test/data" % f)
print("WARNING: New file %s in test/test_email/data" % f)
for f in os.listdir(lib.absolute):
if os.path.isdir(os.path.join(lib.absolute, f)):
pydirs.append((lib, f))