merge heads
This commit is contained in:
commit
12f2bffce1
@ -41,10 +41,6 @@ Linux and the BSD variants of Unix.
|
|||||||
Module :mod:`curses.textpad`
|
Module :mod:`curses.textpad`
|
||||||
Editable text widget for curses supporting :program:`Emacs`\ -like bindings.
|
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`
|
:ref:`curses-howto`
|
||||||
Tutorial material on using curses with Python, by Andrew Kuchling and Eric
|
Tutorial material on using curses with Python, by Andrew Kuchling and Eric
|
||||||
Raymond.
|
Raymond.
|
||||||
@ -592,6 +588,19 @@ The module :mod:`curses` defines the following functions:
|
|||||||
foreground color on the default background.
|
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:
|
.. _curses-window-objects:
|
||||||
|
|
||||||
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
|
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
|
end of that line instead, and trailing blanks are stripped when the window
|
||||||
contents are gathered.
|
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.
|
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ tracebacks:
|
|||||||
* Only ASCII is supported. The ``backslashreplace`` error handler is used on
|
* Only ASCII is supported. The ``backslashreplace`` error handler is used on
|
||||||
encoding.
|
encoding.
|
||||||
* Each string is limited to 100 characters.
|
* 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)
|
displayed. (no source code)
|
||||||
* It is limited to 100 frames and 100 threads.
|
* It is limited to 100 frames and 100 threads.
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@ the package, and perhaps a particular module inside it.
|
|||||||
__revision__ = "$Id$"
|
__revision__ = "$Id$"
|
||||||
|
|
||||||
from _curses import *
|
from _curses import *
|
||||||
from curses.wrapper import wrapper
|
|
||||||
import os as _os
|
import os as _os
|
||||||
import sys as _sys
|
import sys as _sys
|
||||||
|
|
||||||
@ -57,3 +56,48 @@ try:
|
|||||||
has_key
|
has_key
|
||||||
except NameError:
|
except NameError:
|
||||||
from has_key import has_key
|
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()
|
||||||
|
@ -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()
|
|
@ -73,9 +73,10 @@ def decode_header(header):
|
|||||||
An email.errors.HeaderParseError may be raised when certain decoding error
|
An email.errors.HeaderParseError may be raised when certain decoding error
|
||||||
occurs (e.g. a base64 decoding exception).
|
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'):
|
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 no encoding, just return the header with no charset.
|
||||||
if not ecre.search(header):
|
if not ecre.search(header):
|
||||||
return [(header, None)]
|
return [(header, None)]
|
||||||
@ -274,7 +275,10 @@ class Header:
|
|||||||
charset = Charset(charset)
|
charset = Charset(charset)
|
||||||
if not isinstance(s, str):
|
if not isinstance(s, str):
|
||||||
input_charset = charset.input_codec or 'us-ascii'
|
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
|
# Ensure that the bytes we're storing can be decoded to the output
|
||||||
# character set, otherwise an early error is thrown.
|
# character set, otherwise an early error is thrown.
|
||||||
output_charset = charset.output_codec or 'us-ascii'
|
output_charset = charset.output_codec or 'us-ascii'
|
||||||
|
@ -1923,9 +1923,10 @@ class _ProxyFile:
|
|||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""Close the file."""
|
"""Close the file."""
|
||||||
if hasattr(self._file, 'close'):
|
if hasattr(self, '_file'):
|
||||||
self._file.close()
|
if hasattr(self._file, 'close'):
|
||||||
del self._file
|
self._file.close()
|
||||||
|
del self._file
|
||||||
|
|
||||||
def _read(self, size, read_method):
|
def _read(self, size, read_method):
|
||||||
"""Read size bytes using read_method."""
|
"""Read size bytes using read_method."""
|
||||||
@ -1957,6 +1958,10 @@ class _ProxyFile:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def closed(self):
|
def closed(self):
|
||||||
|
if not hasattr(self, '_file'):
|
||||||
|
return True
|
||||||
|
if not hasattr(self._file, 'closed'):
|
||||||
|
return False
|
||||||
return self._file.closed
|
return self._file.closed
|
||||||
|
|
||||||
|
|
||||||
@ -1995,7 +2000,8 @@ class _PartialFile(_ProxyFile):
|
|||||||
def close(self):
|
def close(self):
|
||||||
# do *not* close the underlying file object for partial files,
|
# do *not* close the underlying file object for partial files,
|
||||||
# since it's global to the mailbox object
|
# since it's global to the mailbox object
|
||||||
del self._file
|
if hasattr(self, '_file'):
|
||||||
|
del self._file
|
||||||
|
|
||||||
|
|
||||||
def _lock_file(f, dotlock=True):
|
def _lock_file(f, dotlock=True):
|
||||||
|
@ -4324,12 +4324,27 @@ A very long line that must get split to something other than at the
|
|||||||
|
|
||||||
def test_escaped_8bit_header(self):
|
def test_escaped_8bit_header(self):
|
||||||
x = b'Ynwp4dUEbay Auction Semiar- No Charge \x96 Earn Big'
|
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)
|
h = Header(x, charset=email.charset.UNKNOWN8BIT)
|
||||||
self.assertEqual(str(h),
|
self.assertEqual(str(h),
|
||||||
'Ynwp4dUEbay Auction Semiar- No Charge \uFFFD Earn Big')
|
'Ynwp4dUEbay Auction Semiar- No Charge \uFFFD Earn Big')
|
||||||
self.assertEqual(email.header.decode_header(h), [(x, 'unknown-8bit')])
|
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):
|
def test_modify_returned_list_does_not_change_header(self):
|
||||||
h = Header('test')
|
h = Header('test')
|
||||||
chunks = email.header.decode_header(h)
|
chunks = email.header.decode_header(h)
|
||||||
|
@ -297,6 +297,13 @@ class TestMailbox(TestBase):
|
|||||||
self.assertEqual(data1.decode('ascii').replace(os.linesep, '\n'),
|
self.assertEqual(data1.decode('ascii').replace(os.linesep, '\n'),
|
||||||
_sample_message)
|
_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):
|
def test_iterkeys(self):
|
||||||
# Get keys using iterkeys()
|
# Get keys using iterkeys()
|
||||||
self._check_iteration(self._box.keys, do_keys=True, do_values=False)
|
self._check_iteration(self._box.keys, do_keys=True, do_values=False)
|
||||||
@ -1862,8 +1869,12 @@ class TestProxyFileBase(TestBase):
|
|||||||
|
|
||||||
def _test_close(self, proxy):
|
def _test_close(self, proxy):
|
||||||
# Close a file
|
# Close a file
|
||||||
|
self.assertFalse(proxy.closed)
|
||||||
proxy.close()
|
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):
|
class TestProxyFile(TestProxyFileBase):
|
||||||
|
@ -1013,6 +1013,7 @@ David Wolever
|
|||||||
Klaus-Juergen Wolf
|
Klaus-Juergen Wolf
|
||||||
Dan Wolfe
|
Dan Wolfe
|
||||||
Richard Wolff
|
Richard Wolff
|
||||||
|
Adam Woodbeck
|
||||||
Darren Worrall
|
Darren Worrall
|
||||||
Gordon Worley
|
Gordon Worley
|
||||||
Thomas Wouters
|
Thomas Wouters
|
||||||
|
11
Misc/NEWS
11
Misc/NEWS
@ -193,6 +193,17 @@ Core and Builtins
|
|||||||
Library
|
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 #11767: Correct file descriptor leak in mailbox's __getitem__ method.
|
||||||
|
|
||||||
- Issue #12133: AbstractHTTPHandler.do_open() of urllib.request closes the HTTP
|
- Issue #12133: AbstractHTTPHandler.do_open() of urllib.request closes the HTTP
|
||||||
|
@ -1057,14 +1057,14 @@ def add_files(db):
|
|||||||
lib.add_file("turtle.cfg")
|
lib.add_file("turtle.cfg")
|
||||||
if dir=="pydoc_data":
|
if dir=="pydoc_data":
|
||||||
lib.add_file("_pydoc.css")
|
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
|
# This should contain all non-.svn files listed in subversion
|
||||||
for f in os.listdir(lib.absolute):
|
for f in os.listdir(lib.absolute):
|
||||||
if f.endswith(".txt") or f==".svn":continue
|
if f.endswith(".txt") or f==".svn":continue
|
||||||
if f.endswith(".au") or f.endswith(".gif"):
|
if f.endswith(".au") or f.endswith(".gif"):
|
||||||
lib.add_file(f)
|
lib.add_file(f)
|
||||||
else:
|
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):
|
for f in os.listdir(lib.absolute):
|
||||||
if os.path.isdir(os.path.join(lib.absolute, f)):
|
if os.path.isdir(os.path.join(lib.absolute, f)):
|
||||||
pydirs.append((lib, f))
|
pydirs.append((lib, f))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user