mirror of
https://github.com/python/cpython.git
synced 2025-11-03 03:22:27 +00:00
Merged revisions 53623-53858 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
........
r53624 | peter.astrand | 2007-02-02 20:06:36 +0100 (Fri, 02 Feb 2007) | 1 line
We had several if statements checking the value of a fd. This is unsafe, since valid fds might be zero. We should check for not None instead.
........
r53635 | kurt.kaiser | 2007-02-05 07:03:18 +0100 (Mon, 05 Feb 2007) | 2 lines
Add 'raw' support to configHandler. Patch 1650174 Tal Einat.
........
r53641 | kurt.kaiser | 2007-02-06 00:02:16 +0100 (Tue, 06 Feb 2007) | 5 lines
1. Calltips now 'handle' tuples in the argument list (display '<tuple>' :)
Suggested solution by Christos Georgiou, Bug 791968.
2. Clean up tests, were not failing when they should have been.
4. Remove some camelcase and an unneeded try/except block.
........
r53644 | kurt.kaiser | 2007-02-06 04:21:40 +0100 (Tue, 06 Feb 2007) | 2 lines
Clean up ModifiedInterpreter.runcode() structure
........
r53646 | peter.astrand | 2007-02-06 16:37:50 +0100 (Tue, 06 Feb 2007) | 1 line
Applied patch 1124861.3.patch to solve bug #1124861: Automatically create pipes on Windows, if GetStdHandle fails. Will backport.
........
r53648 | lars.gustaebel | 2007-02-06 19:38:13 +0100 (Tue, 06 Feb 2007) | 4 lines
Patch #1652681: create nonexistent files in append mode and
allow appending to empty files.
........
r53649 | kurt.kaiser | 2007-02-06 20:09:43 +0100 (Tue, 06 Feb 2007) | 4 lines
Updated patch (CodeContext.061217.patch) to
[ 1362975 ] CodeContext - Improved text indentation
Tal Einat 16Dec06
........
r53650 | kurt.kaiser | 2007-02-06 20:21:19 +0100 (Tue, 06 Feb 2007) | 2 lines
narrow exception per [ 1540849 ] except too broad
........
r53653 | kurt.kaiser | 2007-02-07 04:39:41 +0100 (Wed, 07 Feb 2007) | 4 lines
[ 1621265 ] Auto-completion list placement
Move AC window below input line unless not enough space, then put it above.
Patch: Tal Einat
........
r53654 | kurt.kaiser | 2007-02-07 09:07:13 +0100 (Wed, 07 Feb 2007) | 2 lines
Handle AttributeError during calltip lookup
........
r53656 | raymond.hettinger | 2007-02-07 21:08:22 +0100 (Wed, 07 Feb 2007) | 3 lines
SF #1615701: make d.update(m) honor __getitem__() and keys() in dict subclasses
........
r53658 | raymond.hettinger | 2007-02-07 22:04:20 +0100 (Wed, 07 Feb 2007) | 1 line
SF: 1397711 Set docs conflated immutable and hashable
........
r53660 | raymond.hettinger | 2007-02-07 22:42:17 +0100 (Wed, 07 Feb 2007) | 1 line
Check for a common user error with defaultdict().
........
r53662 | raymond.hettinger | 2007-02-07 23:24:07 +0100 (Wed, 07 Feb 2007) | 1 line
Bug #1575169: operator.isSequenceType() now returns False for subclasses of dict.
........
r53664 | raymond.hettinger | 2007-02-08 00:49:03 +0100 (Thu, 08 Feb 2007) | 1 line
Silence compiler warning
........
r53666 | raymond.hettinger | 2007-02-08 01:07:32 +0100 (Thu, 08 Feb 2007) | 1 line
Do not let overflows in enumerate() and count() pass silently.
........
r53668 | raymond.hettinger | 2007-02-08 01:50:39 +0100 (Thu, 08 Feb 2007) | 1 line
Bypass set specific optimizations for set and frozenset subclasses.
........
r53670 | raymond.hettinger | 2007-02-08 02:42:35 +0100 (Thu, 08 Feb 2007) | 1 line
Fix docstring bug
........
r53671 | martin.v.loewis | 2007-02-08 10:13:36 +0100 (Thu, 08 Feb 2007) | 3 lines
Bug #1653736: Complain about keyword arguments to time.isoformat.
Will backport to 2.5.
........
r53679 | kurt.kaiser | 2007-02-08 23:58:18 +0100 (Thu, 08 Feb 2007) | 6 lines
Corrected some bugs in AutoComplete. Also, Page Up/Down in ACW implemented;
mouse and cursor selection in ACWindow implemented; double Tab inserts current
selection and closes ACW (similar to double-click and Return); scroll wheel now
works in ACW. Added AutoComplete instructions to IDLE Help.
........
r53689 | martin.v.loewis | 2007-02-09 13:19:32 +0100 (Fri, 09 Feb 2007) | 3 lines
Bug #1653736: Properly discard third argument to slot_nb_inplace_power.
Will backport.
........
r53691 | martin.v.loewis | 2007-02-09 13:36:48 +0100 (Fri, 09 Feb 2007) | 4 lines
Bug #1600860: Search for shared python library in LIBDIR, not
lib/python/config, on "linux" and "gnu" systems.
Will backport.
........
r53693 | martin.v.loewis | 2007-02-09 13:58:49 +0100 (Fri, 09 Feb 2007) | 2 lines
Update broken link. Will backport to 2.5.
........
r53697 | georg.brandl | 2007-02-09 19:48:41 +0100 (Fri, 09 Feb 2007) | 2 lines
Bug #1656078: typo in in profile docs.
........
r53731 | brett.cannon | 2007-02-11 06:36:00 +0100 (Sun, 11 Feb 2007) | 3 lines
Change a very minor inconsistency (that is purely cosmetic) in the AST
definition.
........
r53735 | skip.montanaro | 2007-02-11 19:24:37 +0100 (Sun, 11 Feb 2007) | 1 line
fix trace.py --ignore-dir
........
r53741 | brett.cannon | 2007-02-11 20:44:41 +0100 (Sun, 11 Feb 2007) | 3 lines
Check in changed Python-ast.c from a cosmetic change to Python.asdl (in
r53731).
........
r53751 | brett.cannon | 2007-02-12 04:51:02 +0100 (Mon, 12 Feb 2007) | 5 lines
Modify Parser/asdl_c.py so that the __version__ number for Python/Python-ast.c
is specified at the top of the file. Also add a note that Python/Python-ast.c
needs to be committed separately after a change to the AST grammar to capture
the revision number of the change (which is what __version__ is set to).
........
r53752 | lars.gustaebel | 2007-02-12 10:25:53 +0100 (Mon, 12 Feb 2007) | 3 lines
Bug #1656581: Point out that external file objects are supposed to be
at position 0.
........
r53754 | martin.v.loewis | 2007-02-12 13:21:10 +0100 (Mon, 12 Feb 2007) | 3 lines
Patch 1463026: Support default namespace in XMLGenerator.
Fixes #847665. Will backport.
........
r53757 | armin.rigo | 2007-02-12 17:23:24 +0100 (Mon, 12 Feb 2007) | 4 lines
Fix the line to what is my guess at the original author's meaning.
(The line has no effect anyway, but is present because it's
customary call the base class __init__).
........
r53763 | martin.v.loewis | 2007-02-13 09:34:45 +0100 (Tue, 13 Feb 2007) | 3 lines
Patch #685268: Consider a package's __path__ in imputil.
Will backport.
........
r53765 | martin.v.loewis | 2007-02-13 10:49:38 +0100 (Tue, 13 Feb 2007) | 2 lines
Patch #698833: Support file decryption in zipfile.
........
r53766 | martin.v.loewis | 2007-02-13 11:10:39 +0100 (Tue, 13 Feb 2007) | 3 lines
Patch #1517891: Make 'a' create the file if it doesn't exist.
Fixes #1514451.
........
r53767 | martin.v.loewis | 2007-02-13 13:08:24 +0100 (Tue, 13 Feb 2007) | 3 lines
Bug #1658794: Remove extraneous 'this'.
Will backport to 2.5.
........
r53769 | martin.v.loewis | 2007-02-13 13:14:19 +0100 (Tue, 13 Feb 2007) | 3 lines
Patch #1657276: Make NETLINK_DNRTMSG conditional.
Will backport.
........
r53771 | lars.gustaebel | 2007-02-13 17:09:24 +0100 (Tue, 13 Feb 2007) | 4 lines
Patch #1647484: Renamed GzipFile's filename attribute to name. The
filename attribute is still accessible as a property that emits a
DeprecationWarning.
........
r53772 | lars.gustaebel | 2007-02-13 17:24:00 +0100 (Tue, 13 Feb 2007) | 3 lines
Strip the '.gz' extension from the filename that is written to the
gzip header.
........
r53774 | martin.v.loewis | 2007-02-14 11:07:37 +0100 (Wed, 14 Feb 2007) | 2 lines
Patch #1432399: Add HCI sockets.
........
r53775 | martin.v.loewis | 2007-02-14 12:30:07 +0100 (Wed, 14 Feb 2007) | 2 lines
Update 1432399 to removal of _BT_SOCKADDR_MEMB.
........
r53776 | martin.v.loewis | 2007-02-14 12:30:56 +0100 (Wed, 14 Feb 2007) | 3 lines
Ignore directory time stamps when considering
whether to rerun libffi configure.
........
r53778 | lars.gustaebel | 2007-02-14 15:45:12 +0100 (Wed, 14 Feb 2007) | 4 lines
A missing binary mode in AppendTest caused failures in Windows
Buildbot.
........
r53782 | martin.v.loewis | 2007-02-15 10:51:35 +0100 (Thu, 15 Feb 2007) | 2 lines
Patch #1397848: add the reasoning behind no-resize-on-shrinkage.
........
r53783 | georg.brandl | 2007-02-15 11:37:59 +0100 (Thu, 15 Feb 2007) | 2 lines
Make functools.wraps() docs a bit clearer.
........
r53785 | georg.brandl | 2007-02-15 12:29:04 +0100 (Thu, 15 Feb 2007) | 2 lines
Patch #1494140: Add documentation for the new struct.Struct object.
........
r53787 | georg.brandl | 2007-02-15 12:29:55 +0100 (Thu, 15 Feb 2007) | 2 lines
Add missing \versionadded.
........
r53800 | brett.cannon | 2007-02-15 23:54:39 +0100 (Thu, 15 Feb 2007) | 11 lines
Update the encoding package's search function to use absolute imports when
calling __import__. This helps make the expected search locations for encoding
modules be more explicit.
One could use an explicit value for __path__ when making the call to __import__
to force the exact location searched for encodings. This would give the most
strict search path possible if one is worried about malicious code being
imported. The unfortunate side-effect of that is that if __path__ was modified
on 'encodings' on purpose in a safe way it would not be picked up in future
__import__ calls.
........
r53801 | brett.cannon | 2007-02-16 20:33:01 +0100 (Fri, 16 Feb 2007) | 2 lines
Make the __import__ call in encodings.__init__ absolute with a level 0 call.
........
r53809 | vinay.sajip | 2007-02-16 23:36:24 +0100 (Fri, 16 Feb 2007) | 1 line
Minor fix for currentframe (SF #1652788).
........
r53818 | raymond.hettinger | 2007-02-19 03:03:19 +0100 (Mon, 19 Feb 2007) | 3 lines
Extend work on revision 52962: Eliminate redundant calls to PyObject_Hash().
........
r53820 | raymond.hettinger | 2007-02-19 05:08:43 +0100 (Mon, 19 Feb 2007) | 1 line
Add merge() function to heapq.
........
r53821 | raymond.hettinger | 2007-02-19 06:28:28 +0100 (Mon, 19 Feb 2007) | 1 line
Add tie-breaker count to preserve sort stability.
........
r53822 | raymond.hettinger | 2007-02-19 07:59:32 +0100 (Mon, 19 Feb 2007) | 1 line
Use C heapreplace() instead of slower _siftup() in pure python.
........
r53823 | raymond.hettinger | 2007-02-19 08:30:21 +0100 (Mon, 19 Feb 2007) | 1 line
Add test for merge stability
........
r53824 | raymond.hettinger | 2007-02-19 10:14:10 +0100 (Mon, 19 Feb 2007) | 1 line
Provide an example of defaultdict with non-zero constant factory function.
........
r53825 | lars.gustaebel | 2007-02-19 10:54:47 +0100 (Mon, 19 Feb 2007) | 2 lines
Moved misplaced news item.
........
r53826 | martin.v.loewis | 2007-02-19 11:55:19 +0100 (Mon, 19 Feb 2007) | 3 lines
Patch #1490190: posixmodule now includes os.chflags() and os.lchflags()
functions on platforms where the underlying system calls are available.
........
r53827 | raymond.hettinger | 2007-02-19 19:15:04 +0100 (Mon, 19 Feb 2007) | 1 line
Fixup docstrings for merge().
........
r53829 | raymond.hettinger | 2007-02-19 21:44:04 +0100 (Mon, 19 Feb 2007) | 1 line
Fixup set/dict interoperability.
........
r53837 | raymond.hettinger | 2007-02-21 06:20:38 +0100 (Wed, 21 Feb 2007) | 1 line
Add itertools.izip_longest().
........
r53838 | raymond.hettinger | 2007-02-21 18:22:05 +0100 (Wed, 21 Feb 2007) | 1 line
Remove filler struct item and fix leak.
........
This commit is contained in:
parent
63eecc7eee
commit
cf297e46b8
69 changed files with 1456 additions and 285 deletions
|
|
@ -487,7 +487,7 @@ def localcontext(ctx=None):
|
|||
28
|
||||
>>> with localcontext():
|
||||
... ctx = getcontext()
|
||||
... ctx.prec() += 2
|
||||
... ctx.prec += 2
|
||||
... print(ctx.prec)
|
||||
...
|
||||
30
|
||||
|
|
|
|||
|
|
@ -185,9 +185,7 @@ class build_ext (Command):
|
|||
|
||||
# for extensions under Cygwin and AtheOS Python's library directory must be
|
||||
# appended to library_dirs
|
||||
if sys.platform[:6] == 'cygwin' or sys.platform[:6] == 'atheos' or \
|
||||
((sys.platform.startswith('linux') or sys.platform.startswith('gnu')) and
|
||||
sysconfig.get_config_var('Py_ENABLE_SHARED')):
|
||||
if sys.platform[:6] == 'cygwin' or sys.platform[:6] == 'atheos':
|
||||
if string.find(sys.executable, sys.exec_prefix) != -1:
|
||||
# building third party extensions
|
||||
self.library_dirs.append(os.path.join(sys.prefix, "lib",
|
||||
|
|
@ -197,6 +195,17 @@ class build_ext (Command):
|
|||
# building python standard extensions
|
||||
self.library_dirs.append('.')
|
||||
|
||||
# for extensions under Linux with a shared Python library,
|
||||
# Python's library directory must be appended to library_dirs
|
||||
if (sys.platform.startswith('linux') or sys.platform.startswith('gnu')) \
|
||||
and sysconfig.get_config_var('Py_ENABLE_SHARED'):
|
||||
if string.find(sys.executable, sys.exec_prefix) != -1:
|
||||
# building third party extensions
|
||||
self.library_dirs.append(sysconfig.get_config_var('LIBDIR'))
|
||||
else:
|
||||
# building python standard extensions
|
||||
self.library_dirs.append('.')
|
||||
|
||||
# The argument parsing will result in self.define being a string, but
|
||||
# it has to be a list of 2-tuples. All the preprocessor symbols
|
||||
# specified by the 'define' option will be set to '1'. Multiple
|
||||
|
|
|
|||
|
|
@ -93,8 +93,10 @@ def search_function(encoding):
|
|||
if not modname or '.' in modname:
|
||||
continue
|
||||
try:
|
||||
mod = __import__('encodings.' + modname,
|
||||
globals(), locals(), _import_tail)
|
||||
# Import is absolute to prevent the possibly malicious import of a
|
||||
# module with side-effects that is not in the 'encodings' package.
|
||||
mod = __import__('encodings.' + modname, fromlist=_import_tail,
|
||||
level=0)
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
|
|
|
|||
18
Lib/gzip.py
18
Lib/gzip.py
|
|
@ -106,7 +106,7 @@ class GzipFile:
|
|||
self._new_member = True
|
||||
self.extrabuf = ""
|
||||
self.extrasize = 0
|
||||
self.filename = filename
|
||||
self.name = filename
|
||||
# Starts small, scales exponentially
|
||||
self.min_readsize = 100
|
||||
|
||||
|
|
@ -127,14 +127,20 @@ class GzipFile:
|
|||
if self.mode == WRITE:
|
||||
self._write_gzip_header()
|
||||
|
||||
@property
|
||||
def filename(self):
|
||||
import warnings
|
||||
warnings.warn("use the name attribute", DeprecationWarning)
|
||||
if self.mode == WRITE and self.name[-3:] != ".gz":
|
||||
return self.name + ".gz"
|
||||
return self.name
|
||||
|
||||
def __repr__(self):
|
||||
s = repr(self.fileobj)
|
||||
return '<gzip ' + s[1:-1] + ' ' + hex(id(self)) + '>'
|
||||
|
||||
def _init_write(self, filename):
|
||||
if filename[-3:] != '.gz':
|
||||
filename = filename + '.gz'
|
||||
self.filename = filename
|
||||
self.name = filename
|
||||
self.crc = zlib.crc32("")
|
||||
self.size = 0
|
||||
self.writebuf = []
|
||||
|
|
@ -143,7 +149,9 @@ class GzipFile:
|
|||
def _write_gzip_header(self):
|
||||
self.fileobj.write('\037\213') # magic header
|
||||
self.fileobj.write('\010') # compression method
|
||||
fname = self.filename[:-3]
|
||||
fname = self.name
|
||||
if fname.endswith(".gz"):
|
||||
fname = fname[:-3]
|
||||
flags = 0
|
||||
if fname:
|
||||
flags = FNAME
|
||||
|
|
|
|||
42
Lib/heapq.py
42
Lib/heapq.py
|
|
@ -126,8 +126,8 @@ Believe me, real good tape sorts were quite spectacular to watch!
|
|||
From all times, sorting has always been a Great Art! :-)
|
||||
"""
|
||||
|
||||
__all__ = ['heappush', 'heappop', 'heapify', 'heapreplace', 'nlargest',
|
||||
'nsmallest']
|
||||
__all__ = ['heappush', 'heappop', 'heapify', 'heapreplace', 'merge',
|
||||
'nlargest', 'nsmallest']
|
||||
|
||||
from itertools import islice, repeat, count, imap, izip, tee
|
||||
from operator import itemgetter, neg
|
||||
|
|
@ -308,6 +308,41 @@ try:
|
|||
except ImportError:
|
||||
pass
|
||||
|
||||
def merge(*iterables):
|
||||
'''Merge multiple sorted inputs into a single sorted output.
|
||||
|
||||
Similar to sorted(itertools.chain(*iterables)) but returns an iterable,
|
||||
does not pull the data into memory all at once, and assumes that each of
|
||||
the input streams is already sorted (smallest to largest).
|
||||
|
||||
>>> list(merge([1,3,5,7], [0,2,4,8], [5,10,15,20], [], [25]))
|
||||
[0, 1, 2, 3, 4, 5, 5, 7, 8, 10, 15, 20, 25]
|
||||
|
||||
'''
|
||||
_heappop, _heapreplace, _StopIteration = heappop, heapreplace, StopIteration
|
||||
|
||||
h = []
|
||||
h_append = h.append
|
||||
for itnum, it in enumerate(map(iter, iterables)):
|
||||
try:
|
||||
next = it.next
|
||||
h_append([next(), itnum, next])
|
||||
except _StopIteration:
|
||||
pass
|
||||
heapify(h)
|
||||
|
||||
while 1:
|
||||
try:
|
||||
while 1:
|
||||
v, itnum, next = s = h[0] # raises IndexError when h is empty
|
||||
yield v
|
||||
s[0] = next() # raises StopIteration when exhausted
|
||||
_heapreplace(h, s) # restore heap condition
|
||||
except _StopIteration:
|
||||
_heappop(h) # remove empty iterator
|
||||
except IndexError:
|
||||
return
|
||||
|
||||
# Extend the implementations of nsmallest and nlargest to use a key= argument
|
||||
_nsmallest = nsmallest
|
||||
def nsmallest(n, iterable, key=None):
|
||||
|
|
@ -341,3 +376,6 @@ if __name__ == "__main__":
|
|||
while heap:
|
||||
sort.append(heappop(heap))
|
||||
print(sort)
|
||||
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
|
|
|
|||
|
|
@ -10,13 +10,14 @@ HIDE_SEQUENCES = ("<FocusOut>", "<ButtonPress>")
|
|||
KEYPRESS_VIRTUAL_EVENT_NAME = "<<autocompletewindow-keypress>>"
|
||||
# We need to bind event beyond <Key> so that the function will be called
|
||||
# before the default specific IDLE function
|
||||
KEYPRESS_SEQUENCES = ("<Key>", "<Key-BackSpace>", "<Key-Return>",
|
||||
"<Key-Up>", "<Key-Down>", "<Key-Home>", "<Key-End>")
|
||||
KEYPRESS_SEQUENCES = ("<Key>", "<Key-BackSpace>", "<Key-Return>", "<Key-Tab>",
|
||||
"<Key-Up>", "<Key-Down>", "<Key-Home>", "<Key-End>",
|
||||
"<Key-Prior>", "<Key-Next>")
|
||||
KEYRELEASE_VIRTUAL_EVENT_NAME = "<<autocompletewindow-keyrelease>>"
|
||||
KEYRELEASE_SEQUENCE = "<KeyRelease>"
|
||||
LISTUPDATE_SEQUENCE = "<ButtonRelease>"
|
||||
LISTUPDATE_SEQUENCE = "<B1-ButtonRelease>"
|
||||
WINCONFIG_SEQUENCE = "<Configure>"
|
||||
DOUBLECLICK_SEQUENCE = "<Double-ButtonRelease>"
|
||||
DOUBLECLICK_SEQUENCE = "<B1-Double-ButtonRelease>"
|
||||
|
||||
class AutoCompleteWindow:
|
||||
|
||||
|
|
@ -49,6 +50,8 @@ class AutoCompleteWindow:
|
|||
# event ids
|
||||
self.hideid = self.keypressid = self.listupdateid = self.winconfigid \
|
||||
= self.keyreleaseid = self.doubleclickid = None
|
||||
# Flag set if last keypress was a tab
|
||||
self.lastkey_was_tab = False
|
||||
|
||||
def _change_start(self, newstart):
|
||||
i = 0
|
||||
|
|
@ -118,11 +121,6 @@ class AutoCompleteWindow:
|
|||
i = 0
|
||||
while i < len(lts) and i < len(selstart) and lts[i] == selstart[i]:
|
||||
i += 1
|
||||
previous_completion = self.completions[cursel - 1]
|
||||
while cursel > 0 and selstart[:i] <= previous_completion:
|
||||
i += 1
|
||||
if selstart == previous_completion:
|
||||
break # maybe we have a duplicate?
|
||||
newstart = selstart[:i]
|
||||
self._change_start(newstart)
|
||||
|
||||
|
|
@ -206,7 +204,7 @@ class AutoCompleteWindow:
|
|||
self.keyrelease_event)
|
||||
self.widget.event_add(KEYRELEASE_VIRTUAL_EVENT_NAME,KEYRELEASE_SEQUENCE)
|
||||
self.listupdateid = listbox.bind(LISTUPDATE_SEQUENCE,
|
||||
self.listupdate_event)
|
||||
self.listselect_event)
|
||||
self.winconfigid = acw.bind(WINCONFIG_SEQUENCE, self.winconfig_event)
|
||||
self.doubleclickid = listbox.bind(DOUBLECLICK_SEQUENCE,
|
||||
self.doubleclick_event)
|
||||
|
|
@ -215,24 +213,34 @@ class AutoCompleteWindow:
|
|||
if not self.is_active():
|
||||
return
|
||||
# Position the completion list window
|
||||
text = self.widget
|
||||
text.see(self.startindex)
|
||||
x, y, cx, cy = text.bbox(self.startindex)
|
||||
acw = self.autocompletewindow
|
||||
self.widget.see(self.startindex)
|
||||
x, y, cx, cy = self.widget.bbox(self.startindex)
|
||||
acw.wm_geometry("+%d+%d" % (x + self.widget.winfo_rootx(),
|
||||
y + self.widget.winfo_rooty() \
|
||||
-acw.winfo_height()))
|
||||
|
||||
acw_width, acw_height = acw.winfo_width(), acw.winfo_height()
|
||||
text_width, text_height = text.winfo_width(), text.winfo_height()
|
||||
new_x = text.winfo_rootx() + min(x, max(0, text_width - acw_width))
|
||||
new_y = text.winfo_rooty() + y
|
||||
if (text_height - (y + cy) >= acw_height # enough height below
|
||||
or y < acw_height): # not enough height above
|
||||
# place acw below current line
|
||||
new_y += cy
|
||||
else:
|
||||
# place acw above current line
|
||||
new_y -= acw_height
|
||||
acw.wm_geometry("+%d+%d" % (new_x, new_y))
|
||||
|
||||
def hide_event(self, event):
|
||||
if not self.is_active():
|
||||
return
|
||||
self.hide_window()
|
||||
|
||||
def listupdate_event(self, event):
|
||||
def listselect_event(self, event):
|
||||
if not self.is_active():
|
||||
return
|
||||
self.userwantswindow = True
|
||||
self._selection_changed()
|
||||
cursel = int(self.listbox.curselection()[0])
|
||||
self._change_start(self.completions[cursel])
|
||||
|
||||
def doubleclick_event(self, event):
|
||||
# Put the selected completion in the text, and close the list
|
||||
|
|
@ -248,7 +256,8 @@ class AutoCompleteWindow:
|
|||
state = event.mc_state
|
||||
else:
|
||||
state = 0
|
||||
|
||||
if keysym != "Tab":
|
||||
self.lastkey_was_tab = False
|
||||
if (len(keysym) == 1 or keysym in ("underscore", "BackSpace")
|
||||
or (self.mode==AutoComplete.COMPLETE_FILES and keysym in
|
||||
("period", "minus"))) \
|
||||
|
|
@ -330,13 +339,21 @@ class AutoCompleteWindow:
|
|||
self.listbox.select_clear(cursel)
|
||||
self.listbox.select_set(newsel)
|
||||
self._selection_changed()
|
||||
self._change_start(self.completions[newsel])
|
||||
return "break"
|
||||
|
||||
elif (keysym == "Tab" and not state):
|
||||
# The user wants a completion, but it is handled by AutoComplete
|
||||
# (not AutoCompleteWindow), so ignore.
|
||||
self.userwantswindow = True
|
||||
return
|
||||
if self.lastkey_was_tab:
|
||||
# two tabs in a row; insert current selection and close acw
|
||||
cursel = int(self.listbox.curselection()[0])
|
||||
self._change_start(self.completions[cursel])
|
||||
self.hide_window()
|
||||
return "break"
|
||||
else:
|
||||
# first tab; let AutoComplete handle the completion
|
||||
self.userwantswindow = True
|
||||
self.lastkey_was_tab = True
|
||||
return
|
||||
|
||||
elif any(s in keysym for s in ("Shift", "Control", "Alt",
|
||||
"Meta", "Command", "Option")):
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@
|
|||
Call Tips are floating windows which display function, class, and method
|
||||
parameter and docstring information when you type an opening parenthesis, and
|
||||
which disappear when you type a closing parenthesis.
|
||||
|
||||
"""
|
||||
import re
|
||||
import sys
|
||||
import types
|
||||
|
||||
|
|
@ -89,6 +91,8 @@ class CallTips:
|
|||
two unrelated modules are being edited some calltips in the current
|
||||
module may be inoperative if the module was not the last to run.
|
||||
|
||||
To find methods, fetch_tip must be fed a fully qualified name.
|
||||
|
||||
"""
|
||||
try:
|
||||
rpcclt = self.editwin.flist.pyshell.interp.rpcclt
|
||||
|
|
@ -108,7 +112,7 @@ class CallTips:
|
|||
namespace.update(__main__.__dict__)
|
||||
try:
|
||||
return eval(name, namespace)
|
||||
except:
|
||||
except (NameError, AttributeError):
|
||||
return None
|
||||
|
||||
def _find_constructor(class_ob):
|
||||
|
|
@ -124,39 +128,37 @@ def _find_constructor(class_ob):
|
|||
|
||||
def get_arg_text(ob):
|
||||
"""Get a string describing the arguments for the given object"""
|
||||
argText = ""
|
||||
arg_text = ""
|
||||
if ob is not None:
|
||||
argOffset = 0
|
||||
arg_offset = 0
|
||||
if type(ob) in (types.ClassType, types.TypeType):
|
||||
# Look for the highest __init__ in the class chain.
|
||||
fob = _find_constructor(ob)
|
||||
if fob is None:
|
||||
fob = lambda: None
|
||||
else:
|
||||
argOffset = 1
|
||||
arg_offset = 1
|
||||
elif type(ob)==types.MethodType:
|
||||
# bit of a hack for methods - turn it into a function
|
||||
# but we drop the "self" param.
|
||||
fob = ob.im_func
|
||||
argOffset = 1
|
||||
arg_offset = 1
|
||||
else:
|
||||
fob = ob
|
||||
# Try and build one for Python defined functions
|
||||
# Try to build one for Python defined functions
|
||||
if type(fob) in [types.FunctionType, types.LambdaType]:
|
||||
try:
|
||||
realArgs = fob.func_code.co_varnames[argOffset:fob.func_code.co_argcount]
|
||||
defaults = fob.func_defaults or []
|
||||
defaults = list(map(lambda name: "=%s" % repr(name), defaults))
|
||||
defaults = [""] * (len(realArgs)-len(defaults)) + defaults
|
||||
items = map(lambda arg, dflt: arg+dflt, realArgs, defaults)
|
||||
if fob.func_code.co_flags & 0x4:
|
||||
items.append("...")
|
||||
if fob.func_code.co_flags & 0x8:
|
||||
items.append("***")
|
||||
argText = ", ".join(items)
|
||||
argText = "(%s)" % argText
|
||||
except:
|
||||
pass
|
||||
argcount = fob.func_code.co_argcount
|
||||
real_args = fob.func_code.co_varnames[arg_offset:argcount]
|
||||
defaults = fob.func_defaults or []
|
||||
defaults = list(map(lambda name: "=%s" % repr(name), defaults))
|
||||
defaults = [""] * (len(real_args) - len(defaults)) + defaults
|
||||
items = map(lambda arg, dflt: arg + dflt, real_args, defaults)
|
||||
if fob.func_code.co_flags & 0x4:
|
||||
items.append("...")
|
||||
if fob.func_code.co_flags & 0x8:
|
||||
items.append("***")
|
||||
arg_text = ", ".join(items)
|
||||
arg_text = "(%s)" % re.sub("\.\d+", "<tuple>", arg_text)
|
||||
# See if we can use the docstring
|
||||
doc = getattr(ob, "__doc__", "")
|
||||
if doc:
|
||||
|
|
@ -164,10 +166,10 @@ def get_arg_text(ob):
|
|||
pos = doc.find("\n")
|
||||
if pos < 0 or pos > 70:
|
||||
pos = 70
|
||||
if argText:
|
||||
argText += "\n"
|
||||
argText += doc[:pos]
|
||||
return argText
|
||||
if arg_text:
|
||||
arg_text += "\n"
|
||||
arg_text += doc[:pos]
|
||||
return arg_text
|
||||
|
||||
#################################################
|
||||
#
|
||||
|
|
@ -181,16 +183,18 @@ if __name__=='__main__':
|
|||
def t4(*args): "(...)"
|
||||
def t5(a, *args): "(a, ...)"
|
||||
def t6(a, b=None, *args, **kw): "(a, b=None, ..., ***)"
|
||||
def t7((a, b), c, (d, e)): "(<tuple>, c, <tuple>)"
|
||||
|
||||
class TC:
|
||||
"(a=None, ...)"
|
||||
def __init__(self, a=None, *b): "(a=None, ...)"
|
||||
class TC(object):
|
||||
"(ai=None, ...)"
|
||||
def __init__(self, ai=None, *b): "(ai=None, ...)"
|
||||
def t1(self): "()"
|
||||
def t2(self, a, b=None): "(a, b=None)"
|
||||
def t3(self, a, *args): "(a, ...)"
|
||||
def t2(self, ai, b=None): "(ai, b=None)"
|
||||
def t3(self, ai, *args): "(ai, ...)"
|
||||
def t4(self, *args): "(...)"
|
||||
def t5(self, a, *args): "(a, ...)"
|
||||
def t6(self, a, b=None, *args, **kw): "(a, b=None, ..., ***)"
|
||||
def t5(self, ai, *args): "(ai, ...)"
|
||||
def t6(self, ai, b=None, *args, **kw): "(ai, b=None, ..., ***)"
|
||||
def t7(self, (ai, b), c, (d, e)): "(<tuple>, c, <tuple>)"
|
||||
|
||||
def test(tests):
|
||||
ct = CallTips()
|
||||
|
|
@ -198,15 +202,20 @@ if __name__=='__main__':
|
|||
for t in tests:
|
||||
expected = t.__doc__ + "\n" + t.__doc__
|
||||
name = t.__name__
|
||||
arg_text = ct.fetch_tip(name)
|
||||
# exercise fetch_tip(), not just get_arg_text()
|
||||
try:
|
||||
qualified_name = "%s.%s" % (t.im_class.__name__, name)
|
||||
except AttributeError:
|
||||
qualified_name = name
|
||||
arg_text = ct.fetch_tip(qualified_name)
|
||||
if arg_text != expected:
|
||||
failed.append(t)
|
||||
print("%s - expected %s, but got %s" % (t, expected,
|
||||
get_arg_text(entity)))
|
||||
fmt = "%s - expected %s, but got %s"
|
||||
print(fmt % (t.__name__, expected, get_arg_text(t)))
|
||||
print("%d of %d tests failed" % (len(failed), len(tests)))
|
||||
|
||||
tc = TC()
|
||||
tests = (t1, t2, t3, t4, t5, t6,
|
||||
TC, tc.t1, tc.t2, tc.t3, tc.t4, tc.t5, tc.t6)
|
||||
tests = (t1, t2, t3, t4, t5, t6, t7,
|
||||
TC, tc.t1, tc.t2, tc.t3, tc.t4, tc.t5, tc.t6, tc.t7)
|
||||
|
||||
test(tests)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ not open blocks are not shown in the context hints pane.
|
|||
|
||||
"""
|
||||
import Tkinter
|
||||
from Tkconstants import TOP, LEFT, X, W, SUNKEN
|
||||
from configHandler import idleConf
|
||||
import re
|
||||
from sys import maxint as INFINITY
|
||||
|
|
@ -24,7 +25,6 @@ getspacesfirstword =\
|
|||
|
||||
class CodeContext:
|
||||
menudefs = [('options', [('!Code Conte_xt', '<<toggle-code-context>>')])]
|
||||
|
||||
context_depth = idleConf.GetOption("extensions", "CodeContext",
|
||||
"numlines", type="int", default=3)
|
||||
bgcolor = idleConf.GetOption("extensions", "CodeContext",
|
||||
|
|
@ -54,66 +54,33 @@ class CodeContext:
|
|||
|
||||
def toggle_code_context_event(self, event=None):
|
||||
if not self.label:
|
||||
# The following code attempts to figure out the required border
|
||||
# width and vertical padding required for the CodeContext widget
|
||||
# to be perfectly aligned with the text in the main Text widget.
|
||||
# This is done by retrieving the appropriate attributes from the
|
||||
# editwin.text and editwin.text_frame widgets.
|
||||
# Calculate the border width and horizontal padding required to
|
||||
# align the context with the text in the main Text widget.
|
||||
#
|
||||
# All values are passed through int(str(<value>)), since some
|
||||
# values may be pixel objects, which can't simply be added added
|
||||
# to ints.
|
||||
#
|
||||
# This code is considered somewhat unstable since it relies on
|
||||
# some of Tk's inner workings. However its effect is merely
|
||||
# cosmetic; failure will only cause the CodeContext text to be
|
||||
# somewhat misaligned with the text in the main Text widget.
|
||||
#
|
||||
# To avoid possible errors, all references to the inner workings
|
||||
# of Tk are executed inside try/except blocks.
|
||||
|
||||
widgets_for_width_calc = self.editwin.text, self.editwin.text_frame
|
||||
|
||||
# calculate the required vertical padding
|
||||
# values may be pixel objects, which can't simply be added to ints.
|
||||
widgets = self.editwin.text, self.editwin.text_frame
|
||||
# Calculate the required vertical padding
|
||||
padx = 0
|
||||
for widget in widgets_for_width_calc:
|
||||
try:
|
||||
# retrieve the "padx" attribte from widget's pack info
|
||||
padx += int(str( widget.pack_info()['padx'] ))
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
# retrieve the widget's "padx" attribte
|
||||
padx += int(str( widget.cget('padx') ))
|
||||
except:
|
||||
pass
|
||||
|
||||
# calculate the required border width
|
||||
border_width = 0
|
||||
for widget in widgets_for_width_calc:
|
||||
try:
|
||||
# retrieve the widget's "border" attribte
|
||||
border_width += int(str( widget.cget('border') ))
|
||||
except:
|
||||
pass
|
||||
|
||||
for widget in widgets:
|
||||
padx += int(str( widget.pack_info()['padx'] ))
|
||||
padx += int(str( widget.cget('padx') ))
|
||||
# Calculate the required border width
|
||||
border = 0
|
||||
for widget in widgets:
|
||||
border += int(str( widget.cget('border') ))
|
||||
self.label = Tkinter.Label(self.editwin.top,
|
||||
text="\n" * (self.context_depth - 1),
|
||||
anchor="w", justify="left",
|
||||
anchor=W, justify=LEFT,
|
||||
font=self.textfont,
|
||||
bg=self.bgcolor, fg=self.fgcolor,
|
||||
width=1, #don't request more than we get
|
||||
padx=padx, #line up with text widget
|
||||
border=border_width, #match border width
|
||||
relief="sunken",
|
||||
)
|
||||
|
||||
# CodeContext's label widget is packed before and above the
|
||||
# text_frame widget, thus ensuring that it will appear directly
|
||||
# above it.
|
||||
self.label.pack(side="top", fill="x", expand=False,
|
||||
padx=padx, border=border,
|
||||
relief=SUNKEN)
|
||||
# Pack the label widget before and above the text_frame widget,
|
||||
# thus ensuring that it will appear directly above text_frame
|
||||
self.label.pack(side=TOP, fill=X, expand=False,
|
||||
before=self.editwin.text_frame)
|
||||
|
||||
else:
|
||||
self.label.destroy()
|
||||
self.label = None
|
||||
|
|
@ -190,7 +157,6 @@ class CodeContext:
|
|||
stopindent)
|
||||
self.info.extend(lines)
|
||||
self.topvisible = new_topvisible
|
||||
|
||||
# empty lines in context pane:
|
||||
context_strings = [""] * max(0, self.context_depth - len(self.info))
|
||||
# followed by the context hint lines:
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ class IOBinding:
|
|||
# gets set to "not modified" at every new prompt.
|
||||
try:
|
||||
interp = self.editwin.interp
|
||||
except:
|
||||
except AttributeError:
|
||||
interp = None
|
||||
if not self.filename and self.get_saved() and not interp:
|
||||
self.editwin.flist.open(filename, self.loadfile)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,19 @@ What's New in IDLE 2.6a1?
|
|||
|
||||
*Release date: XX-XXX-200X*
|
||||
|
||||
- Corrected some bugs in AutoComplete. Also, Page Up/Down in ACW implemented;
|
||||
mouse and cursor selection in ACWindow implemented; double Tab inserts
|
||||
current selection and closes ACW (similar to double-click and Return); scroll
|
||||
wheel now works in ACW. Added AutoComplete instructions to IDLE Help.
|
||||
|
||||
- AutoCompleteWindow moved below input line, will move above if there
|
||||
isn't enough space. Patch 1621265 Tal Einat
|
||||
|
||||
- Calltips now 'handle' tuples in the argument list (display '<tuple>' :)
|
||||
Suggested solution by Christos Georgiou, Bug 791968.
|
||||
|
||||
- Add 'raw' support to configHandler. Patch 1650174 Tal Einat.
|
||||
|
||||
- Avoid hang when encountering a duplicate in a completion list. Bug 1571112.
|
||||
|
||||
- Patch #1362975: Rework CodeContext indentation algorithm to
|
||||
|
|
|
|||
|
|
@ -706,34 +706,36 @@ class ModifiedInterpreter(InteractiveInterpreter):
|
|||
debugger = self.debugger
|
||||
try:
|
||||
self.tkconsole.beginexecuting()
|
||||
try:
|
||||
if not debugger and self.rpcclt is not None:
|
||||
self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
|
||||
(code,), {})
|
||||
elif debugger:
|
||||
debugger.run(code, self.locals)
|
||||
else:
|
||||
exec(code, self.locals)
|
||||
except SystemExit:
|
||||
if not self.tkconsole.closing:
|
||||
if tkMessageBox.askyesno(
|
||||
"Exit?",
|
||||
"Do you want to exit altogether?",
|
||||
default="yes",
|
||||
master=self.tkconsole.text):
|
||||
raise
|
||||
else:
|
||||
self.showtraceback()
|
||||
else:
|
||||
if not debugger and self.rpcclt is not None:
|
||||
self.active_seq = self.rpcclt.asyncqueue("exec", "runcode",
|
||||
(code,), {})
|
||||
elif debugger:
|
||||
debugger.run(code, self.locals)
|
||||
else:
|
||||
exec(code, self.locals)
|
||||
except SystemExit:
|
||||
if not self.tkconsole.closing:
|
||||
if tkMessageBox.askyesno(
|
||||
"Exit?",
|
||||
"Do you want to exit altogether?",
|
||||
default="yes",
|
||||
master=self.tkconsole.text):
|
||||
raise
|
||||
except:
|
||||
if use_subprocess:
|
||||
# When run w/o subprocess, both user and IDLE errors
|
||||
# are printed here; skip message in that case.
|
||||
print("IDLE internal error in runcode()", file=self.tkconsole.stderr)
|
||||
else:
|
||||
else:
|
||||
raise
|
||||
except:
|
||||
if use_subprocess:
|
||||
print("IDLE internal error in runcode()",
|
||||
file=self.tkconsole.stderr)
|
||||
self.showtraceback()
|
||||
if use_subprocess:
|
||||
self.tkconsole.endexecuting()
|
||||
self.tkconsole.endexecuting()
|
||||
else:
|
||||
if self.tkconsole.canceled:
|
||||
self.tkconsole.canceled = False
|
||||
print("KeyboardInterrupt", file=self.tkconsole.stderr)
|
||||
else:
|
||||
self.showtraceback()
|
||||
finally:
|
||||
if not use_subprocess:
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -39,22 +39,19 @@ class IdleConfParser(ConfigParser):
|
|||
self.file=cfgFile
|
||||
ConfigParser.__init__(self,defaults=cfgDefaults)
|
||||
|
||||
def Get(self, section, option, type=None, default=None):
|
||||
def Get(self, section, option, type=None, default=None, raw=False):
|
||||
"""
|
||||
Get an option value for given section/option or return default.
|
||||
If type is specified, return as type.
|
||||
"""
|
||||
if type=='bool':
|
||||
getVal=self.getboolean
|
||||
elif type=='int':
|
||||
getVal=self.getint
|
||||
else:
|
||||
getVal=self.get
|
||||
if self.has_option(section,option):
|
||||
#return getVal(section, option, raw, vars, default)
|
||||
return getVal(section, option)
|
||||
else:
|
||||
if not self.has_option(section, option):
|
||||
return default
|
||||
if type=='bool':
|
||||
return self.getboolean(section, option)
|
||||
elif type=='int':
|
||||
return self.getint(section, option)
|
||||
else:
|
||||
return self.get(section, option, raw=raw)
|
||||
|
||||
def GetOptionList(self,section):
|
||||
"""
|
||||
|
|
@ -219,7 +216,7 @@ class IdleConf:
|
|||
return userDir
|
||||
|
||||
def GetOption(self, configType, section, option, default=None, type=None,
|
||||
warn_on_default=True):
|
||||
warn_on_default=True, raw=False):
|
||||
"""
|
||||
Get an option value for given config type and given general
|
||||
configuration section/option or return a default. If type is specified,
|
||||
|
|
@ -233,9 +230,11 @@ class IdleConf:
|
|||
|
||||
"""
|
||||
if self.userCfg[configType].has_option(section,option):
|
||||
return self.userCfg[configType].Get(section, option, type=type)
|
||||
return self.userCfg[configType].Get(section, option,
|
||||
type=type, raw=raw)
|
||||
elif self.defaultCfg[configType].has_option(section,option):
|
||||
return self.defaultCfg[configType].Get(section, option, type=type)
|
||||
return self.defaultCfg[configType].Get(section, option,
|
||||
type=type, raw=raw)
|
||||
else: #returning default, print warning
|
||||
if warn_on_default:
|
||||
warning = ('\n Warning: configHandler.py - IdleConf.GetOption -\n'
|
||||
|
|
|
|||
|
|
@ -44,6 +44,10 @@ Edit Menu:
|
|||
Find in Files... -- Open a search dialog box for searching files
|
||||
Replace... -- Open a search-and-replace dialog box
|
||||
Go to Line -- Ask for a line number and show that line
|
||||
Show Calltip -- Open a small window with function param hints
|
||||
Show Completions -- Open a scroll window allowing selection keywords
|
||||
and attributes. (see '*TIPS*', below)
|
||||
Show Parens -- Highlight the surrounding parenthesis
|
||||
Expand Word -- Expand the word you have typed to match another
|
||||
word in the same buffer; repeat to get a
|
||||
different expansion
|
||||
|
|
@ -91,6 +95,7 @@ Options Menu:
|
|||
Code Context -- Open a pane at the top of the edit window which
|
||||
shows the block context of the section of code
|
||||
which is scrolling off the top or the window.
|
||||
(Not present in Shell window.)
|
||||
|
||||
Windows Menu:
|
||||
|
||||
|
|
@ -138,8 +143,11 @@ Basic editing and navigation:
|
|||
Control-left/right Arrow moves by words in a strange but useful way.
|
||||
Home/End go to begin/end of line.
|
||||
Control-Home/End go to begin/end of file.
|
||||
Some useful Emacs bindings (Control-a, Control-e, Control-k, etc.)
|
||||
are inherited from Tcl/Tk.
|
||||
Some useful Emacs bindings are inherited from Tcl/Tk:
|
||||
Control-a beginning of line
|
||||
Control-e end of line
|
||||
Control-k kill line (but doesn't put it in clipboard)
|
||||
Control-l center window around the insertion point
|
||||
Standard Windows bindings may work on that platform.
|
||||
Keybindings are selected in the Settings Dialog, look there.
|
||||
|
||||
|
|
@ -155,6 +163,52 @@ Automatic indentation:
|
|||
|
||||
See also the indent/dedent region commands in the edit menu.
|
||||
|
||||
Completions:
|
||||
|
||||
Completions are supplied for functions, classes, and attributes of
|
||||
classes, both built-in and user-defined. Completions are also provided
|
||||
for filenames.
|
||||
|
||||
The AutoCompleteWindow (ACW) will open after a predefined delay
|
||||
(default is two seconds) after a '.' or (in a string) an os.sep is
|
||||
typed. If after one of those characters (plus zero or more other
|
||||
characters) you type a Tab the ACW will open immediately if a possible
|
||||
continuation is found.
|
||||
|
||||
If there is only one possible completion for the characters entered, a
|
||||
Tab will supply that completion without opening the ACW.
|
||||
|
||||
'Show Completions' will force open a completions window. In an empty
|
||||
string, this will contain the files in the current directory. On a
|
||||
blank line, it will contain the built-in and user-defined functions and
|
||||
classes in the current name spaces, plus any modules imported. If some
|
||||
characters have been entered, the ACW will attempt to be more specific.
|
||||
|
||||
If string of characters is typed, the ACW selection will jump to the
|
||||
entry most closely matching those characters. Entering a Tab will cause
|
||||
the longest non-ambiguous match to be entered in the Edit window or
|
||||
Shell. Two Tabs in a row will supply the current ACW selection, as
|
||||
will Return or a double click. Cursor keys, Page Up/Down, mouse
|
||||
selection, and the scrollwheel all operate on the ACW.
|
||||
|
||||
'Hidden' attributes can be accessed by typing the beginning of hidden
|
||||
name after a '.'. e.g. '_'. This allows access to modules with
|
||||
'__all__' set, or to class-private attributes.
|
||||
|
||||
Completions and the 'Expand Word' facility can save a lot of typing!
|
||||
|
||||
Completions are currently limited to those in the namespaces. Names in
|
||||
an Edit window which are not via __main__ or sys.modules will not be
|
||||
found. Run the module once with your imports to correct this
|
||||
situation. Note that IDLE itself places quite a few modules in
|
||||
sys.modules, so much can be found by default, e.g. the re module.
|
||||
|
||||
If you don't like the ACW popping up unbidden, simply make the delay
|
||||
longer or disable the extension. OTOH, you could make the delay zero.
|
||||
|
||||
You could also switch off the CallTips extension. (We will be adding
|
||||
a delay to the call tip window.)
|
||||
|
||||
Python Shell window:
|
||||
|
||||
Control-c interrupts executing command.
|
||||
|
|
@ -165,7 +219,7 @@ Python Shell window:
|
|||
|
||||
Alt-p retrieves previous command matching what you have typed.
|
||||
Alt-n retrieves next.
|
||||
(These are Control-p, Control-n on the Mac)
|
||||
(These are Control-p, Control-n on the Mac)
|
||||
Return while cursor is on a previous command retrieves that command.
|
||||
Expand word is also useful to reduce typing.
|
||||
|
||||
|
|
@ -196,7 +250,7 @@ Other preferences:
|
|||
be changed using the Settings dialog.
|
||||
|
||||
Command line usage:
|
||||
|
||||
|
||||
Enter idle -h at the command prompt to get a usage message.
|
||||
|
||||
Running without a subprocess:
|
||||
|
|
@ -211,3 +265,18 @@ Running without a subprocess:
|
|||
re-import any specific items (e.g. from foo import baz) if the changes
|
||||
are to take effect. For these reasons, it is preferable to run IDLE
|
||||
with the default subprocess if at all possible.
|
||||
|
||||
Extensions:
|
||||
|
||||
IDLE contains an extension facility. See the beginning of
|
||||
config-extensions.def in the idlelib directory for further information.
|
||||
The default extensions are currently:
|
||||
|
||||
FormatParagraph
|
||||
AutoExpand
|
||||
ZoomHeight
|
||||
ScriptBinding
|
||||
CallTips
|
||||
ParenMatch
|
||||
AutoComplete
|
||||
CodeContext
|
||||
|
|
|
|||
|
|
@ -552,6 +552,10 @@ class _FilesystemImporter(Importer):
|
|||
# This method is only used when we look for a module within a package.
|
||||
assert parent
|
||||
|
||||
for submodule_path in parent.__path__:
|
||||
code = self._import_pathname(_os_path_join(submodule_path, modname), fqname)
|
||||
if code is not None:
|
||||
return code
|
||||
return self._import_pathname(_os_path_join(parent.__pkgdir__, modname),
|
||||
fqname)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright 2001-2005 by Vinay Sajip. All Rights Reserved.
|
||||
# Copyright 2001-2007 by Vinay Sajip. All Rights Reserved.
|
||||
#
|
||||
# Permission to use, copy, modify, and distribute this software and its
|
||||
# documentation for any purpose and without fee is hereby granted,
|
||||
|
|
@ -21,7 +21,7 @@ comp.lang.python, and influenced by Apache's log4j system.
|
|||
Should work under Python versions >= 1.5.2, except that source line
|
||||
information is not available unless 'sys._getframe()' is.
|
||||
|
||||
Copyright (C) 2001-2004 Vinay Sajip. All Rights Reserved.
|
||||
Copyright (C) 2001-2007 Vinay Sajip. All Rights Reserved.
|
||||
|
||||
To use, simply 'import logging' and log away!
|
||||
"""
|
||||
|
|
@ -41,8 +41,8 @@ except ImportError:
|
|||
|
||||
__author__ = "Vinay Sajip <vinay_sajip@red-dove.com>"
|
||||
__status__ = "production"
|
||||
__version__ = "0.5.0.1"
|
||||
__date__ = "09 January 2007"
|
||||
__version__ = "0.5.0.2"
|
||||
__date__ = "16 February 2007"
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Miscellaneous module data
|
||||
|
|
@ -68,7 +68,7 @@ def currentframe():
|
|||
except:
|
||||
return sys.exc_traceback.tb_frame.f_back
|
||||
|
||||
if hasattr(sys, '_getframe'): currentframe = sys._getframe
|
||||
if hasattr(sys, '_getframe'): currentframe = lambda: sys._getframe(3)
|
||||
# done filching
|
||||
|
||||
# _srcfile is only used in conjunction with sys._getframe().
|
||||
|
|
|
|||
|
|
@ -60,13 +60,15 @@ def copymode(src, dst):
|
|||
os.chmod(dst, mode)
|
||||
|
||||
def copystat(src, dst):
|
||||
"""Copy all stat info (mode bits, atime and mtime) from src to dst"""
|
||||
"""Copy all stat info (mode bits, atime, mtime, flags) from src to dst"""
|
||||
st = os.stat(src)
|
||||
mode = stat.S_IMODE(st.st_mode)
|
||||
if hasattr(os, 'utime'):
|
||||
os.utime(dst, (st.st_atime, st.st_mtime))
|
||||
if hasattr(os, 'chmod'):
|
||||
os.chmod(dst, mode)
|
||||
if hasattr(os, 'chflags') and hasattr(st, 'st_flags'):
|
||||
os.chflags(dst, st.st_flags)
|
||||
|
||||
|
||||
def copy(src, dst):
|
||||
|
|
|
|||
13
Lib/stat.py
13
Lib/stat.py
|
|
@ -84,3 +84,16 @@ S_IRWXO = 00007
|
|||
S_IROTH = 00004
|
||||
S_IWOTH = 00002
|
||||
S_IXOTH = 00001
|
||||
|
||||
# Names for file flags
|
||||
|
||||
UF_NODUMP = 0x00000001
|
||||
UF_IMMUTABLE = 0x00000002
|
||||
UF_APPEND = 0x00000004
|
||||
UF_OPAQUE = 0x00000008
|
||||
UF_NOUNLINK = 0x00000010
|
||||
SF_ARCHIVED = 0x00010000
|
||||
SF_IMMUTABLE = 0x00020000
|
||||
SF_APPEND = 0x00040000
|
||||
SF_NOUNLINK = 0x00100000
|
||||
SF_SNAPSHOT = 0x00200000
|
||||
|
|
|
|||
|
|
@ -593,14 +593,30 @@ class Popen(object):
|
|||
c2pread, c2pwrite,
|
||||
errread, errwrite)
|
||||
|
||||
if p2cwrite:
|
||||
# On Windows, you cannot just redirect one or two handles: You
|
||||
# either have to redirect all three or none. If the subprocess
|
||||
# user has only redirected one or two handles, we are
|
||||
# automatically creating PIPEs for the rest. We should close
|
||||
# these after the process is started. See bug #1124861.
|
||||
if mswindows:
|
||||
if stdin is None and p2cwrite is not None:
|
||||
os.close(p2cwrite)
|
||||
p2cwrite = None
|
||||
if stdout is None and c2pread is not None:
|
||||
os.close(c2pread)
|
||||
c2pread = None
|
||||
if stderr is None and errread is not None:
|
||||
os.close(errread)
|
||||
errread = None
|
||||
|
||||
if p2cwrite is not None:
|
||||
self.stdin = os.fdopen(p2cwrite, 'wb', bufsize)
|
||||
if c2pread:
|
||||
if c2pread is not None:
|
||||
if universal_newlines:
|
||||
self.stdout = os.fdopen(c2pread, 'rU', bufsize)
|
||||
else:
|
||||
self.stdout = os.fdopen(c2pread, 'rb', bufsize)
|
||||
if errread:
|
||||
if errread is not None:
|
||||
if universal_newlines:
|
||||
self.stderr = os.fdopen(errread, 'rU', bufsize)
|
||||
else:
|
||||
|
|
@ -669,7 +685,9 @@ class Popen(object):
|
|||
|
||||
if stdin is None:
|
||||
p2cread = GetStdHandle(STD_INPUT_HANDLE)
|
||||
elif stdin == PIPE:
|
||||
if p2cread is not None:
|
||||
pass
|
||||
elif stdin is None or stdin == PIPE:
|
||||
p2cread, p2cwrite = CreatePipe(None, 0)
|
||||
# Detach and turn into fd
|
||||
p2cwrite = p2cwrite.Detach()
|
||||
|
|
@ -683,7 +701,9 @@ class Popen(object):
|
|||
|
||||
if stdout is None:
|
||||
c2pwrite = GetStdHandle(STD_OUTPUT_HANDLE)
|
||||
elif stdout == PIPE:
|
||||
if c2pwrite is not None:
|
||||
pass
|
||||
elif stdout is None or stdout == PIPE:
|
||||
c2pread, c2pwrite = CreatePipe(None, 0)
|
||||
# Detach and turn into fd
|
||||
c2pread = c2pread.Detach()
|
||||
|
|
@ -697,7 +717,9 @@ class Popen(object):
|
|||
|
||||
if stderr is None:
|
||||
errwrite = GetStdHandle(STD_ERROR_HANDLE)
|
||||
elif stderr == PIPE:
|
||||
if errwrite is not None:
|
||||
pass
|
||||
elif stderr is None or stderr == PIPE:
|
||||
errread, errwrite = CreatePipe(None, 0)
|
||||
# Detach and turn into fd
|
||||
errread = errread.Detach()
|
||||
|
|
@ -987,29 +1009,29 @@ class Popen(object):
|
|||
# Child
|
||||
try:
|
||||
# Close parent's pipe ends
|
||||
if p2cwrite:
|
||||
if p2cwrite is not None:
|
||||
os.close(p2cwrite)
|
||||
if c2pread:
|
||||
if c2pread is not None:
|
||||
os.close(c2pread)
|
||||
if errread:
|
||||
if errread is not None:
|
||||
os.close(errread)
|
||||
os.close(errpipe_read)
|
||||
|
||||
# Dup fds for child
|
||||
if p2cread:
|
||||
if p2cread is not None:
|
||||
os.dup2(p2cread, 0)
|
||||
if c2pwrite:
|
||||
if c2pwrite is not None:
|
||||
os.dup2(c2pwrite, 1)
|
||||
if errwrite:
|
||||
if errwrite is not None:
|
||||
os.dup2(errwrite, 2)
|
||||
|
||||
# Close pipe fds. Make sure we don't close the same
|
||||
# fd more than once, or standard fds.
|
||||
if p2cread and p2cread not in (0,):
|
||||
if p2cread is not None and p2cread not in (0,):
|
||||
os.close(p2cread)
|
||||
if c2pwrite and c2pwrite not in (p2cread, 1):
|
||||
if c2pwrite is not None and c2pwrite not in (p2cread, 1):
|
||||
os.close(c2pwrite)
|
||||
if errwrite and errwrite not in (p2cread, c2pwrite, 2):
|
||||
if errwrite is not None and errwrite not in (p2cread, c2pwrite, 2):
|
||||
os.close(errwrite)
|
||||
|
||||
# Close all other fds, if asked for
|
||||
|
|
@ -1042,11 +1064,11 @@ class Popen(object):
|
|||
|
||||
# Parent
|
||||
os.close(errpipe_write)
|
||||
if p2cread and p2cwrite:
|
||||
if p2cread is not None and p2cwrite is not None:
|
||||
os.close(p2cread)
|
||||
if c2pwrite and c2pread:
|
||||
if c2pwrite is not None and c2pread is not None:
|
||||
os.close(c2pwrite)
|
||||
if errwrite and errread:
|
||||
if errwrite is not None and errread is not None:
|
||||
os.close(errwrite)
|
||||
|
||||
# Wait for exec to fail or succeed; possibly raising exception
|
||||
|
|
|
|||
|
|
@ -1062,6 +1062,10 @@ class TarFile(object):
|
|||
self.mode = {"r": "rb", "a": "r+b", "w": "wb"}[mode]
|
||||
|
||||
if not fileobj:
|
||||
if self._mode == "a" and not os.path.exists(self.name):
|
||||
# Create nonexistent files in append mode.
|
||||
self._mode = "w"
|
||||
self.mode = "wb"
|
||||
fileobj = _open(self.name, self.mode)
|
||||
self._extfileobj = False
|
||||
else:
|
||||
|
|
@ -1095,7 +1099,8 @@ class TarFile(object):
|
|||
self.fileobj.seek(0)
|
||||
break
|
||||
if tarinfo is None:
|
||||
self.fileobj.seek(- BLOCKSIZE, 1)
|
||||
if self.offset > 0:
|
||||
self.fileobj.seek(- BLOCKSIZE, 1)
|
||||
break
|
||||
|
||||
if self._mode in "aw":
|
||||
|
|
@ -1122,7 +1127,7 @@ class TarFile(object):
|
|||
'r:' open for reading exclusively uncompressed
|
||||
'r:gz' open for reading with gzip compression
|
||||
'r:bz2' open for reading with bzip2 compression
|
||||
'a' or 'a:' open for appending
|
||||
'a' or 'a:' open for appending, creating the file if necessary
|
||||
'w' or 'w:' open for writing without compression
|
||||
'w:gz' open for writing with gzip compression
|
||||
'w:bz2' open for writing with bzip2 compression
|
||||
|
|
|
|||
|
|
@ -1767,6 +1767,11 @@ class TestTime(HarmlessMixedComparison):
|
|||
self.assertEqual(t.isoformat(), "00:00:00.100000")
|
||||
self.assertEqual(t.isoformat(), str(t))
|
||||
|
||||
def test_1653736(self):
|
||||
# verify it doesn't accept extra keyword arguments
|
||||
t = self.theclass(second=1)
|
||||
self.assertRaises(TypeError, t.isoformat, foo=3)
|
||||
|
||||
def test_strftime(self):
|
||||
t = self.theclass(1, 2, 3, 4)
|
||||
self.assertEqual(t.strftime('%H %M %S'), "01 02 03")
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ class TestDefaultDict(unittest.TestCase):
|
|||
self.assertEqual(err.args, (15,))
|
||||
else:
|
||||
self.fail("d2[15] didn't raise KeyError")
|
||||
self.assertRaises(TypeError, defaultdict, 1)
|
||||
|
||||
def test_missing(self):
|
||||
d1 = defaultdict()
|
||||
|
|
@ -60,10 +61,10 @@ class TestDefaultDict(unittest.TestCase):
|
|||
self.assertEqual(repr(d1), "defaultdict(None, {})")
|
||||
d1[11] = 41
|
||||
self.assertEqual(repr(d1), "defaultdict(None, {11: 41})")
|
||||
d2 = defaultdict(0)
|
||||
self.assertEqual(d2.default_factory, 0)
|
||||
d2 = defaultdict(int)
|
||||
self.assertEqual(d2.default_factory, int)
|
||||
d2[12] = 42
|
||||
self.assertEqual(repr(d2), "defaultdict(0, {12: 42})")
|
||||
self.assertEqual(repr(d2), "defaultdict(<type 'int'>, {12: 42})")
|
||||
def foo(): return 43
|
||||
d3 = defaultdict(foo)
|
||||
self.assert_(d3.default_factory is foo)
|
||||
|
|
|
|||
|
|
@ -2093,7 +2093,7 @@ def inherits():
|
|||
__slots__ = ['prec']
|
||||
def __init__(self, value=0.0, prec=12):
|
||||
self.prec = int(prec)
|
||||
float.__init__(value)
|
||||
float.__init__(self, value)
|
||||
def __repr__(self):
|
||||
return "%.*g" % (self.prec, self)
|
||||
vereq(repr(precfloat(1.1)), "1.1")
|
||||
|
|
|
|||
|
|
@ -182,6 +182,14 @@ class DictTest(unittest.TestCase):
|
|||
|
||||
self.assertRaises(ValueError, {}.update, [(1, 2, 3)])
|
||||
|
||||
# SF #1615701: make d.update(m) honor __getitem__() and keys() in dict subclasses
|
||||
class KeyUpperDict(dict):
|
||||
def __getitem__(self, key):
|
||||
return key.upper()
|
||||
d.clear()
|
||||
d.update(KeyUpperDict.fromkeys('abc'))
|
||||
self.assertEqual(d, {'a':'A', 'b':'B', 'c':'C'})
|
||||
|
||||
def test_fromkeys(self):
|
||||
self.assertEqual(dict.fromkeys('abc'), {'a':None, 'b':None, 'c':None})
|
||||
d = {}
|
||||
|
|
|
|||
|
|
@ -153,6 +153,13 @@ class TestGzip(unittest.TestCase):
|
|||
self.assertEqual(f.myfileobj.mode, 'rb')
|
||||
f.close()
|
||||
|
||||
def test_1647484(self):
|
||||
for mode in ('wb', 'rb'):
|
||||
f = gzip.GzipFile(self.filename, mode)
|
||||
self.assert_(hasattr(f, "name"))
|
||||
self.assertEqual(f.name, self.filename)
|
||||
f.close()
|
||||
|
||||
def test_main(verbose=None):
|
||||
test_support.run_unittest(TestGzip)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
"""Unittests for heapq."""
|
||||
|
||||
from heapq import heappush, heappop, heapify, heapreplace, nlargest, nsmallest
|
||||
from heapq import heappush, heappop, heapify, heapreplace, merge, nlargest, nsmallest
|
||||
import random
|
||||
import unittest
|
||||
from test import test_support
|
||||
|
|
@ -103,6 +103,29 @@ class TestHeap(unittest.TestCase):
|
|||
heap_sorted = [heappop(heap) for i in range(size)]
|
||||
self.assertEqual(heap_sorted, sorted(data))
|
||||
|
||||
def test_merge(self):
|
||||
inputs = []
|
||||
for i in xrange(random.randrange(5)):
|
||||
row = sorted(random.randrange(1000) for j in range(random.randrange(10)))
|
||||
inputs.append(row)
|
||||
self.assertEqual(sorted(chain(*inputs)), list(merge(*inputs)))
|
||||
self.assertEqual(list(merge()), [])
|
||||
|
||||
def test_merge_stability(self):
|
||||
class Int(int):
|
||||
pass
|
||||
inputs = [[], [], [], []]
|
||||
for i in range(20000):
|
||||
stream = random.randrange(4)
|
||||
x = random.randrange(500)
|
||||
obj = Int(x)
|
||||
obj.pair = (x, stream)
|
||||
inputs[stream].append(obj)
|
||||
for stream in inputs:
|
||||
stream.sort()
|
||||
result = [i.pair for i in merge(*inputs)]
|
||||
self.assertEqual(result, sorted(result))
|
||||
|
||||
def test_nsmallest(self):
|
||||
data = [(random.randrange(2000), i) for i in range(1000)]
|
||||
for f in (None, lambda x: x[0] * 547 % 2000):
|
||||
|
|
|
|||
|
|
@ -55,8 +55,7 @@ class TestBasicOps(unittest.TestCase):
|
|||
self.assertEqual(take(2, lzip('abc',count(3))), [('a', 3), ('b', 4)])
|
||||
self.assertRaises(TypeError, count, 2, 3)
|
||||
self.assertRaises(TypeError, count, 'a')
|
||||
c = count(sys.maxint-2) # verify that rollover doesn't crash
|
||||
c.next(); c.next(); c.next(); c.next(); c.next()
|
||||
self.assertRaises(OverflowError, list, islice(count(sys.maxint-5), 10))
|
||||
c = count(3)
|
||||
self.assertEqual(repr(c), 'count(3)')
|
||||
c.next()
|
||||
|
|
@ -203,6 +202,51 @@ class TestBasicOps(unittest.TestCase):
|
|||
ids = map(id, list(izip('abc', 'def')))
|
||||
self.assertEqual(len(dict.fromkeys(ids)), len(ids))
|
||||
|
||||
def test_iziplongest(self):
|
||||
for args in [
|
||||
['abc', range(6)],
|
||||
[range(6), 'abc'],
|
||||
[range(1000), range(2000,2100), range(3000,3050)],
|
||||
[range(1000), range(0), range(3000,3050), range(1200), range(1500)],
|
||||
[range(1000), range(0), range(3000,3050), range(1200), range(1500), range(0)],
|
||||
]:
|
||||
target = map(None, *args)
|
||||
self.assertEqual(list(izip_longest(*args)), target)
|
||||
self.assertEqual(list(izip_longest(*args, **{})), target)
|
||||
target = [tuple((e is None and 'X' or e) for e in t) for t in target] # Replace None fills with 'X'
|
||||
self.assertEqual(list(izip_longest(*args, **dict(fillvalue='X'))), target)
|
||||
|
||||
self.assertEqual(take(3,izip_longest('abcdef', count())), list(zip('abcdef', range(3)))) # take 3 from infinite input
|
||||
|
||||
self.assertEqual(list(izip_longest()), list(zip()))
|
||||
self.assertEqual(list(izip_longest([])), list(zip([])))
|
||||
self.assertEqual(list(izip_longest('abcdef')), list(zip('abcdef')))
|
||||
|
||||
self.assertEqual(list(izip_longest('abc', 'defg', **{})), map(None, 'abc', 'defg')) # empty keyword dict
|
||||
self.assertRaises(TypeError, izip_longest, 3)
|
||||
self.assertRaises(TypeError, izip_longest, range(3), 3)
|
||||
|
||||
for stmt in [
|
||||
"izip_longest('abc', fv=1)",
|
||||
"izip_longest('abc', fillvalue=1, bogus_keyword=None)",
|
||||
]:
|
||||
try:
|
||||
eval(stmt, globals(), locals())
|
||||
except TypeError:
|
||||
pass
|
||||
else:
|
||||
self.fail('Did not raise Type in: ' + stmt)
|
||||
|
||||
# Check tuple re-use (implementation detail)
|
||||
self.assertEqual([tuple(list(pair)) for pair in izip_longest('abc', 'def')],
|
||||
list(zip('abc', 'def')))
|
||||
self.assertEqual([pair for pair in izip_longest('abc', 'def')],
|
||||
list(zip('abc', 'def')))
|
||||
ids = map(id, izip_longest('abc', 'def'))
|
||||
self.assertEqual(min(ids), max(ids))
|
||||
ids = map(id, list(izip_longest('abc', 'def')))
|
||||
self.assertEqual(len(dict.fromkeys(ids)), len(ids))
|
||||
|
||||
def test_repeat(self):
|
||||
self.assertEqual(lzip(xrange(3),repeat('a')),
|
||||
[(0, 'a'), (1, 'a'), (2, 'a')])
|
||||
|
|
@ -616,6 +660,15 @@ class TestVariousIteratorArgs(unittest.TestCase):
|
|||
self.assertRaises(TypeError, izip, N(s))
|
||||
self.assertRaises(ZeroDivisionError, list, izip(E(s)))
|
||||
|
||||
def test_iziplongest(self):
|
||||
for s in ("123", "", range(1000), ('do', 1.2), xrange(2000,2200,5)):
|
||||
for g in (G, I, Ig, S, L, R):
|
||||
self.assertEqual(list(izip_longest(g(s))), list(zip(g(s))))
|
||||
self.assertEqual(list(izip_longest(g(s), g(s))), list(zip(g(s), g(s))))
|
||||
self.assertRaises(TypeError, izip_longest, X(s))
|
||||
self.assertRaises(TypeError, izip_longest, N(s))
|
||||
self.assertRaises(ZeroDivisionError, list, izip_longest(E(s)))
|
||||
|
||||
def test_imap(self):
|
||||
for s in (range(10), range(0), range(100), (7,11), xrange(20,50,5)):
|
||||
for g in (G, I, Ig, S, L, R):
|
||||
|
|
|
|||
|
|
@ -210,6 +210,8 @@ class OperatorTestCase(unittest.TestCase):
|
|||
self.failUnless(operator.isSequenceType(xrange(10)))
|
||||
self.failUnless(operator.isSequenceType('yeahbuddy'))
|
||||
self.failIf(operator.isSequenceType(3))
|
||||
class Dict(dict): pass
|
||||
self.failIf(operator.isSequenceType(Dict()))
|
||||
|
||||
def test_lshift(self):
|
||||
self.failUnlessRaises(TypeError, operator.lshift)
|
||||
|
|
|
|||
|
|
@ -192,6 +192,18 @@ class PosixTester(unittest.TestCase):
|
|||
posix.utime(test_support.TESTFN, (int(now), int(now)))
|
||||
posix.utime(test_support.TESTFN, (now, now))
|
||||
|
||||
def test_chflags(self):
|
||||
if hasattr(posix, 'chflags'):
|
||||
st = os.stat(test_support.TESTFN)
|
||||
if hasattr(st, 'st_flags'):
|
||||
posix.chflags(test_support.TESTFN, st.st_flags)
|
||||
|
||||
def test_lchflags(self):
|
||||
if hasattr(posix, 'lchflags'):
|
||||
st = os.stat(test_support.TESTFN)
|
||||
if hasattr(st, 'st_flags'):
|
||||
posix.lchflags(test_support.TESTFN, st.st_flags)
|
||||
|
||||
def test_main():
|
||||
test_support.run_unittest(PosixTester)
|
||||
|
||||
|
|
|
|||
|
|
@ -216,7 +216,44 @@ def test_xmlgen_ns():
|
|||
('<ns1:doc xmlns:ns1="%s"><udoc></udoc></ns1:doc>' %
|
||||
ns_uri)
|
||||
|
||||
# ===== XMLFilterBase
|
||||
def test_1463026_1():
|
||||
result = StringIO()
|
||||
gen = XMLGenerator(result)
|
||||
|
||||
gen.startDocument()
|
||||
gen.startElementNS((None, 'a'), 'a', {(None, 'b'):'c'})
|
||||
gen.endElementNS((None, 'a'), 'a')
|
||||
gen.endDocument()
|
||||
|
||||
return result.getvalue() == start+'<a b="c"></a>'
|
||||
|
||||
def test_1463026_2():
|
||||
result = StringIO()
|
||||
gen = XMLGenerator(result)
|
||||
|
||||
gen.startDocument()
|
||||
gen.startPrefixMapping(None, 'qux')
|
||||
gen.startElementNS(('qux', 'a'), 'a', {})
|
||||
gen.endElementNS(('qux', 'a'), 'a')
|
||||
gen.endPrefixMapping(None)
|
||||
gen.endDocument()
|
||||
|
||||
return result.getvalue() == start+'<a xmlns="qux"></a>'
|
||||
|
||||
def test_1463026_3():
|
||||
result = StringIO()
|
||||
gen = XMLGenerator(result)
|
||||
|
||||
gen.startDocument()
|
||||
gen.startPrefixMapping('my', 'qux')
|
||||
gen.startElementNS(('qux', 'a'), 'a', {(None, 'b'):'c'})
|
||||
gen.endElementNS(('qux', 'a'), 'a')
|
||||
gen.endPrefixMapping('my')
|
||||
gen.endDocument()
|
||||
|
||||
return result.getvalue() == start+'<my:a xmlns:my="qux" b="c"></my:a>'
|
||||
|
||||
# ===== Xmlfilterbase
|
||||
|
||||
def test_filter_basic():
|
||||
result = StringIO()
|
||||
|
|
|
|||
|
|
@ -26,6 +26,14 @@ class ReprWrapper:
|
|||
def __repr__(self):
|
||||
return repr(self.value)
|
||||
|
||||
class HashCountingInt(int):
|
||||
'int-like object that counts the number of times __hash__ is called'
|
||||
def __init__(self, *args):
|
||||
self.hash_count = 0
|
||||
def __hash__(self):
|
||||
self.hash_count += 1
|
||||
return int.__hash__(self)
|
||||
|
||||
class TestJointOps(unittest.TestCase):
|
||||
# Tests common to both set and frozenset
|
||||
|
||||
|
|
@ -273,6 +281,18 @@ class TestJointOps(unittest.TestCase):
|
|||
fo.close()
|
||||
os.remove(test_support.TESTFN)
|
||||
|
||||
def test_do_not_rehash_dict_keys(self):
|
||||
n = 10
|
||||
d = dict.fromkeys(map(HashCountingInt, xrange(n)))
|
||||
self.assertEqual(sum(elem.hash_count for elem in d), n)
|
||||
s = self.thetype(d)
|
||||
self.assertEqual(sum(elem.hash_count for elem in d), n)
|
||||
s.difference(d)
|
||||
self.assertEqual(sum(elem.hash_count for elem in d), n)
|
||||
if hasattr(s, 'symmetric_difference_update'):
|
||||
s.symmetric_difference_update(d)
|
||||
self.assertEqual(sum(elem.hash_count for elem in d), n)
|
||||
|
||||
class TestSet(TestJointOps):
|
||||
thetype = set
|
||||
|
||||
|
|
|
|||
|
|
@ -305,6 +305,61 @@ class WriteTest(BaseTest):
|
|||
self.assertEqual(self.dst.getnames(), [], "added the archive to itself")
|
||||
|
||||
|
||||
class AppendTest(unittest.TestCase):
|
||||
# Test append mode (cp. patch #1652681).
|
||||
|
||||
def setUp(self):
|
||||
self.tarname = tmpname()
|
||||
if os.path.exists(self.tarname):
|
||||
os.remove(self.tarname)
|
||||
|
||||
def _add_testfile(self, fileobj=None):
|
||||
tar = tarfile.open(self.tarname, "a", fileobj=fileobj)
|
||||
tar.addfile(tarfile.TarInfo("bar"))
|
||||
tar.close()
|
||||
|
||||
def _create_testtar(self):
|
||||
src = tarfile.open(tarname())
|
||||
t = src.getmember("0-REGTYPE")
|
||||
t.name = "foo"
|
||||
f = src.extractfile(t)
|
||||
tar = tarfile.open(self.tarname, "w")
|
||||
tar.addfile(t, f)
|
||||
tar.close()
|
||||
|
||||
def _test(self, names=["bar"], fileobj=None):
|
||||
tar = tarfile.open(self.tarname, fileobj=fileobj)
|
||||
self.assert_(tar.getnames() == names)
|
||||
|
||||
def test_non_existing(self):
|
||||
self._add_testfile()
|
||||
self._test()
|
||||
|
||||
def test_empty(self):
|
||||
open(self.tarname, "wb").close()
|
||||
self._add_testfile()
|
||||
self._test()
|
||||
|
||||
def test_empty_fileobj(self):
|
||||
fobj = StringIO.StringIO()
|
||||
self._add_testfile(fobj)
|
||||
fobj.seek(0)
|
||||
self._test(fileobj=fobj)
|
||||
|
||||
def test_fileobj(self):
|
||||
self._create_testtar()
|
||||
data = open(self.tarname, "rb").read()
|
||||
fobj = StringIO.StringIO(data)
|
||||
self._add_testfile(fobj)
|
||||
fobj.seek(0)
|
||||
self._test(names=["foo", "bar"], fileobj=fobj)
|
||||
|
||||
def test_existing(self):
|
||||
self._create_testtar()
|
||||
self._add_testfile()
|
||||
self._test(names=["foo", "bar"])
|
||||
|
||||
|
||||
class Write100Test(BaseTest):
|
||||
# The name field in a tar header stores strings of at most 100 chars.
|
||||
# If a string is shorter than 100 chars it has to be padded with '\0',
|
||||
|
|
@ -711,6 +766,7 @@ def test_main():
|
|||
ReadAsteriskTest,
|
||||
ReadStreamAsteriskTest,
|
||||
WriteTest,
|
||||
AppendTest,
|
||||
Write100Test,
|
||||
WriteSize0Test,
|
||||
WriteStreamTest,
|
||||
|
|
|
|||
|
|
@ -307,6 +307,28 @@ class PyZipFileTests(unittest.TestCase):
|
|||
|
||||
|
||||
class OtherTests(unittest.TestCase):
|
||||
def testCreateNonExistentFileForAppend(self):
|
||||
if os.path.exists(TESTFN):
|
||||
os.unlink(TESTFN)
|
||||
|
||||
filename = 'testfile.txt'
|
||||
content = 'hello, world. this is some content.'
|
||||
|
||||
try:
|
||||
zf = zipfile.ZipFile(TESTFN, 'a')
|
||||
zf.writestr(filename, content)
|
||||
zf.close()
|
||||
except IOError:
|
||||
self.fail('Could not append data to a non-existent zip file.')
|
||||
|
||||
self.assert_(os.path.exists(TESTFN))
|
||||
|
||||
zf = zipfile.ZipFile(TESTFN, 'r')
|
||||
self.assertEqual(zf.read(filename), content)
|
||||
zf.close()
|
||||
|
||||
os.unlink(TESTFN)
|
||||
|
||||
def testCloseErroneousFile(self):
|
||||
# This test checks that the ZipFile constructor closes the file object
|
||||
# it opens if there's an error in the file. If it doesn't, the traceback
|
||||
|
|
@ -349,8 +371,49 @@ class OtherTests(unittest.TestCase):
|
|||
# and report that the first file in the archive was corrupt.
|
||||
self.assertRaises(RuntimeError, zipf.testzip)
|
||||
|
||||
|
||||
class DecryptionTests(unittest.TestCase):
|
||||
# This test checks that ZIP decryption works. Since the library does not
|
||||
# support encryption at the moment, we use a pre-generated encrypted
|
||||
# ZIP file
|
||||
|
||||
data = (
|
||||
'PK\x03\x04\x14\x00\x01\x00\x00\x00n\x92i.#y\xef?&\x00\x00\x00\x1a\x00'
|
||||
'\x00\x00\x08\x00\x00\x00test.txt\xfa\x10\xa0gly|\xfa-\xc5\xc0=\xf9y'
|
||||
'\x18\xe0\xa8r\xb3Z}Lg\xbc\xae\xf9|\x9b\x19\xe4\x8b\xba\xbb)\x8c\xb0\xdbl'
|
||||
'PK\x01\x02\x14\x00\x14\x00\x01\x00\x00\x00n\x92i.#y\xef?&\x00\x00\x00'
|
||||
'\x1a\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x01\x00 \x00\xb6\x81'
|
||||
'\x00\x00\x00\x00test.txtPK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x006\x00'
|
||||
'\x00\x00L\x00\x00\x00\x00\x00' )
|
||||
|
||||
plain = 'zipfile.py encryption test'
|
||||
|
||||
def setUp(self):
|
||||
fp = open(TESTFN, "wb")
|
||||
fp.write(self.data)
|
||||
fp.close()
|
||||
self.zip = zipfile.ZipFile(TESTFN, "r")
|
||||
|
||||
def tearDown(self):
|
||||
self.zip.close()
|
||||
os.unlink(TESTFN)
|
||||
|
||||
def testNoPassword(self):
|
||||
# Reading the encrypted file without password
|
||||
# must generate a RunTime exception
|
||||
self.assertRaises(RuntimeError, self.zip.read, "test.txt")
|
||||
|
||||
def testBadPassword(self):
|
||||
self.zip.setpassword("perl")
|
||||
self.assertRaises(RuntimeError, self.zip.read, "test.txt")
|
||||
|
||||
def testGoodPassword(self):
|
||||
self.zip.setpassword("python")
|
||||
self.assertEquals(self.zip.read("test.txt"), self.plain)
|
||||
|
||||
def test_main():
|
||||
run_unittest(TestsWithSourceFile, TestZip64InSmallFiles, OtherTests, PyZipFileTests)
|
||||
run_unittest(TestsWithSourceFile, TestZip64InSmallFiles, OtherTests,
|
||||
PyZipFileTests, DecryptionTests)
|
||||
#run_unittest(TestZip64InSmallFiles)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
|
|
@ -587,7 +587,7 @@ class Trace:
|
|||
"""
|
||||
if why == 'call':
|
||||
code = frame.f_code
|
||||
filename = code.co_filename
|
||||
filename = frame.f_globals.get('__file__', None)
|
||||
if filename:
|
||||
# XXX modname() doesn't work right for packages, so
|
||||
# the ignore support won't work right for packages
|
||||
|
|
|
|||
|
|
@ -100,6 +100,17 @@ class XMLGenerator(handler.ContentHandler):
|
|||
else:
|
||||
self._out.write(text.encode(self._encoding, _error_handling))
|
||||
|
||||
def _qname(self, name):
|
||||
"""Builds a qualified name from a (ns_url, localname) pair"""
|
||||
if name[0]:
|
||||
# The name is in a non-empty namespace
|
||||
prefix = self._current_context[name[0]]
|
||||
if prefix:
|
||||
# If it is not the default namespace, prepend the prefix
|
||||
return prefix + ":" + name[1]
|
||||
# Return the unqualified name
|
||||
return name[1]
|
||||
|
||||
# ContentHandler methods
|
||||
|
||||
def startDocument(self):
|
||||
|
|
@ -125,29 +136,21 @@ class XMLGenerator(handler.ContentHandler):
|
|||
self._write('</%s>' % name)
|
||||
|
||||
def startElementNS(self, name, qname, attrs):
|
||||
if name[0] is None:
|
||||
# if the name was not namespace-scoped, use the unqualified part
|
||||
name = name[1]
|
||||
else:
|
||||
# else try to restore the original prefix from the namespace
|
||||
name = self._current_context[name[0]] + ":" + name[1]
|
||||
self._write('<' + name)
|
||||
self._write('<' + self._qname(name))
|
||||
|
||||
for pair in self._undeclared_ns_maps:
|
||||
self._write(' xmlns:%s="%s"' % pair)
|
||||
for prefix, uri in self._undeclared_ns_maps:
|
||||
if prefix:
|
||||
self._out.write(' xmlns:%s="%s"' % (prefix, uri))
|
||||
else:
|
||||
self._out.write(' xmlns="%s"' % uri)
|
||||
self._undeclared_ns_maps = []
|
||||
|
||||
for (name, value) in attrs.items():
|
||||
name = self._current_context[name[0]] + ":" + name[1]
|
||||
self._write(' %s=%s' % (name, quoteattr(value)))
|
||||
self._write(' %s=%s' % (self._qname(name), quoteattr(value)))
|
||||
self._write('>')
|
||||
|
||||
def endElementNS(self, name, qname):
|
||||
if name[0] is None:
|
||||
name = name[1]
|
||||
else:
|
||||
name = self._current_context[name[0]] + ":" + name[1]
|
||||
self._write('</%s>' % name)
|
||||
self._write('</%s>' % self._qname(name))
|
||||
|
||||
def characters(self, content):
|
||||
self._write(escape(content))
|
||||
|
|
|
|||
|
|
@ -296,6 +296,65 @@ class ZipInfo (object):
|
|||
extra = extra[ln+4:]
|
||||
|
||||
|
||||
class _ZipDecrypter:
|
||||
"""Class to handle decryption of files stored within a ZIP archive.
|
||||
|
||||
ZIP supports a password-based form of encryption. Even though known
|
||||
plaintext attacks have been found against it, it is still useful
|
||||
for low-level securicy.
|
||||
|
||||
Usage:
|
||||
zd = _ZipDecrypter(mypwd)
|
||||
plain_char = zd(cypher_char)
|
||||
plain_text = map(zd, cypher_text)
|
||||
"""
|
||||
|
||||
def _GenerateCRCTable():
|
||||
"""Generate a CRC-32 table.
|
||||
|
||||
ZIP encryption uses the CRC32 one-byte primitive for scrambling some
|
||||
internal keys. We noticed that a direct implementation is faster than
|
||||
relying on binascii.crc32().
|
||||
"""
|
||||
poly = 0xedb88320
|
||||
table = [0] * 256
|
||||
for i in range(256):
|
||||
crc = i
|
||||
for j in range(8):
|
||||
if crc & 1:
|
||||
crc = ((crc >> 1) & 0x7FFFFFFF) ^ poly
|
||||
else:
|
||||
crc = ((crc >> 1) & 0x7FFFFFFF)
|
||||
table[i] = crc
|
||||
return table
|
||||
crctable = _GenerateCRCTable()
|
||||
|
||||
def _crc32(self, ch, crc):
|
||||
"""Compute the CRC32 primitive on one byte."""
|
||||
return ((crc >> 8) & 0xffffff) ^ self.crctable[(crc ^ ord(ch)) & 0xff]
|
||||
|
||||
def __init__(self, pwd):
|
||||
self.key0 = 305419896
|
||||
self.key1 = 591751049
|
||||
self.key2 = 878082192
|
||||
for p in pwd:
|
||||
self._UpdateKeys(p)
|
||||
|
||||
def _UpdateKeys(self, c):
|
||||
self.key0 = self._crc32(c, self.key0)
|
||||
self.key1 = (self.key1 + (self.key0 & 255)) & 4294967295
|
||||
self.key1 = (self.key1 * 134775813 + 1) & 4294967295
|
||||
self.key2 = self._crc32(chr((self.key1 >> 24) & 255), self.key2)
|
||||
|
||||
def __call__(self, c):
|
||||
"""Decrypt a single character."""
|
||||
c = ord(c)
|
||||
k = self.key2 | 2
|
||||
c = c ^ (((k * (k^1)) >> 8) & 255)
|
||||
c = chr(c)
|
||||
self._UpdateKeys(c)
|
||||
return c
|
||||
|
||||
class ZipFile:
|
||||
""" Class with methods to open, read, write, close, list zip files.
|
||||
|
||||
|
|
@ -330,13 +389,21 @@ class ZipFile:
|
|||
self.filelist = [] # List of ZipInfo instances for archive
|
||||
self.compression = compression # Method of compression
|
||||
self.mode = key = mode.replace('b', '')[0]
|
||||
self.pwd = None
|
||||
|
||||
# Check if we were passed a file-like object
|
||||
if isinstance(file, basestring):
|
||||
self._filePassed = 0
|
||||
self.filename = file
|
||||
modeDict = {'r' : 'rb', 'w': 'wb', 'a' : 'r+b'}
|
||||
self.fp = open(file, modeDict[mode])
|
||||
try:
|
||||
self.fp = open(file, modeDict[mode])
|
||||
except IOError:
|
||||
if mode == 'a':
|
||||
mode = key = 'w'
|
||||
self.fp = open(file, modeDict[mode])
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
self._filePassed = 1
|
||||
self.fp = file
|
||||
|
|
@ -461,7 +528,11 @@ class ZipFile:
|
|||
"""Return the instance of ZipInfo given 'name'."""
|
||||
return self.NameToInfo[name]
|
||||
|
||||
def read(self, name):
|
||||
def setpassword(self, pwd):
|
||||
"""Set default password for encrypted files."""
|
||||
self.pwd = pwd
|
||||
|
||||
def read(self, name, pwd=None):
|
||||
"""Return file bytes (as a string) for name."""
|
||||
if self.mode not in ("r", "a"):
|
||||
raise RuntimeError, 'read() requires mode "r" or "a"'
|
||||
|
|
@ -469,6 +540,13 @@ class ZipFile:
|
|||
raise RuntimeError, \
|
||||
"Attempt to read ZIP archive that was already closed"
|
||||
zinfo = self.getinfo(name)
|
||||
is_encrypted = zinfo.flag_bits & 0x1
|
||||
if is_encrypted:
|
||||
if not pwd:
|
||||
pwd = self.pwd
|
||||
if not pwd:
|
||||
raise RuntimeError, "File %s is encrypted, " \
|
||||
"password required for extraction" % name
|
||||
filepos = self.fp.tell()
|
||||
|
||||
self.fp.seek(zinfo.header_offset, 0)
|
||||
|
|
@ -489,6 +567,18 @@ class ZipFile:
|
|||
zinfo.orig_filename, fname)
|
||||
|
||||
bytes = self.fp.read(zinfo.compress_size)
|
||||
# Go with decryption
|
||||
if is_encrypted:
|
||||
zd = _ZipDecrypter(pwd)
|
||||
# The first 12 bytes in the cypher stream is an encryption header
|
||||
# used to strengthen the algorithm. The first 11 bytes are
|
||||
# completely random, while the 12th contains the MSB of the CRC,
|
||||
# and is used to check the correctness of the password.
|
||||
h = map(zd, bytes[0:12])
|
||||
if ord(h[11]) != ((zinfo.CRC>>24)&255):
|
||||
raise RuntimeError, "Bad password for file %s" % name
|
||||
bytes = "".join(map(zd, bytes[12:]))
|
||||
# Go with decompression
|
||||
self.fp.seek(filepos, 0)
|
||||
if zinfo.compress_type == ZIP_STORED:
|
||||
pass
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue