summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
Diffstat (limited to 'Lib')
-rw-r--r--Lib/_weakrefset.py62
-rw-r--r--Lib/distutils/tests/test_bdist_msi.py10
-rw-r--r--Lib/distutils/tests/test_sdist.py3
-rw-r--r--Lib/email/__init__.py1
-rw-r--r--Lib/email/feedparser.py2
-rw-r--r--Lib/email/generator.py4
-rw-r--r--Lib/email/header.py7
-rw-r--r--Lib/email/parser.py2
-rw-r--r--Lib/email/test/test_email.py59
-rw-r--r--Lib/http/server.py9
-rw-r--r--Lib/idlelib/CallTipWindow.py6
-rw-r--r--Lib/lib2to3/tests/test_parser.py13
-rw-r--r--Lib/logging/__init__.py30
-rw-r--r--Lib/logging/handlers.py76
-rw-r--r--Lib/re.py11
-rw-r--r--Lib/subprocess.py12
-rwxr-xr-xLib/test/regrtest.py27
-rw-r--r--Lib/test/test_aifc.py163
-rw-r--r--Lib/test/test_ast.py6
-rw-r--r--Lib/test/test_base64.py5
-rw-r--r--Lib/test/test_cgi.py5
-rw-r--r--Lib/test/test_descr.py22
-rw-r--r--Lib/test/test_dict.py20
-rw-r--r--Lib/test/test_exceptions.py2
-rw-r--r--Lib/test/test_fractions.py22
-rw-r--r--Lib/test/test_httpservers.py1
-rw-r--r--Lib/test/test_mailbox.py20
-rw-r--r--Lib/test/test_marshal.py30
-rw-r--r--Lib/test/test_minidom.py26
-rw-r--r--Lib/test/test_queue.py8
-rw-r--r--Lib/test/test_re.py50
-rw-r--r--Lib/test/test_strptime.py31
-rw-r--r--Lib/test/test_subprocess.py67
-rw-r--r--Lib/test/test_tools.py39
-rw-r--r--Lib/test/test_unicode.py15
-rw-r--r--Lib/test/test_weakref.py60
-rw-r--r--Lib/test/test_weakset.py103
-rw-r--r--Lib/test/test_zlib.py23
-rw-r--r--Lib/unittest/loader.py13
-rw-r--r--Lib/urllib/request.py5
-rw-r--r--Lib/urllib/response.py2
-rw-r--r--Lib/weakref.py4
-rw-r--r--Lib/xmlrpc/server.py2
43 files changed, 862 insertions, 216 deletions
diff --git a/Lib/_weakrefset.py b/Lib/_weakrefset.py
index 4265369..6a98b88 100644
--- a/Lib/_weakrefset.py
+++ b/Lib/_weakrefset.py
@@ -63,7 +63,7 @@ class WeakSet:
yield item
def __len__(self):
- return sum(x() is not None for x in self.data)
+ return len(self.data) - len(self._pending_removals)
def __contains__(self, item):
try:
@@ -114,36 +114,21 @@ class WeakSet:
def update(self, other):
if self._pending_removals:
self._commit_removals()
- if isinstance(other, self.__class__):
- self.data.update(other.data)
- else:
- for element in other:
- self.add(element)
+ for element in other:
+ self.add(element)
def __ior__(self, other):
self.update(other)
return self
- # Helper functions for simple delegating methods.
- def _apply(self, other, method):
- if not isinstance(other, self.__class__):
- other = self.__class__(other)
- newdata = method(other.data)
- newset = self.__class__()
- newset.data = newdata
- return newset
-
def difference(self, other):
- return self._apply(other, self.data.difference)
+ newset = self.copy()
+ newset.difference_update(other)
+ return newset
__sub__ = difference
def difference_update(self, other):
- if self._pending_removals:
- self._commit_removals()
- if self is other:
- self.data.clear()
- else:
- self.data.difference_update(ref(item) for item in other)
+ self.__isub__(other)
def __isub__(self, other):
if self._pending_removals:
self._commit_removals()
@@ -154,13 +139,11 @@ class WeakSet:
return self
def intersection(self, other):
- return self._apply(other, self.data.intersection)
+ return self.__class__(item for item in other if item in self)
__and__ = intersection
def intersection_update(self, other):
- if self._pending_removals:
- self._commit_removals()
- self.data.intersection_update(ref(item) for item in other)
+ self.__iand__(other)
def __iand__(self, other):
if self._pending_removals:
self._commit_removals()
@@ -169,17 +152,17 @@ class WeakSet:
def issubset(self, other):
return self.data.issubset(ref(item) for item in other)
- __lt__ = issubset
+ __le__ = issubset
- def __le__(self, other):
- return self.data <= set(ref(item) for item in other)
+ def __lt__(self, other):
+ return self.data < set(ref(item) for item in other)
def issuperset(self, other):
return self.data.issuperset(ref(item) for item in other)
- __gt__ = issuperset
+ __ge__ = issuperset
- def __ge__(self, other):
- return self.data >= set(ref(item) for item in other)
+ def __gt__(self, other):
+ return self.data > set(ref(item) for item in other)
def __eq__(self, other):
if not isinstance(other, self.__class__):
@@ -187,27 +170,24 @@ class WeakSet:
return self.data == set(ref(item) for item in other)
def symmetric_difference(self, other):
- return self._apply(other, self.data.symmetric_difference)
+ newset = self.copy()
+ newset.symmetric_difference_update(other)
+ return newset
__xor__ = symmetric_difference
def symmetric_difference_update(self, other):
- if self._pending_removals:
- self._commit_removals()
- if self is other:
- self.data.clear()
- else:
- self.data.symmetric_difference_update(ref(item) for item in other)
+ self.__ixor__(other)
def __ixor__(self, other):
if self._pending_removals:
self._commit_removals()
if self is other:
self.data.clear()
else:
- self.data.symmetric_difference_update(ref(item) for item in other)
+ self.data.symmetric_difference_update(ref(item, self._remove) for item in other)
return self
def union(self, other):
- return self._apply(other, self.data.union)
+ return self.__class__(e for s in (self, other) for e in s)
__or__ = union
def isdisjoint(self, other):
diff --git a/Lib/distutils/tests/test_bdist_msi.py b/Lib/distutils/tests/test_bdist_msi.py
index 9308c79..15d8bdf 100644
--- a/Lib/distutils/tests/test_bdist_msi.py
+++ b/Lib/distutils/tests/test_bdist_msi.py
@@ -1,12 +1,11 @@
"""Tests for distutils.command.bdist_msi."""
-import unittest
import sys
-
+import unittest
from test.support import run_unittest
-
from distutils.tests import support
-@unittest.skipUnless(sys.platform=="win32", "These tests are only for win32")
+
+@unittest.skipUnless(sys.platform == 'win32', 'these tests require Windows')
class BDistMSITestCase(support.TempdirManager,
support.LoggingSilencer,
unittest.TestCase):
@@ -14,10 +13,11 @@ class BDistMSITestCase(support.TempdirManager,
def test_minimal(self):
# minimal test XXX need more tests
from distutils.command.bdist_msi import bdist_msi
- pkg_pth, dist = self.create_dist()
+ project_dir, dist = self.create_dist()
cmd = bdist_msi(dist)
cmd.ensure_finalized()
+
def test_suite():
return unittest.makeSuite(BDistMSITestCase)
diff --git a/Lib/distutils/tests/test_sdist.py b/Lib/distutils/tests/test_sdist.py
index fd71dac..1ba2a1a 100644
--- a/Lib/distutils/tests/test_sdist.py
+++ b/Lib/distutils/tests/test_sdist.py
@@ -6,6 +6,7 @@ import warnings
import zipfile
from os.path import join
from textwrap import dedent
+from test.support import captured_stdout, check_warnings, run_unittest
try:
import zlib
@@ -13,7 +14,6 @@ try:
except ImportError:
ZLIB_SUPPORT = False
-from test.support import captured_stdout, check_warnings, run_unittest
from distutils.command.sdist import sdist, show_formats
from distutils.core import Distribution
@@ -326,6 +326,7 @@ class SDistTestCase(PyPIRCCommandTestCase):
# filling data_files by pointing files in package_data
dist.package_data = {'somecode': ['*.txt']}
self.write_file((self.tmp_dir, 'somecode', 'doc.txt'), '#')
+ cmd.formats = ['gztar']
cmd.ensure_finalized()
cmd.run()
diff --git a/Lib/email/__init__.py b/Lib/email/__init__.py
index bd316fd..ff16f6a 100644
--- a/Lib/email/__init__.py
+++ b/Lib/email/__init__.py
@@ -11,6 +11,7 @@ __all__ = [
'charset',
'encoders',
'errors',
+ 'feedparser',
'generator',
'header',
'iterators',
diff --git a/Lib/email/feedparser.py b/Lib/email/feedparser.py
index 60a8325..aa8a2ff 100644
--- a/Lib/email/feedparser.py
+++ b/Lib/email/feedparser.py
@@ -19,7 +19,7 @@ the current message. Defects are just instances that live on the message
object's .defects attribute.
"""
-__all__ = ['FeedParser']
+__all__ = ['FeedParser', 'BytesFeedParser']
import re
diff --git a/Lib/email/generator.py b/Lib/email/generator.py
index f0e7a95..04c0210 100644
--- a/Lib/email/generator.py
+++ b/Lib/email/generator.py
@@ -4,7 +4,7 @@
"""Classes to generate plain text from a message object tree."""
-__all__ = ['Generator', 'DecodedGenerator']
+__all__ = ['Generator', 'DecodedGenerator', 'BytesGenerator']
import re
import sys
@@ -360,7 +360,7 @@ class BytesGenerator(Generator):
for h, v in msg._headers:
self.write('%s: ' % h)
if isinstance(v, Header):
- self.write(v.encode(maxlinelen=self._maxheaderlen)+NL)
+ self.write(v.encode(maxlinelen=self._maxheaderlen)+self._NL)
elif _has_surrogates(v):
# If we have raw 8bit data in a byte string, we have no idea
# what the encoding is. There is no safe way to split this
diff --git a/Lib/email/header.py b/Lib/email/header.py
index 2e687b7..3250d36 100644
--- a/Lib/email/header.py
+++ b/Lib/email/header.py
@@ -283,7 +283,12 @@ class Header:
# character set, otherwise an early error is thrown.
output_charset = charset.output_codec or 'us-ascii'
if output_charset != _charset.UNKNOWN8BIT:
- s.encode(output_charset, errors)
+ try:
+ s.encode(output_charset, errors)
+ except UnicodeEncodeError:
+ if output_charset!='us-ascii':
+ raise
+ charset = UTF8
self._chunks.append((s, charset))
def encode(self, splitchars=';, \t', maxlinelen=None, linesep='\n'):
diff --git a/Lib/email/parser.py b/Lib/email/parser.py
index 6caaff5..1c931ea 100644
--- a/Lib/email/parser.py
+++ b/Lib/email/parser.py
@@ -4,7 +4,7 @@
"""A parser of RFC 2822 and MIME email messages."""
-__all__ = ['Parser', 'HeaderParser']
+__all__ = ['Parser', 'HeaderParser', 'BytesParser']
import warnings
from io import StringIO, TextIOWrapper
diff --git a/Lib/email/test/test_email.py b/Lib/email/test/test_email.py
index 102e15b..5db34dc 100644
--- a/Lib/email/test/test_email.py
+++ b/Lib/email/test/test_email.py
@@ -619,6 +619,19 @@ class TestMessageAPI(TestEmailBase):
msg['Dummy'] = 'dummy\nX-Injected-Header: test'
self.assertRaises(errors.HeaderParseError, msg.as_string)
+ def test_unicode_header_defaults_to_utf8_encoding(self):
+ # Issue 14291
+ m = MIMEText('abc\n')
+ m['Subject'] = 'É test'
+ self.assertEqual(str(m),textwrap.dedent("""\
+ Content-Type: text/plain; charset="us-ascii"
+ MIME-Version: 1.0
+ Content-Transfer-Encoding: 7bit
+ Subject: =?utf-8?q?=C3=89_test?=
+
+ abc
+ """))
+
# Test the email.encoders module
class TestEncoders(unittest.TestCase):
@@ -1060,9 +1073,13 @@ Subject: =?iso-8859-1?q?Britische_Regierung_gibt_gr=FCnes_Licht_f=FCr_Offshore-W
'f\xfcr Offshore-Windkraftprojekte '
'<a-very-long-address@example.com>')
msg['Reply-To'] = header_string
- self.assertRaises(UnicodeEncodeError, msg.as_string)
+ eq(msg.as_string(maxheaderlen=78), """\
+Reply-To: =?utf-8?q?Britische_Regierung_gibt_gr=C3=BCnes_Licht_f=C3=BCr_Offs?=
+ =?utf-8?q?hore-Windkraftprojekte_=3Ca-very-long-address=40example=2Ecom=3E?=
+
+""")
msg = Message()
- msg['Reply-To'] = Header(header_string, 'utf-8',
+ msg['Reply-To'] = Header(header_string,
header_name='Reply-To')
eq(msg.as_string(maxheaderlen=78), """\
Reply-To: =?utf-8?q?Britische_Regierung_gibt_gr=C3=BCnes_Licht_f=C3=BCr_Offs?=
@@ -1226,7 +1243,6 @@ List: List-Unsubscribe:
=?utf-8?q?_folding_white_space_works?=""")+'\n')
-
# Test mangling of "From " lines in the body of a message
class TestFromMangling(unittest.TestCase):
def setUp(self):
@@ -2502,14 +2518,11 @@ class TestMiscellaneous(TestEmailBase):
def test__all__(self):
module = __import__('email')
- # Can't use sorted() here due to Python 2.3 compatibility
- all = module.__all__[:]
- all.sort()
- self.assertEqual(all, [
- 'base64mime', 'charset', 'encoders', 'errors', 'generator',
- 'header', 'iterators', 'message', 'message_from_binary_file',
- 'message_from_bytes', 'message_from_file',
- 'message_from_string', 'mime', 'parser',
+ self.assertEqual(sorted(module.__all__), [
+ 'base64mime', 'charset', 'encoders', 'errors', 'feedparser',
+ 'generator', 'header', 'iterators', 'message',
+ 'message_from_binary_file', 'message_from_bytes',
+ 'message_from_file', 'message_from_string', 'mime', 'parser',
'quoprimime', 'utils',
])
@@ -3424,6 +3437,30 @@ class Test8BitBytesHandling(unittest.TestCase):
g.flatten(msg)
self.assertEqual(s.getvalue(), source)
+ def test_bytes_generator_b_encoding_linesep(self):
+ # Issue 14062: b encoding was tacking on an extra \n.
+ m = Message()
+ # This has enough non-ascii that it should always end up b encoded.
+ m['Subject'] = Header('žluťoučký kůň')
+ s = BytesIO()
+ g = email.generator.BytesGenerator(s)
+ g.flatten(m, linesep='\r\n')
+ self.assertEqual(
+ s.getvalue(),
+ b'Subject: =?utf-8?b?xb5sdcWlb3XEjWvDvSBrxa/FiA==?=\r\n\r\n')
+
+ def test_generator_b_encoding_linesep(self):
+ # Since this broke in ByteGenerator, test Generator for completeness.
+ m = Message()
+ # This has enough non-ascii that it should always end up b encoded.
+ m['Subject'] = Header('žluťoučký kůň')
+ s = StringIO()
+ g = email.generator.Generator(s)
+ g.flatten(m, linesep='\r\n')
+ self.assertEqual(
+ s.getvalue(),
+ 'Subject: =?utf-8?b?xb5sdcWlb3XEjWvDvSBrxa/FiA==?=\r\n\r\n')
+
maxDiff = None
diff --git a/Lib/http/server.py b/Lib/http/server.py
index 6642729..537df90 100644
--- a/Lib/http/server.py
+++ b/Lib/http/server.py
@@ -850,7 +850,14 @@ def _url_collapse_path_split(path):
# Filter out blank non trailing parts before consuming the '..'.
path_parts = [part for part in path_parts[:-1] if part] + path_parts[-1:]
if path_parts:
- tail_part = path_parts.pop()
+ # Special case for CGI's for PATH_INFO
+ if path.startswith('/cgi-bin') or path.startswith('/htbin'):
+ tail_part = []
+ while path_parts[-1] not in ('cgi-bin','htbin'):
+ tail_part.insert(0,path_parts.pop())
+ tail_part = "/".join(tail_part)
+ else:
+ tail_part = path_parts.pop()
else:
tail_part = ''
head_parts = []
diff --git a/Lib/idlelib/CallTipWindow.py b/Lib/idlelib/CallTipWindow.py
index 27ed085..a2431f8 100644
--- a/Lib/idlelib/CallTipWindow.py
+++ b/Lib/idlelib/CallTipWindow.py
@@ -22,6 +22,7 @@ class CallTip:
self.parenline = self.parencol = None
self.lastline = None
self.hideid = self.checkhideid = None
+ self.checkhide_after_id = None
def position_window(self):
"""Check if needs to reposition the window, and if so - do it."""
@@ -102,7 +103,10 @@ class CallTip:
self.hidetip()
else:
self.position_window()
- self.widget.after(CHECKHIDE_TIME, self.checkhide_event)
+ if self.checkhide_after_id is not None:
+ self.widget.after_cancel(self.checkhide_after_id)
+ self.checkhide_after_id = \
+ self.widget.after(CHECKHIDE_TIME, self.checkhide_event)
def hide_event(self, event):
if not self.tipwindow:
diff --git a/Lib/lib2to3/tests/test_parser.py b/Lib/lib2to3/tests/test_parser.py
index f32404c..3968e6a 100644
--- a/Lib/lib2to3/tests/test_parser.py
+++ b/Lib/lib2to3/tests/test_parser.py
@@ -11,10 +11,14 @@ from __future__ import with_statement
# Testing imports
from . import support
from .support import driver, test_dir
+from test.support import verbose
# Python imports
import os
+import sys
import unittest
+import warnings
+import subprocess
# Local imports
from lib2to3.pgen2 import tokenize
@@ -171,10 +175,12 @@ class TestParserIdempotency(support.TestCase):
try:
tree = driver.parse_string(source)
except ParseError as err:
- print('ParseError on file', filepath, err)
+ if verbose > 0:
+ warnings.warn('ParseError on file %s (%s)' % (filepath, err))
continue
new = str(tree)
- if diff(filepath, new):
+ x = diff(filepath, new)
+ if x:
self.fail("Idempotency failed: %s" % filepath)
def test_extended_unpacking(self):
@@ -183,6 +189,7 @@ class TestParserIdempotency(support.TestCase):
driver.parse_string("(z, *y, w) = m\n")
driver.parse_string("for *z, m in d: pass\n")
+
class TestLiterals(GrammarTest):
def validate(self, s):
@@ -221,7 +228,7 @@ def diff(fn, result):
with open('@', 'w') as f:
f.write(str(result))
fn = fn.replace('"', '\\"')
- return os.system('diff -u "%s" @' % fn)
+ return subprocess.call(['diff', '-u', fn, '@'], stdout=(subprocess.DEVNULL if verbose < 1 else None))
finally:
try:
os.remove("@")
diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py
index 3faad4f..4191b22 100644
--- a/Lib/logging/__init__.py
+++ b/Lib/logging/__init__.py
@@ -1,4 +1,4 @@
-# Copyright 2001-2010 by Vinay Sajip. All Rights Reserved.
+# Copyright 2001-2012 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,
@@ -16,9 +16,9 @@
"""
Logging package for Python. Based on PEP 282 and comments thereto in
-comp.lang.python, and influenced by Apache's log4j system.
+comp.lang.python.
-Copyright (C) 2001-2011 Vinay Sajip. All Rights Reserved.
+Copyright (C) 2001-2012 Vinay Sajip. All Rights Reserved.
To use, simply 'import logging' and log away!
"""
@@ -917,8 +917,12 @@ class StreamHandler(Handler):
"""
Flushes the stream.
"""
- if self.stream and hasattr(self.stream, "flush"):
- self.stream.flush()
+ self.acquire()
+ try:
+ if self.stream and hasattr(self.stream, "flush"):
+ self.stream.flush()
+ finally:
+ self.release()
def emit(self, record):
"""
@@ -969,12 +973,16 @@ class FileHandler(StreamHandler):
"""
Closes the stream.
"""
- if self.stream:
- self.flush()
- if hasattr(self.stream, "close"):
- self.stream.close()
- StreamHandler.close(self)
- self.stream = None
+ self.acquire()
+ try:
+ if self.stream:
+ self.flush()
+ if hasattr(self.stream, "close"):
+ self.stream.close()
+ StreamHandler.close(self)
+ self.stream = None
+ finally:
+ self.release()
def _open(self):
"""
diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py
index 4a6b959..73ce031 100644
--- a/Lib/logging/handlers.py
+++ b/Lib/logging/handlers.py
@@ -1,4 +1,4 @@
-# Copyright 2001-2010 by Vinay Sajip. All Rights Reserved.
+# Copyright 2001-2012 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,
@@ -16,10 +16,9 @@
"""
Additional handlers for the logging package for Python. The core package is
-based on PEP 282 and comments thereto in comp.lang.python, and influenced by
-Apache's log4j system.
+based on PEP 282 and comments thereto in comp.lang.python.
-Copyright (C) 2001-2010 Vinay Sajip. All Rights Reserved.
+Copyright (C) 2001-2012 Vinay Sajip. All Rights Reserved.
To use, simply 'import logging.handlers' and log away!
"""
@@ -271,9 +270,10 @@ class TimedRotatingFileHandler(BaseRotatingHandler):
dstAtRollover = time.localtime(newRolloverAt)[-1]
if dstNow != dstAtRollover:
if not dstNow: # DST kicks in before next rollover, so we need to deduct an hour
- newRolloverAt = newRolloverAt - 3600
+ addend = -3600
else: # DST bows out before next rollover, so we need to add an hour
- newRolloverAt = newRolloverAt + 3600
+ addend = 3600
+ newRolloverAt += addend
result = newRolloverAt
return result
@@ -324,11 +324,20 @@ class TimedRotatingFileHandler(BaseRotatingHandler):
self.stream.close()
self.stream = None
# get the time that this sequence started at and make it a TimeTuple
+ currentTime = int(time.time())
+ dstNow = time.localtime(currentTime)[-1]
t = self.rolloverAt - self.interval
if self.utc:
timeTuple = time.gmtime(t)
else:
timeTuple = time.localtime(t)
+ dstThen = timeTuple[-1]
+ if dstNow != dstThen:
+ if dstNow:
+ addend = 3600
+ else:
+ addend = -3600
+ timeTuple = time.localtime(t + addend)
dfn = self.baseFilename + "." + time.strftime(self.suffix, timeTuple)
if os.path.exists(dfn):
os.remove(dfn)
@@ -338,19 +347,18 @@ class TimedRotatingFileHandler(BaseRotatingHandler):
os.remove(s)
self.mode = 'w'
self.stream = self._open()
- currentTime = int(time.time())
newRolloverAt = self.computeRollover(currentTime)
while newRolloverAt <= currentTime:
newRolloverAt = newRolloverAt + self.interval
#If DST changes and midnight or weekly rollover, adjust for this.
if (self.when == 'MIDNIGHT' or self.when.startswith('W')) and not self.utc:
- dstNow = time.localtime(currentTime)[-1]
dstAtRollover = time.localtime(newRolloverAt)[-1]
if dstNow != dstAtRollover:
if not dstNow: # DST kicks in before next rollover, so we need to deduct an hour
- newRolloverAt = newRolloverAt - 3600
+ addend = -3600
else: # DST bows out before next rollover, so we need to add an hour
- newRolloverAt = newRolloverAt + 3600
+ addend = 3600
+ newRolloverAt += addend
self.rolloverAt = newRolloverAt
class WatchedFileHandler(logging.FileHandler):
@@ -554,10 +562,14 @@ class SocketHandler(logging.Handler):
"""
Closes the socket.
"""
- if self.sock:
- self.sock.close()
- self.sock = None
- logging.Handler.close(self)
+ self.acquire()
+ try:
+ if self.sock:
+ self.sock.close()
+ self.sock = None
+ logging.Handler.close(self)
+ finally:
+ self.release()
class DatagramHandler(SocketHandler):
"""
@@ -752,9 +764,13 @@ class SysLogHandler(logging.Handler):
"""
Closes the socket.
"""
- if self.unixsocket:
- self.socket.close()
- logging.Handler.close(self)
+ self.acquire()
+ try:
+ if self.unixsocket:
+ self.socket.close()
+ logging.Handler.close(self)
+ finally:
+ self.release()
def mapPriority(self, levelName):
"""
@@ -1095,7 +1111,11 @@ class BufferingHandler(logging.Handler):
This version just zaps the buffer to empty.
"""
- self.buffer = []
+ self.acquire()
+ try:
+ self.buffer = []
+ finally:
+ self.release()
def close(self):
"""
@@ -1145,18 +1165,26 @@ class MemoryHandler(BufferingHandler):
The record buffer is also cleared by this operation.
"""
- if self.target:
- for record in self.buffer:
- self.target.handle(record)
- self.buffer = []
+ self.acquire()
+ try:
+ if self.target:
+ for record in self.buffer:
+ self.target.handle(record)
+ self.buffer = []
+ finally:
+ self.release()
def close(self):
"""
Flush, set the target to None and lose the buffer.
"""
self.flush()
- self.target = None
- BufferingHandler.close(self)
+ self.acquire()
+ try:
+ self.target = None
+ BufferingHandler.close(self)
+ finally:
+ self.release()
class QueueHandler(logging.Handler):
diff --git a/Lib/re.py b/Lib/re.py
index 4fe3bd8..3fd59df 100644
--- a/Lib/re.py
+++ b/Lib/re.py
@@ -179,14 +179,19 @@ def subn(pattern, repl, string, count=0, flags=0):
def split(pattern, string, maxsplit=0, flags=0):
"""Split the source string by the occurrences of the pattern,
- returning a list containing the resulting substrings."""
+ returning a list containing the resulting substrings. If
+ capturing parentheses are used in pattern, then the text of all
+ groups in the pattern are also returned as part of the resulting
+ list. If maxsplit is nonzero, at most maxsplit splits occur,
+ and the remainder of the string is returned as the final element
+ of the list."""
return _compile(pattern, flags).split(string, maxsplit)
def findall(pattern, string, flags=0):
"""Return a list of all non-overlapping matches in the string.
- If one or more groups are present in the pattern, return a
- list of groups; this will be a list of tuples if the pattern
+ If one or more capturing groups are present in the pattern, return
+ a list of groups; this will be a list of tuples if the pattern
has more than one group.
Empty matches are included in the result."""
diff --git a/Lib/subprocess.py b/Lib/subprocess.py
index 017f58d..179f41a 100644
--- a/Lib/subprocess.py
+++ b/Lib/subprocess.py
@@ -1075,7 +1075,17 @@ class Popen(object):
def terminate(self):
"""Terminates the process
"""
- _subprocess.TerminateProcess(self._handle, 1)
+ try:
+ _subprocess.TerminateProcess(self._handle, 1)
+ except OSError as e:
+ # ERROR_ACCESS_DENIED (winerror 5) is received when the
+ # process already died.
+ if e.winerror != 5:
+ raise
+ rc = _subprocess.GetExitCodeProcess(self._handle)
+ if rc == _subprocess.STILL_ACTIVE:
+ raise
+ self.returncode = rc
kill = terminate
diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py
index 135a90e..714a116 100755
--- a/Lib/test/regrtest.py
+++ b/Lib/test/regrtest.py
@@ -677,10 +677,10 @@ def main(tests=None, testdir=None, verbose=0, quiet=False,
if bad:
print(count(len(bad), "test"), "failed:")
printlist(bad)
- if environment_changed:
- print("{} altered the execution environment:".format(
- count(len(environment_changed), "test")))
- printlist(environment_changed)
+ if environment_changed:
+ print("{} altered the execution environment:".format(
+ count(len(environment_changed), "test")))
+ printlist(environment_changed)
if skipped and not quiet:
print(count(len(skipped), "test"), "skipped:")
printlist(skipped)
@@ -890,7 +890,9 @@ class saved_test_environment:
'logging._handlers', 'logging._handlerList',
'shutil.archive_formats', 'shutil.unpack_formats',
'sys.warnoptions', 'threading._dangling',
- 'multiprocessing.process._dangling')
+ 'multiprocessing.process._dangling',
+ 'support.TESTFN',
+ )
def get_sys_argv(self):
return id(sys.argv), sys.argv, sys.argv[:]
@@ -1020,6 +1022,21 @@ class saved_test_environment:
multiprocessing.process._dangling.clear()
multiprocessing.process._dangling.update(saved)
+ def get_support_TESTFN(self):
+ if os.path.isfile(support.TESTFN):
+ result = 'f'
+ elif os.path.isdir(support.TESTFN):
+ result = 'd'
+ else:
+ result = None
+ return result
+ def restore_support_TESTFN(self, saved_value):
+ if saved_value is None:
+ if os.path.isfile(support.TESTFN):
+ os.unlink(support.TESTFN)
+ elif os.path.isdir(support.TESTFN):
+ shutil.rmtree(support.TESTFN)
+
def resource_info(self):
for name in self.resources:
method_suffix = name.replace('.', '_')
diff --git a/Lib/test/test_aifc.py b/Lib/test/test_aifc.py
index 236f9b6..ee4ad6b 100644
--- a/Lib/test/test_aifc.py
+++ b/Lib/test/test_aifc.py
@@ -1,7 +1,8 @@
-from test.support import findfile, run_unittest, TESTFN
+from test.support import findfile, run_unittest, TESTFN, captured_stdout, unlink
import unittest
import os
import io
+import struct
import aifc
@@ -20,10 +21,8 @@ class AIFCTest(unittest.TestCase):
self.fout.close()
except (aifc.Error, AttributeError):
pass
- try:
- os.remove(TESTFN)
- except OSError:
- pass
+ unlink(TESTFN)
+ unlink(TESTFN + '.aiff')
def test_skipunknown(self):
#Issue 2245
@@ -32,6 +31,7 @@ class AIFCTest(unittest.TestCase):
def test_params(self):
f = self.f = aifc.open(self.sndfilepath)
+ self.assertEqual(f.getfp().name, self.sndfilepath)
self.assertEqual(f.getnchannels(), 2)
self.assertEqual(f.getsampwidth(), 2)
self.assertEqual(f.getframerate(), 48000)
@@ -45,6 +45,7 @@ class AIFCTest(unittest.TestCase):
def test_read(self):
f = self.f = aifc.open(self.sndfilepath)
+ self.assertEqual(f.readframes(0), b'')
self.assertEqual(f.tell(), 0)
self.assertEqual(f.readframes(2), b'\x00\x00\x00\x00\x0b\xd4\x0b\xd4')
f.rewind()
@@ -58,6 +59,10 @@ class AIFCTest(unittest.TestCase):
self.assertEqual(f.readframes(2), b'\x17t\x17t"\xad"\xad')
f.setpos(pos0)
self.assertEqual(f.readframes(2), b'\x00\x00\x00\x00\x0b\xd4\x0b\xd4')
+ with self.assertRaises(aifc.Error):
+ f.setpos(-1)
+ with self.assertRaises(aifc.Error):
+ f.setpos(f.getnframes() + 1)
def test_write(self):
f = self.f = aifc.open(self.sndfilepath)
@@ -92,8 +97,6 @@ class AIFCTest(unittest.TestCase):
self.assertEqual(f.getparams()[0:3], fout.getparams()[0:3])
self.assertEqual(fout.getcomptype(), b'ULAW')
self.assertEqual(fout.getcompname(), b'foo')
- # XXX: this test fails, not sure if it should succeed or not
- # self.assertEqual(f.readframes(5), fout.readframes(5))
def test_close(self):
class Wrapfile(object):
@@ -112,7 +115,7 @@ class AIFCTest(unittest.TestCase):
def test_write_header_comptype_sampwidth(self):
for comptype in (b'ULAW', b'ulaw', b'ALAW', b'alaw', b'G722'):
- fout = self.fout = aifc.open(io.BytesIO(), 'wb')
+ fout = aifc.open(io.BytesIO(), 'wb')
fout.setnchannels(1)
fout.setframerate(1)
fout.setcomptype(comptype, b'')
@@ -121,7 +124,7 @@ class AIFCTest(unittest.TestCase):
fout.initfp(None)
def test_write_markers_values(self):
- fout = self.fout = aifc.open(io.BytesIO(), 'wb')
+ fout = aifc.open(io.BytesIO(), 'wb')
self.assertEqual(fout.getmarkers(), None)
fout.setmark(1, 0, b'foo1')
fout.setmark(1, 1, b'foo2')
@@ -179,6 +182,148 @@ class AIFCLowLevelTest(unittest.TestCase):
with self.assertRaises(ValueError):
aifc._write_string(f, b'too long' * 255)
+ def test_wrong_open_mode(self):
+ with self.assertRaises(aifc.Error):
+ aifc.open(TESTFN, 'wrong_mode')
+
+ def test_read_wrong_form(self):
+ b1 = io.BytesIO(b'WRNG' + struct.pack('>L', 0))
+ b2 = io.BytesIO(b'FORM' + struct.pack('>L', 4) + b'WRNG')
+ self.assertRaises(aifc.Error, aifc.open, b1)
+ self.assertRaises(aifc.Error, aifc.open, b2)
+
+ def test_read_no_comm_chunk(self):
+ b = io.BytesIO(b'FORM' + struct.pack('>L', 4) + b'AIFF')
+ self.assertRaises(aifc.Error, aifc.open, b)
+
+ def test_read_wrong_compression_type(self):
+ b = b'FORM' + struct.pack('>L', 4) + b'AIFC'
+ b += b'COMM' + struct.pack('>LhlhhLL', 23, 0, 0, 0, 0, 0, 0)
+ b += b'WRNG' + struct.pack('B', 0)
+ self.assertRaises(aifc.Error, aifc.open, io.BytesIO(b))
+
+ def test_read_wrong_marks(self):
+ b = b'FORM' + struct.pack('>L', 4) + b'AIFF'
+ b += b'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0)
+ b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8
+ b += b'MARK' + struct.pack('>LhB', 3, 1, 1)
+ with captured_stdout() as s:
+ f = aifc.open(io.BytesIO(b))
+ self.assertEqual(
+ s.getvalue(),
+ 'Warning: MARK chunk contains only 0 markers instead of 1\n')
+ self.assertEqual(f.getmarkers(), None)
+
+ def test_read_comm_kludge_compname_even(self):
+ b = b'FORM' + struct.pack('>L', 4) + b'AIFC'
+ b += b'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0)
+ b += b'NONE' + struct.pack('B', 4) + b'even' + b'\x00'
+ b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8
+ with captured_stdout() as s:
+ f = aifc.open(io.BytesIO(b))
+ self.assertEqual(s.getvalue(), 'Warning: bad COMM chunk size\n')
+ self.assertEqual(f.getcompname(), b'even')
+
+ def test_read_comm_kludge_compname_odd(self):
+ b = b'FORM' + struct.pack('>L', 4) + b'AIFC'
+ b += b'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0)
+ b += b'NONE' + struct.pack('B', 3) + b'odd'
+ b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8
+ with captured_stdout() as s:
+ f = aifc.open(io.BytesIO(b))
+ self.assertEqual(s.getvalue(), 'Warning: bad COMM chunk size\n')
+ self.assertEqual(f.getcompname(), b'odd')
+
+ def test_write_params_raises(self):
+ fout = aifc.open(io.BytesIO(), 'wb')
+ wrong_params = (0, 0, 0, 0, b'WRNG', '')
+ self.assertRaises(aifc.Error, fout.setparams, wrong_params)
+ self.assertRaises(aifc.Error, fout.getparams)
+ self.assertRaises(aifc.Error, fout.setnchannels, 0)
+ self.assertRaises(aifc.Error, fout.getnchannels)
+ self.assertRaises(aifc.Error, fout.setsampwidth, 0)
+ self.assertRaises(aifc.Error, fout.getsampwidth)
+ self.assertRaises(aifc.Error, fout.setframerate, 0)
+ self.assertRaises(aifc.Error, fout.getframerate)
+ self.assertRaises(aifc.Error, fout.setcomptype, b'WRNG', '')
+ fout.aiff()
+ fout.setnchannels(1)
+ fout.setsampwidth(1)
+ fout.setframerate(1)
+ fout.setnframes(1)
+ fout.writeframes(b'\x00')
+ self.assertRaises(aifc.Error, fout.setparams, (1, 1, 1, 1, 1, 1))
+ self.assertRaises(aifc.Error, fout.setnchannels, 1)
+ self.assertRaises(aifc.Error, fout.setsampwidth, 1)
+ self.assertRaises(aifc.Error, fout.setframerate, 1)
+ self.assertRaises(aifc.Error, fout.setnframes, 1)
+ self.assertRaises(aifc.Error, fout.setcomptype, b'NONE', '')
+ self.assertRaises(aifc.Error, fout.aiff)
+ self.assertRaises(aifc.Error, fout.aifc)
+
+ def test_write_params_singles(self):
+ fout = aifc.open(io.BytesIO(), 'wb')
+ fout.aifc()
+ fout.setnchannels(1)
+ fout.setsampwidth(2)
+ fout.setframerate(3)
+ fout.setnframes(4)
+ fout.setcomptype(b'NONE', b'name')
+ self.assertEqual(fout.getnchannels(), 1)
+ self.assertEqual(fout.getsampwidth(), 2)
+ self.assertEqual(fout.getframerate(), 3)
+ self.assertEqual(fout.getnframes(), 0)
+ self.assertEqual(fout.tell(), 0)
+ self.assertEqual(fout.getcomptype(), b'NONE')
+ self.assertEqual(fout.getcompname(), b'name')
+ fout.writeframes(b'\x00' * 4 * fout.getsampwidth() * fout.getnchannels())
+ self.assertEqual(fout.getnframes(), 4)
+ self.assertEqual(fout.tell(), 4)
+
+ def test_write_params_bunch(self):
+ fout = aifc.open(io.BytesIO(), 'wb')
+ fout.aifc()
+ p = (1, 2, 3, 4, b'NONE', b'name')
+ fout.setparams(p)
+ self.assertEqual(fout.getparams(), p)
+ fout.initfp(None)
+
+ def test_write_header_raises(self):
+ fout = aifc.open(io.BytesIO(), 'wb')
+ self.assertRaises(aifc.Error, fout.close)
+ fout.setnchannels(1)
+ self.assertRaises(aifc.Error, fout.close)
+ fout.setsampwidth(1)
+ self.assertRaises(aifc.Error, fout.close)
+ fout.initfp(None)
+
+ def test_write_header_comptype_raises(self):
+ for comptype in (b'ULAW', b'ulaw', b'ALAW', b'alaw', b'G722'):
+ fout = aifc.open(io.BytesIO(), 'wb')
+ fout.setsampwidth(1)
+ fout.setcomptype(comptype, b'')
+ self.assertRaises(aifc.Error, fout.close)
+ fout.initfp(None)
+
+ def test_write_markers_raises(self):
+ fout = aifc.open(io.BytesIO(), 'wb')
+ self.assertRaises(aifc.Error, fout.setmark, 0, 0, b'')
+ self.assertRaises(aifc.Error, fout.setmark, 1, -1, b'')
+ self.assertRaises(aifc.Error, fout.setmark, 1, 0, None)
+ self.assertRaises(aifc.Error, fout.getmark, 1)
+ fout.initfp(None)
+
+ def test_write_aiff_by_extension(self):
+ sampwidth = 2
+ fout = self.fout = aifc.open(TESTFN + '.aiff', 'wb')
+ fout.setparams((1, sampwidth, 1, 1, b'ULAW', b''))
+ frames = b'\x00' * fout.getnchannels() * sampwidth
+ fout.writeframes(frames)
+ fout.close()
+ f = self.f = aifc.open(TESTFN + '.aiff', 'rb')
+ self.assertEqual(f.getcomptype(), b'NONE')
+ f.close()
+
def test_main():
run_unittest(AIFCTest)
diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py
index be9f05e..f4ce615 100644
--- a/Lib/test/test_ast.py
+++ b/Lib/test/test_ast.py
@@ -195,12 +195,6 @@ class AST_Tests(unittest.TestCase):
with self.assertRaises(AttributeError):
x.vararg
- with self.assertRaises(AttributeError):
- x.foobar = 21
-
- with self.assertRaises(AttributeError):
- ast.AST(lineno=2)
-
with self.assertRaises(TypeError):
# "_ast.AST constructor takes 0 positional arguments"
ast.AST(2)
diff --git a/Lib/test/test_base64.py b/Lib/test/test_base64.py
index 93c623c..ca94504 100644
--- a/Lib/test/test_base64.py
+++ b/Lib/test/test_base64.py
@@ -2,6 +2,7 @@ import unittest
from test import support
import base64
import binascii
+import os
import sys
import subprocess
@@ -227,6 +228,10 @@ class BaseXYTestCase(unittest.TestCase):
class TestMain(unittest.TestCase):
+ def tearDown(self):
+ if os.path.exists(support.TESTFN):
+ os.unlink(support.TESTFN)
+
def get_output(self, *args, **options):
args = (sys.executable, '-m', 'base64') + args
return subprocess.check_output(args, **options)
diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py
index 9951e93..3031fb3 100644
--- a/Lib/test/test_cgi.py
+++ b/Lib/test/test_cgi.py
@@ -118,6 +118,11 @@ def gen_result(data, environ):
class CgiTests(unittest.TestCase):
+ def test_escape(self):
+ self.assertEqual("test &amp; string", cgi.escape("test & string"))
+ self.assertEqual("&lt;test string&gt;", cgi.escape("<test string>"))
+ self.assertEqual("&quot;test string&quot;", cgi.escape('"test string"', True))
+
def test_strict(self):
for orig, expect in parse_strict_test_cases:
# Test basic parsing
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index 92304b4..141d791 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -1,8 +1,10 @@
import builtins
+import gc
import sys
import types
import math
import unittest
+import weakref
from copy import deepcopy
from test import support
@@ -1186,7 +1188,6 @@ order (MRO) for bases """
self.assertEqual(Counted.counter, 0)
# Test lookup leaks [SF bug 572567]
- import gc
if hasattr(gc, 'get_objects'):
class G(object):
def __eq__(self, other):
@@ -4380,7 +4381,6 @@ order (MRO) for bases """
self.assertRaises(AttributeError, getattr, C(), "attr")
self.assertEqual(descr.counter, 4)
- import gc
class EvilGetattribute(object):
# This used to segfault
def __getattr__(self, name):
@@ -4393,6 +4393,9 @@ order (MRO) for bases """
self.assertRaises(AttributeError, getattr, EvilGetattribute(), "attr")
+ def test_type___getattribute__(self):
+ self.assertRaises(TypeError, type.__getattribute__, list, type)
+
def test_abstractmethods(self):
# type pretends not to have __abstractmethods__.
self.assertRaises(AttributeError, getattr, type, "__abstractmethods__")
@@ -4429,6 +4432,21 @@ order (MRO) for bases """
foo = Foo()
str(foo)
+ def test_cycle_through_dict(self):
+ # See bug #1469629
+ class X(dict):
+ def __init__(self):
+ dict.__init__(self)
+ self.__dict__ = self
+ x = X()
+ x.attr = 42
+ wr = weakref.ref(x)
+ del x
+ support.gc_collect()
+ self.assertIsNone(wr())
+ for o in gc.get_objects():
+ self.assertIsNot(type(o), X)
+
class DictProxyTests(unittest.TestCase):
def setUp(self):
class C(object):
diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py
index 1507e42..d2740a3 100644
--- a/Lib/test/test_dict.py
+++ b/Lib/test/test_dict.py
@@ -299,6 +299,26 @@ class DictTest(unittest.TestCase):
x.fail = True
self.assertRaises(Exc, d.setdefault, x, [])
+ def test_setdefault_atomic(self):
+ # Issue #13521: setdefault() calls __hash__ and __eq__ only once.
+ class Hashed(object):
+ def __init__(self):
+ self.hash_count = 0
+ self.eq_count = 0
+ def __hash__(self):
+ self.hash_count += 1
+ return 42
+ def __eq__(self, other):
+ self.eq_count += 1
+ return id(self) == id(other)
+ hashed1 = Hashed()
+ y = {hashed1: 5}
+ hashed2 = Hashed()
+ y.setdefault(hashed2, [])
+ self.assertEqual(hashed1.hash_count, 1)
+ self.assertEqual(hashed2.hash_count, 1)
+ self.assertEqual(hashed1.eq_count + hashed2.eq_count, 1)
+
def test_popitem(self):
# dict.popitem()
for copymode in -1, +1:
diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py
index 0a7ddd4..7a2dd0c 100644
--- a/Lib/test/test_exceptions.py
+++ b/Lib/test/test_exceptions.py
@@ -38,7 +38,7 @@ class ExceptionTests(unittest.TestCase):
try:
try:
import marshal
- marshal.loads('')
+ marshal.loads(b'')
except EOFError:
pass
finally:
diff --git a/Lib/test/test_fractions.py b/Lib/test/test_fractions.py
index 26e132f..084ae0c 100644
--- a/Lib/test/test_fractions.py
+++ b/Lib/test/test_fractions.py
@@ -6,6 +6,7 @@ import math
import numbers
import operator
import fractions
+import sys
import unittest
from copy import copy, deepcopy
from pickle import dumps, loads
@@ -76,6 +77,9 @@ class DummyRational(object):
def __float__(self):
assert False, "__float__ should not be invoked"
+class DummyFraction(fractions.Fraction):
+ """Dummy Fraction subclass for copy and deepcopy testing."""
+
class GcdTest(unittest.TestCase):
def testMisc(self):
@@ -286,9 +290,14 @@ class FractionTest(unittest.TestCase):
self.assertEqual(F(201, 200).limit_denominator(100), F(1))
self.assertEqual(F(201, 200).limit_denominator(101), F(102, 101))
self.assertEqual(F(0).limit_denominator(10000), F(0))
+ for i in (0, -1):
+ self.assertRaisesMessage(
+ ValueError, "max_denominator should be at least 1",
+ F(1).limit_denominator, i)
def testConversions(self):
self.assertTypedEquals(-1, math.trunc(F(-11, 10)))
+ self.assertTypedEquals(1, math.trunc(F(11, 10)))
self.assertTypedEquals(-2, math.floor(F(-11, 10)))
self.assertTypedEquals(-1, math.ceil(F(-11, 10)))
self.assertTypedEquals(-1, math.ceil(F(-10, 10)))
@@ -329,6 +338,7 @@ class FractionTest(unittest.TestCase):
self.assertEqual(F(8, 27), F(2, 3) ** F(3))
self.assertEqual(F(27, 8), F(2, 3) ** F(-3))
self.assertTypedEquals(2.0, F(4) ** F(1, 2))
+ self.assertEqual(F(1, 1), +F(1, 1))
z = pow(F(-1), F(1, 2))
self.assertAlmostEqual(z.real, 0)
self.assertEqual(z.imag, 1)
@@ -395,6 +405,10 @@ class FractionTest(unittest.TestCase):
TypeError,
"unsupported operand type(s) for +: 'Fraction' and 'Decimal'",
operator.add, F(3,11), Decimal('3.1415926'))
+ self.assertRaisesMessage(
+ TypeError,
+ "unsupported operand type(s) for +: 'Decimal' and 'Fraction'",
+ operator.add, Decimal('3.1415926'), F(3,11))
def testComparisons(self):
self.assertTrue(F(1, 2) < F(2, 3))
@@ -538,9 +552,12 @@ class FractionTest(unittest.TestCase):
self.assertEqual("7", str(F(7, 1)))
def testHash(self):
+ hmod = sys.hash_info.modulus
+ hinf = sys.hash_info.inf
self.assertEqual(hash(2.5), hash(F(5, 2)))
self.assertEqual(hash(10**50), hash(F(10**50)))
self.assertNotEqual(hash(float(10**23)), hash(F(10**23)))
+ self.assertEqual(hinf, hash(F(1, hmod)))
# Check that __hash__ produces the same value as hash(), for
# consistency with int and Decimal. (See issue #10356.)
self.assertEqual(hash(F(-1)), F(-1).__hash__())
@@ -574,9 +591,14 @@ class FractionTest(unittest.TestCase):
def test_copy_deepcopy_pickle(self):
r = F(13, 7)
+ dr = DummyFraction(13, 7)
self.assertEqual(r, loads(dumps(r)))
self.assertEqual(id(r), id(copy(r)))
self.assertEqual(id(r), id(deepcopy(r)))
+ self.assertNotEqual(id(dr), id(copy(dr)))
+ self.assertNotEqual(id(dr), id(deepcopy(dr)))
+ self.assertTypedEquals(dr, copy(dr))
+ self.assertTypedEquals(dr, deepcopy(dr))
def test_slots(self):
# Issue 4998
diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py
index e83c048..4d58e4b 100644
--- a/Lib/test/test_httpservers.py
+++ b/Lib/test/test_httpservers.py
@@ -377,6 +377,7 @@ class CGIHTTPServerTestCase(BaseTestCase):
'/.//': ('/', ''),
'cgi-bin/file1.py': ('/cgi-bin', 'file1.py'),
'/cgi-bin/file1.py': ('/cgi-bin', 'file1.py'),
+ '/cgi-bin/file1.py/PATH-INFO': ('/cgi-bin', 'file1.py/PATH-INFO'),
'a': ('/', 'a'),
'/a': ('/', 'a'),
'//a': ('/', 'a'),
diff --git a/Lib/test/test_mailbox.py b/Lib/test/test_mailbox.py
index ef64366..8f76e18 100644
--- a/Lib/test/test_mailbox.py
+++ b/Lib/test/test_mailbox.py
@@ -7,6 +7,7 @@ import email
import email.message
import re
import io
+import shutil
import tempfile
from test import support
import unittest
@@ -38,12 +39,7 @@ class TestBase(unittest.TestCase):
def _delete_recursively(self, target):
# Delete a file or delete a directory recursively
if os.path.isdir(target):
- for path, dirs, files in os.walk(target, topdown=False):
- for name in files:
- os.remove(os.path.join(path, name))
- for name in dirs:
- os.rmdir(os.path.join(path, name))
- os.rmdir(target)
+ shutil.rmtree(target)
elif os.path.exists(target):
os.remove(target)
@@ -115,10 +111,10 @@ class TestMailbox(TestBase):
self.assertMailboxEmpty()
def test_add_that_raises_leaves_mailbox_empty(self):
- # XXX This test will start failing when Message learns to handle
- # non-ASCII string headers, and a different internal failure will
- # need to be found or manufactured.
- with self.assertRaises(ValueError):
+ def raiser(*args, **kw):
+ raise Exception("a fake error")
+ support.patch(self, email.generator.BytesGenerator, 'flatten', raiser)
+ with self.assertRaises(Exception):
self._box.add(email.message_from_string("From: Alphöso"))
self.assertEqual(len(self._box), 0)
self._box.close()
@@ -2029,6 +2025,10 @@ class MaildirTestCase(unittest.TestCase):
def setUp(self):
# create a new maildir mailbox to work with:
self._dir = support.TESTFN
+ if os.path.isdir(self._dir):
+ shutil.rmtree(self._dir)
+ elif os.path.isfile(self._dir):
+ os.unlink(self._dir)
os.mkdir(self._dir)
os.mkdir(os.path.join(self._dir, "cur"))
os.mkdir(os.path.join(self._dir, "tmp"))
diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py
index cd100f9..96a70ec 100644
--- a/Lib/test/test_marshal.py
+++ b/Lib/test/test_marshal.py
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
from test import support
+import array
import marshal
import sys
import unittest
@@ -137,6 +138,27 @@ class ContainerTestCase(unittest.TestCase, HelperMixin):
for constructor in (set, frozenset):
self.helper(constructor(self.d.keys()))
+
+class BufferTestCase(unittest.TestCase, HelperMixin):
+
+ def test_bytearray(self):
+ b = bytearray(b"abc")
+ self.helper(b)
+ new = marshal.loads(marshal.dumps(b))
+ self.assertEqual(type(new), bytes)
+
+ def test_memoryview(self):
+ b = memoryview(b"abc")
+ self.helper(b)
+ new = marshal.loads(marshal.dumps(b))
+ self.assertEqual(type(new), bytes)
+
+ def test_array(self):
+ a = array.array('B', b"abc")
+ new = marshal.loads(marshal.dumps(a))
+ self.assertEqual(new, b"abc")
+
+
class BugsTestCase(unittest.TestCase):
def test_bug_5888452(self):
# Simple-minded check for SF 588452: Debug build crashes
@@ -162,7 +184,7 @@ class BugsTestCase(unittest.TestCase):
pass
def test_loads_recursion(self):
- s = 'c' + ('X' * 4*4) + '{' * 2**20
+ s = b'c' + (b'X' * 4*4) + b'{' * 2**20
self.assertRaises(ValueError, marshal.loads, s)
def test_recursion_limit(self):
@@ -235,6 +257,11 @@ class BugsTestCase(unittest.TestCase):
finally:
support.unlink(support.TESTFN)
+ def test_loads_reject_unicode_strings(self):
+ # Issue #14177: marshal.loads() should not accept unicode strings
+ unicode_string = 'T'
+ self.assertRaises(TypeError, marshal.loads, unicode_string)
+
def test_main():
support.run_unittest(IntTestCase,
@@ -243,6 +270,7 @@ def test_main():
CodeTestCase,
ContainerTestCase,
ExceptionTestCase,
+ BufferTestCase,
BugsTestCase)
if __name__ == "__main__":
diff --git a/Lib/test/test_minidom.py b/Lib/test/test_minidom.py
index f3fa1b8..4a69b00 100644
--- a/Lib/test/test_minidom.py
+++ b/Lib/test/test_minidom.py
@@ -350,13 +350,31 @@ class MinidomTest(unittest.TestCase):
def testGetAttrList(self):
pass
- def testGetAttrValues(self): pass
+ def testGetAttrValues(self):
+ pass
- def testGetAttrLength(self): pass
+ def testGetAttrLength(self):
+ pass
- def testGetAttribute(self): pass
+ def testGetAttribute(self):
+ dom = Document()
+ child = dom.appendChild(
+ dom.createElementNS("http://www.python.org", "python:abc"))
+ self.assertEqual(child.getAttribute('missing'), '')
- def testGetAttributeNS(self): pass
+ def testGetAttributeNS(self):
+ dom = Document()
+ child = dom.appendChild(
+ dom.createElementNS("http://www.python.org", "python:abc"))
+ child.setAttributeNS("http://www.w3.org", "xmlns:python",
+ "http://www.python.org")
+ self.assertEqual(child.getAttributeNS("http://www.w3.org", "python"),
+ 'http://www.python.org')
+ self.assertEqual(child.getAttributeNS("http://www.w3.org", "other"),
+ '')
+ child2 = child.appendChild(dom.createElement('abc'))
+ self.assertEqual(child2.getAttributeNS("http://www.python.org", "missing"),
+ '')
def testGetAttributeNode(self): pass
diff --git a/Lib/test/test_queue.py b/Lib/test/test_queue.py
index 8287a5d..86ad9c0 100644
--- a/Lib/test/test_queue.py
+++ b/Lib/test/test_queue.py
@@ -82,7 +82,7 @@ class BlockingTestMixin:
self.fail("trigger thread ended but event never set")
-class BaseQueueTest(unittest.TestCase, BlockingTestMixin):
+class BaseQueueTestMixin(BlockingTestMixin):
def setUp(self):
self.cum = 0
self.cumlock = threading.Lock()
@@ -229,13 +229,13 @@ class BaseQueueTest(unittest.TestCase, BlockingTestMixin):
with self.assertRaises(queue.Full):
q.put_nowait(4)
-class QueueTest(BaseQueueTest):
+class QueueTest(BaseQueueTestMixin, unittest.TestCase):
type2test = queue.Queue
-class LifoQueueTest(BaseQueueTest):
+class LifoQueueTest(BaseQueueTestMixin, unittest.TestCase):
type2test = queue.LifoQueue
-class PriorityQueueTest(BaseQueueTest):
+class PriorityQueueTest(BaseQueueTestMixin, unittest.TestCase):
type2test = queue.PriorityQueue
diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py
index fe8bc34..940ba39 100644
--- a/Lib/test/test_re.py
+++ b/Lib/test/test_re.py
@@ -1,4 +1,5 @@
-from test.support import verbose, run_unittest
+from test.support import verbose, run_unittest, gc_collect
+import io
import re
from re import Scanner
import sys
@@ -16,6 +17,17 @@ import unittest
class ReTests(unittest.TestCase):
+ def test_keep_buffer(self):
+ # See bug 14212
+ b = bytearray(b'x')
+ it = re.finditer(b'a', b)
+ with self.assertRaises(BufferError):
+ b.extend(b'x'*400)
+ list(it)
+ del it
+ gc_collect()
+ b.extend(b'x'*400)
+
def test_weakref(self):
s = 'QabbbcR'
x = re.compile('ab+c')
@@ -355,6 +367,32 @@ class ReTests(unittest.TestCase):
self.assertEqual(re.search(r"\d\D\w\W\s\S",
"1aa! a", re.UNICODE).group(0), "1aa! a")
+ def test_string_boundaries(self):
+ # See http://bugs.python.org/issue10713
+ self.assertEqual(re.search(r"\b(abc)\b", "abc").group(1),
+ "abc")
+ # There's a word boundary at the start of a string.
+ self.assertTrue(re.match(r"\b", "abc"))
+ # A non-empty string includes a non-boundary zero-length match.
+ self.assertTrue(re.search(r"\B", "abc"))
+ # There is no non-boundary match at the start of a string.
+ self.assertFalse(re.match(r"\B", "abc"))
+ # However, an empty string contains no word boundaries, and also no
+ # non-boundaries.
+ self.assertEqual(re.search(r"\B", ""), None)
+ # This one is questionable and different from the perlre behaviour,
+ # but describes current behavior.
+ self.assertEqual(re.search(r"\b", ""), None)
+ # A single word-character string has two boundaries, but no
+ # non-boundary gaps.
+ self.assertEqual(len(re.findall(r"\b", "a")), 2)
+ self.assertEqual(len(re.findall(r"\B", "a")), 0)
+ # If there are no words, there are no boundaries
+ self.assertEqual(len(re.findall(r"\b", " ")), 0)
+ self.assertEqual(len(re.findall(r"\b", " ")), 0)
+ # Can match around the whitespace.
+ self.assertEqual(len(re.findall(r"\B", " ")), 2)
+
def test_bigcharset(self):
self.assertEqual(re.match("([\u2222\u2223])",
"\u2222").group(1), "\u2222")
@@ -780,6 +818,16 @@ class ReTests(unittest.TestCase):
self.assertRaises(OverflowError, _sre.compile, "abc", 0, [long_overflow])
self.assertRaises(TypeError, _sre.compile, {}, 0, [])
+ def test_compile(self):
+ # Test return value when given string and pattern as parameter
+ pattern = re.compile('random pattern')
+ self.assertIsInstance(pattern, re._pattern_type)
+ same_pattern = re.compile(pattern)
+ self.assertIsInstance(same_pattern, re._pattern_type)
+ self.assertIs(same_pattern, pattern)
+ # Test behaviour when not given a string or pattern as parameter
+ self.assertRaises(TypeError, re.compile, 0)
+
def run_re_tests():
from test.re_tests import tests, SUCCEED, FAIL, SYNTAX_ERROR
if verbose:
diff --git a/Lib/test/test_strptime.py b/Lib/test/test_strptime.py
index 89c08ed..98d759b 100644
--- a/Lib/test/test_strptime.py
+++ b/Lib/test/test_strptime.py
@@ -38,9 +38,9 @@ class LocaleTime_Tests(unittest.TestCase):
comparison = testing[self.time_tuple[tuple_position]]
self.assertIn(strftime_output, testing,
"%s: not found in tuple" % error_msg)
- self.assertTrue(comparison == strftime_output,
- "%s: position within tuple incorrect; %s != %s" %
- (error_msg, comparison, strftime_output))
+ self.assertEqual(comparison, strftime_output,
+ "%s: position within tuple incorrect; %s != %s" %
+ (error_msg, comparison, strftime_output))
def test_weekday(self):
# Make sure that full and abbreviated weekday names are correct in
@@ -65,8 +65,8 @@ class LocaleTime_Tests(unittest.TestCase):
"AM/PM representation not in tuple")
if self.time_tuple[3] < 12: position = 0
else: position = 1
- self.assertTrue(strftime_output == self.LT_ins.am_pm[position],
- "AM/PM representation in the wrong position within the tuple")
+ self.assertEqual(self.LT_ins.am_pm[position], strftime_output,
+ "AM/PM representation in the wrong position within the tuple")
def test_timezone(self):
# Make sure timezone is correct
@@ -86,17 +86,14 @@ class LocaleTime_Tests(unittest.TestCase):
# output.
magic_date = (1999, 3, 17, 22, 44, 55, 2, 76, 0)
strftime_output = time.strftime("%c", magic_date)
- self.assertTrue(strftime_output == time.strftime(self.LT_ins.LC_date_time,
- magic_date),
- "LC_date_time incorrect")
+ self.assertEqual(time.strftime(self.LT_ins.LC_date_time, magic_date),
+ strftime_output, "LC_date_time incorrect")
strftime_output = time.strftime("%x", magic_date)
- self.assertTrue(strftime_output == time.strftime(self.LT_ins.LC_date,
- magic_date),
- "LC_date incorrect")
+ self.assertEqual(time.strftime(self.LT_ins.LC_date, magic_date),
+ strftime_output, "LC_date incorrect")
strftime_output = time.strftime("%X", magic_date)
- self.assertTrue(strftime_output == time.strftime(self.LT_ins.LC_time,
- magic_date),
- "LC_time incorrect")
+ self.assertEqual(time.strftime(self.LT_ins.LC_time, magic_date),
+ strftime_output, "LC_time incorrect")
LT = _strptime.LocaleTime()
LT.am_pm = ('', '')
self.assertTrue(LT.LC_time, "LocaleTime's LC directives cannot handle "
@@ -168,8 +165,8 @@ class TimeRETests(unittest.TestCase):
# Fixes bug #661354
test_locale = _strptime.LocaleTime()
test_locale.timezone = (frozenset(), frozenset())
- self.assertTrue(_strptime.TimeRE(test_locale).pattern("%Z") == '',
- "with timezone == ('',''), TimeRE().pattern('%Z') != ''")
+ self.assertEqual(_strptime.TimeRE(test_locale).pattern("%Z"), '',
+ "with timezone == ('',''), TimeRE().pattern('%Z') != ''")
def test_matching_with_escapes(self):
# Make sure a format that requires escaping of characters works
@@ -195,7 +192,7 @@ class TimeRETests(unittest.TestCase):
# so as to not allow to subpatterns to end up next to each other and
# "steal" characters from each other.
pattern = self.time_re.pattern('%j %H')
- self.assertTrue(not re.match(pattern, "180"))
+ self.assertFalse(re.match(pattern, "180"))
self.assertTrue(re.match(pattern, "18 0"))
diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py
index fb0b834..6150e88 100644
--- a/Lib/test/test_subprocess.py
+++ b/Lib/test/test_subprocess.py
@@ -989,6 +989,27 @@ class POSIXProcessTestCase(BaseTestCase):
getattr(p, method)(*args)
return p
+ def _kill_dead_process(self, method, *args):
+ # Do not inherit file handles from the parent.
+ # It should fix failures on some platforms.
+ p = subprocess.Popen([sys.executable, "-c", """if 1:
+ import sys, time
+ sys.stdout.write('x\\n')
+ sys.stdout.flush()
+ """],
+ close_fds=True,
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ # Wait for the interpreter to be completely initialized before
+ # sending any signal.
+ p.stdout.read(1)
+ # The process should end after this
+ time.sleep(1)
+ # This shouldn't raise even though the child is now dead
+ getattr(p, method)(*args)
+ p.communicate()
+
def test_send_signal(self):
p = self._kill_process('send_signal', signal.SIGINT)
_, stderr = p.communicate()
@@ -1007,6 +1028,18 @@ class POSIXProcessTestCase(BaseTestCase):
self.assertStderrEqual(stderr, b'')
self.assertEqual(p.wait(), -signal.SIGTERM)
+ def test_send_signal_dead(self):
+ # Sending a signal to a dead process
+ self._kill_dead_process('send_signal', signal.SIGINT)
+
+ def test_kill_dead(self):
+ # Killing a dead process
+ self._kill_dead_process('kill')
+
+ def test_terminate_dead(self):
+ # Terminating a dead process
+ self._kill_dead_process('terminate')
+
def check_close_std_fds(self, fds):
# Issue #9905: test that subprocess pipes still work properly with
# some standard fds closed
@@ -1568,6 +1601,31 @@ class Win32ProcessTestCase(BaseTestCase):
returncode = p.wait()
self.assertNotEqual(returncode, 0)
+ def _kill_dead_process(self, method, *args):
+ p = subprocess.Popen([sys.executable, "-c", """if 1:
+ import sys, time
+ sys.stdout.write('x\\n')
+ sys.stdout.flush()
+ sys.exit(42)
+ """],
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ self.addCleanup(p.stdout.close)
+ self.addCleanup(p.stderr.close)
+ self.addCleanup(p.stdin.close)
+ # Wait for the interpreter to be completely initialized before
+ # sending any signal.
+ p.stdout.read(1)
+ # The process should end after this
+ time.sleep(1)
+ # This shouldn't raise even though the child is now dead
+ getattr(p, method)(*args)
+ _, stderr = p.communicate()
+ self.assertStderrEqual(stderr, b'')
+ rc = p.wait()
+ self.assertEqual(rc, 42)
+
def test_send_signal(self):
self._kill_process('send_signal', signal.SIGTERM)
@@ -1577,6 +1635,15 @@ class Win32ProcessTestCase(BaseTestCase):
def test_terminate(self):
self._kill_process('terminate')
+ def test_send_signal_dead(self):
+ self._kill_dead_process('send_signal', signal.SIGTERM)
+
+ def test_kill_dead(self):
+ self._kill_dead_process('kill')
+
+ def test_terminate_dead(self):
+ self._kill_dead_process('terminate')
+
# The module says:
# "NB This only works (and is only relevant) for UNIX."
diff --git a/Lib/test/test_tools.py b/Lib/test/test_tools.py
new file mode 100644
index 0000000..1682124
--- /dev/null
+++ b/Lib/test/test_tools.py
@@ -0,0 +1,39 @@
+"""Tests for scripts in the Tools directory.
+
+This file contains regression tests for some of the scripts found in the
+Tools directory of a Python checkout or tarball, such as reindent.py.
+"""
+
+import os
+import unittest
+import sysconfig
+from test import support
+from test.script_helper import assert_python_ok
+
+if not sysconfig.is_python_build():
+ # XXX some installers do contain the tools, should we detect that
+ # and run the tests in that case too?
+ raise unittest.SkipTest('test irrelevant for an installed Python')
+
+srcdir = sysconfig.get_config_var('projectbase')
+basepath = os.path.join(os.getcwd(), srcdir, 'Tools')
+
+
+class ReindentTests(unittest.TestCase):
+ script = os.path.join(basepath, 'scripts', 'reindent.py')
+
+ def test_noargs(self):
+ assert_python_ok(self.script)
+
+ def test_help(self):
+ rc, out, err = assert_python_ok(self.script, '-h')
+ self.assertEqual(out, b'')
+ self.assertGreater(err, b'')
+
+
+def test_main():
+ support.run_unittest(ReindentTests)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py
index 259a181..19b06a0 100644
--- a/Lib/test/test_unicode.py
+++ b/Lib/test/test_unicode.py
@@ -891,12 +891,15 @@ class UnicodeTest(string_tests.CommonTest,
self.assertEqual('{foo._x}'.format_map({'foo': C(20)}), '20')
# test various errors
- self.assertRaises(TypeError, '{'.format_map)
- self.assertRaises(TypeError, '}'.format_map)
- self.assertRaises(TypeError, 'a{'.format_map)
- self.assertRaises(TypeError, 'a}'.format_map)
- self.assertRaises(TypeError, '{a'.format_map)
- self.assertRaises(TypeError, '}a'.format_map)
+ self.assertRaises(TypeError, ''.format_map)
+ self.assertRaises(TypeError, 'a'.format_map)
+
+ self.assertRaises(ValueError, '{'.format_map, {})
+ self.assertRaises(ValueError, '}'.format_map, {})
+ self.assertRaises(ValueError, 'a{'.format_map, {})
+ self.assertRaises(ValueError, 'a}'.format_map, {})
+ self.assertRaises(ValueError, '{a'.format_map, {})
+ self.assertRaises(ValueError, '}a'.format_map, {})
# issue #12579: can't supply positional params to format_map
self.assertRaises(ValueError, '{}'.format_map, {'a' : 2})
diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py
index 8b5bbc3..74b9a87 100644
--- a/Lib/test/test_weakref.py
+++ b/Lib/test/test_weakref.py
@@ -812,11 +812,71 @@ class Object:
def __hash__(self):
return hash(self.arg)
+class RefCycle:
+ def __init__(self):
+ self.cycle = self
+
class MappingTestCase(TestBase):
COUNT = 10
+ def check_len_cycles(self, dict_type, cons):
+ N = 20
+ items = [RefCycle() for i in range(N)]
+ dct = dict_type(cons(o) for o in items)
+ # Keep an iterator alive
+ it = dct.items()
+ try:
+ next(it)
+ except StopIteration:
+ pass
+ del items
+ gc.collect()
+ n1 = len(dct)
+ del it
+ gc.collect()
+ n2 = len(dct)
+ # one item may be kept alive inside the iterator
+ self.assertIn(n1, (0, 1))
+ self.assertEqual(n2, 0)
+
+ def test_weak_keyed_len_cycles(self):
+ self.check_len_cycles(weakref.WeakKeyDictionary, lambda k: (k, 1))
+
+ def test_weak_valued_len_cycles(self):
+ self.check_len_cycles(weakref.WeakValueDictionary, lambda k: (1, k))
+
+ def check_len_race(self, dict_type, cons):
+ # Extended sanity checks for len() in the face of cyclic collection
+ self.addCleanup(gc.set_threshold, *gc.get_threshold())
+ for th in range(1, 100):
+ N = 20
+ gc.collect(0)
+ gc.set_threshold(th, th, th)
+ items = [RefCycle() for i in range(N)]
+ dct = dict_type(cons(o) for o in items)
+ del items
+ # All items will be collected at next garbage collection pass
+ it = dct.items()
+ try:
+ next(it)
+ except StopIteration:
+ pass
+ n1 = len(dct)
+ del it
+ n2 = len(dct)
+ self.assertGreaterEqual(n1, 0)
+ self.assertLessEqual(n1, N)
+ self.assertGreaterEqual(n2, 0)
+ self.assertLessEqual(n2, n1)
+
+ def test_weak_keyed_len_race(self):
+ self.check_len_race(weakref.WeakKeyDictionary, lambda k: (k, 1))
+
+ def test_weak_valued_len_race(self):
+ self.check_len_race(weakref.WeakValueDictionary, lambda k: (1, k))
+
def test_weak_values(self):
#
# This exercises d.copy(), d.items(), d[], del d[], len(d).
diff --git a/Lib/test/test_weakset.py b/Lib/test/test_weakset.py
index 3cddf40..4d3878f 100644
--- a/Lib/test/test_weakset.py
+++ b/Lib/test/test_weakset.py
@@ -17,6 +17,10 @@ import contextlib
class Foo:
pass
+class RefCycle:
+ def __init__(self):
+ self.cycle = self
+
class TestWeakSet(unittest.TestCase):
@@ -24,6 +28,12 @@ class TestWeakSet(unittest.TestCase):
# need to keep references to them
self.items = [ustr(c) for c in ('a', 'b', 'c')]
self.items2 = [ustr(c) for c in ('x', 'y', 'z')]
+ self.ab_items = [ustr(c) for c in 'ab']
+ self.abcde_items = [ustr(c) for c in 'abcde']
+ self.def_items = [ustr(c) for c in 'def']
+ self.ab_weakset = WeakSet(self.ab_items)
+ self.abcde_weakset = WeakSet(self.abcde_items)
+ self.def_weakset = WeakSet(self.def_items)
self.letters = [ustr(c) for c in string.ascii_letters]
self.s = WeakSet(self.items)
self.d = dict.fromkeys(self.items)
@@ -67,6 +77,11 @@ class TestWeakSet(unittest.TestCase):
x = WeakSet(self.items + self.items2)
c = C(self.items2)
self.assertEqual(self.s.union(c), x)
+ del c
+ self.assertEqual(len(u), len(self.items) + len(self.items2))
+ self.items2.pop()
+ gc.collect()
+ self.assertEqual(len(u), len(self.items) + len(self.items2))
def test_or(self):
i = self.s.union(self.items2)
@@ -74,14 +89,19 @@ class TestWeakSet(unittest.TestCase):
self.assertEqual(self.s | frozenset(self.items2), i)
def test_intersection(self):
- i = self.s.intersection(self.items2)
+ s = WeakSet(self.letters)
+ i = s.intersection(self.items2)
for c in self.letters:
- self.assertEqual(c in i, c in self.d and c in self.items2)
- self.assertEqual(self.s, WeakSet(self.items))
+ self.assertEqual(c in i, c in self.items2 and c in self.letters)
+ self.assertEqual(s, WeakSet(self.letters))
self.assertEqual(type(i), WeakSet)
for C in set, frozenset, dict.fromkeys, list, tuple:
x = WeakSet([])
- self.assertEqual(self.s.intersection(C(self.items2)), x)
+ self.assertEqual(i.intersection(C(self.items)), x)
+ self.assertEqual(len(i), len(self.items2))
+ self.items2.pop()
+ gc.collect()
+ self.assertEqual(len(i), len(self.items2))
def test_isdisjoint(self):
self.assertTrue(self.s.isdisjoint(WeakSet(self.items2)))
@@ -112,6 +132,10 @@ class TestWeakSet(unittest.TestCase):
self.assertEqual(self.s, WeakSet(self.items))
self.assertEqual(type(i), WeakSet)
self.assertRaises(TypeError, self.s.symmetric_difference, [[]])
+ self.assertEqual(len(i), len(self.items) + len(self.items2))
+ self.items2.pop()
+ gc.collect()
+ self.assertEqual(len(i), len(self.items) + len(self.items2))
def test_xor(self):
i = self.s.symmetric_difference(self.items2)
@@ -119,22 +143,28 @@ class TestWeakSet(unittest.TestCase):
self.assertEqual(self.s ^ frozenset(self.items2), i)
def test_sub_and_super(self):
- pl, ql, rl = map(lambda s: [ustr(c) for c in s], ['ab', 'abcde', 'def'])
- p, q, r = map(WeakSet, (pl, ql, rl))
- self.assertTrue(p < q)
- self.assertTrue(p <= q)
- self.assertTrue(q <= q)
- self.assertTrue(q > p)
- self.assertTrue(q >= p)
- self.assertFalse(q < r)
- self.assertFalse(q <= r)
- self.assertFalse(q > r)
- self.assertFalse(q >= r)
+ self.assertTrue(self.ab_weakset <= self.abcde_weakset)
+ self.assertTrue(self.abcde_weakset <= self.abcde_weakset)
+ self.assertTrue(self.abcde_weakset >= self.ab_weakset)
+ self.assertFalse(self.abcde_weakset <= self.def_weakset)
+ self.assertFalse(self.abcde_weakset >= self.def_weakset)
self.assertTrue(set('a').issubset('abc'))
self.assertTrue(set('abc').issuperset('a'))
self.assertFalse(set('a').issubset('cbs'))
self.assertFalse(set('cbs').issuperset('a'))
+ def test_lt(self):
+ self.assertTrue(self.ab_weakset < self.abcde_weakset)
+ self.assertFalse(self.abcde_weakset < self.def_weakset)
+ self.assertFalse(self.ab_weakset < self.ab_weakset)
+ self.assertFalse(WeakSet() < WeakSet())
+
+ def test_gt(self):
+ self.assertTrue(self.abcde_weakset > self.ab_weakset)
+ self.assertFalse(self.abcde_weakset > self.def_weakset)
+ self.assertFalse(self.ab_weakset > self.ab_weakset)
+ self.assertFalse(WeakSet() > WeakSet())
+
def test_gc(self):
# Create a nest of cycles to exercise overall ref count check
s = WeakSet(Foo() for i in range(1000))
@@ -359,6 +389,49 @@ class TestWeakSet(unittest.TestCase):
s.clear()
self.assertEqual(len(s), 0)
+ def test_len_cycles(self):
+ N = 20
+ items = [RefCycle() for i in range(N)]
+ s = WeakSet(items)
+ del items
+ it = iter(s)
+ try:
+ next(it)
+ except StopIteration:
+ pass
+ gc.collect()
+ n1 = len(s)
+ del it
+ gc.collect()
+ n2 = len(s)
+ # one item may be kept alive inside the iterator
+ self.assertIn(n1, (0, 1))
+ self.assertEqual(n2, 0)
+
+ def test_len_race(self):
+ # Extended sanity checks for len() in the face of cyclic collection
+ self.addCleanup(gc.set_threshold, *gc.get_threshold())
+ for th in range(1, 100):
+ N = 20
+ gc.collect(0)
+ gc.set_threshold(th, th, th)
+ items = [RefCycle() for i in range(N)]
+ s = WeakSet(items)
+ del items
+ # All items will be collected at next garbage collection pass
+ it = iter(s)
+ try:
+ next(it)
+ except StopIteration:
+ pass
+ n1 = len(s)
+ del it
+ n2 = len(s)
+ self.assertGreaterEqual(n1, 0)
+ self.assertLessEqual(n1, N)
+ self.assertGreaterEqual(n2, 0)
+ self.assertLessEqual(n2, n1)
+
def test_main(verbose=None):
support.run_unittest(TestWeakSet)
diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py
index dffa2ca..60081e2 100644
--- a/Lib/test/test_zlib.py
+++ b/Lib/test/test_zlib.py
@@ -66,24 +66,11 @@ class ChecksumTestCase(unittest.TestCase):
# Issue #10276 - check that inputs >=4GB are handled correctly.
class ChecksumBigBufferTestCase(unittest.TestCase):
- def setUp(self):
- with open(support.TESTFN, "wb+") as f:
- f.seek(_4G)
- f.write(b"asdf")
- f.flush()
- self.mapping = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
-
- def tearDown(self):
- self.mapping.close()
- support.unlink(support.TESTFN)
-
- @unittest.skipUnless(mmap, "mmap() is not available.")
- @unittest.skipUnless(sys.maxsize > _4G, "Can't run on a 32-bit system.")
- @unittest.skipUnless(support.is_resource_enabled("largefile"),
- "May use lots of disk space.")
- def test_big_buffer(self):
- self.assertEqual(zlib.crc32(self.mapping), 3058686908)
- self.assertEqual(zlib.adler32(self.mapping), 82837919)
+ @bigmemtest(size=_4G + 4, memuse=1, dry_run=False)
+ def test_big_buffer(self, size):
+ data = b"nyan" * (_1G + 1)
+ self.assertEqual(zlib.crc32(data), 1044521549)
+ self.assertEqual(zlib.adler32(data), 2256789997)
class ExceptionTestCase(unittest.TestCase):
diff --git a/Lib/unittest/loader.py b/Lib/unittest/loader.py
index ab36400..541884e 100644
--- a/Lib/unittest/loader.py
+++ b/Lib/unittest/loader.py
@@ -34,6 +34,11 @@ def _make_failed_test(classname, methodname, exception, suiteClass):
TestClass = type(classname, (case.TestCase,), attrs)
return suiteClass((TestClass(methodname),))
+def _jython_aware_splitext(path):
+ if path.lower().endswith('$py.class'):
+ return path[:-9]
+ return os.path.splitext(path)[0]
+
class TestLoader(object):
"""
@@ -221,7 +226,7 @@ class TestLoader(object):
return os.path.dirname(full_path)
def _get_name_from_path(self, path):
- path = os.path.splitext(os.path.normpath(path))[0]
+ path = _jython_aware_splitext(os.path.normpath(path))
_relpath = os.path.relpath(path, self._top_level_dir)
assert not os.path.isabs(_relpath), "Path must be within the project"
@@ -258,11 +263,11 @@ class TestLoader(object):
yield _make_failed_import_test(name, self.suiteClass)
else:
mod_file = os.path.abspath(getattr(module, '__file__', full_path))
- realpath = os.path.splitext(mod_file)[0]
- fullpath_noext = os.path.splitext(full_path)[0]
+ realpath = _jython_aware_splitext(mod_file)
+ fullpath_noext = _jython_aware_splitext(full_path)
if realpath.lower() != fullpath_noext.lower():
module_dir = os.path.dirname(realpath)
- mod_name = os.path.splitext(os.path.basename(full_path))[0]
+ mod_name = _jython_aware_splitext(os.path.basename(full_path))
expected_dir = os.path.dirname(full_path)
msg = ("%r module incorrectly imported from %r. Expected %r. "
"Is this module globally installed?")
diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py
index 94b713e..fe2cfcd 100644
--- a/Lib/urllib/request.py
+++ b/Lib/urllib/request.py
@@ -1062,8 +1062,9 @@ class AbstractHTTPHandler(BaseHandler):
if request.data is not None: # POST
data = request.data
if isinstance(data, str):
- raise TypeError("POST data should be bytes"
- " or an iterable of bytes. It cannot be str.")
+ msg = "POST data should be bytes or an iterable of bytes."\
+ "It cannot be str"
+ raise TypeError(msg)
if not request.has_header('Content-type'):
request.add_unredirected_header(
'Content-type',
diff --git a/Lib/urllib/response.py b/Lib/urllib/response.py
index 8c6dcca..ffaa5fa 100644
--- a/Lib/urllib/response.py
+++ b/Lib/urllib/response.py
@@ -61,11 +61,11 @@ class addclosehook(addbase):
self.hookargs = hookargs
def close(self):
- addbase.close(self)
if self.closehook:
self.closehook(*self.hookargs)
self.closehook = None
self.hookargs = None
+ addbase.close(self)
class addinfo(addbase):
"""class to add an info() method to an open file."""
diff --git a/Lib/weakref.py b/Lib/weakref.py
index 468f8f1..fcb6b74 100644
--- a/Lib/weakref.py
+++ b/Lib/weakref.py
@@ -78,7 +78,7 @@ class WeakValueDictionary(collections.MutableMapping):
del self.data[key]
def __len__(self):
- return sum(wr() is not None for wr in self.data.values())
+ return len(self.data) - len(self._pending_removals)
def __contains__(self, key):
try:
@@ -290,7 +290,7 @@ class WeakKeyDictionary(collections.MutableMapping):
return self.data[ref(key)]
def __len__(self):
- return len(self.data)
+ return len(self.data) - len(self._pending_removals)
def __repr__(self):
return "<WeakKeyDictionary at %s>" % id(self)
diff --git a/Lib/xmlrpc/server.py b/Lib/xmlrpc/server.py
index d7ed3f3..fd17026 100644
--- a/Lib/xmlrpc/server.py
+++ b/Lib/xmlrpc/server.py
@@ -1,4 +1,4 @@
-"""XML-RPC Servers.
+r"""XML-RPC Servers.
This module can be used to create simple XML-RPC servers
by creating a server and either installing functions, a