summaryrefslogtreecommitdiff
path: root/Lib/test
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/test')
-rw-r--r--Lib/test/__main__.py5
-rw-r--r--Lib/test/_test_multiprocessing.py24
-rw-r--r--Lib/test/audiotests.py3
-rw-r--r--Lib/test/autotest.py5
-rw-r--r--Lib/test/capath/0e4015b9.016
-rw-r--r--Lib/test/capath/b1930218.021
-rw-r--r--Lib/test/capath/ce7b8643.016
-rw-r--r--Lib/test/capath/ceff1710.021
-rw-r--r--Lib/test/datetimetester.py51
-rw-r--r--Lib/test/eintrdata/eintr_tester.py8
-rw-r--r--Lib/test/libregrtest/__init__.py5
-rw-r--r--Lib/test/libregrtest/cmdline.py342
-rw-r--r--Lib/test/libregrtest/main.py508
-rw-r--r--Lib/test/libregrtest/refleak.py202
-rw-r--r--Lib/test/libregrtest/runtest.py260
-rw-r--r--Lib/test/libregrtest/runtest_mp.py245
-rw-r--r--Lib/test/libregrtest/save_env.py286
-rw-r--r--Lib/test/libregrtest/setup.py121
-rw-r--r--Lib/test/lock_tests.py12
-rw-r--r--Lib/test/make_ssl_certs.py1
-rw-r--r--Lib/test/pickletester.py23
-rw-r--r--[-rwxr-xr-x]Lib/test/regrtest.py1593
-rw-r--r--Lib/test/seq_tests.py1
-rw-r--r--Lib/test/signalinterproctester.py84
-rw-r--r--Lib/test/support/__init__.py68
-rw-r--r--Lib/test/test__locale.py1
-rw-r--r--Lib/test/test__osx_support.py1
-rw-r--r--Lib/test/test_aifc.py1
-rw-r--r--Lib/test/test_argparse.py15
-rw-r--r--Lib/test/test_array.py23
-rw-r--r--Lib/test/test_ast.py140
-rw-r--r--Lib/test/test_asynchat.py32
-rw-r--r--Lib/test/test_bigmem.py1
-rw-r--r--Lib/test/test_binascii.py26
-rw-r--r--Lib/test/test_binhex.py1
-rw-r--r--Lib/test/test_binop.py2
-rw-r--r--Lib/test/test_buffer.py1
-rw-r--r--Lib/test/test_bytes.py121
-rw-r--r--Lib/test/test_calendar.py17
-rw-r--r--Lib/test/test_capi.py90
-rw-r--r--Lib/test/test_charmapcodec.py2
-rw-r--r--Lib/test/test_cmd_line.py3
-rw-r--r--Lib/test/test_cmd_line_script.py5
-rw-r--r--Lib/test/test_codeccallbacks.py1
-rw-r--r--Lib/test/test_codecencodings_cn.py1
-rw-r--r--Lib/test/test_codecencodings_hk.py1
-rw-r--r--Lib/test/test_codecencodings_iso2022.py1
-rw-r--r--Lib/test/test_codecencodings_jp.py1
-rw-r--r--Lib/test/test_codecencodings_kr.py1
-rw-r--r--Lib/test/test_codecencodings_tw.py1
-rw-r--r--Lib/test/test_codecmaps_cn.py1
-rw-r--r--Lib/test/test_codecmaps_hk.py1
-rw-r--r--Lib/test/test_codecmaps_jp.py1
-rw-r--r--Lib/test/test_codecmaps_kr.py1
-rw-r--r--Lib/test/test_codecmaps_tw.py1
-rw-r--r--Lib/test/test_codecs.py144
-rw-r--r--Lib/test/test_codeop.py1
-rw-r--r--Lib/test/test_collections.py53
-rw-r--r--Lib/test/test_compileall.py45
-rw-r--r--Lib/test/test_contextlib.py35
-rw-r--r--Lib/test/test_copy.py2
-rw-r--r--Lib/test/test_cprofile.py2
-rw-r--r--Lib/test/test_csv.py29
-rw-r--r--Lib/test/test_dbm.py1
-rw-r--r--Lib/test/test_dbm_gnu.py2
-rw-r--r--Lib/test/test_dbm_ndbm.py2
-rw-r--r--Lib/test/test_decimal.py33
-rw-r--r--Lib/test/test_deque.py79
-rw-r--r--Lib/test/test_descr.py9
-rw-r--r--Lib/test/test_devpoll.py3
-rw-r--r--Lib/test/test_dict.py13
-rw-r--r--Lib/test/test_dictcomps.py2
-rw-r--r--Lib/test/test_dictviews.py22
-rw-r--r--Lib/test/test_dis.py524
-rw-r--r--Lib/test/test_doctest.py7
-rw-r--r--Lib/test/test_dynamic.py1
-rw-r--r--Lib/test/test_eintr.py12
-rw-r--r--Lib/test/test_email/__init__.py1
-rw-r--r--Lib/test/test_email/test_asian_codecs.py1
-rw-r--r--Lib/test/test_email/test_email.py1
-rw-r--r--Lib/test/test_email/test_headerregistry.py1
-rw-r--r--Lib/test/test_enum.py29
-rw-r--r--Lib/test/test_epoll.py1
-rw-r--r--Lib/test/test_faulthandler.py92
-rw-r--r--Lib/test/test_file.py4
-rw-r--r--Lib/test/test_fileinput.py36
-rw-r--r--Lib/test/test_float.py1
-rw-r--r--Lib/test/test_format.py2
-rw-r--r--Lib/test/test_fractions.py14
-rw-r--r--Lib/test/test_fstring.py745
-rw-r--r--Lib/test/test_ftplib.py11
-rw-r--r--Lib/test/test_functools.py2
-rw-r--r--Lib/test/test_gc.py2
-rw-r--r--Lib/test/test_gdb.py28
-rw-r--r--Lib/test/test_generators.py6
-rw-r--r--Lib/test/test_genericpath.py270
-rw-r--r--Lib/test/test_getargs2.py12
-rw-r--r--Lib/test/test_gettext.py7
-rw-r--r--Lib/test/test_grammar.py38
-rw-r--r--Lib/test/test_grp.py10
-rw-r--r--Lib/test/test_heapq.py1
-rw-r--r--Lib/test/test_hmac.py1
-rw-r--r--Lib/test/test_htmlparser.py1
-rw-r--r--Lib/test/test_httpservers.py46
-rw-r--r--Lib/test/test_idle.py1
-rw-r--r--Lib/test/test_imaplib.py49
-rw-r--r--Lib/test/test_imp.py3
-rw-r--r--Lib/test/test_importlib/extension/test_case_sensitivity.py3
-rw-r--r--Lib/test/test_importlib/extension/test_finder.py1
-rw-r--r--Lib/test/test_importlib/extension/test_path_hook.py2
-rw-r--r--Lib/test/test_importlib/frozen/test_loader.py2
-rw-r--r--Lib/test/test_importlib/import_/test___package__.py55
-rw-r--r--Lib/test/test_importlib/import_/test_packages.py1
-rw-r--r--Lib/test/test_importlib/import_/test_path.py68
-rw-r--r--Lib/test/test_importlib/import_/test_relative_imports.py24
-rw-r--r--Lib/test/test_importlib/regrtest.py17
-rw-r--r--Lib/test/test_importlib/source/test_case_sensitivity.py1
-rw-r--r--Lib/test/test_importlib/source/test_file_loader.py9
-rw-r--r--Lib/test/test_importlib/source/test_path_hook.py11
-rw-r--r--Lib/test/test_importlib/source/test_source_encoding.py1
-rw-r--r--Lib/test/test_importlib/test_abc.py22
-rw-r--r--Lib/test/test_importlib/test_api.py31
-rw-r--r--Lib/test/test_importlib/test_locks.py1
-rw-r--r--Lib/test/test_importlib/test_namespace_pkgs.py38
-rw-r--r--Lib/test/test_importlib/test_windows.py2
-rw-r--r--Lib/test/test_inspect.py11
-rw-r--r--Lib/test/test_io.py9
-rw-r--r--Lib/test/test_iterlen.py1
-rw-r--r--Lib/test/test_itertools.py51
-rw-r--r--Lib/test/test_json/__init__.py1
-rw-r--r--Lib/test/test_json/test_fail.py1
-rw-r--r--Lib/test/test_kqueue.py1
-rw-r--r--Lib/test/test_linecache.py75
-rw-r--r--Lib/test/test_list.py2
-rw-r--r--Lib/test/test_logging.py14
-rw-r--r--Lib/test/test_long.py33
-rw-r--r--Lib/test/test_macpath.py2
-rw-r--r--Lib/test/test_mailbox.py5
-rw-r--r--Lib/test/test_mailcap.py1
-rw-r--r--Lib/test/test_marshal.py7
-rw-r--r--Lib/test/test_math.py1
-rw-r--r--Lib/test/test_mmap.py8
-rw-r--r--Lib/test/test_msilib.py1
-rw-r--r--Lib/test/test_multibytecodec.py2
-rw-r--r--Lib/test/test_multiprocessing_main_handling.py3
-rw-r--r--Lib/test/test_nis.py1
-rw-r--r--Lib/test/test_normalization.py1
-rw-r--r--Lib/test/test_operator.py50
-rw-r--r--Lib/test/test_optparse.py7
-rw-r--r--Lib/test/test_ordered_dict.py12
-rw-r--r--Lib/test/test_os.py400
-rw-r--r--Lib/test/test_parser.py1
-rw-r--r--Lib/test/test_pathlib.py8
-rw-r--r--Lib/test/test_pdb.py1
-rw-r--r--Lib/test/test_peepholer.py20
-rw-r--r--Lib/test/test_pep3151.py1
-rw-r--r--Lib/test/test_pep352.py1
-rw-r--r--Lib/test/test_pickle.py5
-rw-r--r--Lib/test/test_pickletools.py34
-rw-r--r--Lib/test/test_pipes.py7
-rw-r--r--Lib/test/test_plistlib.py1
-rw-r--r--Lib/test/test_poplib.py1
-rw-r--r--Lib/test/test_posix.py7
-rw-r--r--Lib/test/test_posixpath.py2
-rw-r--r--Lib/test/test_pow.py2
-rw-r--r--Lib/test/test_pty.py1
-rw-r--r--Lib/test/test_pulldom.py1
-rw-r--r--Lib/test/test_pyclbr.py2
-rw-r--r--Lib/test/test_pydoc.py16
-rw-r--r--Lib/test/test_quopri.py2
-rw-r--r--Lib/test/test_range.py2
-rw-r--r--Lib/test/test_readline.py64
-rw-r--r--Lib/test/test_regrtest.py608
-rw-r--r--Lib/test/test_richcmp.py25
-rw-r--r--Lib/test/test_rlcompleter.py55
-rw-r--r--Lib/test/test_robotparser.py92
-rw-r--r--Lib/test/test_sched.py1
-rw-r--r--Lib/test/test_secrets.py123
-rw-r--r--Lib/test/test_set.py25
-rw-r--r--Lib/test/test_signal.py171
-rw-r--r--Lib/test/test_site.py7
-rw-r--r--Lib/test/test_smtpd.py41
-rw-r--r--Lib/test/test_socket.py13
-rw-r--r--Lib/test/test_socketserver.py101
-rw-r--r--Lib/test/test_sort.py1
-rw-r--r--Lib/test/test_spwd.py15
-rw-r--r--Lib/test/test_ssl.py695
-rw-r--r--Lib/test/test_statistics.py28
-rw-r--r--Lib/test/test_strptime.py66
-rw-r--r--Lib/test/test_subprocess.py128
-rw-r--r--Lib/test/test_sunau.py1
-rw-r--r--Lib/test/test_support.py31
-rw-r--r--Lib/test/test_symbol.py54
-rw-r--r--Lib/test/test_syntax.py12
-rw-r--r--Lib/test/test_sys_settrace.py4
-rw-r--r--Lib/test/test_tarfile.py18
-rw-r--r--Lib/test/test_telnetlib.py6
-rw-r--r--Lib/test/test_threading.py11
-rw-r--r--Lib/test/test_time.py598
-rw-r--r--Lib/test/test_tokenize.py55
-rw-r--r--Lib/test/test_tools/__init__.py1
-rw-r--r--Lib/test/test_tools/test_gprof2html.py3
-rw-r--r--Lib/test/test_tools/test_md5sum.py3
-rw-r--r--Lib/test/test_tools/test_pdeps.py4
-rw-r--r--Lib/test/test_tools/test_unparse.py9
-rw-r--r--Lib/test/test_trace.py66
-rw-r--r--Lib/test/test_traceback.py16
-rw-r--r--Lib/test/test_tracemalloc.py219
-rw-r--r--Lib/test/test_ttk_guionly.py1
-rw-r--r--Lib/test/test_ttk_textonly.py1
-rw-r--r--Lib/test/test_unpack.py21
-rw-r--r--Lib/test/test_unpack_ex.py1
-rw-r--r--Lib/test/test_urllib2_localnet.py39
-rw-r--r--Lib/test/test_urllibnet.py1
-rw-r--r--Lib/test/test_urlparse.py36
-rw-r--r--Lib/test/test_userdict.py6
-rw-r--r--Lib/test/test_userlist.py2
-rw-r--r--Lib/test/test_userstring.py3
-rw-r--r--Lib/test/test_uu.py1
-rw-r--r--Lib/test/test_venv.py29
-rw-r--r--Lib/test/test_warnings/__init__.py45
-rw-r--r--Lib/test/test_warnings/data/import_warning.py2
-rw-r--r--Lib/test/test_wave.py8
-rw-r--r--Lib/test/test_weakset.py9
-rw-r--r--Lib/test/test_winreg.py1
-rw-r--r--Lib/test/test_with.py9
-rw-r--r--Lib/test/test_xml_etree.py16
-rw-r--r--Lib/test/test_xml_etree_c.py4
-rw-r--r--Lib/test/test_xmlrpc.py2
-rw-r--r--Lib/test/test_xmlrpc_net.py3
-rw-r--r--Lib/test/test_zipfile.py99
-rw-r--r--Lib/test/test_zipimport.py21
-rw-r--r--Lib/test/test_zipimport_support.py1
-rw-r--r--Lib/test/test_zlib.py4
234 files changed, 7747 insertions, 3944 deletions
diff --git a/Lib/test/__main__.py b/Lib/test/__main__.py
index d5fbe159d7..19a6b2b890 100644
--- a/Lib/test/__main__.py
+++ b/Lib/test/__main__.py
@@ -1,3 +1,2 @@
-from test import regrtest
-
-regrtest.main_in_temp_cwd()
+from test.libregrtest import main
+main()
diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py
index 11a6310a76..16407db7b3 100644
--- a/Lib/test/_test_multiprocessing.py
+++ b/Lib/test/_test_multiprocessing.py
@@ -1668,6 +1668,10 @@ def sqr(x, wait=0.0):
def mul(x, y):
return x*y
+def raise_large_valuerror(wait):
+ time.sleep(wait)
+ raise ValueError("x" * 1024**2)
+
class SayWhenError(ValueError): pass
def exception_throwing_generator(total, when):
@@ -1910,6 +1914,26 @@ class _TestPool(BaseTestCase):
with self.assertRaises(RuntimeError):
p.apply(self._test_wrapped_exception)
+ def test_map_no_failfast(self):
+ # Issue #23992: the fail-fast behaviour when an exception is raised
+ # during map() would make Pool.join() deadlock, because a worker
+ # process would fill the result queue (after the result handler thread
+ # terminated, hence not draining it anymore).
+
+ t_start = time.time()
+
+ with self.assertRaises(ValueError):
+ with self.Pool(2) as p:
+ try:
+ p.map(raise_large_valuerror, [0, 1])
+ finally:
+ time.sleep(0.5)
+ p.close()
+ p.join()
+
+ # check that we indeed waited for all jobs
+ self.assertGreater(time.time() - t_start, 0.9)
+
def raising():
raise KeyError("key")
diff --git a/Lib/test/audiotests.py b/Lib/test/audiotests.py
index 0ae2242851..d3e8e9ee44 100644
--- a/Lib/test/audiotests.py
+++ b/Lib/test/audiotests.py
@@ -1,9 +1,8 @@
from test.support import findfile, TESTFN, unlink
-import unittest
import array
import io
import pickle
-import sys
+
class UnseekableIO(io.FileIO):
def tell(self):
diff --git a/Lib/test/autotest.py b/Lib/test/autotest.py
index 41c2088727..fa85cc153a 100644
--- a/Lib/test/autotest.py
+++ b/Lib/test/autotest.py
@@ -1,6 +1,5 @@
# This should be equivalent to running regrtest.py from the cmdline.
# It can be especially handy if you're in an interactive shell, e.g.,
# from test import autotest.
-
-from test import regrtest
-regrtest.main()
+from test.libregrtest import main
+main()
diff --git a/Lib/test/capath/0e4015b9.0 b/Lib/test/capath/0e4015b9.0
deleted file mode 100644
index b6d259bcb2..0000000000
--- a/Lib/test/capath/0e4015b9.0
+++ /dev/null
@@ -1,16 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIClTCCAf6gAwIBAgIJAKGU95wKR8pTMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV
-BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u
-IFNvZnR3YXJlIEZvdW5kYXRpb24xIzAhBgNVBAMMGnNlbGYtc2lnbmVkLnB5dGhv
-bnRlc3QubmV0MB4XDTE0MTEwMjE4MDkyOVoXDTI0MTAzMDE4MDkyOVowcDELMAkG
-A1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMwIQYDVQQKDBpQeXRo
-b24gU29mdHdhcmUgRm91bmRhdGlvbjEjMCEGA1UEAwwac2VsZi1zaWduZWQucHl0
-aG9udGVzdC5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANDXQXW9tjyZ
-Xt0Iv2tLL1+jinr4wGg36ioLDLFkMf+2Y1GL0v0BnKYG4N1OKlAU15LXGeGer8vm
-Sv/yIvmdrELvhAbbo3w4a9TMYQA4XkIVLdvu3mvNOAet+8PMJxn26dbDhG809ALv
-EHY57lQsBS3G59RZyBPVqAqmImWNJnVzAgMBAAGjNzA1MCUGA1UdEQQeMByCGnNl
-bGYtc2lnbmVkLnB5dGhvbnRlc3QubmV0MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN
-AQEFBQADgYEAIuzAhgMouJpNdf3URCHIineyoSt6WK/9+eyUcjlKOrDoXNZaD72h
-TXMeKYoWvJyVcSLKL8ckPtDobgP2OTt0UkyAaj0n+ZHaqq1lH2yVfGUA1ILJv515
-C8BqbvVZuqm3i7ygmw3bqE/lYMgOrYtXXnqOrz6nvsE6Yc9V9rFflOM=
------END CERTIFICATE-----
diff --git a/Lib/test/capath/b1930218.0 b/Lib/test/capath/b1930218.0
new file mode 100644
index 0000000000..373349cae0
--- /dev/null
+++ b/Lib/test/capath/b1930218.0
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIJALCSZLHy2iHQMA0GCSqGSIb3DQEBBQUAME0xCzAJBgNV
+BAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEW
+MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAeFw0xMzAxMDQxOTQ3MDdaFw0yMzAxMDIx
+OTQ3MDdaME0xCzAJBgNVBAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUg
+Rm91bmRhdGlvbiBDQTEWMBQGA1UEAwwNb3VyLWNhLXNlcnZlcjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAOfe6eMMnwC2of0rW5bSb8zgvoa5IF7sA3pV
+q+qk6flJhdJm1e3HeupWji2P50LiYiipn9Ybjuu1tJyfFKvf5pSLdh0+bSRh7Qy/
+AIphDN9cyDZzFgDNR7ptpKR0iIMjChn8Cac8SkvT5x0t5OpMVCHzJtuJNxjUArtA
+Ml+k/y0c99S77I7PXIKs5nwIbEiFYQd/JeBc4Lw0X+C5BEd1yEcLjbzWyGhfM4Ni
+0iBENbGtgRqKzbw1sFyLR9YY6ZwYl8wBPCnM6B7k5MG43ufCERiHWpM02KYl9xRx
+6+QhotIPLi7UYgA109bvXGBLTKkU4t0VWEY3Mya35y5d7ULkxU0CAwEAAaNQME4w
+HQYDVR0OBBYEFLzdYtl22hvSVGvP4GabHh57VgwLMB8GA1UdIwQYMBaAFLzdYtl2
+2hvSVGvP4GabHh57VgwLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB
+AH0K9cuN0129mY74Kw+668LZpidPLnsvDmTYHDVQTu78kLmNbajFxgawr/Mtvzu4
+QgfdGH1tlVRXhRhgRy/reBv56Bf9Wg2HFyisTGrmvCn09FVwKULeheqrbCMGZDB1
+Ao5TvF4BMzfMHs24pP3K5F9lO4MchvFVAqA6j9uRt0AUtOeN0u5zuuPlNC28lG9O
+JAb3X4sOp45r3l519DKaULFEM5rQBeJ4gv/b2opj66nd0b+gYa3jnookXWIO50yR
+f+/fNDY7L131hLIvxG2TlhpvMCjx2hKaZLRAMx293itTqOq+1rxOlvVE+zIYrtUf
+9mmvtk57HVjsO6lTo15YyJ4=
+-----END CERTIFICATE-----
diff --git a/Lib/test/capath/ce7b8643.0 b/Lib/test/capath/ce7b8643.0
deleted file mode 100644
index b6d259bcb2..0000000000
--- a/Lib/test/capath/ce7b8643.0
+++ /dev/null
@@ -1,16 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIClTCCAf6gAwIBAgIJAKGU95wKR8pTMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV
-BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u
-IFNvZnR3YXJlIEZvdW5kYXRpb24xIzAhBgNVBAMMGnNlbGYtc2lnbmVkLnB5dGhv
-bnRlc3QubmV0MB4XDTE0MTEwMjE4MDkyOVoXDTI0MTAzMDE4MDkyOVowcDELMAkG
-A1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMwIQYDVQQKDBpQeXRo
-b24gU29mdHdhcmUgRm91bmRhdGlvbjEjMCEGA1UEAwwac2VsZi1zaWduZWQucHl0
-aG9udGVzdC5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANDXQXW9tjyZ
-Xt0Iv2tLL1+jinr4wGg36ioLDLFkMf+2Y1GL0v0BnKYG4N1OKlAU15LXGeGer8vm
-Sv/yIvmdrELvhAbbo3w4a9TMYQA4XkIVLdvu3mvNOAet+8PMJxn26dbDhG809ALv
-EHY57lQsBS3G59RZyBPVqAqmImWNJnVzAgMBAAGjNzA1MCUGA1UdEQQeMByCGnNl
-bGYtc2lnbmVkLnB5dGhvbnRlc3QubmV0MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN
-AQEFBQADgYEAIuzAhgMouJpNdf3URCHIineyoSt6WK/9+eyUcjlKOrDoXNZaD72h
-TXMeKYoWvJyVcSLKL8ckPtDobgP2OTt0UkyAaj0n+ZHaqq1lH2yVfGUA1ILJv515
-C8BqbvVZuqm3i7ygmw3bqE/lYMgOrYtXXnqOrz6nvsE6Yc9V9rFflOM=
------END CERTIFICATE-----
diff --git a/Lib/test/capath/ceff1710.0 b/Lib/test/capath/ceff1710.0
new file mode 100644
index 0000000000..373349cae0
--- /dev/null
+++ b/Lib/test/capath/ceff1710.0
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDbTCCAlWgAwIBAgIJALCSZLHy2iHQMA0GCSqGSIb3DQEBBQUAME0xCzAJBgNV
+BAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUgRm91bmRhdGlvbiBDQTEW
+MBQGA1UEAwwNb3VyLWNhLXNlcnZlcjAeFw0xMzAxMDQxOTQ3MDdaFw0yMzAxMDIx
+OTQ3MDdaME0xCzAJBgNVBAYTAlhZMSYwJAYDVQQKDB1QeXRob24gU29mdHdhcmUg
+Rm91bmRhdGlvbiBDQTEWMBQGA1UEAwwNb3VyLWNhLXNlcnZlcjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAOfe6eMMnwC2of0rW5bSb8zgvoa5IF7sA3pV
+q+qk6flJhdJm1e3HeupWji2P50LiYiipn9Ybjuu1tJyfFKvf5pSLdh0+bSRh7Qy/
+AIphDN9cyDZzFgDNR7ptpKR0iIMjChn8Cac8SkvT5x0t5OpMVCHzJtuJNxjUArtA
+Ml+k/y0c99S77I7PXIKs5nwIbEiFYQd/JeBc4Lw0X+C5BEd1yEcLjbzWyGhfM4Ni
+0iBENbGtgRqKzbw1sFyLR9YY6ZwYl8wBPCnM6B7k5MG43ufCERiHWpM02KYl9xRx
+6+QhotIPLi7UYgA109bvXGBLTKkU4t0VWEY3Mya35y5d7ULkxU0CAwEAAaNQME4w
+HQYDVR0OBBYEFLzdYtl22hvSVGvP4GabHh57VgwLMB8GA1UdIwQYMBaAFLzdYtl2
+2hvSVGvP4GabHh57VgwLMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB
+AH0K9cuN0129mY74Kw+668LZpidPLnsvDmTYHDVQTu78kLmNbajFxgawr/Mtvzu4
+QgfdGH1tlVRXhRhgRy/reBv56Bf9Wg2HFyisTGrmvCn09FVwKULeheqrbCMGZDB1
+Ao5TvF4BMzfMHs24pP3K5F9lO4MchvFVAqA6j9uRt0AUtOeN0u5zuuPlNC28lG9O
+JAb3X4sOp45r3l519DKaULFEM5rQBeJ4gv/b2opj66nd0b+gYa3jnookXWIO50yR
+f+/fNDY7L131hLIvxG2TlhpvMCjx2hKaZLRAMx293itTqOq+1rxOlvVE+zIYrtUf
+9mmvtk57HVjsO6lTo15YyJ4=
+-----END CERTIFICATE-----
diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py
index f5222c7e48..8fc01390b3 100644
--- a/Lib/test/datetimetester.py
+++ b/Lib/test/datetimetester.py
@@ -284,7 +284,8 @@ class TestTimeZone(unittest.TestCase):
with self.assertRaises(TypeError): self.EST.dst(5)
def test_tzname(self):
- self.assertEqual('UTC+00:00', timezone(ZERO).tzname(None))
+ self.assertEqual('UTC', timezone.utc.tzname(None))
+ self.assertEqual('UTC', timezone(ZERO).tzname(None))
self.assertEqual('UTC-05:00', timezone(-5 * HOUR).tzname(None))
self.assertEqual('UTC+09:30', timezone(9.5 * HOUR).tzname(None))
self.assertEqual('UTC-00:01', timezone(timedelta(minutes=-1)).tzname(None))
@@ -1558,13 +1559,32 @@ class TestDateTime(TestDate):
self.assertEqual(dt, dt2)
def test_isoformat(self):
- t = self.theclass(2, 3, 2, 4, 5, 1, 123)
- self.assertEqual(t.isoformat(), "0002-03-02T04:05:01.000123")
- self.assertEqual(t.isoformat('T'), "0002-03-02T04:05:01.000123")
- self.assertEqual(t.isoformat(' '), "0002-03-02 04:05:01.000123")
- self.assertEqual(t.isoformat('\x00'), "0002-03-02\x0004:05:01.000123")
+ t = self.theclass(1, 2, 3, 4, 5, 1, 123)
+ self.assertEqual(t.isoformat(), "0001-02-03T04:05:01.000123")
+ self.assertEqual(t.isoformat('T'), "0001-02-03T04:05:01.000123")
+ self.assertEqual(t.isoformat(' '), "0001-02-03 04:05:01.000123")
+ self.assertEqual(t.isoformat('\x00'), "0001-02-03\x0004:05:01.000123")
+ self.assertEqual(t.isoformat(timespec='hours'), "0001-02-03T04")
+ self.assertEqual(t.isoformat(timespec='minutes'), "0001-02-03T04:05")
+ self.assertEqual(t.isoformat(timespec='seconds'), "0001-02-03T04:05:01")
+ self.assertEqual(t.isoformat(timespec='milliseconds'), "0001-02-03T04:05:01.000")
+ self.assertEqual(t.isoformat(timespec='microseconds'), "0001-02-03T04:05:01.000123")
+ self.assertEqual(t.isoformat(timespec='auto'), "0001-02-03T04:05:01.000123")
+ self.assertEqual(t.isoformat(sep=' ', timespec='minutes'), "0001-02-03 04:05")
+ self.assertRaises(ValueError, t.isoformat, timespec='foo')
# str is ISO format with the separator forced to a blank.
- self.assertEqual(str(t), "0002-03-02 04:05:01.000123")
+ self.assertEqual(str(t), "0001-02-03 04:05:01.000123")
+
+ t = self.theclass(1, 2, 3, 4, 5, 1, 999500, tzinfo=timezone.utc)
+ self.assertEqual(t.isoformat(timespec='milliseconds'), "0001-02-03T04:05:01.999+00:00")
+
+ t = self.theclass(1, 2, 3, 4, 5, 1, 999500)
+ self.assertEqual(t.isoformat(timespec='milliseconds'), "0001-02-03T04:05:01.999")
+
+ t = self.theclass(1, 2, 3, 4, 5, 1)
+ self.assertEqual(t.isoformat(timespec='auto'), "0001-02-03T04:05:01")
+ self.assertEqual(t.isoformat(timespec='milliseconds'), "0001-02-03T04:05:01.000")
+ self.assertEqual(t.isoformat(timespec='microseconds'), "0001-02-03T04:05:01.000000")
t = self.theclass(2, 3, 2)
self.assertEqual(t.isoformat(), "0002-03-02T00:00:00")
@@ -2324,6 +2344,23 @@ class TestTime(HarmlessMixedComparison, unittest.TestCase):
self.assertEqual(t.isoformat(), "00:00:00.100000")
self.assertEqual(t.isoformat(), str(t))
+ t = self.theclass(hour=12, minute=34, second=56, microsecond=123456)
+ self.assertEqual(t.isoformat(timespec='hours'), "12")
+ self.assertEqual(t.isoformat(timespec='minutes'), "12:34")
+ self.assertEqual(t.isoformat(timespec='seconds'), "12:34:56")
+ self.assertEqual(t.isoformat(timespec='milliseconds'), "12:34:56.123")
+ self.assertEqual(t.isoformat(timespec='microseconds'), "12:34:56.123456")
+ self.assertEqual(t.isoformat(timespec='auto'), "12:34:56.123456")
+ self.assertRaises(ValueError, t.isoformat, timespec='monkey')
+
+ t = self.theclass(hour=12, minute=34, second=56, microsecond=999500)
+ self.assertEqual(t.isoformat(timespec='milliseconds'), "12:34:56.999")
+
+ t = self.theclass(hour=12, minute=34, second=56, microsecond=0)
+ self.assertEqual(t.isoformat(timespec='milliseconds'), "12:34:56.000")
+ self.assertEqual(t.isoformat(timespec='microseconds'), "12:34:56.000000")
+ self.assertEqual(t.isoformat(timespec='auto'), "12:34:56")
+
def test_1653736(self):
# verify it doesn't accept extra keyword arguments
t = self.theclass(second=1)
diff --git a/Lib/test/eintrdata/eintr_tester.py b/Lib/test/eintrdata/eintr_tester.py
index 9931a5515b..ffcdb98605 100644
--- a/Lib/test/eintrdata/eintr_tester.py
+++ b/Lib/test/eintrdata/eintr_tester.py
@@ -9,7 +9,7 @@ sub-second periodicity (contrarily to signal()).
"""
import contextlib
-import io
+import faulthandler
import os
import select
import signal
@@ -50,6 +50,10 @@ class EINTRBaseTest(unittest.TestCase):
signal.setitimer(signal.ITIMER_REAL, cls.signal_delay,
cls.signal_period)
+ # Issue #25277: Use faulthandler to try to debug a hang on FreeBSD
+ if hasattr(faulthandler, 'dump_traceback_later'):
+ faulthandler.dump_traceback_later(10 * 60, exit=True)
+
@classmethod
def stop_alarm(cls):
signal.setitimer(signal.ITIMER_REAL, 0, 0)
@@ -58,6 +62,8 @@ class EINTRBaseTest(unittest.TestCase):
def tearDownClass(cls):
cls.stop_alarm()
signal.signal(signal.SIGALRM, cls.orig_handler)
+ if hasattr(faulthandler, 'cancel_dump_traceback_later'):
+ faulthandler.cancel_dump_traceback_later()
def subprocess(self, *args, **kw):
cmd_args = (sys.executable, '-c') + args
diff --git a/Lib/test/libregrtest/__init__.py b/Lib/test/libregrtest/__init__.py
new file mode 100644
index 0000000000..7ba0e6e535
--- /dev/null
+++ b/Lib/test/libregrtest/__init__.py
@@ -0,0 +1,5 @@
+# We import importlib *ASAP* in order to test #15386
+import importlib
+
+from test.libregrtest.cmdline import _parse_args, RESOURCE_NAMES
+from test.libregrtest.main import main
diff --git a/Lib/test/libregrtest/cmdline.py b/Lib/test/libregrtest/cmdline.py
new file mode 100644
index 0000000000..de09a0122a
--- /dev/null
+++ b/Lib/test/libregrtest/cmdline.py
@@ -0,0 +1,342 @@
+import argparse
+import os
+import sys
+from test import support
+
+
+USAGE = """\
+python -m test [options] [test_name1 [test_name2 ...]]
+python path/to/Lib/test/regrtest.py [options] [test_name1 [test_name2 ...]]
+"""
+
+DESCRIPTION = """\
+Run Python regression tests.
+
+If no arguments or options are provided, finds all files matching
+the pattern "test_*" in the Lib/test subdirectory and runs
+them in alphabetical order (but see -M and -u, below, for exceptions).
+
+For more rigorous testing, it is useful to use the following
+command line:
+
+python -E -Wd -m test [options] [test_name1 ...]
+"""
+
+EPILOG = """\
+Additional option details:
+
+-r randomizes test execution order. You can use --randseed=int to provide an
+int seed value for the randomizer; this is useful for reproducing troublesome
+test orders.
+
+-s On the first invocation of regrtest using -s, the first test file found
+or the first test file given on the command line is run, and the name of
+the next test is recorded in a file named pynexttest. If run from the
+Python build directory, pynexttest is located in the 'build' subdirectory,
+otherwise it is located in tempfile.gettempdir(). On subsequent runs,
+the test in pynexttest is run, and the next test is written to pynexttest.
+When the last test has been run, pynexttest is deleted. In this way it
+is possible to single step through the test files. This is useful when
+doing memory analysis on the Python interpreter, which process tends to
+consume too many resources to run the full regression test non-stop.
+
+-S is used to continue running tests after an aborted run. It will
+maintain the order a standard run (ie, this assumes -r is not used).
+This is useful after the tests have prematurely stopped for some external
+reason and you want to start running from where you left off rather
+than starting from the beginning.
+
+-f reads the names of tests from the file given as f's argument, one
+or more test names per line. Whitespace is ignored. Blank lines and
+lines beginning with '#' are ignored. This is especially useful for
+whittling down failures involving interactions among tests.
+
+-L causes the leaks(1) command to be run just before exit if it exists.
+leaks(1) is available on Mac OS X and presumably on some other
+FreeBSD-derived systems.
+
+-R runs each test several times and examines sys.gettotalrefcount() to
+see if the test appears to be leaking references. The argument should
+be of the form stab:run:fname where 'stab' is the number of times the
+test is run to let gettotalrefcount settle down, 'run' is the number
+of times further it is run and 'fname' is the name of the file the
+reports are written to. These parameters all have defaults (5, 4 and
+"reflog.txt" respectively), and the minimal invocation is '-R :'.
+
+-M runs tests that require an exorbitant amount of memory. These tests
+typically try to ascertain containers keep working when containing more than
+2 billion objects, which only works on 64-bit systems. There are also some
+tests that try to exhaust the address space of the process, which only makes
+sense on 32-bit systems with at least 2Gb of memory. The passed-in memlimit,
+which is a string in the form of '2.5Gb', determines howmuch memory the
+tests will limit themselves to (but they may go slightly over.) The number
+shouldn't be more memory than the machine has (including swap memory). You
+should also keep in mind that swap memory is generally much, much slower
+than RAM, and setting memlimit to all available RAM or higher will heavily
+tax the machine. On the other hand, it is no use running these tests with a
+limit of less than 2.5Gb, and many require more than 20Gb. Tests that expect
+to use more than memlimit memory will be skipped. The big-memory tests
+generally run very, very long.
+
+-u is used to specify which special resource intensive tests to run,
+such as those requiring large file support or network connectivity.
+The argument is a comma-separated list of words indicating the
+resources to test. Currently only the following are defined:
+
+ all - Enable all special resources.
+
+ none - Disable all special resources (this is the default).
+
+ audio - Tests that use the audio device. (There are known
+ cases of broken audio drivers that can crash Python or
+ even the Linux kernel.)
+
+ curses - Tests that use curses and will modify the terminal's
+ state and output modes.
+
+ largefile - It is okay to run some test that may create huge
+ files. These tests can take a long time and may
+ consume >2GB of disk space temporarily.
+
+ network - It is okay to run tests that use external network
+ resource, e.g. testing SSL support for sockets.
+
+ decimal - Test the decimal module against a large suite that
+ verifies compliance with standards.
+
+ cpu - Used for certain CPU-heavy tests.
+
+ subprocess Run all tests for the subprocess module.
+
+ urlfetch - It is okay to download files required on testing.
+
+ gui - Run tests that require a running GUI.
+
+To enable all resources except one, use '-uall,-<resource>'. For
+example, to run all the tests except for the gui tests, give the
+option '-uall,-gui'.
+"""
+
+
+RESOURCE_NAMES = ('audio', 'curses', 'largefile', 'network',
+ 'decimal', 'cpu', 'subprocess', 'urlfetch', 'gui')
+
+class _ArgParser(argparse.ArgumentParser):
+
+ def error(self, message):
+ super().error(message + "\nPass -h or --help for complete help.")
+
+
+def _create_parser():
+ # Set prog to prevent the uninformative "__main__.py" from displaying in
+ # error messages when using "python -m test ...".
+ parser = _ArgParser(prog='regrtest.py',
+ usage=USAGE,
+ description=DESCRIPTION,
+ epilog=EPILOG,
+ add_help=False,
+ formatter_class=argparse.RawDescriptionHelpFormatter)
+
+ # Arguments with this clause added to its help are described further in
+ # the epilog's "Additional option details" section.
+ more_details = ' See the section at bottom for more details.'
+
+ group = parser.add_argument_group('General options')
+ # We add help explicitly to control what argument group it renders under.
+ group.add_argument('-h', '--help', action='help',
+ help='show this help message and exit')
+ group.add_argument('--timeout', metavar='TIMEOUT', type=float,
+ help='dump the traceback and exit if a test takes '
+ 'more than TIMEOUT seconds; disabled if TIMEOUT '
+ 'is negative or equals to zero')
+ group.add_argument('--wait', action='store_true',
+ help='wait for user input, e.g., allow a debugger '
+ 'to be attached')
+ group.add_argument('--slaveargs', metavar='ARGS')
+ group.add_argument('-S', '--start', metavar='START',
+ help='the name of the test at which to start.' +
+ more_details)
+
+ group = parser.add_argument_group('Verbosity')
+ group.add_argument('-v', '--verbose', action='count',
+ help='run tests in verbose mode with output to stdout')
+ group.add_argument('-w', '--verbose2', action='store_true',
+ help='re-run failed tests in verbose mode')
+ group.add_argument('-W', '--verbose3', action='store_true',
+ help='display test output on failure')
+ group.add_argument('-q', '--quiet', action='store_true',
+ help='no output unless one or more tests fail')
+ group.add_argument('-o', '--slow', action='store_true', dest='print_slow',
+ help='print the slowest 10 tests')
+ group.add_argument('--header', action='store_true',
+ help='print header with interpreter info')
+
+ group = parser.add_argument_group('Selecting tests')
+ group.add_argument('-r', '--randomize', action='store_true',
+ help='randomize test execution order.' + more_details)
+ group.add_argument('--randseed', metavar='SEED',
+ dest='random_seed', type=int,
+ help='pass a random seed to reproduce a previous '
+ 'random run')
+ group.add_argument('-f', '--fromfile', metavar='FILE',
+ help='read names of tests to run from a file.' +
+ more_details)
+ group.add_argument('-x', '--exclude', action='store_true',
+ help='arguments are tests to *exclude*')
+ group.add_argument('-s', '--single', action='store_true',
+ help='single step through a set of tests.' +
+ more_details)
+ group.add_argument('-m', '--match', metavar='PAT',
+ dest='match_tests',
+ help='match test cases and methods with glob pattern PAT')
+ group.add_argument('-G', '--failfast', action='store_true',
+ help='fail as soon as a test fails (only with -v or -W)')
+ group.add_argument('-u', '--use', metavar='RES1,RES2,...',
+ action='append', type=resources_list,
+ help='specify which special resource intensive tests '
+ 'to run.' + more_details)
+ group.add_argument('-M', '--memlimit', metavar='LIMIT',
+ help='run very large memory-consuming tests.' +
+ more_details)
+ group.add_argument('--testdir', metavar='DIR',
+ type=relative_filename,
+ help='execute test files in the specified directory '
+ '(instead of the Python stdlib test suite)')
+
+ group = parser.add_argument_group('Special runs')
+ group.add_argument('-l', '--findleaks', action='store_true',
+ help='if GC is available detect tests that leak memory')
+ group.add_argument('-L', '--runleaks', action='store_true',
+ help='run the leaks(1) command just before exit.' +
+ more_details)
+ group.add_argument('-R', '--huntrleaks', metavar='RUNCOUNTS',
+ type=huntrleaks,
+ help='search for reference leaks (needs debug build, '
+ 'very slow).' + more_details)
+ group.add_argument('-j', '--multiprocess', metavar='PROCESSES',
+ dest='use_mp', type=int,
+ help='run PROCESSES processes at once')
+ group.add_argument('-T', '--coverage', action='store_true',
+ dest='trace',
+ help='turn on code coverage tracing using the trace '
+ 'module')
+ group.add_argument('-D', '--coverdir', metavar='DIR',
+ type=relative_filename,
+ help='directory where coverage files are put')
+ group.add_argument('-N', '--nocoverdir',
+ action='store_const', const=None, dest='coverdir',
+ help='put coverage files alongside modules')
+ group.add_argument('-t', '--threshold', metavar='THRESHOLD',
+ type=int,
+ help='call gc.set_threshold(THRESHOLD)')
+ group.add_argument('-n', '--nowindows', action='store_true',
+ help='suppress error message boxes on Windows')
+ group.add_argument('-F', '--forever', action='store_true',
+ help='run the specified tests in a loop, until an '
+ 'error happens')
+ group.add_argument('--list-tests', action='store_true',
+ help="only write the name of tests that will be run, "
+ "don't execute them")
+ group.add_argument('-P', '--pgo', dest='pgo', action='store_true',
+ help='enable Profile Guided Optimization training')
+
+ parser.add_argument('args', nargs=argparse.REMAINDER,
+ help=argparse.SUPPRESS)
+
+ return parser
+
+
+def relative_filename(string):
+ # CWD is replaced with a temporary dir before calling main(), so we
+ # join it with the saved CWD so it ends up where the user expects.
+ return os.path.join(support.SAVEDCWD, string)
+
+
+def huntrleaks(string):
+ args = string.split(':')
+ if len(args) not in (2, 3):
+ raise argparse.ArgumentTypeError(
+ 'needs 2 or 3 colon-separated arguments')
+ nwarmup = int(args[0]) if args[0] else 5
+ ntracked = int(args[1]) if args[1] else 4
+ fname = args[2] if len(args) > 2 and args[2] else 'reflog.txt'
+ return nwarmup, ntracked, fname
+
+
+def resources_list(string):
+ u = [x.lower() for x in string.split(',')]
+ for r in u:
+ if r == 'all' or r == 'none':
+ continue
+ if r[0] == '-':
+ r = r[1:]
+ if r not in RESOURCE_NAMES:
+ raise argparse.ArgumentTypeError('invalid resource: ' + r)
+ return u
+
+
+def _parse_args(args, **kwargs):
+ # Defaults
+ ns = argparse.Namespace(testdir=None, verbose=0, quiet=False,
+ exclude=False, single=False, randomize=False, fromfile=None,
+ findleaks=False, use_resources=None, trace=False, coverdir='coverage',
+ runleaks=False, huntrleaks=False, verbose2=False, print_slow=False,
+ random_seed=None, use_mp=None, verbose3=False, forever=False,
+ header=False, failfast=False, match_tests=None, pgo=False)
+ for k, v in kwargs.items():
+ if not hasattr(ns, k):
+ raise TypeError('%r is an invalid keyword argument '
+ 'for this function' % k)
+ setattr(ns, k, v)
+ if ns.use_resources is None:
+ ns.use_resources = []
+
+ parser = _create_parser()
+ parser.parse_args(args=args, namespace=ns)
+
+ if ns.single and ns.fromfile:
+ parser.error("-s and -f don't go together!")
+ if ns.use_mp and ns.trace:
+ parser.error("-T and -j don't go together!")
+ if ns.use_mp and ns.findleaks:
+ parser.error("-l and -j don't go together!")
+ if ns.failfast and not (ns.verbose or ns.verbose3):
+ parser.error("-G/--failfast needs either -v or -W")
+ if ns.pgo and (ns.verbose or ns.verbose2 or ns.verbose3):
+ parser.error("--pgo/-v don't go together!")
+
+ if ns.nowindows:
+ print("Warning: the --nowindows (-n) option is deprecated. "
+ "Use -vv to display assertions in stderr.", file=sys.stderr)
+
+ if ns.quiet:
+ ns.verbose = 0
+ if ns.timeout is not None:
+ if ns.timeout <= 0:
+ ns.timeout = None
+ if ns.use_mp is not None:
+ if ns.use_mp <= 0:
+ # Use all cores + extras for tests that like to sleep
+ ns.use_mp = 2 + (os.cpu_count() or 1)
+ if ns.use:
+ for a in ns.use:
+ for r in a:
+ if r == 'all':
+ ns.use_resources[:] = RESOURCE_NAMES
+ continue
+ if r == 'none':
+ del ns.use_resources[:]
+ continue
+ remove = False
+ if r[0] == '-':
+ remove = True
+ r = r[1:]
+ if remove:
+ if r in ns.use_resources:
+ ns.use_resources.remove(r)
+ elif r not in ns.use_resources:
+ ns.use_resources.append(r)
+ if ns.random_seed is not None:
+ ns.randomize = True
+
+ return ns
diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py
new file mode 100644
index 0000000000..e503c131ac
--- /dev/null
+++ b/Lib/test/libregrtest/main.py
@@ -0,0 +1,508 @@
+import datetime
+import faulthandler
+import math
+import os
+import platform
+import random
+import re
+import sys
+import sysconfig
+import tempfile
+import textwrap
+import time
+from test.libregrtest.cmdline import _parse_args
+from test.libregrtest.runtest import (
+ findtests, runtest,
+ STDTESTS, NOTTESTS, PASSED, FAILED, ENV_CHANGED, SKIPPED, RESOURCE_DENIED,
+ INTERRUPTED, CHILD_ERROR,
+ PROGRESS_MIN_TIME, format_test_result)
+from test.libregrtest.setup import setup_tests
+from test import support
+try:
+ import gc
+except ImportError:
+ gc = None
+
+
+# When tests are run from the Python build directory, it is best practice
+# to keep the test files in a subfolder. This eases the cleanup of leftover
+# files using the "make distclean" command.
+if sysconfig.is_python_build():
+ TEMPDIR = os.path.join(sysconfig.get_config_var('srcdir'), 'build')
+else:
+ TEMPDIR = tempfile.gettempdir()
+TEMPDIR = os.path.abspath(TEMPDIR)
+
+
+class Regrtest:
+ """Execute a test suite.
+
+ This also parses command-line options and modifies its behavior
+ accordingly.
+
+ tests -- a list of strings containing test names (optional)
+ testdir -- the directory in which to look for tests (optional)
+
+ Users other than the Python test suite will certainly want to
+ specify testdir; if it's omitted, the directory containing the
+ Python test suite is searched for.
+
+ If the tests argument is omitted, the tests listed on the
+ command-line will be used. If that's empty, too, then all *.py
+ files beginning with test_ will be used.
+
+ The other default arguments (verbose, quiet, exclude,
+ single, randomize, findleaks, use_resources, trace, coverdir,
+ print_slow, and random_seed) allow programmers calling main()
+ directly to set the values that would normally be set by flags
+ on the command line.
+ """
+ def __init__(self):
+ # Namespace of command line options
+ self.ns = None
+
+ # tests
+ self.tests = []
+ self.selected = []
+
+ # test results
+ self.good = []
+ self.bad = []
+ self.skipped = []
+ self.resource_denieds = []
+ self.environment_changed = []
+ self.interrupted = False
+
+ # used by --slow
+ self.test_times = []
+
+ # used by --coverage, trace.Trace instance
+ self.tracer = None
+
+ # used by --findleaks, store for gc.garbage
+ self.found_garbage = []
+
+ # used to display the progress bar "[ 3/100]"
+ self.start_time = time.monotonic()
+ self.test_count = ''
+ self.test_count_width = 1
+
+ # used by --single
+ self.next_single_test = None
+ self.next_single_filename = None
+
+ def accumulate_result(self, test, result):
+ ok, test_time = result
+ if ok not in (CHILD_ERROR, INTERRUPTED):
+ self.test_times.append((test_time, test))
+ if ok == PASSED:
+ self.good.append(test)
+ elif ok == FAILED:
+ self.bad.append(test)
+ elif ok == ENV_CHANGED:
+ self.environment_changed.append(test)
+ elif ok == SKIPPED:
+ self.skipped.append(test)
+ elif ok == RESOURCE_DENIED:
+ self.skipped.append(test)
+ self.resource_denieds.append(test)
+
+ def time_delta(self, ceil=False):
+ seconds = time.monotonic() - self.start_time
+ if ceil:
+ seconds = math.ceil(seconds)
+ else:
+ seconds = int(seconds)
+ return datetime.timedelta(seconds=seconds)
+
+ def display_progress(self, test_index, test):
+ if self.ns.quiet:
+ return
+ if self.bad and not self.ns.pgo:
+ fmt = "{time} [{test_index:{count_width}}{test_count}/{nbad}] {test_name}"
+ else:
+ fmt = "{time} [{test_index:{count_width}}{test_count}] {test_name}"
+ line = fmt.format(count_width=self.test_count_width,
+ test_index=test_index,
+ test_count=self.test_count,
+ nbad=len(self.bad),
+ test_name=test,
+ time=self.time_delta())
+ print(line, flush=True)
+
+ def parse_args(self, kwargs):
+ ns = _parse_args(sys.argv[1:], **kwargs)
+
+ if ns.timeout and not hasattr(faulthandler, 'dump_traceback_later'):
+ print("Warning: The timeout option requires "
+ "faulthandler.dump_traceback_later", file=sys.stderr)
+ ns.timeout = None
+
+ if ns.threshold is not None and gc is None:
+ print('No GC available, ignore --threshold.', file=sys.stderr)
+ ns.threshold = None
+
+ if ns.findleaks:
+ if gc is not None:
+ # Uncomment the line below to report garbage that is not
+ # freeable by reference counting alone. By default only
+ # garbage that is not collectable by the GC is reported.
+ pass
+ #gc.set_debug(gc.DEBUG_SAVEALL)
+ else:
+ print('No GC available, disabling --findleaks',
+ file=sys.stderr)
+ ns.findleaks = False
+
+ # Strip .py extensions.
+ removepy(ns.args)
+
+ return ns
+
+ def find_tests(self, tests):
+ self.tests = tests
+
+ if self.ns.single:
+ self.next_single_filename = os.path.join(TEMPDIR, 'pynexttest')
+ try:
+ with open(self.next_single_filename, 'r') as fp:
+ next_test = fp.read().strip()
+ self.tests = [next_test]
+ except OSError:
+ pass
+
+ if self.ns.fromfile:
+ self.tests = []
+ # regex to match 'test_builtin' in line:
+ # '0:00:00 [ 4/400] test_builtin -- test_dict took 1 sec'
+ regex = (r'^(?:[0-9]+:[0-9]+:[0-9]+ *)?'
+ r'(?:\[[0-9/ ]+\] *)?'
+ r'(test_[a-zA-Z0-9_]+)')
+ regex = re.compile(regex)
+ with open(os.path.join(support.SAVEDCWD, self.ns.fromfile)) as fp:
+ for line in fp:
+ line = line.strip()
+ if line.startswith('#'):
+ continue
+ match = regex.match(line)
+ if match is None:
+ continue
+ self.tests.append(match.group(1))
+
+ removepy(self.tests)
+
+ stdtests = STDTESTS[:]
+ nottests = NOTTESTS.copy()
+ if self.ns.exclude:
+ for arg in self.ns.args:
+ if arg in stdtests:
+ stdtests.remove(arg)
+ nottests.add(arg)
+ self.ns.args = []
+
+ # if testdir is set, then we are not running the python tests suite, so
+ # don't add default tests to be executed or skipped (pass empty values)
+ if self.ns.testdir:
+ alltests = findtests(self.ns.testdir, list(), set())
+ else:
+ alltests = findtests(self.ns.testdir, stdtests, nottests)
+
+ if not self.ns.fromfile:
+ self.selected = self.tests or self.ns.args or alltests
+ else:
+ self.selected = self.tests
+ if self.ns.single:
+ self.selected = self.selected[:1]
+ try:
+ pos = alltests.index(self.selected[0])
+ self.next_single_test = alltests[pos + 1]
+ except IndexError:
+ pass
+
+ # Remove all the selected tests that precede start if it's set.
+ if self.ns.start:
+ try:
+ del self.selected[:self.selected.index(self.ns.start)]
+ except ValueError:
+ print("Couldn't find starting test (%s), using all tests"
+ % self.ns.start, file=sys.stderr)
+
+ if self.ns.randomize:
+ if self.ns.random_seed is None:
+ self.ns.random_seed = random.randrange(10000000)
+ random.seed(self.ns.random_seed)
+ random.shuffle(self.selected)
+
+ def list_tests(self):
+ for name in self.selected:
+ print(name)
+
+ def rerun_failed_tests(self):
+ self.ns.verbose = True
+ self.ns.failfast = False
+ self.ns.verbose3 = False
+ self.ns.match_tests = None
+
+ print("Re-running failed tests in verbose mode")
+ for test in self.bad[:]:
+ print("Re-running test %r in verbose mode" % test, flush=True)
+ try:
+ self.ns.verbose = True
+ ok = runtest(self.ns, test)
+ except KeyboardInterrupt:
+ # print a newline separate from the ^C
+ print()
+ break
+ else:
+ if ok[0] in {PASSED, ENV_CHANGED, SKIPPED, RESOURCE_DENIED}:
+ self.bad.remove(test)
+ else:
+ if self.bad:
+ print(count(len(self.bad), 'test'), "failed again:")
+ printlist(self.bad)
+
+ def display_result(self):
+ if self.interrupted:
+ # print a newline after ^C
+ print()
+ print("Test suite interrupted by signal SIGINT.")
+ executed = set(self.good) | set(self.bad) | set(self.skipped)
+ omitted = set(self.selected) - executed
+ print(count(len(omitted), "test"), "omitted:")
+ printlist(omitted)
+
+ # If running the test suite for PGO then no one cares about
+ # results.
+ if self.ns.pgo:
+ return
+
+ if self.good and not self.ns.quiet:
+ if (not self.bad
+ and not self.skipped
+ and not self.interrupted
+ and len(self.good) > 1):
+ print("All", end=' ')
+ print(count(len(self.good), "test"), "OK.")
+
+ if self.ns.print_slow:
+ self.test_times.sort(reverse=True)
+ print("10 slowest tests:")
+ for time, test in self.test_times[:10]:
+ print("%s: %.1fs" % (test, time))
+
+ if self.bad:
+ print(count(len(self.bad), "test"), "failed:")
+ printlist(self.bad)
+
+ if self.environment_changed:
+ print("{} altered the execution environment:".format(
+ count(len(self.environment_changed), "test")))
+ printlist(self.environment_changed)
+
+ if self.skipped and not self.ns.quiet:
+ print(count(len(self.skipped), "test"), "skipped:")
+ printlist(self.skipped)
+
+ def run_tests_sequential(self):
+ if self.ns.trace:
+ import trace
+ self.tracer = trace.Trace(trace=False, count=True)
+
+ save_modules = sys.modules.keys()
+
+ print("Run tests sequentially")
+
+ previous_test = None
+ for test_index, test in enumerate(self.tests, 1):
+ start_time = time.monotonic()
+
+ text = test
+ if previous_test:
+ text = '%s -- %s' % (text, previous_test)
+ self.display_progress(test_index, text)
+
+ if self.tracer:
+ # If we're tracing code coverage, then we don't exit with status
+ # if on a false return value from main.
+ cmd = ('result = runtest(self.ns, test); '
+ 'self.accumulate_result(test, result)')
+ ns = dict(locals())
+ self.tracer.runctx(cmd, globals=globals(), locals=ns)
+ result = ns['result']
+ else:
+ try:
+ result = runtest(self.ns, test)
+ except KeyboardInterrupt:
+ self.accumulate_result(test, (INTERRUPTED, None))
+ self.interrupted = True
+ break
+ else:
+ self.accumulate_result(test, result)
+
+ previous_test = format_test_result(test, result[0])
+ test_time = time.monotonic() - start_time
+ if test_time >= PROGRESS_MIN_TIME:
+ previous_test = "%s in %.0f sec" % (previous_test, test_time)
+ elif result[0] == PASSED:
+ # be quiet: say nothing if the test passed shortly
+ previous_test = None
+
+ if self.ns.findleaks:
+ gc.collect()
+ if gc.garbage:
+ print("Warning: test created", len(gc.garbage), end=' ')
+ print("uncollectable object(s).")
+ # move the uncollectable objects somewhere so we don't see
+ # them again
+ self.found_garbage.extend(gc.garbage)
+ del gc.garbage[:]
+
+ # Unload the newly imported modules (best effort finalization)
+ for module in sys.modules.keys():
+ if module not in save_modules and module.startswith("test."):
+ support.unload(module)
+
+ if previous_test:
+ print(previous_test)
+
+ def _test_forever(self, tests):
+ while True:
+ for test in tests:
+ yield test
+ if self.bad:
+ return
+
+ def run_tests(self):
+ # For a partial run, we do not need to clutter the output.
+ if (self.ns.verbose
+ or self.ns.header
+ or not (self.ns.pgo or self.ns.quiet or self.ns.single
+ or self.tests or self.ns.args)):
+ # Print basic platform information
+ print("==", platform.python_implementation(), *sys.version.split())
+ print("== ", platform.platform(aliased=True),
+ "%s-endian" % sys.byteorder)
+ print("== ", "hash algorithm:", sys.hash_info.algorithm,
+ "64bit" if sys.maxsize > 2**32 else "32bit")
+ print("== ", os.getcwd())
+ print("Testing with flags:", sys.flags)
+
+ if self.ns.randomize:
+ print("Using random seed", self.ns.random_seed)
+
+ if self.ns.forever:
+ self.tests = self._test_forever(list(self.selected))
+ self.test_count = ''
+ self.test_count_width = 3
+ else:
+ self.tests = iter(self.selected)
+ self.test_count = '/{}'.format(len(self.selected))
+ self.test_count_width = len(self.test_count) - 1
+
+ if self.ns.use_mp:
+ from test.libregrtest.runtest_mp import run_tests_multiprocess
+ run_tests_multiprocess(self)
+ else:
+ self.run_tests_sequential()
+
+ def finalize(self):
+ if self.next_single_filename:
+ if self.next_single_test:
+ with open(self.next_single_filename, 'w') as fp:
+ fp.write(self.next_single_test + '\n')
+ else:
+ os.unlink(self.next_single_filename)
+
+ if self.tracer:
+ r = self.tracer.results()
+ r.write_results(show_missing=True, summary=True,
+ coverdir=self.ns.coverdir)
+
+ print("Total duration: %s" % self.time_delta(ceil=True))
+
+ if self.ns.runleaks:
+ os.system("leaks %d" % os.getpid())
+
+ def main(self, tests=None, **kwargs):
+ global TEMPDIR
+
+ if sysconfig.is_python_build():
+ try:
+ os.mkdir(TEMPDIR)
+ except FileExistsError:
+ pass
+
+ # Define a writable temp dir that will be used as cwd while running
+ # the tests. The name of the dir includes the pid to allow parallel
+ # testing (see the -j option).
+ test_cwd = 'test_python_{}'.format(os.getpid())
+ test_cwd = os.path.join(TEMPDIR, test_cwd)
+
+ # Run the tests in a context manager that temporarily changes the CWD to a
+ # temporary and writable directory. If it's not possible to create or
+ # change the CWD, the original CWD will be used. The original CWD is
+ # available from support.SAVEDCWD.
+ with support.temp_cwd(test_cwd, quiet=True):
+ self._main(tests, kwargs)
+
+ def _main(self, tests, kwargs):
+ self.ns = self.parse_args(kwargs)
+
+ if self.ns.slaveargs is not None:
+ from test.libregrtest.runtest_mp import run_tests_slave
+ run_tests_slave(self.ns.slaveargs)
+
+ if self.ns.wait:
+ input("Press any key to continue...")
+
+ setup_tests(self.ns)
+
+ self.find_tests(tests)
+
+ if self.ns.list_tests:
+ self.list_tests()
+ sys.exit(0)
+
+ self.run_tests()
+ self.display_result()
+
+ if self.ns.verbose2 and self.bad:
+ self.rerun_failed_tests()
+
+ self.finalize()
+ sys.exit(len(self.bad) > 0 or self.interrupted)
+
+
+def removepy(names):
+ if not names:
+ return
+ for idx, name in enumerate(names):
+ basename, ext = os.path.splitext(name)
+ if ext == '.py':
+ names[idx] = basename
+
+
+def count(n, word):
+ if n == 1:
+ return "%d %s" % (n, word)
+ else:
+ return "%d %ss" % (n, word)
+
+
+def printlist(x, width=70, indent=4):
+ """Print the elements of iterable x to stdout.
+
+ Optional arg width (default 70) is the maximum line length.
+ Optional arg indent (default 4) is the number of blanks with which to
+ begin each line.
+ """
+
+ blanks = ' ' * indent
+ # Print the sorted list: 'x' may be a '--random' list or a set()
+ print(textwrap.fill(' '.join(str(elt) for elt in sorted(x)), width,
+ initial_indent=blanks, subsequent_indent=blanks))
+
+
+def main(tests=None, **kwargs):
+ """Run the Python suite."""
+ Regrtest().main(tests=tests, **kwargs)
diff --git a/Lib/test/libregrtest/refleak.py b/Lib/test/libregrtest/refleak.py
new file mode 100644
index 0000000000..59dc49fe77
--- /dev/null
+++ b/Lib/test/libregrtest/refleak.py
@@ -0,0 +1,202 @@
+import errno
+import os
+import re
+import sys
+import warnings
+from inspect import isabstract
+from test import support
+
+
+try:
+ MAXFD = os.sysconf("SC_OPEN_MAX")
+except Exception:
+ MAXFD = 256
+
+
+def fd_count():
+ """Count the number of open file descriptors"""
+ if sys.platform.startswith(('linux', 'freebsd')):
+ try:
+ names = os.listdir("/proc/self/fd")
+ return len(names)
+ except FileNotFoundError:
+ pass
+
+ count = 0
+ for fd in range(MAXFD):
+ try:
+ # Prefer dup() over fstat(). fstat() can require input/output
+ # whereas dup() doesn't.
+ fd2 = os.dup(fd)
+ except OSError as e:
+ if e.errno != errno.EBADF:
+ raise
+ else:
+ os.close(fd2)
+ count += 1
+ return count
+
+
+def dash_R(the_module, test, indirect_test, huntrleaks):
+ """Run a test multiple times, looking for reference leaks.
+
+ Returns:
+ False if the test didn't leak references; True if we detected refleaks.
+ """
+ # This code is hackish and inelegant, but it seems to do the job.
+ import copyreg
+ import collections.abc
+
+ if not hasattr(sys, 'gettotalrefcount'):
+ raise Exception("Tracking reference leaks requires a debug build "
+ "of Python")
+
+ # Save current values for dash_R_cleanup() to restore.
+ fs = warnings.filters[:]
+ ps = copyreg.dispatch_table.copy()
+ pic = sys.path_importer_cache.copy()
+ try:
+ import zipimport
+ except ImportError:
+ zdc = None # Run unmodified on platforms without zipimport support
+ else:
+ zdc = zipimport._zip_directory_cache.copy()
+ abcs = {}
+ for abc in [getattr(collections.abc, a) for a in collections.abc.__all__]:
+ if not isabstract(abc):
+ continue
+ for obj in abc.__subclasses__() + [abc]:
+ abcs[obj] = obj._abc_registry.copy()
+
+ nwarmup, ntracked, fname = huntrleaks
+ fname = os.path.join(support.SAVEDCWD, fname)
+ repcount = nwarmup + ntracked
+ rc_deltas = [0] * repcount
+ alloc_deltas = [0] * repcount
+ fd_deltas = [0] * repcount
+
+ print("beginning", repcount, "repetitions", file=sys.stderr)
+ print(("1234567890"*(repcount//10 + 1))[:repcount], file=sys.stderr,
+ flush=True)
+ # initialize variables to make pyflakes quiet
+ rc_before = alloc_before = fd_before = 0
+ for i in range(repcount):
+ indirect_test()
+ alloc_after, rc_after, fd_after = dash_R_cleanup(fs, ps, pic, zdc,
+ abcs)
+ print('.', end='', flush=True)
+ if i >= nwarmup:
+ rc_deltas[i] = rc_after - rc_before
+ alloc_deltas[i] = alloc_after - alloc_before
+ fd_deltas[i] = fd_after - fd_before
+ alloc_before = alloc_after
+ rc_before = rc_after
+ fd_before = fd_after
+ print(file=sys.stderr)
+ # These checkers return False on success, True on failure
+ def check_rc_deltas(deltas):
+ return any(deltas)
+ def check_alloc_deltas(deltas):
+ # At least 1/3rd of 0s
+ if 3 * deltas.count(0) < len(deltas):
+ return True
+ # Nothing else than 1s, 0s and -1s
+ if not set(deltas) <= {1,0,-1}:
+ return True
+ return False
+ failed = False
+ for deltas, item_name, checker in [
+ (rc_deltas, 'references', check_rc_deltas),
+ (alloc_deltas, 'memory blocks', check_alloc_deltas),
+ (fd_deltas, 'file descriptors', check_rc_deltas)]:
+ if checker(deltas):
+ msg = '%s leaked %s %s, sum=%s' % (
+ test, deltas[nwarmup:], item_name, sum(deltas))
+ print(msg, file=sys.stderr, flush=True)
+ with open(fname, "a") as refrep:
+ print(msg, file=refrep)
+ refrep.flush()
+ failed = True
+ return failed
+
+
+def dash_R_cleanup(fs, ps, pic, zdc, abcs):
+ import gc, copyreg
+ import _strptime, linecache
+ import urllib.parse, urllib.request, mimetypes, doctest
+ import struct, filecmp, collections.abc
+ from distutils.dir_util import _path_created
+ from weakref import WeakSet
+
+ # Clear the warnings registry, so they can be displayed again
+ for mod in sys.modules.values():
+ if hasattr(mod, '__warningregistry__'):
+ del mod.__warningregistry__
+
+ # Restore some original values.
+ warnings.filters[:] = fs
+ copyreg.dispatch_table.clear()
+ copyreg.dispatch_table.update(ps)
+ sys.path_importer_cache.clear()
+ sys.path_importer_cache.update(pic)
+ try:
+ import zipimport
+ except ImportError:
+ pass # Run unmodified on platforms without zipimport support
+ else:
+ zipimport._zip_directory_cache.clear()
+ zipimport._zip_directory_cache.update(zdc)
+
+ # clear type cache
+ sys._clear_type_cache()
+
+ # Clear ABC registries, restoring previously saved ABC registries.
+ for abc in [getattr(collections.abc, a) for a in collections.abc.__all__]:
+ if not isabstract(abc):
+ continue
+ for obj in abc.__subclasses__() + [abc]:
+ obj._abc_registry = abcs.get(obj, WeakSet()).copy()
+ obj._abc_cache.clear()
+ obj._abc_negative_cache.clear()
+
+ # Flush standard output, so that buffered data is sent to the OS and
+ # associated Python objects are reclaimed.
+ for stream in (sys.stdout, sys.stderr, sys.__stdout__, sys.__stderr__):
+ if stream is not None:
+ stream.flush()
+
+ # Clear assorted module caches.
+ _path_created.clear()
+ re.purge()
+ _strptime._regex_cache.clear()
+ urllib.parse.clear_cache()
+ urllib.request.urlcleanup()
+ linecache.clearcache()
+ mimetypes._default_mime_types()
+ filecmp._cache.clear()
+ struct._clearcache()
+ doctest.master = None
+ try:
+ import ctypes
+ except ImportError:
+ # Don't worry about resetting the cache if ctypes is not supported
+ pass
+ else:
+ ctypes._reset_cache()
+
+ # Collect cyclic trash and read memory statistics immediately after.
+ func1 = sys.getallocatedblocks
+ func2 = sys.gettotalrefcount
+ gc.collect()
+ return func1(), func2(), fd_count()
+
+
+def warm_caches():
+ # char cache
+ s = bytes(range(256))
+ for i in range(256):
+ s[i:i+1]
+ # unicode cache
+ [chr(i) for i in range(256)]
+ # int cache
+ list(range(-5, 257))
diff --git a/Lib/test/libregrtest/runtest.py b/Lib/test/libregrtest/runtest.py
new file mode 100644
index 0000000000..ef1feb738a
--- /dev/null
+++ b/Lib/test/libregrtest/runtest.py
@@ -0,0 +1,260 @@
+import faulthandler
+import importlib
+import io
+import os
+import sys
+import time
+import traceback
+import unittest
+from test import support
+from test.libregrtest.refleak import dash_R
+from test.libregrtest.save_env import saved_test_environment
+
+
+# Test result constants.
+PASSED = 1
+FAILED = 0
+ENV_CHANGED = -1
+SKIPPED = -2
+RESOURCE_DENIED = -3
+INTERRUPTED = -4
+CHILD_ERROR = -5 # error in a child process
+
+_FORMAT_TEST_RESULT = {
+ PASSED: '%s passed',
+ FAILED: '%s failed',
+ ENV_CHANGED: '%s failed (env changed)',
+ SKIPPED: '%s skipped',
+ RESOURCE_DENIED: '%s skipped (resource denied)',
+ INTERRUPTED: '%s interrupted',
+ CHILD_ERROR: '%s crashed',
+}
+
+# Minimum duration of a test to display its duration or to mention that
+# the test is running in background
+PROGRESS_MIN_TIME = 30.0 # seconds
+
+# small set of tests to determine if we have a basically functioning interpreter
+# (i.e. if any of these fail, then anything else is likely to follow)
+STDTESTS = [
+ 'test_grammar',
+ 'test_opcodes',
+ 'test_dict',
+ 'test_builtin',
+ 'test_exceptions',
+ 'test_types',
+ 'test_unittest',
+ 'test_doctest',
+ 'test_doctest2',
+ 'test_support'
+]
+
+# set of tests that we don't want to be executed when using regrtest
+NOTTESTS = set()
+
+
+def format_test_result(test_name, result):
+ fmt = _FORMAT_TEST_RESULT.get(result, "%s")
+ return fmt % test_name
+
+
+def findtests(testdir=None, stdtests=STDTESTS, nottests=NOTTESTS):
+ """Return a list of all applicable test modules."""
+ testdir = findtestdir(testdir)
+ names = os.listdir(testdir)
+ tests = []
+ others = set(stdtests) | nottests
+ for name in names:
+ mod, ext = os.path.splitext(name)
+ if mod[:5] == "test_" and ext in (".py", "") and mod not in others:
+ tests.append(mod)
+ return stdtests + sorted(tests)
+
+
+def runtest(ns, test):
+ """Run a single test.
+
+ test -- the name of the test
+ verbose -- if true, print more messages
+ quiet -- if true, don't print 'skipped' messages (probably redundant)
+ huntrleaks -- run multiple times to test for leaks; requires a debug
+ build; a triple corresponding to -R's three arguments
+ output_on_failure -- if true, display test output on failure
+ timeout -- dump the traceback and exit if a test takes more than
+ timeout seconds
+ failfast, match_tests -- See regrtest command-line flags for these.
+ pgo -- if true, suppress any info irrelevant to a generating a PGO build
+
+ Returns the tuple result, test_time, where result is one of the constants:
+ INTERRUPTED KeyboardInterrupt when run under -j
+ RESOURCE_DENIED test skipped because resource denied
+ SKIPPED test skipped for some other reason
+ ENV_CHANGED test failed because it changed the execution environment
+ FAILED test failed
+ PASSED test passed
+ """
+
+ verbose = ns.verbose
+ quiet = ns.quiet
+ huntrleaks = ns.huntrleaks
+ output_on_failure = ns.verbose3
+ failfast = ns.failfast
+ match_tests = ns.match_tests
+ timeout = ns.timeout
+ pgo = ns.pgo
+
+ use_timeout = (timeout is not None)
+ if use_timeout:
+ faulthandler.dump_traceback_later(timeout, exit=True)
+ try:
+ support.match_tests = match_tests
+ if failfast:
+ support.failfast = True
+ if output_on_failure:
+ support.verbose = True
+
+ # Reuse the same instance to all calls to runtest(). Some
+ # tests keep a reference to sys.stdout or sys.stderr
+ # (eg. test_argparse).
+ if runtest.stringio is None:
+ stream = io.StringIO()
+ runtest.stringio = stream
+ else:
+ stream = runtest.stringio
+ stream.seek(0)
+ stream.truncate()
+
+ orig_stdout = sys.stdout
+ orig_stderr = sys.stderr
+ try:
+ sys.stdout = stream
+ sys.stderr = stream
+ result = runtest_inner(ns, test, verbose, quiet, huntrleaks,
+ display_failure=False, pgo=pgo)
+ if result[0] == FAILED:
+ output = stream.getvalue()
+ orig_stderr.write(output)
+ orig_stderr.flush()
+ finally:
+ sys.stdout = orig_stdout
+ sys.stderr = orig_stderr
+ else:
+ support.verbose = verbose # Tell tests to be moderately quiet
+ result = runtest_inner(ns, test, verbose, quiet, huntrleaks,
+ display_failure=not verbose, pgo=pgo)
+ return result
+ finally:
+ if use_timeout:
+ faulthandler.cancel_dump_traceback_later()
+ cleanup_test_droppings(test, verbose)
+runtest.stringio = None
+
+
+def runtest_inner(ns, test, verbose, quiet,
+ huntrleaks=False, display_failure=True, *, pgo=False):
+ support.unload(test)
+
+ test_time = 0.0
+ refleak = False # True if the test leaked references.
+ try:
+ if test.startswith('test.') or ns.testdir:
+ abstest = test
+ else:
+ # Always import it from the test package
+ abstest = 'test.' + test
+ with saved_test_environment(test, verbose, quiet, pgo=pgo) as environment:
+ start_time = time.time()
+ the_module = importlib.import_module(abstest)
+ # If the test has a test_main, that will run the appropriate
+ # tests. If not, use normal unittest test loading.
+ test_runner = getattr(the_module, "test_main", None)
+ if test_runner is None:
+ def test_runner():
+ loader = unittest.TestLoader()
+ tests = loader.loadTestsFromModule(the_module)
+ for error in loader.errors:
+ print(error, file=sys.stderr)
+ if loader.errors:
+ raise Exception("errors while loading tests")
+ support.run_unittest(tests)
+ test_runner()
+ if huntrleaks:
+ refleak = dash_R(the_module, test, test_runner, huntrleaks)
+ test_time = time.time() - start_time
+ except support.ResourceDenied as msg:
+ if not quiet and not pgo:
+ print(test, "skipped --", msg, flush=True)
+ return RESOURCE_DENIED, test_time
+ except unittest.SkipTest as msg:
+ if not quiet and not pgo:
+ print(test, "skipped --", msg, flush=True)
+ return SKIPPED, test_time
+ except KeyboardInterrupt:
+ raise
+ except support.TestFailed as msg:
+ if not pgo:
+ if display_failure:
+ print("test", test, "failed --", msg, file=sys.stderr,
+ flush=True)
+ else:
+ print("test", test, "failed", file=sys.stderr, flush=True)
+ return FAILED, test_time
+ except:
+ msg = traceback.format_exc()
+ if not pgo:
+ print("test", test, "crashed --", msg, file=sys.stderr,
+ flush=True)
+ return FAILED, test_time
+ else:
+ if refleak:
+ return FAILED, test_time
+ if environment.changed:
+ return ENV_CHANGED, test_time
+ return PASSED, test_time
+
+
+def cleanup_test_droppings(testname, verbose):
+ import shutil
+ import stat
+ import gc
+
+ # First kill any dangling references to open files etc.
+ # This can also issue some ResourceWarnings which would otherwise get
+ # triggered during the following test run, and possibly produce failures.
+ gc.collect()
+
+ # Try to clean up junk commonly left behind. While tests shouldn't leave
+ # any files or directories behind, when a test fails that can be tedious
+ # for it to arrange. The consequences can be especially nasty on Windows,
+ # since if a test leaves a file open, it cannot be deleted by name (while
+ # there's nothing we can do about that here either, we can display the
+ # name of the offending test, which is a real help).
+ for name in (support.TESTFN,
+ "db_home",
+ ):
+ if not os.path.exists(name):
+ continue
+
+ if os.path.isdir(name):
+ kind, nuker = "directory", shutil.rmtree
+ elif os.path.isfile(name):
+ kind, nuker = "file", os.unlink
+ else:
+ raise SystemError("os.path says %r exists but is neither "
+ "directory nor file" % name)
+
+ if verbose:
+ print("%r left behind %s %r" % (testname, kind, name))
+ try:
+ # if we have chmod, fix possible permissions problems
+ # that might prevent cleanup
+ if (hasattr(os, 'chmod')):
+ os.chmod(name, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
+ nuker(name)
+ except Exception as msg:
+ print(("%r left behind %s %r and it couldn't be "
+ "removed: %s" % (testname, kind, name, msg)), file=sys.stderr)
+
+
+def findtestdir(path=None):
+ return path or os.path.dirname(os.path.dirname(__file__)) or os.curdir
diff --git a/Lib/test/libregrtest/runtest_mp.py b/Lib/test/libregrtest/runtest_mp.py
new file mode 100644
index 0000000000..9604c16600
--- /dev/null
+++ b/Lib/test/libregrtest/runtest_mp.py
@@ -0,0 +1,245 @@
+import faulthandler
+import json
+import os
+import queue
+import sys
+import time
+import traceback
+import types
+from test import support
+try:
+ import threading
+except ImportError:
+ print("Multiprocess option requires thread support")
+ sys.exit(2)
+
+from test.libregrtest.runtest import (
+ runtest, INTERRUPTED, CHILD_ERROR, PROGRESS_MIN_TIME,
+ format_test_result)
+from test.libregrtest.setup import setup_tests
+
+
+# Display the running tests if nothing happened last N seconds
+PROGRESS_UPDATE = 30.0 # seconds
+
+# If interrupted, display the wait progress every N seconds
+WAIT_PROGRESS = 2.0 # seconds
+
+
+def run_test_in_subprocess(testname, ns):
+ """Run the given test in a subprocess with --slaveargs.
+
+ ns is the option Namespace parsed from command-line arguments. regrtest
+ is invoked in a subprocess with the --slaveargs argument; when the
+ subprocess exits, its return code, stdout and stderr are returned as a
+ 3-tuple.
+ """
+ from subprocess import Popen, PIPE
+
+ ns_dict = vars(ns)
+ slaveargs = (ns_dict, testname)
+ slaveargs = json.dumps(slaveargs)
+
+ cmd = [sys.executable, *support.args_from_interpreter_flags(),
+ '-X', 'faulthandler',
+ '-m', 'test.regrtest',
+ '--slaveargs', slaveargs]
+ if ns.pgo:
+ cmd += ['--pgo']
+
+ # Running the child from the same working directory as regrtest's original
+ # invocation ensures that TEMPDIR for the child is the same when
+ # sysconfig.is_python_build() is true. See issue 15300.
+ popen = Popen(cmd,
+ stdout=PIPE, stderr=PIPE,
+ universal_newlines=True,
+ close_fds=(os.name != 'nt'),
+ cwd=support.SAVEDCWD)
+ with popen:
+ stdout, stderr = popen.communicate()
+ retcode = popen.wait()
+ return retcode, stdout, stderr
+
+
+def run_tests_slave(slaveargs):
+ ns_dict, testname = json.loads(slaveargs)
+ ns = types.SimpleNamespace(**ns_dict)
+
+ setup_tests(ns)
+
+ try:
+ result = runtest(ns, testname)
+ except KeyboardInterrupt:
+ result = INTERRUPTED, ''
+ except BaseException as e:
+ traceback.print_exc()
+ result = CHILD_ERROR, str(e)
+
+ print() # Force a newline (just in case)
+ print(json.dumps(result), flush=True)
+ sys.exit(0)
+
+
+# We do not use a generator so multiple threads can call next().
+class MultiprocessIterator:
+
+ """A thread-safe iterator over tests for multiprocess mode."""
+
+ def __init__(self, tests):
+ self.interrupted = False
+ self.lock = threading.Lock()
+ self.tests = tests
+
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ with self.lock:
+ if self.interrupted:
+ raise StopIteration('tests interrupted')
+ return next(self.tests)
+
+
+class MultiprocessThread(threading.Thread):
+ def __init__(self, pending, output, ns):
+ super().__init__()
+ self.pending = pending
+ self.output = output
+ self.ns = ns
+ self.current_test = None
+ self.start_time = None
+
+ def _runtest(self):
+ try:
+ test = next(self.pending)
+ except StopIteration:
+ self.output.put((None, None, None, None))
+ return True
+
+ try:
+ self.start_time = time.monotonic()
+ self.current_test = test
+
+ retcode, stdout, stderr = run_test_in_subprocess(test, self.ns)
+ finally:
+ self.current_test = None
+
+ stdout, _, result = stdout.strip().rpartition("\n")
+ if retcode != 0:
+ result = (CHILD_ERROR, "Exit code %s" % retcode)
+ self.output.put((test, stdout.rstrip(), stderr.rstrip(),
+ result))
+ return True
+
+ if not result:
+ self.output.put((None, None, None, None))
+ return True
+
+ result = json.loads(result)
+ self.output.put((test, stdout.rstrip(), stderr.rstrip(),
+ result))
+ return False
+
+ def run(self):
+ try:
+ stop = False
+ while not stop:
+ stop = self._runtest()
+ except BaseException:
+ self.output.put((None, None, None, None))
+ raise
+
+
+def run_tests_multiprocess(regrtest):
+ output = queue.Queue()
+ pending = MultiprocessIterator(regrtest.tests)
+ test_timeout = regrtest.ns.timeout
+ use_timeout = (test_timeout is not None)
+
+ workers = [MultiprocessThread(pending, output, regrtest.ns)
+ for i in range(regrtest.ns.use_mp)]
+ print("Run tests in parallel using %s child processes"
+ % len(workers))
+ for worker in workers:
+ worker.start()
+
+ def get_running(workers):
+ running = []
+ for worker in workers:
+ current_test = worker.current_test
+ if not current_test:
+ continue
+ dt = time.monotonic() - worker.start_time
+ if dt >= PROGRESS_MIN_TIME:
+ running.append('%s (%.0f sec)' % (current_test, dt))
+ return running
+
+ finished = 0
+ test_index = 1
+ get_timeout = max(PROGRESS_UPDATE, PROGRESS_MIN_TIME)
+ try:
+ while finished < regrtest.ns.use_mp:
+ if use_timeout:
+ faulthandler.dump_traceback_later(test_timeout, exit=True)
+
+ try:
+ item = output.get(timeout=get_timeout)
+ except queue.Empty:
+ running = get_running(workers)
+ if running and not regrtest.ns.pgo:
+ print('running: %s' % ', '.join(running))
+ continue
+
+ test, stdout, stderr, result = item
+ if test is None:
+ finished += 1
+ continue
+ regrtest.accumulate_result(test, result)
+
+ # Display progress
+ ok, test_time = result
+ text = format_test_result(test, ok)
+ if (ok not in (CHILD_ERROR, INTERRUPTED)
+ and test_time >= PROGRESS_MIN_TIME
+ and not regrtest.ns.pgo):
+ text += ' (%.0f sec)' % test_time
+ running = get_running(workers)
+ if running and not regrtest.ns.pgo:
+ text += ' -- running: %s' % ', '.join(running)
+ regrtest.display_progress(test_index, text)
+
+ # Copy stdout and stderr from the child process
+ if stdout:
+ print(stdout, flush=True)
+ if stderr and not regrtest.ns.pgo:
+ print(stderr, file=sys.stderr, flush=True)
+
+ if result[0] == INTERRUPTED:
+ raise KeyboardInterrupt
+ if result[0] == CHILD_ERROR:
+ msg = "Child error on {}: {}".format(test, result[1])
+ raise Exception(msg)
+ test_index += 1
+ except KeyboardInterrupt:
+ regrtest.interrupted = True
+ pending.interrupted = True
+ print()
+ finally:
+ if use_timeout:
+ faulthandler.cancel_dump_traceback_later()
+
+ # If tests are interrupted, wait until tests complete
+ wait_start = time.monotonic()
+ while True:
+ running = [worker.current_test for worker in workers]
+ running = list(filter(bool, running))
+ if not running:
+ break
+
+ dt = time.monotonic() - wait_start
+ line = "Waiting for %s (%s tests)" % (', '.join(running), len(running))
+ if dt >= WAIT_PROGRESS:
+ line = "%s since %.0f sec" % (line, dt)
+ print(line)
+ for worker in workers:
+ worker.join(WAIT_PROGRESS)
diff --git a/Lib/test/libregrtest/save_env.py b/Lib/test/libregrtest/save_env.py
new file mode 100644
index 0000000000..5bb9e19a91
--- /dev/null
+++ b/Lib/test/libregrtest/save_env.py
@@ -0,0 +1,286 @@
+import builtins
+import locale
+import logging
+import os
+import shutil
+import sys
+import sysconfig
+import warnings
+from test import support
+try:
+ import threading
+except ImportError:
+ threading = None
+try:
+ import _multiprocessing, multiprocessing.process
+except ImportError:
+ multiprocessing = None
+
+
+# Unit tests are supposed to leave the execution environment unchanged
+# once they complete. But sometimes tests have bugs, especially when
+# tests fail, and the changes to environment go on to mess up other
+# tests. This can cause issues with buildbot stability, since tests
+# are run in random order and so problems may appear to come and go.
+# There are a few things we can save and restore to mitigate this, and
+# the following context manager handles this task.
+
+class saved_test_environment:
+ """Save bits of the test environment and restore them at block exit.
+
+ with saved_test_environment(testname, verbose, quiet):
+ #stuff
+
+ Unless quiet is True, a warning is printed to stderr if any of
+ the saved items was changed by the test. The attribute 'changed'
+ is initially False, but is set to True if a change is detected.
+
+ If verbose is more than 1, the before and after state of changed
+ items is also printed.
+ """
+
+ changed = False
+
+ def __init__(self, testname, verbose=0, quiet=False, *, pgo=False):
+ self.testname = testname
+ self.verbose = verbose
+ self.quiet = quiet
+ self.pgo = pgo
+
+ # To add things to save and restore, add a name XXX to the resources list
+ # and add corresponding get_XXX/restore_XXX functions. get_XXX should
+ # return the value to be saved and compared against a second call to the
+ # get function when test execution completes. restore_XXX should accept
+ # the saved value and restore the resource using it. It will be called if
+ # and only if a change in the value is detected.
+ #
+ # Note: XXX will have any '.' replaced with '_' characters when determining
+ # the corresponding method names.
+
+ resources = ('sys.argv', 'cwd', 'sys.stdin', 'sys.stdout', 'sys.stderr',
+ 'os.environ', 'sys.path', 'sys.path_hooks', '__import__',
+ 'warnings.filters', 'asyncore.socket_map',
+ 'logging._handlers', 'logging._handlerList', 'sys.gettrace',
+ 'sys.warnoptions',
+ # multiprocessing.process._cleanup() may release ref
+ # to a thread, so check processes first.
+ 'multiprocessing.process._dangling', 'threading._dangling',
+ 'sysconfig._CONFIG_VARS', 'sysconfig._INSTALL_SCHEMES',
+ 'files', 'locale', 'warnings.showwarning',
+ 'shutil_archive_formats', 'shutil_unpack_formats',
+ )
+
+ def get_sys_argv(self):
+ return id(sys.argv), sys.argv, sys.argv[:]
+ def restore_sys_argv(self, saved_argv):
+ sys.argv = saved_argv[1]
+ sys.argv[:] = saved_argv[2]
+
+ def get_cwd(self):
+ return os.getcwd()
+ def restore_cwd(self, saved_cwd):
+ os.chdir(saved_cwd)
+
+ def get_sys_stdout(self):
+ return sys.stdout
+ def restore_sys_stdout(self, saved_stdout):
+ sys.stdout = saved_stdout
+
+ def get_sys_stderr(self):
+ return sys.stderr
+ def restore_sys_stderr(self, saved_stderr):
+ sys.stderr = saved_stderr
+
+ def get_sys_stdin(self):
+ return sys.stdin
+ def restore_sys_stdin(self, saved_stdin):
+ sys.stdin = saved_stdin
+
+ def get_os_environ(self):
+ return id(os.environ), os.environ, dict(os.environ)
+ def restore_os_environ(self, saved_environ):
+ os.environ = saved_environ[1]
+ os.environ.clear()
+ os.environ.update(saved_environ[2])
+
+ def get_sys_path(self):
+ return id(sys.path), sys.path, sys.path[:]
+ def restore_sys_path(self, saved_path):
+ sys.path = saved_path[1]
+ sys.path[:] = saved_path[2]
+
+ def get_sys_path_hooks(self):
+ return id(sys.path_hooks), sys.path_hooks, sys.path_hooks[:]
+ def restore_sys_path_hooks(self, saved_hooks):
+ sys.path_hooks = saved_hooks[1]
+ sys.path_hooks[:] = saved_hooks[2]
+
+ def get_sys_gettrace(self):
+ return sys.gettrace()
+ def restore_sys_gettrace(self, trace_fxn):
+ sys.settrace(trace_fxn)
+
+ def get___import__(self):
+ return builtins.__import__
+ def restore___import__(self, import_):
+ builtins.__import__ = import_
+
+ def get_warnings_filters(self):
+ return id(warnings.filters), warnings.filters, warnings.filters[:]
+ def restore_warnings_filters(self, saved_filters):
+ warnings.filters = saved_filters[1]
+ warnings.filters[:] = saved_filters[2]
+
+ def get_asyncore_socket_map(self):
+ asyncore = sys.modules.get('asyncore')
+ # XXX Making a copy keeps objects alive until __exit__ gets called.
+ return asyncore and asyncore.socket_map.copy() or {}
+ def restore_asyncore_socket_map(self, saved_map):
+ asyncore = sys.modules.get('asyncore')
+ if asyncore is not None:
+ asyncore.close_all(ignore_all=True)
+ asyncore.socket_map.update(saved_map)
+
+ def get_shutil_archive_formats(self):
+ # we could call get_archives_formats() but that only returns the
+ # registry keys; we want to check the values too (the functions that
+ # are registered)
+ return shutil._ARCHIVE_FORMATS, shutil._ARCHIVE_FORMATS.copy()
+ def restore_shutil_archive_formats(self, saved):
+ shutil._ARCHIVE_FORMATS = saved[0]
+ shutil._ARCHIVE_FORMATS.clear()
+ shutil._ARCHIVE_FORMATS.update(saved[1])
+
+ def get_shutil_unpack_formats(self):
+ return shutil._UNPACK_FORMATS, shutil._UNPACK_FORMATS.copy()
+ def restore_shutil_unpack_formats(self, saved):
+ shutil._UNPACK_FORMATS = saved[0]
+ shutil._UNPACK_FORMATS.clear()
+ shutil._UNPACK_FORMATS.update(saved[1])
+
+ def get_logging__handlers(self):
+ # _handlers is a WeakValueDictionary
+ return id(logging._handlers), logging._handlers, logging._handlers.copy()
+ def restore_logging__handlers(self, saved_handlers):
+ # Can't easily revert the logging state
+ pass
+
+ def get_logging__handlerList(self):
+ # _handlerList is a list of weakrefs to handlers
+ return id(logging._handlerList), logging._handlerList, logging._handlerList[:]
+ def restore_logging__handlerList(self, saved_handlerList):
+ # Can't easily revert the logging state
+ pass
+
+ def get_sys_warnoptions(self):
+ return id(sys.warnoptions), sys.warnoptions, sys.warnoptions[:]
+ def restore_sys_warnoptions(self, saved_options):
+ sys.warnoptions = saved_options[1]
+ sys.warnoptions[:] = saved_options[2]
+
+ # Controlling dangling references to Thread objects can make it easier
+ # to track reference leaks.
+ def get_threading__dangling(self):
+ if not threading:
+ return None
+ # This copies the weakrefs without making any strong reference
+ return threading._dangling.copy()
+ def restore_threading__dangling(self, saved):
+ if not threading:
+ return
+ threading._dangling.clear()
+ threading._dangling.update(saved)
+
+ # Same for Process objects
+ def get_multiprocessing_process__dangling(self):
+ if not multiprocessing:
+ return None
+ # Unjoined process objects can survive after process exits
+ multiprocessing.process._cleanup()
+ # This copies the weakrefs without making any strong reference
+ return multiprocessing.process._dangling.copy()
+ def restore_multiprocessing_process__dangling(self, saved):
+ if not multiprocessing:
+ return
+ multiprocessing.process._dangling.clear()
+ multiprocessing.process._dangling.update(saved)
+
+ def get_sysconfig__CONFIG_VARS(self):
+ # make sure the dict is initialized
+ sysconfig.get_config_var('prefix')
+ return (id(sysconfig._CONFIG_VARS), sysconfig._CONFIG_VARS,
+ dict(sysconfig._CONFIG_VARS))
+ def restore_sysconfig__CONFIG_VARS(self, saved):
+ sysconfig._CONFIG_VARS = saved[1]
+ sysconfig._CONFIG_VARS.clear()
+ sysconfig._CONFIG_VARS.update(saved[2])
+
+ def get_sysconfig__INSTALL_SCHEMES(self):
+ return (id(sysconfig._INSTALL_SCHEMES), sysconfig._INSTALL_SCHEMES,
+ sysconfig._INSTALL_SCHEMES.copy())
+ def restore_sysconfig__INSTALL_SCHEMES(self, saved):
+ sysconfig._INSTALL_SCHEMES = saved[1]
+ sysconfig._INSTALL_SCHEMES.clear()
+ sysconfig._INSTALL_SCHEMES.update(saved[2])
+
+ def get_files(self):
+ return sorted(fn + ('/' if os.path.isdir(fn) else '')
+ for fn in os.listdir())
+ def restore_files(self, saved_value):
+ fn = support.TESTFN
+ if fn not in saved_value and (fn + '/') not in saved_value:
+ if os.path.isfile(fn):
+ support.unlink(fn)
+ elif os.path.isdir(fn):
+ support.rmtree(fn)
+
+ _lc = [getattr(locale, lc) for lc in dir(locale)
+ if lc.startswith('LC_')]
+ def get_locale(self):
+ pairings = []
+ for lc in self._lc:
+ try:
+ pairings.append((lc, locale.setlocale(lc, None)))
+ except (TypeError, ValueError):
+ continue
+ return pairings
+ def restore_locale(self, saved):
+ for lc, setting in saved:
+ locale.setlocale(lc, setting)
+
+ def get_warnings_showwarning(self):
+ return warnings.showwarning
+ def restore_warnings_showwarning(self, fxn):
+ warnings.showwarning = fxn
+
+ def resource_info(self):
+ for name in self.resources:
+ method_suffix = name.replace('.', '_')
+ get_name = 'get_' + method_suffix
+ restore_name = 'restore_' + method_suffix
+ yield name, getattr(self, get_name), getattr(self, restore_name)
+
+ def __enter__(self):
+ self.saved_values = dict((name, get()) for name, get, restore
+ in self.resource_info())
+ return self
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ saved_values = self.saved_values
+ del self.saved_values
+ for name, get, restore in self.resource_info():
+ current = get()
+ original = saved_values.pop(name)
+ # Check for changes to the resource's value
+ if current != original:
+ self.changed = True
+ restore(original)
+ if not self.quiet and not self.pgo:
+ print("Warning -- {} was modified by {}".format(
+ name, self.testname),
+ file=sys.stderr)
+ if self.verbose > 1:
+ print(" Before: {}\n After: {} ".format(
+ original, current),
+ file=sys.stderr)
+ return False
diff --git a/Lib/test/libregrtest/setup.py b/Lib/test/libregrtest/setup.py
new file mode 100644
index 0000000000..1d24531fc2
--- /dev/null
+++ b/Lib/test/libregrtest/setup.py
@@ -0,0 +1,121 @@
+import atexit
+import faulthandler
+import os
+import signal
+import sys
+import unittest
+from test import support
+try:
+ import gc
+except ImportError:
+ gc = None
+
+from test.libregrtest.refleak import warm_caches
+
+
+def setup_tests(ns):
+ # Display the Python traceback on fatal errors (e.g. segfault)
+ faulthandler.enable(all_threads=True)
+
+ # Display the Python traceback on SIGALRM or SIGUSR1 signal
+ signals = []
+ if hasattr(signal, 'SIGALRM'):
+ signals.append(signal.SIGALRM)
+ if hasattr(signal, 'SIGUSR1'):
+ signals.append(signal.SIGUSR1)
+ for signum in signals:
+ faulthandler.register(signum, chain=True)
+
+ replace_stdout()
+ support.record_original_stdout(sys.stdout)
+
+ if ns.testdir:
+ # Prepend test directory to sys.path, so runtest() will be able
+ # to locate tests
+ sys.path.insert(0, os.path.abspath(ns.testdir))
+
+ # Some times __path__ and __file__ are not absolute (e.g. while running from
+ # Lib/) and, if we change the CWD to run the tests in a temporary dir, some
+ # imports might fail. This affects only the modules imported before os.chdir().
+ # These modules are searched first in sys.path[0] (so '' -- the CWD) and if
+ # they are found in the CWD their __file__ and __path__ will be relative (this
+ # happens before the chdir). All the modules imported after the chdir, are
+ # not found in the CWD, and since the other paths in sys.path[1:] are absolute
+ # (site.py absolutize them), the __file__ and __path__ will be absolute too.
+ # Therefore it is necessary to absolutize manually the __file__ and __path__ of
+ # the packages to prevent later imports to fail when the CWD is different.
+ for module in sys.modules.values():
+ if hasattr(module, '__path__'):
+ for index, path in enumerate(module.__path__):
+ module.__path__[index] = os.path.abspath(path)
+ if hasattr(module, '__file__'):
+ module.__file__ = os.path.abspath(module.__file__)
+
+ # MacOSX (a.k.a. Darwin) has a default stack size that is too small
+ # for deeply recursive regular expressions. We see this as crashes in
+ # the Python test suite when running test_re.py and test_sre.py. The
+ # fix is to set the stack limit to 2048.
+ # This approach may also be useful for other Unixy platforms that
+ # suffer from small default stack limits.
+ if sys.platform == 'darwin':
+ try:
+ import resource
+ except ImportError:
+ pass
+ else:
+ soft, hard = resource.getrlimit(resource.RLIMIT_STACK)
+ newsoft = min(hard, max(soft, 1024*2048))
+ resource.setrlimit(resource.RLIMIT_STACK, (newsoft, hard))
+
+ if ns.huntrleaks:
+ unittest.BaseTestSuite._cleanup = False
+
+ # Avoid false positives due to various caches
+ # filling slowly with random data:
+ warm_caches()
+
+ if ns.memlimit is not None:
+ support.set_memlimit(ns.memlimit)
+
+ if ns.threshold is not None:
+ gc.set_threshold(ns.threshold)
+
+ try:
+ import msvcrt
+ except ImportError:
+ pass
+ else:
+ msvcrt.SetErrorMode(msvcrt.SEM_FAILCRITICALERRORS|
+ msvcrt.SEM_NOALIGNMENTFAULTEXCEPT|
+ msvcrt.SEM_NOGPFAULTERRORBOX|
+ msvcrt.SEM_NOOPENFILEERRORBOX)
+ try:
+ msvcrt.CrtSetReportMode
+ except AttributeError:
+ # release build
+ pass
+ else:
+ for m in [msvcrt.CRT_WARN, msvcrt.CRT_ERROR, msvcrt.CRT_ASSERT]:
+ if ns.verbose and ns.verbose >= 2:
+ msvcrt.CrtSetReportMode(m, msvcrt.CRTDBG_MODE_FILE)
+ msvcrt.CrtSetReportFile(m, msvcrt.CRTDBG_FILE_STDERR)
+ else:
+ msvcrt.CrtSetReportMode(m, 0)
+
+ support.use_resources = ns.use_resources
+
+
+def replace_stdout():
+ """Set stdout encoder error handler to backslashreplace (as stderr error
+ handler) to avoid UnicodeEncodeError when printing a traceback"""
+ stdout = sys.stdout
+ sys.stdout = open(stdout.fileno(), 'w',
+ encoding=stdout.encoding,
+ errors="backslashreplace",
+ closefd=False,
+ newline='\n')
+
+ def restore_stdout():
+ sys.stdout.close()
+ sys.stdout = stdout
+ atexit.register(restore_stdout)
diff --git a/Lib/test/lock_tests.py b/Lib/test/lock_tests.py
index a64aa18cd3..a6cb3b169b 100644
--- a/Lib/test/lock_tests.py
+++ b/Lib/test/lock_tests.py
@@ -7,6 +7,7 @@ import time
from _thread import start_new_thread, TIMEOUT_MAX
import threading
import unittest
+import weakref
from test import support
@@ -198,6 +199,17 @@ class BaseLockTests(BaseTestCase):
self.assertFalse(results[0])
self.assertTimeout(results[1], 0.5)
+ def test_weakref_exists(self):
+ lock = self.locktype()
+ ref = weakref.ref(lock)
+ self.assertIsNotNone(ref())
+
+ def test_weakref_deleted(self):
+ lock = self.locktype()
+ ref = weakref.ref(lock)
+ del lock
+ self.assertIsNone(ref())
+
class LockTests(BaseLockTests):
"""
diff --git a/Lib/test/make_ssl_certs.py b/Lib/test/make_ssl_certs.py
index 81d04f82dc..e4326d7b33 100644
--- a/Lib/test/make_ssl_certs.py
+++ b/Lib/test/make_ssl_certs.py
@@ -3,7 +3,6 @@ and friends."""
import os
import shutil
-import sys
import tempfile
from subprocess import *
diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py
index f252a0a10f..8deb56fa0f 100644
--- a/Lib/test/pickletester.py
+++ b/Lib/test/pickletester.py
@@ -1000,7 +1000,7 @@ class AbstractUnpickleTests(unittest.TestCase):
b'0', # POP
b'1', # POP_MARK
b'2', # DUP
- # b'(2', # PyUnpickler doesn't raise
+ b'(2',
b'R', # REDUCE
b')R',
b'a', # APPEND
@@ -1009,7 +1009,7 @@ class AbstractUnpickleTests(unittest.TestCase):
b'Nb',
b'd', # DICT
b'e', # APPENDS
- # b'(e', # PyUnpickler raises AttributeError
+ b'(e',
b'ibuiltins\nlist\n', # INST
b'l', # LIST
b'o', # OBJ
@@ -1022,7 +1022,7 @@ class AbstractUnpickleTests(unittest.TestCase):
b'NNs',
b't', # TUPLE
b'u', # SETITEMS
- # b'(u', # PyUnpickler doesn't raise
+ b'(u',
b'}(Nu',
b'\x81', # NEWOBJ
b')\x81',
@@ -1033,7 +1033,7 @@ class AbstractUnpickleTests(unittest.TestCase):
b'N\x87',
b'NN\x87',
b'\x90', # ADDITEMS
- # b'(\x90', # PyUnpickler raises AttributeError
+ b'(\x90',
b'\x91', # FROZENSET
b'\x92', # NEWOBJ_EX
b')}\x92',
@@ -1046,7 +1046,7 @@ class AbstractUnpickleTests(unittest.TestCase):
def test_bad_mark(self):
badpickles = [
- # b'N(.', # STOP
+ b'N(.', # STOP
b'N(2', # DUP
b'cbuiltins\nlist\n)(R', # REDUCE
b'cbuiltins\nlist\n()R',
@@ -1081,7 +1081,7 @@ class AbstractUnpickleTests(unittest.TestCase):
b'N(\x94', # MEMOIZE
]
for p in badpickles:
- self.check_unpickling_error(self.bad_mark_errors, p)
+ self.check_unpickling_error(self.bad_stack_errors, p)
def test_truncated_data(self):
self.check_unpickling_error(EOFError, b'')
@@ -1855,16 +1855,14 @@ class AbstractPickleTests(unittest.TestCase):
x.abc = 666
for proto in protocols:
with self.subTest(proto=proto):
- if 2 <= proto < 4:
- self.assertRaises(ValueError, self.dumps, x, proto)
- continue
s = self.dumps(x, proto)
if proto < 1:
self.assertIn(b'\nL64206', s) # LONG
elif proto < 2:
self.assertIn(b'M\xce\xfa', s) # BININT2
+ elif proto < 4:
+ self.assertIn(b'X\x04\x00\x00\x00FACE', s) # BINUNICODE
else:
- assert proto >= 4
self.assertIn(b'\x8c\x04FACE', s) # SHORT_BINUNICODE
self.assertFalse(opcode_in_pickle(pickle.NEWOBJ, s))
self.assertEqual(opcode_in_pickle(pickle.NEWOBJ_EX, s),
@@ -2583,11 +2581,6 @@ class AbstractPickleModuleTests(unittest.TestCase):
self.assertRaises(pickle.PicklingError, BadPickler().dump, 0)
self.assertRaises(pickle.UnpicklingError, BadUnpickler().load)
- def test_bad_input(self):
- # Test issue4298
- s = bytes([0x58, 0, 0, 0, 0x54])
- self.assertRaises(EOFError, pickle.loads, s)
-
class AbstractPersistentPicklerTests(unittest.TestCase):
diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py
index fecfd0967a..21b0edfd07 100755..100644
--- a/Lib/test/regrtest.py
+++ b/Lib/test/regrtest.py
@@ -6,1604 +6,33 @@ Script to run Python regression tests.
Run this script with -h or --help for documentation.
"""
-USAGE = """\
-python -m test [options] [test_name1 [test_name2 ...]]
-python path/to/Lib/test/regrtest.py [options] [test_name1 [test_name2 ...]]
-"""
-
-DESCRIPTION = """\
-Run Python regression tests.
-
-If no arguments or options are provided, finds all files matching
-the pattern "test_*" in the Lib/test subdirectory and runs
-them in alphabetical order (but see -M and -u, below, for exceptions).
-
-For more rigorous testing, it is useful to use the following
-command line:
-
-python -E -Wd -m test [options] [test_name1 ...]
-"""
-
-EPILOG = """\
-Additional option details:
-
--r randomizes test execution order. You can use --randseed=int to provide an
-int seed value for the randomizer; this is useful for reproducing troublesome
-test orders.
-
--s On the first invocation of regrtest using -s, the first test file found
-or the first test file given on the command line is run, and the name of
-the next test is recorded in a file named pynexttest. If run from the
-Python build directory, pynexttest is located in the 'build' subdirectory,
-otherwise it is located in tempfile.gettempdir(). On subsequent runs,
-the test in pynexttest is run, and the next test is written to pynexttest.
-When the last test has been run, pynexttest is deleted. In this way it
-is possible to single step through the test files. This is useful when
-doing memory analysis on the Python interpreter, which process tends to
-consume too many resources to run the full regression test non-stop.
-
--S is used to continue running tests after an aborted run. It will
-maintain the order a standard run (ie, this assumes -r is not used).
-This is useful after the tests have prematurely stopped for some external
-reason and you want to start running from where you left off rather
-than starting from the beginning.
-
--f reads the names of tests from the file given as f's argument, one
-or more test names per line. Whitespace is ignored. Blank lines and
-lines beginning with '#' are ignored. This is especially useful for
-whittling down failures involving interactions among tests.
-
--L causes the leaks(1) command to be run just before exit if it exists.
-leaks(1) is available on Mac OS X and presumably on some other
-FreeBSD-derived systems.
-
--R runs each test several times and examines sys.gettotalrefcount() to
-see if the test appears to be leaking references. The argument should
-be of the form stab:run:fname where 'stab' is the number of times the
-test is run to let gettotalrefcount settle down, 'run' is the number
-of times further it is run and 'fname' is the name of the file the
-reports are written to. These parameters all have defaults (5, 4 and
-"reflog.txt" respectively), and the minimal invocation is '-R :'.
-
--M runs tests that require an exorbitant amount of memory. These tests
-typically try to ascertain containers keep working when containing more than
-2 billion objects, which only works on 64-bit systems. There are also some
-tests that try to exhaust the address space of the process, which only makes
-sense on 32-bit systems with at least 2Gb of memory. The passed-in memlimit,
-which is a string in the form of '2.5Gb', determines howmuch memory the
-tests will limit themselves to (but they may go slightly over.) The number
-shouldn't be more memory than the machine has (including swap memory). You
-should also keep in mind that swap memory is generally much, much slower
-than RAM, and setting memlimit to all available RAM or higher will heavily
-tax the machine. On the other hand, it is no use running these tests with a
-limit of less than 2.5Gb, and many require more than 20Gb. Tests that expect
-to use more than memlimit memory will be skipped. The big-memory tests
-generally run very, very long.
-
--u is used to specify which special resource intensive tests to run,
-such as those requiring large file support or network connectivity.
-The argument is a comma-separated list of words indicating the
-resources to test. Currently only the following are defined:
-
- all - Enable all special resources.
-
- none - Disable all special resources (this is the default).
-
- audio - Tests that use the audio device. (There are known
- cases of broken audio drivers that can crash Python or
- even the Linux kernel.)
-
- curses - Tests that use curses and will modify the terminal's
- state and output modes.
-
- largefile - It is okay to run some test that may create huge
- files. These tests can take a long time and may
- consume >2GB of disk space temporarily.
-
- network - It is okay to run tests that use external network
- resource, e.g. testing SSL support for sockets.
-
- decimal - Test the decimal module against a large suite that
- verifies compliance with standards.
-
- cpu - Used for certain CPU-heavy tests.
-
- subprocess Run all tests for the subprocess module.
-
- urlfetch - It is okay to download files required on testing.
-
- gui - Run tests that require a running GUI.
-
-To enable all resources except one, use '-uall,-<resource>'. For
-example, to run all the tests except for the gui tests, give the
-option '-uall,-gui'.
-"""
-
# We import importlib *ASAP* in order to test #15386
import importlib
-import argparse
-import builtins
-import faulthandler
-import io
-import json
-import locale
-import logging
import os
-import platform
-import random
-import re
-import shutil
-import signal
import sys
-import sysconfig
-import tempfile
-import time
-import traceback
-import unittest
-import warnings
-from inspect import isabstract
-
-try:
- import threading
-except ImportError:
- threading = None
-try:
- import _multiprocessing, multiprocessing.process
-except ImportError:
- multiprocessing = None
-
-
-# Some times __path__ and __file__ are not absolute (e.g. while running from
-# Lib/) and, if we change the CWD to run the tests in a temporary dir, some
-# imports might fail. This affects only the modules imported before os.chdir().
-# These modules are searched first in sys.path[0] (so '' -- the CWD) and if
-# they are found in the CWD their __file__ and __path__ will be relative (this
-# happens before the chdir). All the modules imported after the chdir, are
-# not found in the CWD, and since the other paths in sys.path[1:] are absolute
-# (site.py absolutize them), the __file__ and __path__ will be absolute too.
-# Therefore it is necessary to absolutize manually the __file__ and __path__ of
-# the packages to prevent later imports to fail when the CWD is different.
-for module in sys.modules.values():
- if hasattr(module, '__path__'):
- module.__path__ = [os.path.abspath(path) for path in module.__path__]
- if hasattr(module, '__file__'):
- module.__file__ = os.path.abspath(module.__file__)
-
-
-# MacOSX (a.k.a. Darwin) has a default stack size that is too small
-# for deeply recursive regular expressions. We see this as crashes in
-# the Python test suite when running test_re.py and test_sre.py. The
-# fix is to set the stack limit to 2048.
-# This approach may also be useful for other Unixy platforms that
-# suffer from small default stack limits.
-if sys.platform == 'darwin':
- try:
- import resource
- except ImportError:
- pass
- else:
- soft, hard = resource.getrlimit(resource.RLIMIT_STACK)
- newsoft = min(hard, max(soft, 1024*2048))
- resource.setrlimit(resource.RLIMIT_STACK, (newsoft, hard))
-
-# Test result constants.
-PASSED = 1
-FAILED = 0
-ENV_CHANGED = -1
-SKIPPED = -2
-RESOURCE_DENIED = -3
-INTERRUPTED = -4
-CHILD_ERROR = -5 # error in a child process
-
-from test import support
-
-RESOURCE_NAMES = ('audio', 'curses', 'largefile', 'network',
- 'decimal', 'cpu', 'subprocess', 'urlfetch', 'gui')
-
-# When tests are run from the Python build directory, it is best practice
-# to keep the test files in a subfolder. This eases the cleanup of leftover
-# files using the "make distclean" command.
-if sysconfig.is_python_build():
- TEMPDIR = os.path.join(sysconfig.get_config_var('srcdir'), 'build')
-else:
- TEMPDIR = tempfile.gettempdir()
-TEMPDIR = os.path.abspath(TEMPDIR)
-
-class _ArgParser(argparse.ArgumentParser):
-
- def error(self, message):
- super().error(message + "\nPass -h or --help for complete help.")
-
-def _create_parser():
- # Set prog to prevent the uninformative "__main__.py" from displaying in
- # error messages when using "python -m test ...".
- parser = _ArgParser(prog='regrtest.py',
- usage=USAGE,
- description=DESCRIPTION,
- epilog=EPILOG,
- add_help=False,
- formatter_class=argparse.RawDescriptionHelpFormatter)
-
- # Arguments with this clause added to its help are described further in
- # the epilog's "Additional option details" section.
- more_details = ' See the section at bottom for more details.'
-
- group = parser.add_argument_group('General options')
- # We add help explicitly to control what argument group it renders under.
- group.add_argument('-h', '--help', action='help',
- help='show this help message and exit')
- group.add_argument('--timeout', metavar='TIMEOUT', type=float,
- help='dump the traceback and exit if a test takes '
- 'more than TIMEOUT seconds; disabled if TIMEOUT '
- 'is negative or equals to zero')
- group.add_argument('--wait', action='store_true',
- help='wait for user input, e.g., allow a debugger '
- 'to be attached')
- group.add_argument('--slaveargs', metavar='ARGS')
- group.add_argument('-S', '--start', metavar='START',
- help='the name of the test at which to start.' +
- more_details)
-
- group = parser.add_argument_group('Verbosity')
- group.add_argument('-v', '--verbose', action='count',
- help='run tests in verbose mode with output to stdout')
- group.add_argument('-w', '--verbose2', action='store_true',
- help='re-run failed tests in verbose mode')
- group.add_argument('-W', '--verbose3', action='store_true',
- help='display test output on failure')
- group.add_argument('-q', '--quiet', action='store_true',
- help='no output unless one or more tests fail')
- group.add_argument('-o', '--slow', action='store_true', dest='print_slow',
- help='print the slowest 10 tests')
- group.add_argument('--header', action='store_true',
- help='print header with interpreter info')
-
- group = parser.add_argument_group('Selecting tests')
- group.add_argument('-r', '--randomize', action='store_true',
- help='randomize test execution order.' + more_details)
- group.add_argument('--randseed', metavar='SEED',
- dest='random_seed', type=int,
- help='pass a random seed to reproduce a previous '
- 'random run')
- group.add_argument('-f', '--fromfile', metavar='FILE',
- help='read names of tests to run from a file.' +
- more_details)
- group.add_argument('-x', '--exclude', action='store_true',
- help='arguments are tests to *exclude*')
- group.add_argument('-s', '--single', action='store_true',
- help='single step through a set of tests.' +
- more_details)
- group.add_argument('-m', '--match', metavar='PAT',
- dest='match_tests',
- help='match test cases and methods with glob pattern PAT')
- group.add_argument('-G', '--failfast', action='store_true',
- help='fail as soon as a test fails (only with -v or -W)')
- group.add_argument('-u', '--use', metavar='RES1,RES2,...',
- action='append', type=resources_list,
- help='specify which special resource intensive tests '
- 'to run.' + more_details)
- group.add_argument('-M', '--memlimit', metavar='LIMIT',
- help='run very large memory-consuming tests.' +
- more_details)
- group.add_argument('--testdir', metavar='DIR',
- type=relative_filename,
- help='execute test files in the specified directory '
- '(instead of the Python stdlib test suite)')
-
- group = parser.add_argument_group('Special runs')
- group.add_argument('-l', '--findleaks', action='store_true',
- help='if GC is available detect tests that leak memory')
- group.add_argument('-L', '--runleaks', action='store_true',
- help='run the leaks(1) command just before exit.' +
- more_details)
- group.add_argument('-R', '--huntrleaks', metavar='RUNCOUNTS',
- type=huntrleaks,
- help='search for reference leaks (needs debug build, '
- 'very slow).' + more_details)
- group.add_argument('-j', '--multiprocess', metavar='PROCESSES',
- dest='use_mp', type=int,
- help='run PROCESSES processes at once')
- group.add_argument('-T', '--coverage', action='store_true',
- dest='trace',
- help='turn on code coverage tracing using the trace '
- 'module')
- group.add_argument('-D', '--coverdir', metavar='DIR',
- type=relative_filename,
- help='directory where coverage files are put')
- group.add_argument('-N', '--nocoverdir',
- action='store_const', const=None, dest='coverdir',
- help='put coverage files alongside modules')
- group.add_argument('-t', '--threshold', metavar='THRESHOLD',
- type=int,
- help='call gc.set_threshold(THRESHOLD)')
- group.add_argument('-n', '--nowindows', action='store_true',
- help='suppress error message boxes on Windows')
- group.add_argument('-F', '--forever', action='store_true',
- help='run the specified tests in a loop, until an '
- 'error happens')
- group.add_argument('-P', '--pgo', dest='pgo', action='store_true',
- help='enable Profile Guided Optimization training')
-
- parser.add_argument('args', nargs=argparse.REMAINDER,
- help=argparse.SUPPRESS)
-
- return parser
-
-def relative_filename(string):
- # CWD is replaced with a temporary dir before calling main(), so we
- # join it with the saved CWD so it ends up where the user expects.
- return os.path.join(support.SAVEDCWD, string)
-
-def huntrleaks(string):
- args = string.split(':')
- if len(args) not in (2, 3):
- raise argparse.ArgumentTypeError(
- 'needs 2 or 3 colon-separated arguments')
- nwarmup = int(args[0]) if args[0] else 5
- ntracked = int(args[1]) if args[1] else 4
- fname = args[2] if len(args) > 2 and args[2] else 'reflog.txt'
- return nwarmup, ntracked, fname
-
-def resources_list(string):
- u = [x.lower() for x in string.split(',')]
- for r in u:
- if r == 'all' or r == 'none':
- continue
- if r[0] == '-':
- r = r[1:]
- if r not in RESOURCE_NAMES:
- raise argparse.ArgumentTypeError('invalid resource: ' + r)
- return u
-
-def _parse_args(args, **kwargs):
- # Defaults
- ns = argparse.Namespace(testdir=None, verbose=0, quiet=False,
- exclude=False, single=False, randomize=False, fromfile=None,
- findleaks=False, use_resources=None, trace=False, coverdir='coverage',
- runleaks=False, huntrleaks=False, verbose2=False, print_slow=False,
- random_seed=None, use_mp=None, verbose3=False, forever=False,
- header=False, failfast=False, match_tests=None, pgo=False)
- for k, v in kwargs.items():
- if not hasattr(ns, k):
- raise TypeError('%r is an invalid keyword argument '
- 'for this function' % k)
- setattr(ns, k, v)
- if ns.use_resources is None:
- ns.use_resources = []
-
- parser = _create_parser()
- parser.parse_args(args=args, namespace=ns)
-
- if ns.single and ns.fromfile:
- parser.error("-s and -f don't go together!")
- if ns.use_mp and ns.trace:
- parser.error("-T and -j don't go together!")
- if ns.use_mp and ns.findleaks:
- parser.error("-l and -j don't go together!")
- if ns.use_mp and ns.memlimit:
- parser.error("-M and -j don't go together!")
- if ns.failfast and not (ns.verbose or ns.verbose3):
- parser.error("-G/--failfast needs either -v or -W")
-
- if ns.quiet:
- ns.verbose = 0
- if ns.timeout is not None:
- if hasattr(faulthandler, 'dump_traceback_later'):
- if ns.timeout <= 0:
- ns.timeout = None
- else:
- print("Warning: The timeout option requires "
- "faulthandler.dump_traceback_later")
- ns.timeout = None
- if ns.use_mp is not None:
- if ns.use_mp <= 0:
- # Use all cores + extras for tests that like to sleep
- ns.use_mp = 2 + (os.cpu_count() or 1)
- if ns.use_mp == 1:
- ns.use_mp = None
- if ns.use:
- for a in ns.use:
- for r in a:
- if r == 'all':
- ns.use_resources[:] = RESOURCE_NAMES
- continue
- if r == 'none':
- del ns.use_resources[:]
- continue
- remove = False
- if r[0] == '-':
- remove = True
- r = r[1:]
- if remove:
- if r in ns.use_resources:
- ns.use_resources.remove(r)
- elif r not in ns.use_resources:
- ns.use_resources.append(r)
- if ns.random_seed is not None:
- ns.randomize = True
-
- return ns
-
-
-def run_test_in_subprocess(testname, ns):
- """Run the given test in a subprocess with --slaveargs.
-
- ns is the option Namespace parsed from command-line arguments. regrtest
- is invoked in a subprocess with the --slaveargs argument; when the
- subprocess exits, its return code, stdout and stderr are returned as a
- 3-tuple.
- """
- from subprocess import Popen, PIPE
- base_cmd = ([sys.executable] + support.args_from_interpreter_flags() +
- ['-X', 'faulthandler', '-m', 'test.regrtest'])
- # required to spawn a new process with PGO flag on/off
- if ns.pgo:
- base_cmd = base_cmd + ['--pgo']
- slaveargs = (
- (testname, ns.verbose, ns.quiet),
- dict(huntrleaks=ns.huntrleaks,
- use_resources=ns.use_resources,
- output_on_failure=ns.verbose3,
- timeout=ns.timeout, failfast=ns.failfast,
- match_tests=ns.match_tests, pgo=ns.pgo))
- # Running the child from the same working directory as regrtest's original
- # invocation ensures that TEMPDIR for the child is the same when
- # sysconfig.is_python_build() is true. See issue 15300.
- popen = Popen(base_cmd + ['--slaveargs', json.dumps(slaveargs)],
- stdout=PIPE, stderr=PIPE,
- universal_newlines=True,
- close_fds=(os.name != 'nt'),
- cwd=support.SAVEDCWD)
- stdout, stderr = popen.communicate()
- retcode = popen.wait()
- return retcode, stdout, stderr
-
-
-def main(tests=None, **kwargs):
- """Execute a test suite.
-
- This also parses command-line options and modifies its behavior
- accordingly.
-
- tests -- a list of strings containing test names (optional)
- testdir -- the directory in which to look for tests (optional)
-
- Users other than the Python test suite will certainly want to
- specify testdir; if it's omitted, the directory containing the
- Python test suite is searched for.
-
- If the tests argument is omitted, the tests listed on the
- command-line will be used. If that's empty, too, then all *.py
- files beginning with test_ will be used.
-
- The other default arguments (verbose, quiet, exclude,
- single, randomize, findleaks, use_resources, trace, coverdir,
- print_slow, and random_seed) allow programmers calling main()
- directly to set the values that would normally be set by flags
- on the command line.
- """
- # Display the Python traceback on fatal errors (e.g. segfault)
- faulthandler.enable(all_threads=True)
-
- # Display the Python traceback on SIGALRM or SIGUSR1 signal
- signals = []
- if hasattr(signal, 'SIGALRM'):
- signals.append(signal.SIGALRM)
- if hasattr(signal, 'SIGUSR1'):
- signals.append(signal.SIGUSR1)
- for signum in signals:
- faulthandler.register(signum, chain=True)
-
- replace_stdout()
-
- support.record_original_stdout(sys.stdout)
-
- ns = _parse_args(sys.argv[1:], **kwargs)
-
- if ns.huntrleaks:
- # Avoid false positives due to various caches
- # filling slowly with random data:
- warm_caches()
- if ns.memlimit is not None:
- support.set_memlimit(ns.memlimit)
- if ns.threshold is not None:
- import gc
- gc.set_threshold(ns.threshold)
- if ns.nowindows:
- print('The --nowindows (-n) option is deprecated. '
- 'Use -vv to display assertions in stderr.')
- try:
- import msvcrt
- except ImportError:
- pass
- else:
- msvcrt.SetErrorMode(msvcrt.SEM_FAILCRITICALERRORS|
- msvcrt.SEM_NOALIGNMENTFAULTEXCEPT|
- msvcrt.SEM_NOGPFAULTERRORBOX|
- msvcrt.SEM_NOOPENFILEERRORBOX)
- try:
- msvcrt.CrtSetReportMode
- except AttributeError:
- # release build
- pass
- else:
- for m in [msvcrt.CRT_WARN, msvcrt.CRT_ERROR, msvcrt.CRT_ASSERT]:
- if ns.verbose and ns.verbose >= 2:
- msvcrt.CrtSetReportMode(m, msvcrt.CRTDBG_MODE_FILE)
- msvcrt.CrtSetReportFile(m, msvcrt.CRTDBG_FILE_STDERR)
- else:
- msvcrt.CrtSetReportMode(m, 0)
- if ns.wait:
- input("Press any key to continue...")
-
- if ns.slaveargs is not None:
- args, kwargs = json.loads(ns.slaveargs)
- if kwargs.get('huntrleaks'):
- unittest.BaseTestSuite._cleanup = False
- try:
- result = runtest(*args, **kwargs)
- except KeyboardInterrupt:
- result = INTERRUPTED, ''
- except BaseException as e:
- traceback.print_exc()
- result = CHILD_ERROR, str(e)
- sys.stdout.flush()
- print() # Force a newline (just in case)
- print(json.dumps(result))
- sys.exit(0)
-
- good = []
- bad = []
- skipped = []
- resource_denieds = []
- environment_changed = []
- interrupted = False
-
- if ns.findleaks:
- try:
- import gc
- except ImportError:
- print('No GC available, disabling findleaks.')
- ns.findleaks = False
- else:
- # Uncomment the line below to report garbage that is not
- # freeable by reference counting alone. By default only
- # garbage that is not collectable by the GC is reported.
- #gc.set_debug(gc.DEBUG_SAVEALL)
- found_garbage = []
-
- if ns.huntrleaks:
- unittest.BaseTestSuite._cleanup = False
-
- if ns.single:
- filename = os.path.join(TEMPDIR, 'pynexttest')
- try:
- with open(filename, 'r') as fp:
- next_test = fp.read().strip()
- tests = [next_test]
- except OSError:
- pass
-
- if ns.fromfile:
- tests = []
- with open(os.path.join(support.SAVEDCWD, ns.fromfile)) as fp:
- count_pat = re.compile(r'\[\s*\d+/\s*\d+\]')
- for line in fp:
- line = count_pat.sub('', line)
- guts = line.split() # assuming no test has whitespace in its name
- if guts and not guts[0].startswith('#'):
- tests.extend(guts)
-
- # Strip .py extensions.
- removepy(ns.args)
- removepy(tests)
-
- stdtests = STDTESTS[:]
- nottests = NOTTESTS.copy()
- if ns.exclude:
- for arg in ns.args:
- if arg in stdtests:
- stdtests.remove(arg)
- nottests.add(arg)
- ns.args = []
-
- # For a partial run, we do not need to clutter the output.
- if (ns.verbose or ns.header or
- not (ns.pgo or ns.quiet or ns.single or tests or ns.args)):
- # Print basic platform information
- print("==", platform.python_implementation(), *sys.version.split())
- print("== ", platform.platform(aliased=True),
- "%s-endian" % sys.byteorder)
- print("== ", "hash algorithm:", sys.hash_info.algorithm,
- "64bit" if sys.maxsize > 2**32 else "32bit")
- print("== ", os.getcwd())
- print("Testing with flags:", sys.flags)
-
- # if testdir is set, then we are not running the python tests suite, so
- # don't add default tests to be executed or skipped (pass empty values)
- if ns.testdir:
- alltests = findtests(ns.testdir, list(), set())
- else:
- alltests = findtests(ns.testdir, stdtests, nottests)
-
- selected = tests or ns.args or alltests
- if ns.single:
- selected = selected[:1]
- try:
- next_single_test = alltests[alltests.index(selected[0])+1]
- except IndexError:
- next_single_test = None
- # Remove all the selected tests that precede start if it's set.
- if ns.start:
- try:
- del selected[:selected.index(ns.start)]
- except ValueError:
- print("Couldn't find starting test (%s), using all tests" % ns.start)
- if ns.randomize:
- if ns.random_seed is None:
- ns.random_seed = random.randrange(10000000)
- random.seed(ns.random_seed)
- print("Using random seed", ns.random_seed)
- random.shuffle(selected)
- if ns.trace:
- import trace, tempfile
- tracer = trace.Trace(ignoredirs=[sys.base_prefix, sys.base_exec_prefix,
- tempfile.gettempdir()],
- trace=False, count=True)
-
- test_times = []
- support.verbose = ns.verbose # Tell tests to be moderately quiet
- support.use_resources = ns.use_resources
- save_modules = sys.modules.keys()
-
- def accumulate_result(test, result):
- ok, test_time = result
- if ok not in (CHILD_ERROR, INTERRUPTED):
- test_times.append((test_time, test))
- if ok == PASSED:
- good.append(test)
- elif ok == FAILED:
- bad.append(test)
- elif ok == ENV_CHANGED:
- environment_changed.append(test)
- elif ok == SKIPPED:
- skipped.append(test)
- elif ok == RESOURCE_DENIED:
- skipped.append(test)
- resource_denieds.append(test)
-
- if ns.forever:
- def test_forever(tests=list(selected)):
- while True:
- for test in tests:
- yield test
- if bad:
- return
- tests = test_forever()
- test_count = ''
- test_count_width = 3
- else:
- tests = iter(selected)
- test_count = '/{}'.format(len(selected))
- test_count_width = len(test_count) - 1
-
- if ns.use_mp:
- try:
- from threading import Thread
- except ImportError:
- print("Multiprocess option requires thread support")
- sys.exit(2)
- from queue import Queue
- debug_output_pat = re.compile(r"\[\d+ refs, \d+ blocks\]$")
- output = Queue()
- pending = MultiprocessTests(tests)
- def work():
- # A worker thread.
- try:
- while True:
- try:
- test = next(pending)
- except StopIteration:
- output.put((None, None, None, None))
- return
- retcode, stdout, stderr = run_test_in_subprocess(test, ns)
- # Strip last refcount output line if it exists, since it
- # comes from the shutdown of the interpreter in the subcommand.
- stderr = debug_output_pat.sub("", stderr)
- stdout, _, result = stdout.strip().rpartition("\n")
- if retcode != 0:
- result = (CHILD_ERROR, "Exit code %s" % retcode)
- output.put((test, stdout.rstrip(), stderr.rstrip(), result))
- return
- if not result:
- output.put((None, None, None, None))
- return
- result = json.loads(result)
- output.put((test, stdout.rstrip(), stderr.rstrip(), result))
- except BaseException:
- output.put((None, None, None, None))
- raise
- workers = [Thread(target=work) for i in range(ns.use_mp)]
- for worker in workers:
- worker.start()
- finished = 0
- test_index = 1
- try:
- while finished < ns.use_mp:
- test, stdout, stderr, result = output.get()
- if test is None:
- finished += 1
- continue
- accumulate_result(test, result)
- if not ns.quiet:
- if bad and not ns.pgo:
- fmt = "[{1:{0}}{2}/{3}] {4}"
- else:
- fmt = "[{1:{0}}{2}] {4}"
- print(fmt.format(
- test_count_width, test_index, test_count,
- len(bad), test))
- if stdout:
- print(stdout)
- if stderr and not ns.pgo:
- print(stderr, file=sys.stderr)
- sys.stdout.flush()
- sys.stderr.flush()
- if result[0] == INTERRUPTED:
- raise KeyboardInterrupt
- if result[0] == CHILD_ERROR:
- raise Exception("Child error on {}: {}".format(test, result[1]))
- test_index += 1
- except KeyboardInterrupt:
- interrupted = True
- pending.interrupted = True
- for worker in workers:
- worker.join()
- else:
- for test_index, test in enumerate(tests, 1):
- if not ns.quiet:
- if bad and not ns.pgo:
- fmt = "[{1:{0}}{2}/{3}] {4}"
- else:
- fmt = "[{1:{0}}{2}] {4}"
- print(fmt.format(
- test_count_width, test_index, test_count, len(bad), test))
- sys.stdout.flush()
- if ns.trace:
- # If we're tracing code coverage, then we don't exit with status
- # if on a false return value from main.
- tracer.runctx('runtest(test, ns.verbose, ns.quiet, timeout=ns.timeout)',
- globals=globals(), locals=vars())
- else:
- try:
- result = runtest(test, ns.verbose, ns.quiet,
- ns.huntrleaks,
- output_on_failure=ns.verbose3,
- timeout=ns.timeout, failfast=ns.failfast,
- match_tests=ns.match_tests, pgo=ns.pgo)
- accumulate_result(test, result)
- except KeyboardInterrupt:
- interrupted = True
- break
- if ns.findleaks:
- gc.collect()
- if gc.garbage:
- print("Warning: test created", len(gc.garbage), end=' ')
- print("uncollectable object(s).")
- # move the uncollectable objects somewhere so we don't see
- # them again
- found_garbage.extend(gc.garbage)
- del gc.garbage[:]
- # Unload the newly imported modules (best effort finalization)
- for module in sys.modules.keys():
- if module not in save_modules and module.startswith("test."):
- support.unload(module)
-
- if interrupted and not ns.pgo:
- # print a newline after ^C
- print()
- print("Test suite interrupted by signal SIGINT.")
- omitted = set(selected) - set(good) - set(bad) - set(skipped)
- print(count(len(omitted), "test"), "omitted:")
- printlist(omitted)
- if good and not ns.quiet and not ns.pgo:
- if not bad and not skipped and not interrupted and len(good) > 1:
- print("All", end=' ')
- print(count(len(good), "test"), "OK.")
- if ns.print_slow:
- test_times.sort(reverse=True)
- print("10 slowest tests:")
- for time, test in test_times[:10]:
- print("%s: %.1fs" % (test, time))
- if bad and not ns.pgo:
- print(count(len(bad), "test"), "failed:")
- printlist(bad)
- if environment_changed and not ns.pgo:
- print("{} altered the execution environment:".format(
- count(len(environment_changed), "test")))
- printlist(environment_changed)
- if skipped and not ns.quiet and not ns.pgo:
- print(count(len(skipped), "test"), "skipped:")
- printlist(skipped)
-
- if ns.verbose2 and bad:
- print("Re-running failed tests in verbose mode")
- for test in bad[:]:
- if not ns.pgo:
- print("Re-running test %r in verbose mode" % test)
- sys.stdout.flush()
- try:
- ns.verbose = True
- ok = runtest(test, True, ns.quiet, ns.huntrleaks,
- timeout=ns.timeout, pgo=ns.pgo)
- except KeyboardInterrupt:
- # print a newline separate from the ^C
- print()
- break
- else:
- if ok[0] in {PASSED, ENV_CHANGED, SKIPPED, RESOURCE_DENIED}:
- bad.remove(test)
- else:
- if bad:
- print(count(len(bad), 'test'), "failed again:")
- printlist(bad)
-
- if ns.single:
- if next_single_test:
- with open(filename, 'w') as fp:
- fp.write(next_single_test + '\n')
- else:
- os.unlink(filename)
+from test.libregrtest import main
- if ns.trace:
- r = tracer.results()
- r.write_results(show_missing=True, summary=True, coverdir=ns.coverdir)
- if ns.runleaks:
- os.system("leaks %d" % os.getpid())
+# Alias for backward compatibility (just in case)
+main_in_temp_cwd = main
- sys.exit(len(bad) > 0 or interrupted)
+def _main():
+ global __file__
-# small set of tests to determine if we have a basically functioning interpreter
-# (i.e. if any of these fail, then anything else is likely to follow)
-STDTESTS = [
- 'test_grammar',
- 'test_opcodes',
- 'test_dict',
- 'test_builtin',
- 'test_exceptions',
- 'test_types',
- 'test_unittest',
- 'test_doctest',
- 'test_doctest2',
- 'test_support'
-]
-
-# set of tests that we don't want to be executed when using regrtest
-NOTTESTS = set()
-
-def findtests(testdir=None, stdtests=STDTESTS, nottests=NOTTESTS):
- """Return a list of all applicable test modules."""
- testdir = findtestdir(testdir)
- names = os.listdir(testdir)
- tests = []
- others = set(stdtests) | nottests
- for name in names:
- mod, ext = os.path.splitext(name)
- if mod[:5] == "test_" and ext in (".py", "") and mod not in others:
- tests.append(mod)
- return stdtests + sorted(tests)
-
-# We do not use a generator so multiple threads can call next().
-class MultiprocessTests(object):
-
- """A thread-safe iterator over tests for multiprocess mode."""
-
- def __init__(self, tests):
- self.interrupted = False
- self.lock = threading.Lock()
- self.tests = tests
-
- def __iter__(self):
- return self
-
- def __next__(self):
- with self.lock:
- if self.interrupted:
- raise StopIteration('tests interrupted')
- return next(self.tests)
-
-def replace_stdout():
- """Set stdout encoder error handler to backslashreplace (as stderr error
- handler) to avoid UnicodeEncodeError when printing a traceback"""
- import atexit
-
- stdout = sys.stdout
- sys.stdout = open(stdout.fileno(), 'w',
- encoding=stdout.encoding,
- errors="backslashreplace",
- closefd=False,
- newline='\n')
-
- def restore_stdout():
- sys.stdout.close()
- sys.stdout = stdout
- atexit.register(restore_stdout)
-
-def runtest(test, verbose, quiet,
- huntrleaks=False, use_resources=None,
- output_on_failure=False, failfast=False, match_tests=None,
- timeout=None, *, pgo=False):
- """Run a single test.
-
- test -- the name of the test
- verbose -- if true, print more messages
- quiet -- if true, don't print 'skipped' messages (probably redundant)
- huntrleaks -- run multiple times to test for leaks; requires a debug
- build; a triple corresponding to -R's three arguments
- use_resources -- list of extra resources to use
- output_on_failure -- if true, display test output on failure
- timeout -- dump the traceback and exit if a test takes more than
- timeout seconds
- failfast, match_tests -- See regrtest command-line flags for these.
- pgo -- if true, do not print unnecessary info when running the test
- for Profile Guided Optimization build
-
- Returns the tuple result, test_time, where result is one of the constants:
- INTERRUPTED KeyboardInterrupt when run under -j
- RESOURCE_DENIED test skipped because resource denied
- SKIPPED test skipped for some other reason
- ENV_CHANGED test failed because it changed the execution environment
- FAILED test failed
- PASSED test passed
- """
- if use_resources is not None:
- support.use_resources = use_resources
- use_timeout = (timeout is not None)
- if use_timeout:
- faulthandler.dump_traceback_later(timeout, exit=True)
- try:
- support.match_tests = match_tests
- if failfast:
- support.failfast = True
- if output_on_failure:
- support.verbose = True
-
- # Reuse the same instance to all calls to runtest(). Some
- # tests keep a reference to sys.stdout or sys.stderr
- # (eg. test_argparse).
- if runtest.stringio is None:
- stream = io.StringIO()
- runtest.stringio = stream
- else:
- stream = runtest.stringio
- stream.seek(0)
- stream.truncate()
-
- orig_stdout = sys.stdout
- orig_stderr = sys.stderr
- try:
- sys.stdout = stream
- sys.stderr = stream
- result = runtest_inner(test, verbose, quiet, huntrleaks,
- display_failure=False, pgo=pgo)
- if result[0] == FAILED and not pgo:
- output = stream.getvalue()
- orig_stderr.write(output)
- orig_stderr.flush()
- finally:
- sys.stdout = orig_stdout
- sys.stderr = orig_stderr
- else:
- support.verbose = verbose # Tell tests to be moderately quiet
- result = runtest_inner(test, verbose, quiet, huntrleaks,
- display_failure=not verbose, pgo=pgo)
- return result
- finally:
- if use_timeout:
- faulthandler.cancel_dump_traceback_later()
- cleanup_test_droppings(test, verbose)
-runtest.stringio = None
-
-# Unit tests are supposed to leave the execution environment unchanged
-# once they complete. But sometimes tests have bugs, especially when
-# tests fail, and the changes to environment go on to mess up other
-# tests. This can cause issues with buildbot stability, since tests
-# are run in random order and so problems may appear to come and go.
-# There are a few things we can save and restore to mitigate this, and
-# the following context manager handles this task.
-
-class saved_test_environment:
- """Save bits of the test environment and restore them at block exit.
-
- with saved_test_environment(testname, verbose, quiet):
- #stuff
-
- Unless quiet is True, a warning is printed to stderr if any of
- the saved items was changed by the test. The attribute 'changed'
- is initially False, but is set to True if a change is detected.
-
- If verbose is more than 1, the before and after state of changed
- items is also printed.
- """
-
- changed = False
-
- def __init__(self, testname, verbose=0, quiet=False, *, pgo=False):
- self.testname = testname
- self.verbose = verbose
- self.quiet = quiet
- self.pgo = pgo
-
- # To add things to save and restore, add a name XXX to the resources list
- # and add corresponding get_XXX/restore_XXX functions. get_XXX should
- # return the value to be saved and compared against a second call to the
- # get function when test execution completes. restore_XXX should accept
- # the saved value and restore the resource using it. It will be called if
- # and only if a change in the value is detected.
- #
- # Note: XXX will have any '.' replaced with '_' characters when determining
- # the corresponding method names.
-
- resources = ('sys.argv', 'cwd', 'sys.stdin', 'sys.stdout', 'sys.stderr',
- 'os.environ', 'sys.path', 'sys.path_hooks', '__import__',
- 'warnings.filters', 'asyncore.socket_map',
- 'logging._handlers', 'logging._handlerList', 'sys.gettrace',
- 'sys.warnoptions',
- # multiprocessing.process._cleanup() may release ref
- # to a thread, so check processes first.
- 'multiprocessing.process._dangling', 'threading._dangling',
- 'sysconfig._CONFIG_VARS', 'sysconfig._INSTALL_SCHEMES',
- 'files', 'locale', 'warnings.showwarning',
- 'shutil_archive_formats', 'shutil_unpack_formats',
- )
-
- def get_sys_argv(self):
- return id(sys.argv), sys.argv, sys.argv[:]
- def restore_sys_argv(self, saved_argv):
- sys.argv = saved_argv[1]
- sys.argv[:] = saved_argv[2]
-
- def get_cwd(self):
- return os.getcwd()
- def restore_cwd(self, saved_cwd):
- os.chdir(saved_cwd)
-
- def get_sys_stdout(self):
- return sys.stdout
- def restore_sys_stdout(self, saved_stdout):
- sys.stdout = saved_stdout
-
- def get_sys_stderr(self):
- return sys.stderr
- def restore_sys_stderr(self, saved_stderr):
- sys.stderr = saved_stderr
-
- def get_sys_stdin(self):
- return sys.stdin
- def restore_sys_stdin(self, saved_stdin):
- sys.stdin = saved_stdin
-
- def get_os_environ(self):
- return id(os.environ), os.environ, dict(os.environ)
- def restore_os_environ(self, saved_environ):
- os.environ = saved_environ[1]
- os.environ.clear()
- os.environ.update(saved_environ[2])
-
- def get_sys_path(self):
- return id(sys.path), sys.path, sys.path[:]
- def restore_sys_path(self, saved_path):
- sys.path = saved_path[1]
- sys.path[:] = saved_path[2]
-
- def get_sys_path_hooks(self):
- return id(sys.path_hooks), sys.path_hooks, sys.path_hooks[:]
- def restore_sys_path_hooks(self, saved_hooks):
- sys.path_hooks = saved_hooks[1]
- sys.path_hooks[:] = saved_hooks[2]
-
- def get_sys_gettrace(self):
- return sys.gettrace()
- def restore_sys_gettrace(self, trace_fxn):
- sys.settrace(trace_fxn)
-
- def get___import__(self):
- return builtins.__import__
- def restore___import__(self, import_):
- builtins.__import__ = import_
-
- def get_warnings_filters(self):
- return id(warnings.filters), warnings.filters, warnings.filters[:]
- def restore_warnings_filters(self, saved_filters):
- warnings.filters = saved_filters[1]
- warnings.filters[:] = saved_filters[2]
-
- def get_asyncore_socket_map(self):
- asyncore = sys.modules.get('asyncore')
- # XXX Making a copy keeps objects alive until __exit__ gets called.
- return asyncore and asyncore.socket_map.copy() or {}
- def restore_asyncore_socket_map(self, saved_map):
- asyncore = sys.modules.get('asyncore')
- if asyncore is not None:
- asyncore.close_all(ignore_all=True)
- asyncore.socket_map.update(saved_map)
-
- def get_shutil_archive_formats(self):
- # we could call get_archives_formats() but that only returns the
- # registry keys; we want to check the values too (the functions that
- # are registered)
- return shutil._ARCHIVE_FORMATS, shutil._ARCHIVE_FORMATS.copy()
- def restore_shutil_archive_formats(self, saved):
- shutil._ARCHIVE_FORMATS = saved[0]
- shutil._ARCHIVE_FORMATS.clear()
- shutil._ARCHIVE_FORMATS.update(saved[1])
-
- def get_shutil_unpack_formats(self):
- return shutil._UNPACK_FORMATS, shutil._UNPACK_FORMATS.copy()
- def restore_shutil_unpack_formats(self, saved):
- shutil._UNPACK_FORMATS = saved[0]
- shutil._UNPACK_FORMATS.clear()
- shutil._UNPACK_FORMATS.update(saved[1])
-
- def get_logging__handlers(self):
- # _handlers is a WeakValueDictionary
- return id(logging._handlers), logging._handlers, logging._handlers.copy()
- def restore_logging__handlers(self, saved_handlers):
- # Can't easily revert the logging state
- pass
-
- def get_logging__handlerList(self):
- # _handlerList is a list of weakrefs to handlers
- return id(logging._handlerList), logging._handlerList, logging._handlerList[:]
- def restore_logging__handlerList(self, saved_handlerList):
- # Can't easily revert the logging state
- pass
-
- def get_sys_warnoptions(self):
- return id(sys.warnoptions), sys.warnoptions, sys.warnoptions[:]
- def restore_sys_warnoptions(self, saved_options):
- sys.warnoptions = saved_options[1]
- sys.warnoptions[:] = saved_options[2]
-
- # Controlling dangling references to Thread objects can make it easier
- # to track reference leaks.
- def get_threading__dangling(self):
- if not threading:
- return None
- # This copies the weakrefs without making any strong reference
- return threading._dangling.copy()
- def restore_threading__dangling(self, saved):
- if not threading:
- return
- threading._dangling.clear()
- threading._dangling.update(saved)
-
- # Same for Process objects
- def get_multiprocessing_process__dangling(self):
- if not multiprocessing:
- return None
- # Unjoined process objects can survive after process exits
- multiprocessing.process._cleanup()
- # This copies the weakrefs without making any strong reference
- return multiprocessing.process._dangling.copy()
- def restore_multiprocessing_process__dangling(self, saved):
- if not multiprocessing:
- return
- multiprocessing.process._dangling.clear()
- multiprocessing.process._dangling.update(saved)
-
- def get_sysconfig__CONFIG_VARS(self):
- # make sure the dict is initialized
- sysconfig.get_config_var('prefix')
- return (id(sysconfig._CONFIG_VARS), sysconfig._CONFIG_VARS,
- dict(sysconfig._CONFIG_VARS))
- def restore_sysconfig__CONFIG_VARS(self, saved):
- sysconfig._CONFIG_VARS = saved[1]
- sysconfig._CONFIG_VARS.clear()
- sysconfig._CONFIG_VARS.update(saved[2])
-
- def get_sysconfig__INSTALL_SCHEMES(self):
- return (id(sysconfig._INSTALL_SCHEMES), sysconfig._INSTALL_SCHEMES,
- sysconfig._INSTALL_SCHEMES.copy())
- def restore_sysconfig__INSTALL_SCHEMES(self, saved):
- sysconfig._INSTALL_SCHEMES = saved[1]
- sysconfig._INSTALL_SCHEMES.clear()
- sysconfig._INSTALL_SCHEMES.update(saved[2])
-
- def get_files(self):
- return sorted(fn + ('/' if os.path.isdir(fn) else '')
- for fn in os.listdir())
- def restore_files(self, saved_value):
- fn = support.TESTFN
- if fn not in saved_value and (fn + '/') not in saved_value:
- if os.path.isfile(fn):
- support.unlink(fn)
- elif os.path.isdir(fn):
- support.rmtree(fn)
-
- _lc = [getattr(locale, lc) for lc in dir(locale)
- if lc.startswith('LC_')]
- def get_locale(self):
- pairings = []
- for lc in self._lc:
- try:
- pairings.append((lc, locale.setlocale(lc, None)))
- except (TypeError, ValueError):
- continue
- return pairings
- def restore_locale(self, saved):
- for lc, setting in saved:
- locale.setlocale(lc, setting)
-
- def get_warnings_showwarning(self):
- return warnings.showwarning
- def restore_warnings_showwarning(self, fxn):
- warnings.showwarning = fxn
-
- def resource_info(self):
- for name in self.resources:
- method_suffix = name.replace('.', '_')
- get_name = 'get_' + method_suffix
- restore_name = 'restore_' + method_suffix
- yield name, getattr(self, get_name), getattr(self, restore_name)
-
- def __enter__(self):
- self.saved_values = dict((name, get()) for name, get, restore
- in self.resource_info())
- return self
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- saved_values = self.saved_values
- del self.saved_values
- for name, get, restore in self.resource_info():
- current = get()
- original = saved_values.pop(name)
- # Check for changes to the resource's value
- if current != original:
- self.changed = True
- restore(original)
- if not self.quiet and not self.pgo:
- print("Warning -- {} was modified by {}".format(
- name, self.testname),
- file=sys.stderr)
- if self.verbose > 1 and not self.pgo:
- print(" Before: {}\n After: {} ".format(
- original, current),
- file=sys.stderr)
- return False
-
-
-def runtest_inner(test, verbose, quiet,
- huntrleaks=False, display_failure=True, pgo=False):
- support.unload(test)
-
- test_time = 0.0
- refleak = False # True if the test leaked references.
- try:
- if test.startswith('test.'):
- abstest = test
- else:
- # Always import it from the test package
- abstest = 'test.' + test
- with saved_test_environment(test, verbose, quiet, pgo=pgo) as environment:
- start_time = time.time()
- the_module = importlib.import_module(abstest)
- # If the test has a test_main, that will run the appropriate
- # tests. If not, use normal unittest test loading.
- test_runner = getattr(the_module, "test_main", None)
- if test_runner is None:
- def test_runner():
- loader = unittest.TestLoader()
- tests = loader.loadTestsFromModule(the_module)
- for error in loader.errors:
- print(error, file=sys.stderr)
- if loader.errors:
- raise Exception("errors while loading tests")
- support.run_unittest(tests)
- test_runner()
- if huntrleaks:
- refleak = dash_R(the_module, test, test_runner, huntrleaks)
- test_time = time.time() - start_time
- except support.ResourceDenied as msg:
- if not quiet and not pgo:
- print(test, "skipped --", msg)
- sys.stdout.flush()
- return RESOURCE_DENIED, test_time
- except unittest.SkipTest as msg:
- if not quiet and not pgo:
- print(test, "skipped --", msg)
- sys.stdout.flush()
- return SKIPPED, test_time
- except KeyboardInterrupt:
- raise
- except support.TestFailed as msg:
- if not pgo:
- if display_failure:
- print("test", test, "failed --", msg, file=sys.stderr)
- else:
- print("test", test, "failed", file=sys.stderr)
- sys.stderr.flush()
- return FAILED, test_time
- except:
- msg = traceback.format_exc()
- if not pgo:
- print("test", test, "crashed --", msg, file=sys.stderr)
- sys.stderr.flush()
- return FAILED, test_time
- else:
- if refleak:
- return FAILED, test_time
- if environment.changed:
- return ENV_CHANGED, test_time
- return PASSED, test_time
-
-def cleanup_test_droppings(testname, verbose):
- import shutil
- import stat
- import gc
-
- # First kill any dangling references to open files etc.
- # This can also issue some ResourceWarnings which would otherwise get
- # triggered during the following test run, and possibly produce failures.
- gc.collect()
-
- # Try to clean up junk commonly left behind. While tests shouldn't leave
- # any files or directories behind, when a test fails that can be tedious
- # for it to arrange. The consequences can be especially nasty on Windows,
- # since if a test leaves a file open, it cannot be deleted by name (while
- # there's nothing we can do about that here either, we can display the
- # name of the offending test, which is a real help).
- for name in (support.TESTFN,
- "db_home",
- ):
- if not os.path.exists(name):
- continue
-
- if os.path.isdir(name):
- kind, nuker = "directory", shutil.rmtree
- elif os.path.isfile(name):
- kind, nuker = "file", os.unlink
- else:
- raise SystemError("os.path says %r exists but is neither "
- "directory nor file" % name)
-
- if verbose:
- print("%r left behind %s %r" % (testname, kind, name))
- try:
- # if we have chmod, fix possible permissions problems
- # that might prevent cleanup
- if (hasattr(os, 'chmod')):
- os.chmod(name, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
- nuker(name)
- except Exception as msg:
- print(("%r left behind %s %r and it couldn't be "
- "removed: %s" % (testname, kind, name, msg)), file=sys.stderr)
-
-def dash_R(the_module, test, indirect_test, huntrleaks):
- """Run a test multiple times, looking for reference leaks.
-
- Returns:
- False if the test didn't leak references; True if we detected refleaks.
- """
- # This code is hackish and inelegant, but it seems to do the job.
- import copyreg
- import collections.abc
-
- if not hasattr(sys, 'gettotalrefcount'):
- raise Exception("Tracking reference leaks requires a debug build "
- "of Python")
-
- # Save current values for dash_R_cleanup() to restore.
- fs = warnings.filters[:]
- ps = copyreg.dispatch_table.copy()
- pic = sys.path_importer_cache.copy()
- try:
- import zipimport
- except ImportError:
- zdc = None # Run unmodified on platforms without zipimport support
- else:
- zdc = zipimport._zip_directory_cache.copy()
- abcs = {}
- for abc in [getattr(collections.abc, a) for a in collections.abc.__all__]:
- if not isabstract(abc):
- continue
- for obj in abc.__subclasses__() + [abc]:
- abcs[obj] = obj._abc_registry.copy()
-
- nwarmup, ntracked, fname = huntrleaks
- fname = os.path.join(support.SAVEDCWD, fname)
- repcount = nwarmup + ntracked
- rc_deltas = [0] * repcount
- alloc_deltas = [0] * repcount
-
- print("beginning", repcount, "repetitions", file=sys.stderr)
- print(("1234567890"*(repcount//10 + 1))[:repcount], file=sys.stderr)
- sys.stderr.flush()
- for i in range(repcount):
- indirect_test()
- alloc_after, rc_after = dash_R_cleanup(fs, ps, pic, zdc, abcs)
- sys.stderr.write('.')
- sys.stderr.flush()
- if i >= nwarmup:
- rc_deltas[i] = rc_after - rc_before
- alloc_deltas[i] = alloc_after - alloc_before
- alloc_before, rc_before = alloc_after, rc_after
- print(file=sys.stderr)
- # These checkers return False on success, True on failure
- def check_rc_deltas(deltas):
- return any(deltas)
- def check_alloc_deltas(deltas):
- # At least 1/3rd of 0s
- if 3 * deltas.count(0) < len(deltas):
- return True
- # Nothing else than 1s, 0s and -1s
- if not set(deltas) <= {1,0,-1}:
- return True
- return False
- failed = False
- for deltas, item_name, checker in [
- (rc_deltas, 'references', check_rc_deltas),
- (alloc_deltas, 'memory blocks', check_alloc_deltas)]:
- if checker(deltas):
- msg = '%s leaked %s %s, sum=%s' % (
- test, deltas[nwarmup:], item_name, sum(deltas))
- print(msg, file=sys.stderr)
- sys.stderr.flush()
- with open(fname, "a") as refrep:
- print(msg, file=refrep)
- refrep.flush()
- failed = True
- return failed
-
-def dash_R_cleanup(fs, ps, pic, zdc, abcs):
- import gc, copyreg
- import _strptime, linecache
- import urllib.parse, urllib.request, mimetypes, doctest
- import struct, filecmp, collections.abc
- from distutils.dir_util import _path_created
- from weakref import WeakSet
-
- # Clear the warnings registry, so they can be displayed again
- for mod in sys.modules.values():
- if hasattr(mod, '__warningregistry__'):
- del mod.__warningregistry__
-
- # Restore some original values.
- warnings.filters[:] = fs
- copyreg.dispatch_table.clear()
- copyreg.dispatch_table.update(ps)
- sys.path_importer_cache.clear()
- sys.path_importer_cache.update(pic)
- try:
- import zipimport
- except ImportError:
- pass # Run unmodified on platforms without zipimport support
- else:
- zipimport._zip_directory_cache.clear()
- zipimport._zip_directory_cache.update(zdc)
-
- # clear type cache
- sys._clear_type_cache()
-
- # Clear ABC registries, restoring previously saved ABC registries.
- for abc in [getattr(collections.abc, a) for a in collections.abc.__all__]:
- if not isabstract(abc):
- continue
- for obj in abc.__subclasses__() + [abc]:
- obj._abc_registry = abcs.get(obj, WeakSet()).copy()
- obj._abc_cache.clear()
- obj._abc_negative_cache.clear()
-
- # Flush standard output, so that buffered data is sent to the OS and
- # associated Python objects are reclaimed.
- for stream in (sys.stdout, sys.stderr, sys.__stdout__, sys.__stderr__):
- if stream is not None:
- stream.flush()
-
- # Clear assorted module caches.
- _path_created.clear()
- re.purge()
- _strptime._regex_cache.clear()
- urllib.parse.clear_cache()
- urllib.request.urlcleanup()
- linecache.clearcache()
- mimetypes._default_mime_types()
- filecmp._cache.clear()
- struct._clearcache()
- doctest.master = None
- try:
- import ctypes
- except ImportError:
- # Don't worry about resetting the cache if ctypes is not supported
- pass
- else:
- ctypes._reset_cache()
-
- # Collect cyclic trash and read memory statistics immediately after.
- func1 = sys.getallocatedblocks
- func2 = sys.gettotalrefcount
- gc.collect()
- return func1(), func2()
-
-def warm_caches():
- # char cache
- s = bytes(range(256))
- for i in range(256):
- s[i:i+1]
- # unicode cache
- x = [chr(i) for i in range(256)]
- # int cache
- x = list(range(-5, 257))
-
-def findtestdir(path=None):
- return path or os.path.dirname(__file__) or os.curdir
-
-def removepy(names):
- if not names:
- return
- for idx, name in enumerate(names):
- basename, ext = os.path.splitext(name)
- if ext == '.py':
- names[idx] = basename
-
-def count(n, word):
- if n == 1:
- return "%d %s" % (n, word)
- else:
- return "%d %ss" % (n, word)
-
-def printlist(x, width=70, indent=4):
- """Print the elements of iterable x to stdout.
-
- Optional arg width (default 70) is the maximum line length.
- Optional arg indent (default 4) is the number of blanks with which to
- begin each line.
- """
-
- from textwrap import fill
- blanks = ' ' * indent
- # Print the sorted list: 'x' may be a '--random' list or a set()
- print(fill(' '.join(str(elt) for elt in sorted(x)), width,
- initial_indent=blanks, subsequent_indent=blanks))
-
-
-def main_in_temp_cwd():
- """Run main() in a temporary working directory."""
- if sysconfig.is_python_build():
- try:
- os.mkdir(TEMPDIR)
- except FileExistsError:
- pass
-
- # Define a writable temp dir that will be used as cwd while running
- # the tests. The name of the dir includes the pid to allow parallel
- # testing (see the -j option).
- test_cwd = 'test_python_{}'.format(os.getpid())
- test_cwd = os.path.join(TEMPDIR, test_cwd)
-
- # Run the tests in a context manager that temporarily changes the CWD to a
- # temporary and writable directory. If it's not possible to create or
- # change the CWD, the original CWD will be used. The original CWD is
- # available from support.SAVEDCWD.
- with support.temp_cwd(test_cwd, quiet=True):
- main()
-
-
-if __name__ == '__main__':
# Remove regrtest.py's own directory from the module search path. Despite
# the elimination of implicit relative imports, this is still needed to
# ensure that submodules of the test package do not inappropriately appear
# as top-level modules even when people (or buildbots!) invoke regrtest.py
# directly instead of using the -m switch
mydir = os.path.abspath(os.path.normpath(os.path.dirname(sys.argv[0])))
- i = len(sys.path)
+ i = len(sys.path) - 1
while i >= 0:
- i -= 1
if os.path.abspath(os.path.normpath(sys.path[i])) == mydir:
del sys.path[i]
+ else:
+ i -= 1
# findtestdir() gets the dirname out of __file__, so we have to make it
# absolute before changing the working directory.
@@ -1614,4 +43,8 @@ if __name__ == '__main__':
# sanity check
assert __file__ == os.path.abspath(sys.argv[0])
- main_in_temp_cwd()
+ main()
+
+
+if __name__ == '__main__':
+ _main()
diff --git a/Lib/test/seq_tests.py b/Lib/test/seq_tests.py
index 72f4845a97..1e7a6f6522 100644
--- a/Lib/test/seq_tests.py
+++ b/Lib/test/seq_tests.py
@@ -318,7 +318,6 @@ class CommonTest(unittest.TestCase):
self.assertEqual(id(s), id(s*1))
def test_bigrepeat(self):
- import sys
if sys.maxsize <= 2147483647:
x = self.type2test([0])
x *= 2**16
diff --git a/Lib/test/signalinterproctester.py b/Lib/test/signalinterproctester.py
new file mode 100644
index 0000000000..d3ae170983
--- /dev/null
+++ b/Lib/test/signalinterproctester.py
@@ -0,0 +1,84 @@
+import os
+import signal
+import subprocess
+import sys
+import time
+import unittest
+
+
+class SIGUSR1Exception(Exception):
+ pass
+
+
+class InterProcessSignalTests(unittest.TestCase):
+ def setUp(self):
+ self.got_signals = {'SIGHUP': 0, 'SIGUSR1': 0, 'SIGALRM': 0}
+
+ def sighup_handler(self, signum, frame):
+ self.got_signals['SIGHUP'] += 1
+
+ def sigusr1_handler(self, signum, frame):
+ self.got_signals['SIGUSR1'] += 1
+ raise SIGUSR1Exception
+
+ def wait_signal(self, child, signame, exc_class=None):
+ try:
+ if child is not None:
+ # This wait should be interrupted by exc_class
+ # (if set)
+ child.wait()
+
+ timeout = 10.0
+ deadline = time.monotonic() + timeout
+
+ while time.monotonic() < deadline:
+ if self.got_signals[signame]:
+ return
+ signal.pause()
+ except BaseException as exc:
+ if exc_class is not None and isinstance(exc, exc_class):
+ # got the expected exception
+ return
+ raise
+
+ self.fail('signal %s not received after %s seconds'
+ % (signame, timeout))
+
+ def subprocess_send_signal(self, pid, signame):
+ code = 'import os, signal; os.kill(%s, signal.%s)' % (pid, signame)
+ args = [sys.executable, '-I', '-c', code]
+ return subprocess.Popen(args)
+
+ def test_interprocess_signal(self):
+ # Install handlers. This function runs in a sub-process, so we
+ # don't worry about re-setting the default handlers.
+ signal.signal(signal.SIGHUP, self.sighup_handler)
+ signal.signal(signal.SIGUSR1, self.sigusr1_handler)
+ signal.signal(signal.SIGUSR2, signal.SIG_IGN)
+ signal.signal(signal.SIGALRM, signal.default_int_handler)
+
+ # Let the sub-processes know who to send signals to.
+ pid = str(os.getpid())
+
+ with self.subprocess_send_signal(pid, "SIGHUP") as child:
+ self.wait_signal(child, 'SIGHUP')
+ self.assertEqual(self.got_signals, {'SIGHUP': 1, 'SIGUSR1': 0,
+ 'SIGALRM': 0})
+
+ with self.subprocess_send_signal(pid, "SIGUSR1") as child:
+ self.wait_signal(child, 'SIGUSR1', SIGUSR1Exception)
+ self.assertEqual(self.got_signals, {'SIGHUP': 1, 'SIGUSR1': 1,
+ 'SIGALRM': 0})
+
+ with self.subprocess_send_signal(pid, "SIGUSR2") as child:
+ # Nothing should happen: SIGUSR2 is ignored
+ child.wait()
+
+ signal.alarm(1)
+ self.wait_signal(None, 'SIGALRM', KeyboardInterrupt)
+ self.assertEqual(self.got_signals, {'SIGHUP': 1, 'SIGUSR1': 1,
+ 'SIGALRM': 0})
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index e124fab610..04e8629134 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -26,6 +26,7 @@ import sys
import sysconfig
import tempfile
import time
+import types
import unittest
import urllib.error
import warnings
@@ -89,6 +90,7 @@ __all__ = [
"bigmemtest", "bigaddrspacetest", "cpython_only", "get_attribute",
"requires_IEEE_754", "skip_unless_xattr", "requires_zlib",
"anticipate_failure", "load_package_tests", "detect_api_mismatch",
+ "check__all__",
# sys
"is_jython", "check_impl_detail",
# network
@@ -900,7 +902,7 @@ def temp_dir(path=None, quiet=False):
yield path
finally:
if dir_created:
- shutil.rmtree(path)
+ rmtree(path)
@contextlib.contextmanager
def change_cwd(path, quiet=False):
@@ -2073,6 +2075,11 @@ def args_from_interpreter_flags():
settings in sys.flags and sys.warnoptions."""
return subprocess._args_from_interpreter_flags()
+def optim_args_from_interpreter_flags():
+ """Return a list of command-line arguments reproducing the current
+ optimization settings in sys.flags."""
+ return subprocess._optim_args_from_interpreter_flags()
+
#============================================================
# Support for assertions about logging.
#============================================================
@@ -2224,6 +2231,65 @@ def detect_api_mismatch(ref_api, other_api, *, ignore=()):
return missing_items
+def check__all__(test_case, module, name_of_module=None, extra=(),
+ blacklist=()):
+ """Assert that the __all__ variable of 'module' contains all public names.
+
+ The module's public names (its API) are detected automatically based on
+ whether they match the public name convention and were defined in
+ 'module'.
+
+ The 'name_of_module' argument can specify (as a string or tuple thereof)
+ what module(s) an API could be defined in in order to be detected as a
+ public API. One case for this is when 'module' imports part of its public
+ API from other modules, possibly a C backend (like 'csv' and its '_csv').
+
+ The 'extra' argument can be a set of names that wouldn't otherwise be
+ automatically detected as "public", like objects without a proper
+ '__module__' attriubute. If provided, it will be added to the
+ automatically detected ones.
+
+ The 'blacklist' argument can be a set of names that must not be treated
+ as part of the public API even though their names indicate otherwise.
+
+ Usage:
+ import bar
+ import foo
+ import unittest
+ from test import support
+
+ class MiscTestCase(unittest.TestCase):
+ def test__all__(self):
+ support.check__all__(self, foo)
+
+ class OtherTestCase(unittest.TestCase):
+ def test__all__(self):
+ extra = {'BAR_CONST', 'FOO_CONST'}
+ blacklist = {'baz'} # Undocumented name.
+ # bar imports part of its API from _bar.
+ support.check__all__(self, bar, ('bar', '_bar'),
+ extra=extra, blacklist=blacklist)
+
+ """
+
+ if name_of_module is None:
+ name_of_module = (module.__name__, )
+ elif isinstance(name_of_module, str):
+ name_of_module = (name_of_module, )
+
+ expected = set(extra)
+
+ for name in dir(module):
+ if name.startswith('_') or name in blacklist:
+ continue
+ obj = getattr(module, name)
+ if (getattr(obj, '__module__', None) in name_of_module or
+ (not hasattr(obj, '__module__') and
+ not isinstance(obj, types.ModuleType))):
+ expected.add(name)
+ test_case.assertCountEqual(module.__all__, expected)
+
+
class SuppressCrashReport:
"""Try to prevent a crash report from popping up.
diff --git a/Lib/test/test__locale.py b/Lib/test/test__locale.py
index 58f2f04fcd..ab4e247961 100644
--- a/Lib/test/test__locale.py
+++ b/Lib/test/test__locale.py
@@ -4,7 +4,6 @@ try:
except ImportError:
nl_langinfo = None
-import codecs
import locale
import sys
import unittest
diff --git a/Lib/test/test__osx_support.py b/Lib/test/test__osx_support.py
index ac6325a751..bcba8caa29 100644
--- a/Lib/test/test__osx_support.py
+++ b/Lib/test/test__osx_support.py
@@ -4,7 +4,6 @@ Test suite for _osx_support: shared OS X support functions.
import os
import platform
-import shutil
import stat
import sys
import unittest
diff --git a/Lib/test/test_aifc.py b/Lib/test/test_aifc.py
index ab5143787b..1bd1f89c8a 100644
--- a/Lib/test/test_aifc.py
+++ b/Lib/test/test_aifc.py
@@ -2,7 +2,6 @@ from test.support import findfile, TESTFN, unlink
import unittest
from test import audiotests
from audioop import byteswap
-import os
import io
import sys
import struct
diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py
index f9ee398899..52c624771c 100644
--- a/Lib/test/test_argparse.py
+++ b/Lib/test/test_argparse.py
@@ -4512,6 +4512,21 @@ class TestStrings(TestCase):
string = "Namespace(bar='spam', foo=42)"
self.assertStringEqual(ns, string)
+ def test_namespace_starkwargs_notidentifier(self):
+ ns = argparse.Namespace(**{'"': 'quote'})
+ string = """Namespace(**{'"': 'quote'})"""
+ self.assertStringEqual(ns, string)
+
+ def test_namespace_kwargs_and_starkwargs_notidentifier(self):
+ ns = argparse.Namespace(a=1, **{'"': 'quote'})
+ string = """Namespace(a=1, **{'"': 'quote'})"""
+ self.assertStringEqual(ns, string)
+
+ def test_namespace_starkwargs_identifier(self):
+ ns = argparse.Namespace(**{'valid': True})
+ string = "Namespace(valid=True)"
+ self.assertStringEqual(ns, string)
+
def test_parser(self):
parser = argparse.ArgumentParser(prog='PROG')
string = (
diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py
index 482526eec1..8fd54cc1db 100644
--- a/Lib/test/test_array.py
+++ b/Lib/test/test_array.py
@@ -7,8 +7,6 @@ from test import support
import weakref
import pickle
import operator
-import io
-import math
import struct
import sys
import warnings
@@ -318,8 +316,19 @@ class BaseTest:
d = pickle.dumps((itorig, orig), proto)
it, a = pickle.loads(d)
a.fromlist(data2)
- self.assertEqual(type(it), type(itorig))
- self.assertEqual(list(it), data2)
+ self.assertEqual(list(it), [])
+
+ def test_exhausted_iterator(self):
+ a = array.array(self.typecode, self.example)
+ self.assertEqual(list(a), list(self.example))
+ exhit = iter(a)
+ empit = iter(a)
+ for x in exhit: # exhaust the iterator
+ next(empit) # not exhausted
+ a.append(self.outside)
+ self.assertEqual(list(exhit), [])
+ self.assertEqual(list(empit), [self.outside])
+ self.assertEqual(list(a), list(self.example) + [self.outside])
def test_insert(self):
a = array.array(self.typecode, self.example)
@@ -1070,6 +1079,12 @@ class BaseTest:
a = array.array('B', b"")
self.assertRaises(BufferError, getbuffer_with_null_view, a)
+ def test_free_after_iterating(self):
+ support.check_free_after_iterating(self, iter, array.array,
+ (self.typecode,))
+ support.check_free_after_iterating(self, reversed, array.array,
+ (self.typecode,))
+
class StringTest(BaseTest):
def test_setitem(self):
diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py
index d3e6d35943..7b43be6dfc 100644
--- a/Lib/test/test_ast.py
+++ b/Lib/test/test_ast.py
@@ -1,7 +1,8 @@
+import ast
+import dis
import os
import sys
import unittest
-import ast
import weakref
from test import support
@@ -238,7 +239,7 @@ class AST_Tests(unittest.TestCase):
ast_tree = compile(i, "?", kind, ast.PyCF_ONLY_AST)
self.assertEqual(to_tuple(ast_tree), o)
self._assertTrueorder(ast_tree, (0, 0))
- with self.subTest(action="compiling", input=i):
+ with self.subTest(action="compiling", input=i, kind=kind):
compile(ast_tree, "?", kind)
def test_slice(self):
@@ -547,6 +548,17 @@ class ASTHelpers_Test(unittest.TestCase):
compile(mod, 'test', 'exec')
self.assertIn("invalid integer value: None", str(cm.exception))
+ def test_level_as_none(self):
+ body = [ast.ImportFrom(module='time',
+ names=[ast.alias(name='sleep')],
+ level=None,
+ lineno=0, col_offset=0)]
+ mod = ast.Module(body)
+ code = compile(mod, 'test', 'exec')
+ ns = {}
+ exec(code, ns)
+ self.assertIn('sleep', ns)
+
class ASTValidatorTests(unittest.TestCase):
@@ -933,6 +945,125 @@ class ASTValidatorTests(unittest.TestCase):
compile(mod, fn, "exec")
+class ConstantTests(unittest.TestCase):
+ """Tests on the ast.Constant node type."""
+
+ def compile_constant(self, value):
+ tree = ast.parse("x = 123")
+
+ node = tree.body[0].value
+ new_node = ast.Constant(value=value)
+ ast.copy_location(new_node, node)
+ tree.body[0].value = new_node
+
+ code = compile(tree, "<string>", "exec")
+
+ ns = {}
+ exec(code, ns)
+ return ns['x']
+
+ def test_validation(self):
+ with self.assertRaises(TypeError) as cm:
+ self.compile_constant([1, 2, 3])
+ self.assertEqual(str(cm.exception),
+ "got an invalid type in Constant: list")
+
+ def test_singletons(self):
+ for const in (None, False, True, Ellipsis, b'', frozenset()):
+ with self.subTest(const=const):
+ value = self.compile_constant(const)
+ self.assertIs(value, const)
+
+ def test_values(self):
+ nested_tuple = (1,)
+ nested_frozenset = frozenset({1})
+ for level in range(3):
+ nested_tuple = (nested_tuple, 2)
+ nested_frozenset = frozenset({nested_frozenset, 2})
+ values = (123, 123.0, 123j,
+ "unicode", b'bytes',
+ tuple("tuple"), frozenset("frozenset"),
+ nested_tuple, nested_frozenset)
+ for value in values:
+ with self.subTest(value=value):
+ result = self.compile_constant(value)
+ self.assertEqual(result, value)
+
+ def test_assign_to_constant(self):
+ tree = ast.parse("x = 1")
+
+ target = tree.body[0].targets[0]
+ new_target = ast.Constant(value=1)
+ ast.copy_location(new_target, target)
+ tree.body[0].targets[0] = new_target
+
+ with self.assertRaises(ValueError) as cm:
+ compile(tree, "string", "exec")
+ self.assertEqual(str(cm.exception),
+ "expression which can't be assigned "
+ "to in Store context")
+
+ def test_get_docstring(self):
+ tree = ast.parse("'docstring'\nx = 1")
+ self.assertEqual(ast.get_docstring(tree), 'docstring')
+
+ tree.body[0].value = ast.Constant(value='constant docstring')
+ self.assertEqual(ast.get_docstring(tree), 'constant docstring')
+
+ def get_load_const(self, tree):
+ # Compile to bytecode, disassemble and get parameter of LOAD_CONST
+ # instructions
+ co = compile(tree, '<string>', 'exec')
+ consts = []
+ for instr in dis.get_instructions(co):
+ if instr.opname == 'LOAD_CONST':
+ consts.append(instr.argval)
+ return consts
+
+ @support.cpython_only
+ def test_load_const(self):
+ consts = [None,
+ True, False,
+ 124,
+ 2.0,
+ 3j,
+ "unicode",
+ b'bytes',
+ (1, 2, 3)]
+
+ code = '\n'.join(['x={!r}'.format(const) for const in consts])
+ code += '\nx = ...'
+ consts.extend((Ellipsis, None))
+
+ tree = ast.parse(code)
+ self.assertEqual(self.get_load_const(tree),
+ consts)
+
+ # Replace expression nodes with constants
+ for assign, const in zip(tree.body, consts):
+ assert isinstance(assign, ast.Assign), ast.dump(assign)
+ new_node = ast.Constant(value=const)
+ ast.copy_location(new_node, assign.value)
+ assign.value = new_node
+
+ self.assertEqual(self.get_load_const(tree),
+ consts)
+
+ def test_literal_eval(self):
+ tree = ast.parse("1 + 2")
+ binop = tree.body[0].value
+
+ new_left = ast.Constant(value=10)
+ ast.copy_location(new_left, binop.left)
+ binop.left = new_left
+
+ new_right = ast.Constant(value=20)
+ ast.copy_location(new_right, binop.right)
+ binop.right = new_right
+
+ self.assertEqual(ast.literal_eval(binop), 30)
+
+
def main():
if __name__ != '__main__':
return
@@ -940,8 +1071,9 @@ def main():
for statements, kind in ((exec_tests, "exec"), (single_tests, "single"),
(eval_tests, "eval")):
print(kind+"_results = [")
- for s in statements:
- print(repr(to_tuple(compile(s, "?", kind, 0x400)))+",")
+ for statement in statements:
+ tree = ast.parse(statement, "?", kind)
+ print("%r," % (to_tuple(tree),))
print("]")
print("main()")
raise SystemExit
diff --git a/Lib/test/test_asynchat.py b/Lib/test/test_asynchat.py
index 3a33fc8b2d..0eba76db47 100644
--- a/Lib/test/test_asynchat.py
+++ b/Lib/test/test_asynchat.py
@@ -12,7 +12,6 @@ import socket
import sys
import time
import unittest
-import warnings
import unittest.mock
try:
import threading
@@ -297,37 +296,6 @@ class TestHelperFunctions(unittest.TestCase):
self.assertEqual(asynchat.find_prefix_at_end("qwertydkjf", "\r\n"), 0)
-class TestFifo(unittest.TestCase):
- def test_basic(self):
- with self.assertWarns(DeprecationWarning) as cm:
- f = asynchat.fifo()
- self.assertEqual(str(cm.warning),
- "fifo class will be removed in Python 3.6")
- f.push(7)
- f.push(b'a')
- self.assertEqual(len(f), 2)
- self.assertEqual(f.first(), 7)
- self.assertEqual(f.pop(), (1, 7))
- self.assertEqual(len(f), 1)
- self.assertEqual(f.first(), b'a')
- self.assertEqual(f.is_empty(), False)
- self.assertEqual(f.pop(), (1, b'a'))
- self.assertEqual(len(f), 0)
- self.assertEqual(f.is_empty(), True)
- self.assertEqual(f.pop(), (0, None))
-
- def test_given_list(self):
- with self.assertWarns(DeprecationWarning) as cm:
- f = asynchat.fifo([b'x', 17, 3])
- self.assertEqual(str(cm.warning),
- "fifo class will be removed in Python 3.6")
- self.assertEqual(len(f), 3)
- self.assertEqual(f.pop(), (1, b'x'))
- self.assertEqual(f.pop(), (1, 17))
- self.assertEqual(f.pop(), (1, 3))
- self.assertEqual(f.pop(), (0, None))
-
-
class TestNotConnected(unittest.TestCase):
def test_disallow_negative_terminator(self):
# Issue #11259
diff --git a/Lib/test/test_bigmem.py b/Lib/test/test_bigmem.py
index 40ac9bff2f..6133bbcac5 100644
--- a/Lib/test/test_bigmem.py
+++ b/Lib/test/test_bigmem.py
@@ -14,7 +14,6 @@ from test.support import bigmemtest, _1G, _2G, _4G
import unittest
import operator
import sys
-import functools
# These tests all use one of the bigmemtest decorators to indicate how much
# memory they use and how much memory they need to be even meaningful. The
diff --git a/Lib/test/test_binascii.py b/Lib/test/test_binascii.py
index 8367afe083..fbc933e4e6 100644
--- a/Lib/test/test_binascii.py
+++ b/Lib/test/test_binascii.py
@@ -159,11 +159,25 @@ class BinASCIITest(unittest.TestCase):
# Then calculate the hexbin4 binary-to-ASCII translation
rle = binascii.rlecode_hqx(self.data)
a = binascii.b2a_hqx(self.type2test(rle))
+
b, _ = binascii.a2b_hqx(self.type2test(a))
res = binascii.rledecode_hqx(b)
-
self.assertEqual(res, self.rawdata)
+ def test_rle(self):
+ # test repetition with a repetition longer than the limit of 255
+ data = (b'a' * 100 + b'b' + b'c' * 300)
+
+ encoded = binascii.rlecode_hqx(data)
+ self.assertEqual(encoded,
+ (b'a\x90d' # 'a' * 100
+ b'b' # 'b'
+ b'c\x90\xff' # 'c' * 255
+ b'c\x90-')) # 'c' * 45
+
+ decoded = binascii.rledecode_hqx(encoded)
+ self.assertEqual(decoded, data)
+
def test_hex(self):
# test hexlification
s = b'{s\005\000\000\000worldi\002\000\000\000s\005\000\000\000helloi\001\000\000\0000'
@@ -262,6 +276,16 @@ class BinASCIITest(unittest.TestCase):
# non-ASCII string
self.assertRaises(ValueError, a2b, "\x80")
+ def test_b2a_base64_newline(self):
+ # Issue #25357: test newline parameter
+ b = self.type2test(b'hello')
+ self.assertEqual(binascii.b2a_base64(b),
+ b'aGVsbG8=\n')
+ self.assertEqual(binascii.b2a_base64(b, newline=True),
+ b'aGVsbG8=\n')
+ self.assertEqual(binascii.b2a_base64(b, newline=False),
+ b'aGVsbG8=')
+
class ArrayBinASCIITest(BinASCIITest):
def type2test(self, s):
diff --git a/Lib/test/test_binhex.py b/Lib/test/test_binhex.py
index 9d4c85afaa..21f446325a 100644
--- a/Lib/test/test_binhex.py
+++ b/Lib/test/test_binhex.py
@@ -4,7 +4,6 @@
Based on an original test by Roger E. Masse.
"""
import binhex
-import os
import unittest
from test import support
diff --git a/Lib/test/test_binop.py b/Lib/test/test_binop.py
index e9dbddcd93..fc8d30fac1 100644
--- a/Lib/test/test_binop.py
+++ b/Lib/test/test_binop.py
@@ -2,7 +2,7 @@
import unittest
from test import support
-from operator import eq, ne, lt, gt, le, ge
+from operator import eq, le
from abc import ABCMeta
def gcd(a, b):
diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py
index 2eef9fc685..b83f2f107c 100644
--- a/Lib/test/test_buffer.py
+++ b/Lib/test/test_buffer.py
@@ -16,7 +16,6 @@ import unittest
from test import support
from itertools import permutations, product
from random import randrange, sample, choice
-from sysconfig import get_config_var
import warnings
import sys, array, io
from decimal import Decimal
diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py
index 65c00d7a5f..1cedd3a855 100644
--- a/Lib/test/test_bytes.py
+++ b/Lib/test/test_bytes.py
@@ -300,6 +300,20 @@ class BaseBytesTest:
self.assertRaises(ValueError, self.type2test.fromhex, '\x00')
self.assertRaises(ValueError, self.type2test.fromhex, '12 \x00 34')
+ for data, pos in (
+ # invalid first hexadecimal character
+ ('12 x4 56', 3),
+ # invalid second hexadecimal character
+ ('12 3x 56', 4),
+ # two invalid hexadecimal characters
+ ('12 xy 56', 3),
+ # test non-ASCII string
+ ('12 3\xff 56', 4),
+ ):
+ with self.assertRaises(ValueError) as cm:
+ self.type2test.fromhex(data)
+ self.assertIn('at position %s' % pos, str(cm.exception))
+
def test_hex(self):
self.assertRaises(TypeError, self.type2test.hex)
self.assertRaises(TypeError, self.type2test.hex, 1)
@@ -722,26 +736,107 @@ class BytesTest(BaseBytesTest, unittest.TestCase):
# Test PyBytes_FromFormat()
def test_from_format(self):
- test.support.import_module('ctypes')
- from ctypes import pythonapi, py_object, c_int, c_char_p
+ ctypes = test.support.import_module('ctypes')
+ _testcapi = test.support.import_module('_testcapi')
+ from ctypes import pythonapi, py_object
+ from ctypes import (
+ c_int, c_uint,
+ c_long, c_ulong,
+ c_size_t, c_ssize_t,
+ c_char_p)
+
PyBytes_FromFormat = pythonapi.PyBytes_FromFormat
PyBytes_FromFormat.restype = py_object
+ # basic tests
self.assertEqual(PyBytes_FromFormat(b'format'),
b'format')
-
+ self.assertEqual(PyBytes_FromFormat(b'Hello %s !', b'world'),
+ b'Hello world !')
+
+ # test formatters
+ self.assertEqual(PyBytes_FromFormat(b'c=%c', c_int(0)),
+ b'c=\0')
+ self.assertEqual(PyBytes_FromFormat(b'c=%c', c_int(ord('@'))),
+ b'c=@')
+ self.assertEqual(PyBytes_FromFormat(b'c=%c', c_int(255)),
+ b'c=\xff')
+ self.assertEqual(PyBytes_FromFormat(b'd=%d ld=%ld zd=%zd',
+ c_int(1), c_long(2),
+ c_size_t(3)),
+ b'd=1 ld=2 zd=3')
+ self.assertEqual(PyBytes_FromFormat(b'd=%d ld=%ld zd=%zd',
+ c_int(-1), c_long(-2),
+ c_size_t(-3)),
+ b'd=-1 ld=-2 zd=-3')
+ self.assertEqual(PyBytes_FromFormat(b'u=%u lu=%lu zu=%zu',
+ c_uint(123), c_ulong(456),
+ c_size_t(789)),
+ b'u=123 lu=456 zu=789')
+ self.assertEqual(PyBytes_FromFormat(b'i=%i', c_int(123)),
+ b'i=123')
+ self.assertEqual(PyBytes_FromFormat(b'i=%i', c_int(-123)),
+ b'i=-123')
+ self.assertEqual(PyBytes_FromFormat(b'x=%x', c_int(0xabc)),
+ b'x=abc')
+
+ sizeof_ptr = ctypes.sizeof(c_char_p)
+
+ if os.name == 'nt':
+ # Windows (MSCRT)
+ ptr_format = '0x%0{}X'.format(2 * sizeof_ptr)
+ def ptr_formatter(ptr):
+ return (ptr_format % ptr)
+ else:
+ # UNIX (glibc)
+ def ptr_formatter(ptr):
+ return '%#x' % ptr
+
+ ptr = 0xabcdef
+ self.assertEqual(PyBytes_FromFormat(b'ptr=%p', c_char_p(ptr)),
+ ('ptr=' + ptr_formatter(ptr)).encode('ascii'))
+ self.assertEqual(PyBytes_FromFormat(b's=%s', c_char_p(b'cstr')),
+ b's=cstr')
+
+ # test minimum and maximum integer values
+ size_max = c_size_t(-1).value
+ for formatstr, ctypes_type, value, py_formatter in (
+ (b'%d', c_int, _testcapi.INT_MIN, str),
+ (b'%d', c_int, _testcapi.INT_MAX, str),
+ (b'%ld', c_long, _testcapi.LONG_MIN, str),
+ (b'%ld', c_long, _testcapi.LONG_MAX, str),
+ (b'%lu', c_ulong, _testcapi.ULONG_MAX, str),
+ (b'%zd', c_ssize_t, _testcapi.PY_SSIZE_T_MIN, str),
+ (b'%zd', c_ssize_t, _testcapi.PY_SSIZE_T_MAX, str),
+ (b'%zu', c_size_t, size_max, str),
+ (b'%p', c_char_p, size_max, ptr_formatter),
+ ):
+ self.assertEqual(PyBytes_FromFormat(formatstr, ctypes_type(value)),
+ py_formatter(value).encode('ascii')),
+
+ # width and precision (width is currently ignored)
+ self.assertEqual(PyBytes_FromFormat(b'%5s', b'a'),
+ b'a')
+ self.assertEqual(PyBytes_FromFormat(b'%.3s', b'abcdef'),
+ b'abc')
+
+ # '%%' formatter
+ self.assertEqual(PyBytes_FromFormat(b'%%'),
+ b'%')
+ self.assertEqual(PyBytes_FromFormat(b'[%%]'),
+ b'[%]')
+ self.assertEqual(PyBytes_FromFormat(b'%%%c', c_int(ord('_'))),
+ b'%_')
+ self.assertEqual(PyBytes_FromFormat(b'%%s'),
+ b'%s')
+
+ # Invalid formats and partial formatting
self.assertEqual(PyBytes_FromFormat(b'%'), b'%')
- self.assertEqual(PyBytes_FromFormat(b'%%'), b'%')
- self.assertEqual(PyBytes_FromFormat(b'%%s'), b'%s')
- self.assertEqual(PyBytes_FromFormat(b'[%%]'), b'[%]')
- self.assertEqual(PyBytes_FromFormat(b'%%%c', c_int(ord('_'))), b'%_')
-
- self.assertEqual(PyBytes_FromFormat(b'c:%c', c_int(255)),
- b'c:\xff')
- self.assertEqual(PyBytes_FromFormat(b's:%s', c_char_p(b'cstr')),
- b's:cstr')
+ self.assertEqual(PyBytes_FromFormat(b'x=%i y=%', c_int(2), c_int(3)),
+ b'x=2 y=%')
- # Issue #19969
+ # Issue #19969: %c must raise OverflowError for values
+ # not in the range [0; 255]
self.assertRaises(OverflowError,
PyBytes_FromFormat, b'%c', c_int(-1))
self.assertRaises(OverflowError,
diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py
index 80ed632588..6dad058e77 100644
--- a/Lib/test/test_calendar.py
+++ b/Lib/test/test_calendar.py
@@ -702,19 +702,19 @@ class CommandLineTestCase(unittest.TestCase):
def assertFailure(self, *args):
rc, stdout, stderr = assert_python_failure('-m', 'calendar', *args)
- self.assertIn(b'Usage:', stderr)
+ self.assertIn(b'usage:', stderr)
self.assertEqual(rc, 2)
def test_help(self):
stdout = self.run_ok('-h')
- self.assertIn(b'Usage:', stdout)
+ self.assertIn(b'usage:', stdout)
self.assertIn(b'calendar.py', stdout)
self.assertIn(b'--help', stdout)
def test_illegal_arguments(self):
self.assertFailure('-z')
- #self.assertFailure('spam')
- #self.assertFailure('2004', 'spam')
+ self.assertFailure('spam')
+ self.assertFailure('2004', 'spam')
self.assertFailure('-t', 'html', '2004', '1')
def test_output_current_year(self):
@@ -815,5 +815,14 @@ class CommandLineTestCase(unittest.TestCase):
b'href="custom.css" />', stdout)
+class MiscTestCase(unittest.TestCase):
+ def test__all__(self):
+ blacklist = {'mdays', 'January', 'February', 'EPOCH',
+ 'MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY',
+ 'SATURDAY', 'SUNDAY', 'different_locale', 'c',
+ 'prweek', 'week', 'format', 'formatstring', 'main'}
+ support.check__all__(self, calendar, blacklist=blacklist)
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py
index 1eadd2249e..a0746f097a 100644
--- a/Lib/test/test_capi.py
+++ b/Lib/test/test_capi.py
@@ -4,8 +4,10 @@
import os
import pickle
import random
+import re
import subprocess
import sys
+import sysconfig
import textwrap
import time
import unittest
@@ -442,6 +444,7 @@ class EmbeddingTests(unittest.TestCase):
self.maxDiff = None
self.assertEqual(out.strip(), expected_output)
+
class SkipitemTest(unittest.TestCase):
def test_skipitem(self):
@@ -491,10 +494,10 @@ class SkipitemTest(unittest.TestCase):
_testcapi.parse_tuple_and_keywords(tuple_1, dict_b,
format.encode("ascii"), keywords)
when_not_skipped = False
- except TypeError as e:
+ except SystemError as e:
s = "argument 1 (impossible<bad format char>)"
when_not_skipped = (str(e) == s)
- except RuntimeError as e:
+ except TypeError:
when_not_skipped = False
# test the format unit when skipped
@@ -503,7 +506,7 @@ class SkipitemTest(unittest.TestCase):
_testcapi.parse_tuple_and_keywords(empty_tuple, dict_b,
optional_format.encode("ascii"), keywords)
when_skipped = False
- except RuntimeError as e:
+ except SystemError as e:
s = "impossible<bad format char>: '{}'".format(format)
when_skipped = (str(e) == s)
@@ -524,6 +527,7 @@ class SkipitemTest(unittest.TestCase):
self.assertRaises(ValueError, _testcapi.parse_tuple_and_keywords,
(), {}, b'', [42])
+
@unittest.skipUnless(threading, 'Threading required for this test.')
class TestThreadState(unittest.TestCase):
@@ -548,6 +552,7 @@ class TestThreadState(unittest.TestCase):
t.start()
t.join()
+
class Test_testcapi(unittest.TestCase):
def test__testcapi(self):
for name in dir(_testcapi):
@@ -556,5 +561,84 @@ class Test_testcapi(unittest.TestCase):
test = getattr(_testcapi, name)
test()
+
+class PyMemDebugTests(unittest.TestCase):
+ PYTHONMALLOC = 'debug'
+ # '0x04c06e0' or '04C06E0'
+ PTR_REGEX = r'(?:0x)?[0-9a-fA-F]+'
+
+ def check(self, code):
+ with support.SuppressCrashReport():
+ out = assert_python_failure('-c', code,
+ PYTHONMALLOC=self.PYTHONMALLOC)
+ stderr = out.err
+ return stderr.decode('ascii', 'replace')
+
+ def test_buffer_overflow(self):
+ out = self.check('import _testcapi; _testcapi.pymem_buffer_overflow()')
+ regex = (r"Debug memory block at address p={ptr}: API 'm'\n"
+ r" 16 bytes originally requested\n"
+ r" The [0-9] pad bytes at p-[0-9] are FORBIDDENBYTE, as expected.\n"
+ r" The [0-9] pad bytes at tail={ptr} are not all FORBIDDENBYTE \(0x[0-9a-f]{{2}}\):\n"
+ r" at tail\+0: 0x78 \*\*\* OUCH\n"
+ r" at tail\+1: 0xfb\n"
+ r" at tail\+2: 0xfb\n"
+ r" .*\n"
+ r" The block was made by call #[0-9]+ to debug malloc/realloc.\n"
+ r" Data at p: cb cb cb .*\n"
+ r"\n"
+ r"Fatal Python error: bad trailing pad byte")
+ regex = regex.format(ptr=self.PTR_REGEX)
+ regex = re.compile(regex, flags=re.DOTALL)
+ self.assertRegex(out, regex)
+
+ def test_api_misuse(self):
+ out = self.check('import _testcapi; _testcapi.pymem_api_misuse()')
+ regex = (r"Debug memory block at address p={ptr}: API 'm'\n"
+ r" 16 bytes originally requested\n"
+ r" The [0-9] pad bytes at p-[0-9] are FORBIDDENBYTE, as expected.\n"
+ r" The [0-9] pad bytes at tail={ptr} are FORBIDDENBYTE, as expected.\n"
+ r" The block was made by call #[0-9]+ to debug malloc/realloc.\n"
+ r" Data at p: cb cb cb .*\n"
+ r"\n"
+ r"Fatal Python error: bad ID: Allocated using API 'm', verified using API 'r'\n")
+ regex = regex.format(ptr=self.PTR_REGEX)
+ self.assertRegex(out, regex)
+
+ def check_malloc_without_gil(self, code):
+ out = self.check(code)
+ expected = ('Fatal Python error: Python memory allocator called '
+ 'without holding the GIL')
+ self.assertIn(expected, out)
+
+ def test_pymem_malloc_without_gil(self):
+ # Debug hooks must raise an error if PyMem_Malloc() is called
+ # without holding the GIL
+ code = 'import _testcapi; _testcapi.pymem_malloc_without_gil()'
+ self.check_malloc_without_gil(code)
+
+ def test_pyobject_malloc_without_gil(self):
+ # Debug hooks must raise an error if PyObject_Malloc() is called
+ # without holding the GIL
+ code = 'import _testcapi; _testcapi.pyobject_malloc_without_gil()'
+ self.check_malloc_without_gil(code)
+
+
+class PyMemMallocDebugTests(PyMemDebugTests):
+ PYTHONMALLOC = 'malloc_debug'
+
+
+@unittest.skipUnless(sysconfig.get_config_var('WITH_PYMALLOC') == 1,
+ 'need pymalloc')
+class PyMemPymallocDebugTests(PyMemDebugTests):
+ PYTHONMALLOC = 'pymalloc_debug'
+
+
+@unittest.skipUnless(Py_DEBUG, 'need Py_DEBUG')
+class PyMemDefaultTests(PyMemDebugTests):
+ # test default allocator of Python compiled in debug mode
+ PYTHONMALLOC = ''
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/test/test_charmapcodec.py b/Lib/test/test_charmapcodec.py
index 4064aef935..0d4594d8c0 100644
--- a/Lib/test/test_charmapcodec.py
+++ b/Lib/test/test_charmapcodec.py
@@ -9,7 +9,7 @@ Written by Marc-Andre Lemburg (mal@lemburg.com).
"""#"
-import test.support, unittest
+import unittest
import codecs
diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py
index dce418b65c..8faa8e1986 100644
--- a/Lib/test/test_cmd_line.py
+++ b/Lib/test/test_cmd_line.py
@@ -348,8 +348,9 @@ class CmdLineTest(unittest.TestCase):
test.support.SuppressCrashReport().__enter__()
sys.stdout.write('x')
os.close(sys.stdout.fileno())"""
- rc, out, err = assert_python_ok('-c', code)
+ rc, out, err = assert_python_failure('-c', code)
self.assertEqual(b'', out)
+ self.assertEqual(120, rc)
self.assertRegex(err.decode('ascii', 'ignore'),
'Exception ignored in.*\nOSError: .*')
diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py
index b2be9b1b70..01fb7dcf40 100644
--- a/Lib/test/test_cmd_line_script.py
+++ b/Lib/test/test_cmd_line_script.py
@@ -138,9 +138,8 @@ class CmdLineTest(unittest.TestCase):
expected_argv0, expected_path0,
expected_package, expected_loader,
*cmd_line_switches):
- if not __debug__:
- cmd_line_switches += ('-' + 'O' * sys.flags.optimize,)
- run_args = cmd_line_switches + (script_name,) + tuple(example_args)
+ run_args = [*support.optim_args_from_interpreter_flags(),
+ *cmd_line_switches, script_name, *example_args]
rc, out, err = assert_python_ok(*run_args, __isolated=False)
self._check_output(script_name, rc, out + err, expected_file,
expected_argv0, expected_path0,
diff --git a/Lib/test/test_codeccallbacks.py b/Lib/test/test_codeccallbacks.py
index ee1e28a763..c8cdacf718 100644
--- a/Lib/test/test_codeccallbacks.py
+++ b/Lib/test/test_codeccallbacks.py
@@ -4,7 +4,6 @@ import sys
import test.support
import unicodedata
import unittest
-import warnings
class PosReturn:
# this can be used for configurable callbacks
diff --git a/Lib/test/test_codecencodings_cn.py b/Lib/test/test_codecencodings_cn.py
index d0e3a15d16..3bdf7d0e14 100644
--- a/Lib/test/test_codecencodings_cn.py
+++ b/Lib/test/test_codecencodings_cn.py
@@ -3,7 +3,6 @@
# Codec encoding tests for PRC encodings.
#
-from test import support
from test import multibytecodec_support
import unittest
diff --git a/Lib/test/test_codecencodings_hk.py b/Lib/test/test_codecencodings_hk.py
index bb9be11184..c5e2f999ef 100644
--- a/Lib/test/test_codecencodings_hk.py
+++ b/Lib/test/test_codecencodings_hk.py
@@ -3,7 +3,6 @@
# Codec encoding tests for HongKong encodings.
#
-from test import support
from test import multibytecodec_support
import unittest
diff --git a/Lib/test/test_codecencodings_iso2022.py b/Lib/test/test_codecencodings_iso2022.py
index 8a3ca70de6..00ea1c39dd 100644
--- a/Lib/test/test_codecencodings_iso2022.py
+++ b/Lib/test/test_codecencodings_iso2022.py
@@ -1,6 +1,5 @@
# Codec encoding tests for ISO 2022 encodings.
-from test import support
from test import multibytecodec_support
import unittest
diff --git a/Lib/test/test_codecencodings_jp.py b/Lib/test/test_codecencodings_jp.py
index 44b63a00c8..94378d124f 100644
--- a/Lib/test/test_codecencodings_jp.py
+++ b/Lib/test/test_codecencodings_jp.py
@@ -3,7 +3,6 @@
# Codec encoding tests for Japanese encodings.
#
-from test import support
from test import multibytecodec_support
import unittest
diff --git a/Lib/test/test_codecencodings_kr.py b/Lib/test/test_codecencodings_kr.py
index b6a74fbd5b..863d16b8fd 100644
--- a/Lib/test/test_codecencodings_kr.py
+++ b/Lib/test/test_codecencodings_kr.py
@@ -3,7 +3,6 @@
# Codec encoding tests for ROK encodings.
#
-from test import support
from test import multibytecodec_support
import unittest
diff --git a/Lib/test/test_codecencodings_tw.py b/Lib/test/test_codecencodings_tw.py
index 9174296726..bb1d133cad 100644
--- a/Lib/test/test_codecencodings_tw.py
+++ b/Lib/test/test_codecencodings_tw.py
@@ -3,7 +3,6 @@
# Codec encoding tests for ROC encodings.
#
-from test import support
from test import multibytecodec_support
import unittest
diff --git a/Lib/test/test_codecmaps_cn.py b/Lib/test/test_codecmaps_cn.py
index f1bd3840c9..89e51c6e2a 100644
--- a/Lib/test/test_codecmaps_cn.py
+++ b/Lib/test/test_codecmaps_cn.py
@@ -3,7 +3,6 @@
# Codec mapping tests for PRC encodings
#
-from test import support
from test import multibytecodec_support
import unittest
diff --git a/Lib/test/test_codecmaps_hk.py b/Lib/test/test_codecmaps_hk.py
index 4c0c4156da..7a48d24fdd 100644
--- a/Lib/test/test_codecmaps_hk.py
+++ b/Lib/test/test_codecmaps_hk.py
@@ -3,7 +3,6 @@
# Codec mapping tests for HongKong encodings
#
-from test import support
from test import multibytecodec_support
import unittest
diff --git a/Lib/test/test_codecmaps_jp.py b/Lib/test/test_codecmaps_jp.py
index 577382329a..fdfec8085b 100644
--- a/Lib/test/test_codecmaps_jp.py
+++ b/Lib/test/test_codecmaps_jp.py
@@ -3,7 +3,6 @@
# Codec mapping tests for Japanese encodings
#
-from test import support
from test import multibytecodec_support
import unittest
diff --git a/Lib/test/test_codecmaps_kr.py b/Lib/test/test_codecmaps_kr.py
index 6cb41c8b29..471cd749b8 100644
--- a/Lib/test/test_codecmaps_kr.py
+++ b/Lib/test/test_codecmaps_kr.py
@@ -3,7 +3,6 @@
# Codec mapping tests for ROK encodings
#
-from test import support
from test import multibytecodec_support
import unittest
diff --git a/Lib/test/test_codecmaps_tw.py b/Lib/test/test_codecmaps_tw.py
index 2ea44b56f1..145a97d511 100644
--- a/Lib/test/test_codecmaps_tw.py
+++ b/Lib/test/test_codecmaps_tw.py
@@ -3,7 +3,6 @@
# Codec mapping tests for ROC encodings
#
-from test import support
from test import multibytecodec_support
import unittest
diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py
index 0479542745..d8753402ef 100644
--- a/Lib/test/test_codecs.py
+++ b/Lib/test/test_codecs.py
@@ -4,7 +4,6 @@ import io
import locale
import sys
import unittest
-import warnings
import encodings
from test import support
@@ -27,6 +26,7 @@ def coding_checker(self, coder):
self.assertEqual(coder(input), (expect, len(input)))
return check
+
class Queue(object):
"""
queue: write bytes at one end, read bytes from the other end
@@ -47,6 +47,7 @@ class Queue(object):
self._buffer = self._buffer[size:]
return s
+
class MixInCheckStateHandling:
def check_state_handling_decode(self, encoding, u, s):
for i in range(len(s)+1):
@@ -80,6 +81,7 @@ class MixInCheckStateHandling:
part2 = d.encode(u[i:], True)
self.assertEqual(s, part1+part2)
+
class ReadTest(MixInCheckStateHandling):
def check_partial(self, input, partialresults):
# get a StreamReader for the encoding and feed the bytestring version
@@ -358,6 +360,12 @@ class ReadTest(MixInCheckStateHandling):
self.assertEqual("[\uDC80]".encode(self.encoding, "replace"),
"[?]".encode(self.encoding))
+ # sequential surrogate characters
+ self.assertEqual("[\uD800\uDC80]".encode(self.encoding, "ignore"),
+ "[]".encode(self.encoding))
+ self.assertEqual("[\uD800\uDC80]".encode(self.encoding, "replace"),
+ "[??]".encode(self.encoding))
+
bom = "".encode(self.encoding)
for before, after in [("\U00010fff", "A"), ("[", "]"),
("A", "\U00010fff")]:
@@ -383,6 +391,7 @@ class ReadTest(MixInCheckStateHandling):
self.assertEqual(test_sequence.decode(self.encoding, "backslashreplace"),
before + backslashreplace + after)
+
class UTF32Test(ReadTest, unittest.TestCase):
encoding = "utf-32"
if sys.byteorder == 'little':
@@ -478,6 +487,7 @@ class UTF32Test(ReadTest, unittest.TestCase):
self.assertEqual('\U00010000' * 1024,
codecs.utf_32_decode(encoded_be)[0])
+
class UTF32LETest(ReadTest, unittest.TestCase):
encoding = "utf-32-le"
ill_formed_sequence = b"\x80\xdc\x00\x00"
@@ -523,6 +533,7 @@ class UTF32LETest(ReadTest, unittest.TestCase):
self.assertEqual('\U00010000' * 1024,
codecs.utf_32_le_decode(encoded)[0])
+
class UTF32BETest(ReadTest, unittest.TestCase):
encoding = "utf-32-be"
ill_formed_sequence = b"\x00\x00\xdc\x80"
@@ -747,6 +758,7 @@ class UTF8Test(ReadTest, unittest.TestCase):
encoding = "utf-8"
ill_formed_sequence = b"\xed\xb2\x80"
ill_formed_sequence_replace = "\ufffd" * 3
+ BOM = b''
def test_partial(self):
self.check_partial(
@@ -775,27 +787,49 @@ class UTF8Test(ReadTest, unittest.TestCase):
self.check_state_handling_decode(self.encoding,
u, u.encode(self.encoding))
+ def test_decode_error(self):
+ for data, error_handler, expected in (
+ (b'[\x80\xff]', 'ignore', '[]'),
+ (b'[\x80\xff]', 'replace', '[\ufffd\ufffd]'),
+ (b'[\x80\xff]', 'surrogateescape', '[\udc80\udcff]'),
+ (b'[\x80\xff]', 'backslashreplace', '[\\x80\\xff]'),
+ ):
+ with self.subTest(data=data, error_handler=error_handler,
+ expected=expected):
+ self.assertEqual(data.decode(self.encoding, error_handler),
+ expected)
+
def test_lone_surrogates(self):
super().test_lone_surrogates()
# not sure if this is making sense for
# UTF-16 and UTF-32
- self.assertEqual("[\uDC80]".encode('utf-8', "surrogateescape"),
- b'[\x80]')
+ self.assertEqual("[\uDC80]".encode(self.encoding, "surrogateescape"),
+ self.BOM + b'[\x80]')
+
+ with self.assertRaises(UnicodeEncodeError) as cm:
+ "[\uDC80\uD800\uDFFF]".encode(self.encoding, "surrogateescape")
+ exc = cm.exception
+ self.assertEqual(exc.object[exc.start:exc.end], '\uD800\uDFFF')
def test_surrogatepass_handler(self):
- self.assertEqual("abc\ud800def".encode("utf-8", "surrogatepass"),
- b"abc\xed\xa0\x80def")
- self.assertEqual(b"abc\xed\xa0\x80def".decode("utf-8", "surrogatepass"),
+ self.assertEqual("abc\ud800def".encode(self.encoding, "surrogatepass"),
+ self.BOM + b"abc\xed\xa0\x80def")
+ self.assertEqual("\U00010fff\uD800".encode(self.encoding, "surrogatepass"),
+ self.BOM + b"\xf0\x90\xbf\xbf\xed\xa0\x80")
+ self.assertEqual("[\uD800\uDC80]".encode(self.encoding, "surrogatepass"),
+ self.BOM + b'[\xed\xa0\x80\xed\xb2\x80]')
+
+ self.assertEqual(b"abc\xed\xa0\x80def".decode(self.encoding, "surrogatepass"),
"abc\ud800def")
- self.assertEqual("\U00010fff\uD800".encode("utf-8", "surrogatepass"),
- b"\xf0\x90\xbf\xbf\xed\xa0\x80")
- self.assertEqual(b"\xf0\x90\xbf\xbf\xed\xa0\x80".decode("utf-8", "surrogatepass"),
+ self.assertEqual(b"\xf0\x90\xbf\xbf\xed\xa0\x80".decode(self.encoding, "surrogatepass"),
"\U00010fff\uD800")
+
self.assertTrue(codecs.lookup_error("surrogatepass"))
with self.assertRaises(UnicodeDecodeError):
- b"abc\xed\xa0".decode("utf-8", "surrogatepass")
+ b"abc\xed\xa0".decode(self.encoding, "surrogatepass")
with self.assertRaises(UnicodeDecodeError):
- b"abc\xed\xa0z".decode("utf-8", "surrogatepass")
+ b"abc\xed\xa0z".decode(self.encoding, "surrogatepass")
+
@unittest.skipUnless(sys.platform == 'win32',
'cp65001 is a Windows-only codec')
@@ -1059,6 +1093,7 @@ class ReadBufferTest(unittest.TestCase):
class UTF8SigTest(UTF8Test, unittest.TestCase):
encoding = "utf-8-sig"
+ BOM = codecs.BOM_UTF8
def test_partial(self):
self.check_partial(
@@ -1194,6 +1229,7 @@ class EscapeDecodeTest(unittest.TestCase):
self.assertEqual(decode(br"[\x0]\x0", "ignore"), (b"[]", 8))
self.assertEqual(decode(br"[\x0]\x0", "replace"), (b"[?]?", 8))
+
class RecodingTest(unittest.TestCase):
def test_recoding(self):
f = io.BytesIO()
@@ -1313,6 +1349,7 @@ for i in punycode_testcases:
if len(i)!=2:
print(repr(i))
+
class PunycodeTest(unittest.TestCase):
def test_encode(self):
for uni, puny in punycode_testcases:
@@ -1332,6 +1369,7 @@ class PunycodeTest(unittest.TestCase):
puny = puny.decode("ascii").encode("ascii")
self.assertEqual(uni, puny.decode("punycode"))
+
class UnicodeInternalTest(unittest.TestCase):
@unittest.skipUnless(SIZEOF_WCHAR_T == 4, 'specific to 32-bit wchar_t')
def test_bug1251300(self):
@@ -1586,6 +1624,7 @@ class NameprepTest(unittest.TestCase):
except Exception as e:
raise support.TestFailed("Test 3.%d: %s" % (pos+1, str(e)))
+
class IDNACodecTest(unittest.TestCase):
def test_builtin_decode(self):
self.assertEqual(str(b"python.org", "idna"), "python.org")
@@ -1672,6 +1711,7 @@ class IDNACodecTest(unittest.TestCase):
self.assertRaises(Exception,
b"python.org".decode, "idna", errors)
+
class CodecsModuleTest(unittest.TestCase):
def test_decode(self):
@@ -1780,6 +1820,7 @@ class CodecsModuleTest(unittest.TestCase):
self.assertRaises(UnicodeError,
codecs.decode, b'abc', 'undefined', errors)
+
class StreamReaderTest(unittest.TestCase):
def setUp(self):
@@ -1790,6 +1831,7 @@ class StreamReaderTest(unittest.TestCase):
f = self.reader(self.stream)
self.assertEqual(f.readlines(), ['\ud55c\n', '\uae00'])
+
class EncodedFileTest(unittest.TestCase):
def test_basic(self):
@@ -1920,6 +1962,7 @@ broken_unicode_with_stateful = [
"unicode_internal"
]
+
class BasicUnicodeTest(unittest.TestCase, MixInCheckStateHandling):
def test_basics(self):
s = "abc123" # all codecs should be able to encode these
@@ -2082,6 +2125,7 @@ class BasicUnicodeTest(unittest.TestCase, MixInCheckStateHandling):
self.check_state_handling_decode(encoding, u, u.encode(encoding))
self.check_state_handling_encode(encoding, u, u.encode(encoding))
+
class CharmapTest(unittest.TestCase):
def test_decode_with_string_map(self):
self.assertEqual(
@@ -2332,6 +2376,7 @@ class WithStmtTest(unittest.TestCase):
info.streamwriter, 'strict') as srw:
self.assertEqual(srw.read(), "\xfc")
+
class TypesTest(unittest.TestCase):
def test_decode_unicode(self):
# Most decoders don't accept unicode input
@@ -2622,6 +2667,7 @@ else:
bytes_transform_encodings.append("bz2_codec")
transform_aliases["bz2_codec"] = ["bz2"]
+
class TransformCodecTest(unittest.TestCase):
def test_basics(self):
@@ -3099,5 +3145,81 @@ class CodePageTest(unittest.TestCase):
self.assertEqual(decoded, ('abc', 3))
+class ASCIITest(unittest.TestCase):
+ def test_encode(self):
+ self.assertEqual('abc123'.encode('ascii'), b'abc123')
+
+ def test_encode_error(self):
+ for data, error_handler, expected in (
+ ('[\x80\xff\u20ac]', 'ignore', b'[]'),
+ ('[\x80\xff\u20ac]', 'replace', b'[???]'),
+ ('[\x80\xff\u20ac]', 'xmlcharrefreplace', b'[&#128;&#255;&#8364;]'),
+ ('[\x80\xff\u20ac\U000abcde]', 'backslashreplace',
+ b'[\\x80\\xff\\u20ac\\U000abcde]'),
+ ('[\udc80\udcff]', 'surrogateescape', b'[\x80\xff]'),
+ ):
+ with self.subTest(data=data, error_handler=error_handler,
+ expected=expected):
+ self.assertEqual(data.encode('ascii', error_handler),
+ expected)
+
+ def test_encode_surrogateescape_error(self):
+ with self.assertRaises(UnicodeEncodeError):
+ # the first character can be decoded, but not the second
+ '\udc80\xff'.encode('ascii', 'surrogateescape')
+
+ def test_decode(self):
+ self.assertEqual(b'abc'.decode('ascii'), 'abc')
+
+ def test_decode_error(self):
+ for data, error_handler, expected in (
+ (b'[\x80\xff]', 'ignore', '[]'),
+ (b'[\x80\xff]', 'replace', '[\ufffd\ufffd]'),
+ (b'[\x80\xff]', 'surrogateescape', '[\udc80\udcff]'),
+ (b'[\x80\xff]', 'backslashreplace', '[\\x80\\xff]'),
+ ):
+ with self.subTest(data=data, error_handler=error_handler,
+ expected=expected):
+ self.assertEqual(data.decode('ascii', error_handler),
+ expected)
+
+
+class Latin1Test(unittest.TestCase):
+ def test_encode(self):
+ for data, expected in (
+ ('abc', b'abc'),
+ ('\x80\xe9\xff', b'\x80\xe9\xff'),
+ ):
+ with self.subTest(data=data, expected=expected):
+ self.assertEqual(data.encode('latin1'), expected)
+
+ def test_encode_errors(self):
+ for data, error_handler, expected in (
+ ('[\u20ac\udc80]', 'ignore', b'[]'),
+ ('[\u20ac\udc80]', 'replace', b'[??]'),
+ ('[\u20ac\U000abcde]', 'backslashreplace',
+ b'[\\u20ac\\U000abcde]'),
+ ('[\u20ac\udc80]', 'xmlcharrefreplace', b'[&#8364;&#56448;]'),
+ ('[\udc80\udcff]', 'surrogateescape', b'[\x80\xff]'),
+ ):
+ with self.subTest(data=data, error_handler=error_handler,
+ expected=expected):
+ self.assertEqual(data.encode('latin1', error_handler),
+ expected)
+
+ def test_encode_surrogateescape_error(self):
+ with self.assertRaises(UnicodeEncodeError):
+ # the first character can be decoded, but not the second
+ '\udc80\u20ac'.encode('latin1', 'surrogateescape')
+
+ def test_decode(self):
+ for data, expected in (
+ (b'abc', 'abc'),
+ (b'[\x80\xff]', '[\x80\xff]'),
+ ):
+ with self.subTest(data=data, expected=expected):
+ self.assertEqual(data.decode('latin1'), expected)
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/test/test_codeop.py b/Lib/test/test_codeop.py
index 509bf5dfd2..98da26fa5d 100644
--- a/Lib/test/test_codeop.py
+++ b/Lib/test/test_codeop.py
@@ -282,7 +282,6 @@ class CodeopTests(unittest.TestCase):
ai("if (a == 1 and b = 2): pass")
ai("del 1")
- ai("del ()")
ai("del (1,)")
ai("del [1]")
ai("del '1'")
diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py
index 4c32e094f9..3824a87365 100644
--- a/Lib/test/test_collections.py
+++ b/Lib/test/test_collections.py
@@ -20,10 +20,10 @@ from collections import UserDict, UserString, UserList
from collections import ChainMap
from collections import deque
from collections.abc import Awaitable, Coroutine, AsyncIterator, AsyncIterable
-from collections.abc import Hashable, Iterable, Iterator, Generator
+from collections.abc import Hashable, Iterable, Iterator, Generator, Reversible
from collections.abc import Sized, Container, Callable
from collections.abc import Set, MutableSet
-from collections.abc import Mapping, MutableMapping, KeysView, ItemsView
+from collections.abc import Mapping, MutableMapping, KeysView, ItemsView, ValuesView
from collections.abc import Sequence, MutableSequence
from collections.abc import ByteString
@@ -689,6 +689,31 @@ class TestOneTrickPonyABCs(ABCTestCase):
self.validate_abstract_methods(Iterable, '__iter__')
self.validate_isinstance(Iterable, '__iter__')
+ def test_Reversible(self):
+ # Check some non-reversibles
+ non_samples = [None, 42, 3.14, 1j, dict(), set(), frozenset()]
+ for x in non_samples:
+ self.assertNotIsInstance(x, Reversible)
+ self.assertFalse(issubclass(type(x), Reversible), repr(type(x)))
+ # Check some reversibles
+ samples = [tuple(), list()]
+ for x in samples:
+ self.assertIsInstance(x, Reversible)
+ self.assertTrue(issubclass(type(x), Reversible), repr(type(x)))
+ # Check also Mapping, MutableMapping, and Sequence
+ self.assertTrue(issubclass(Sequence, Reversible), repr(Sequence))
+ self.assertFalse(issubclass(Mapping, Reversible), repr(Mapping))
+ self.assertFalse(issubclass(MutableMapping, Reversible), repr(MutableMapping))
+ # Check direct subclassing
+ class R(Reversible):
+ def __iter__(self):
+ return iter(list())
+ def __reversed__(self):
+ return iter(list())
+ self.assertEqual(list(reversed(R())), [])
+ self.assertFalse(issubclass(float, R))
+ self.validate_abstract_methods(Reversible, '__reversed__', '__iter__')
+
def test_Iterator(self):
non_samples = [None, 42, 3.14, 1j, b"", "", (), [], {}, set()]
for x in non_samples:
@@ -842,14 +867,14 @@ class TestOneTrickPonyABCs(ABCTestCase):
self.validate_isinstance(Callable, '__call__')
def test_direct_subclassing(self):
- for B in Hashable, Iterable, Iterator, Sized, Container, Callable:
+ for B in Hashable, Iterable, Iterator, Reversible, Sized, Container, Callable:
class C(B):
pass
self.assertTrue(issubclass(C, B))
self.assertFalse(issubclass(int, C))
def test_registration(self):
- for B in Hashable, Iterable, Iterator, Sized, Container, Callable:
+ for B in Hashable, Iterable, Iterator, Reversible, Sized, Container, Callable:
class C:
__hash__ = None # Make sure it isn't hashable by default
self.assertFalse(issubclass(C, B), B.__name__)
@@ -1049,6 +1074,26 @@ class TestCollectionABCs(ABCTestCase):
self.assertFalse(ncs > cs)
self.assertTrue(ncs >= cs)
+ def test_issue26915(self):
+ # Container membership test should check identity first
+ class CustomEqualObject:
+ def __eq__(self, other):
+ return False
+ class CustomSequence(list):
+ def __contains__(self, value):
+ return Sequence.__contains__(self, value)
+
+ nan = float('nan')
+ obj = CustomEqualObject()
+ containers = [
+ CustomSequence([nan, obj]),
+ ItemsView({1: nan, 2: obj}),
+ ValuesView({1: nan, 2: obj})
+ ]
+ for container in containers:
+ for elem in container:
+ self.assertIn(elem, container)
+
def assertSameSet(self, s1, s2):
# coerce both to a real set then check equality
self.assertSetEqual(set(s1), set(s2))
diff --git a/Lib/test/test_compileall.py b/Lib/test/test_compileall.py
index 2ce8a61e39..9b424a7250 100644
--- a/Lib/test/test_compileall.py
+++ b/Lib/test/test_compileall.py
@@ -1,6 +1,7 @@
import sys
import compileall
import importlib.util
+import test.test_importlib.util
import os
import pathlib
import py_compile
@@ -40,6 +41,11 @@ class CompileallTests(unittest.TestCase):
def tearDown(self):
shutil.rmtree(self.directory)
+ def add_bad_source_file(self):
+ self.bad_source_path = os.path.join(self.directory, '_test_bad.py')
+ with open(self.bad_source_path, 'w') as file:
+ file.write('x (\n')
+
def data(self):
with open(self.bc_path, 'rb') as file:
data = file.read(8)
@@ -78,15 +84,43 @@ class CompileallTests(unittest.TestCase):
os.unlink(fn)
except:
pass
- compileall.compile_file(self.source_path, force=False, quiet=True)
+ self.assertTrue(compileall.compile_file(self.source_path,
+ force=False, quiet=True))
self.assertTrue(os.path.isfile(self.bc_path) and
not os.path.isfile(self.bc_path2))
os.unlink(self.bc_path)
- compileall.compile_dir(self.directory, force=False, quiet=True)
+ self.assertTrue(compileall.compile_dir(self.directory, force=False,
+ quiet=True))
self.assertTrue(os.path.isfile(self.bc_path) and
os.path.isfile(self.bc_path2))
os.unlink(self.bc_path)
os.unlink(self.bc_path2)
+ # Test against bad files
+ self.add_bad_source_file()
+ self.assertFalse(compileall.compile_file(self.bad_source_path,
+ force=False, quiet=2))
+ self.assertFalse(compileall.compile_dir(self.directory,
+ force=False, quiet=2))
+
+ def test_compile_path(self):
+ # Exclude Lib/test/ which contains invalid Python files like
+ # Lib/test/badsyntax_pep3120.py
+ testdir = os.path.realpath(os.path.dirname(__file__))
+ if testdir in sys.path:
+ self.addCleanup(setattr, sys, 'path', sys.path)
+
+ sys.path = list(sys.path)
+ try:
+ sys.path.remove(testdir)
+ except ValueError:
+ pass
+
+ self.assertTrue(compileall.compile_path(quiet=2))
+
+ with test.test_importlib.util.import_state(path=[self.directory]):
+ self.add_bad_source_file()
+ self.assertFalse(compileall.compile_path(skip_curdir=False,
+ force=True, quiet=2))
def test_no_pycache_in_non_package(self):
# Bug 8563 reported that __pycache__ directories got created by
@@ -197,10 +231,9 @@ class CommandLineTests(unittest.TestCase):
raise unittest.SkipTest('not all entries on sys.path are writable')
def _get_run_args(self, args):
- interp_args = ['-S']
- if sys.flags.optimize:
- interp_args.append({1 : '-O', 2 : '-OO'}[sys.flags.optimize])
- return interp_args + ['-m', 'compileall'] + list(args)
+ return [*support.optim_args_from_interpreter_flags(),
+ '-S', '-m', 'compileall',
+ *args]
def assertRunOK(self, *args, **env_vars):
rc, out, err = script_helper.assert_python_ok(
diff --git a/Lib/test/test_contextlib.py b/Lib/test/test_contextlib.py
index 30a6377bed..5c8bc981fe 100644
--- a/Lib/test/test_contextlib.py
+++ b/Lib/test/test_contextlib.py
@@ -12,6 +12,39 @@ except ImportError:
threading = None
+class TestAbstractContextManager(unittest.TestCase):
+
+ def test_enter(self):
+ class DefaultEnter(AbstractContextManager):
+ def __exit__(self, *args):
+ super().__exit__(*args)
+
+ manager = DefaultEnter()
+ self.assertIs(manager.__enter__(), manager)
+
+ def test_exit_is_abstract(self):
+ class MissingExit(AbstractContextManager):
+ pass
+
+ with self.assertRaises(TypeError):
+ MissingExit()
+
+ def test_structural_subclassing(self):
+ class ManagerFromScratch:
+ def __enter__(self):
+ return self
+ def __exit__(self, exc_type, exc_value, traceback):
+ return None
+
+ self.assertTrue(issubclass(ManagerFromScratch, AbstractContextManager))
+
+ class DefaultEnter(AbstractContextManager):
+ def __exit__(self, *args):
+ super().__exit__(*args)
+
+ self.assertTrue(issubclass(DefaultEnter, AbstractContextManager))
+
+
class ContextManagerTestCase(unittest.TestCase):
def test_contextmanager_plain(self):
@@ -89,7 +122,7 @@ class ContextManagerTestCase(unittest.TestCase):
def woohoo():
yield
try:
- with self.assertWarnsRegex(PendingDeprecationWarning,
+ with self.assertWarnsRegex(DeprecationWarning,
"StopIteration"):
with woohoo():
raise stop_exc
diff --git a/Lib/test/test_copy.py b/Lib/test/test_copy.py
index 0e1f670bf0..45a692022f 100644
--- a/Lib/test/test_copy.py
+++ b/Lib/test/test_copy.py
@@ -98,7 +98,7 @@ class TestCopy(unittest.TestCase):
tests = [None, ..., NotImplemented,
42, 2**100, 3.14, True, False, 1j,
"hello", "hello\u1234", f.__code__,
- b"world", bytes(range(256)), range(10),
+ b"world", bytes(range(256)), range(10), slice(1, 10, 2),
NewStyle, Classic, max, WithMetaclass]
for x in tests:
self.assertIs(copy.copy(x), x)
diff --git a/Lib/test/test_cprofile.py b/Lib/test/test_cprofile.py
index f18983fbb2..53f8917330 100644
--- a/Lib/test/test_cprofile.py
+++ b/Lib/test/test_cprofile.py
@@ -6,7 +6,7 @@ from test.support import run_unittest, TESTFN, unlink
# rip off all interesting stuff from test_profile
import cProfile
from test.test_profile import ProfileTest, regenerate_expected_output
-from test.profilee import testfunc
+
class CProfileTest(ProfileTest):
profilerclass = cProfile.Profile
diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py
index 77c315edb1..e97c9f366e 100644
--- a/Lib/test/test_csv.py
+++ b/Lib/test/test_csv.py
@@ -2,9 +2,7 @@
# csv package unit tests
import copy
-import io
import sys
-import os
import unittest
from io import StringIO
from tempfile import TemporaryFile
@@ -426,17 +424,16 @@ class TestDialectRegistry(unittest.TestCase):
self.assertRaises(TypeError, csv.reader, [], quoting = -1)
self.assertRaises(TypeError, csv.reader, [], quoting = 100)
- # See issue #22995
- ## def test_copy(self):
- ## for name in csv.list_dialects():
- ## dialect = csv.get_dialect(name)
- ## self.assertRaises(TypeError, copy.copy, dialect)
+ def test_copy(self):
+ for name in csv.list_dialects():
+ dialect = csv.get_dialect(name)
+ self.assertRaises(TypeError, copy.copy, dialect)
- ## def test_pickle(self):
- ## for name in csv.list_dialects():
- ## dialect = csv.get_dialect(name)
- ## for proto in range(pickle.HIGHEST_PROTOCOL + 1):
- ## self.assertRaises(TypeError, pickle.dumps, dialect, proto)
+ def test_pickle(self):
+ for name in csv.list_dialects():
+ dialect = csv.get_dialect(name)
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ self.assertRaises(TypeError, pickle.dumps, dialect, proto)
class TestCsvBase(unittest.TestCase):
def readerAssertEqual(self, input, expected_result):
@@ -1080,7 +1077,6 @@ class TestUnicode(unittest.TestCase):
"François Pinard"]
def test_unicode_read(self):
- import io
with TemporaryFile("w+", newline='', encoding="utf-8") as fileobj:
fileobj.write(",".join(self.names) + "\r\n")
fileobj.seek(0)
@@ -1089,7 +1085,6 @@ class TestUnicode(unittest.TestCase):
def test_unicode_write(self):
- import io
with TemporaryFile("w+", newline='', encoding="utf-8") as fileobj:
writer = csv.writer(fileobj)
writer.writerow(self.names)
@@ -1098,5 +1093,11 @@ class TestUnicode(unittest.TestCase):
self.assertEqual(fileobj.read(), expected)
+class MiscTestCase(unittest.TestCase):
+ def test__all__(self):
+ extra = {'__doc__', '__version__'}
+ support.check__all__(self, csv, ('csv', '_csv'), extra=extra)
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/Lib/test/test_dbm.py b/Lib/test/test_dbm.py
index 623d9929d5..f0a428deaf 100644
--- a/Lib/test/test_dbm.py
+++ b/Lib/test/test_dbm.py
@@ -1,6 +1,5 @@
"""Test script for the dbm.open function based on testdumbdbm.py"""
-import os
import unittest
import glob
import test.support
diff --git a/Lib/test/test_dbm_gnu.py b/Lib/test/test_dbm_gnu.py
index a7808f51c7..304b332869 100644
--- a/Lib/test/test_dbm_gnu.py
+++ b/Lib/test/test_dbm_gnu.py
@@ -2,7 +2,7 @@ from test import support
gdbm = support.import_module("dbm.gnu") #skip if not supported
import unittest
import os
-from test.support import verbose, TESTFN, unlink
+from test.support import TESTFN, unlink
filename = TESTFN
diff --git a/Lib/test/test_dbm_ndbm.py b/Lib/test/test_dbm_ndbm.py
index 2291561def..49f4426e4c 100644
--- a/Lib/test/test_dbm_ndbm.py
+++ b/Lib/test/test_dbm_ndbm.py
@@ -1,8 +1,6 @@
from test import support
support.import_module("dbm.ndbm") #skip if not supported
import unittest
-import os
-import random
import dbm.ndbm
from dbm.ndbm import error
diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py
index c0d21b1c80..f56f9add58 100644
--- a/Lib/test/test_decimal.py
+++ b/Lib/test/test_decimal.py
@@ -2047,6 +2047,39 @@ class UsabilityTest(unittest.TestCase):
d = Decimal( (1, (0, 2, 7, 1), 'F') )
self.assertEqual(d.as_tuple(), (1, (0,), 'F'))
+ def test_as_integer_ratio(self):
+ Decimal = self.decimal.Decimal
+
+ # exceptional cases
+ self.assertRaises(OverflowError,
+ Decimal.as_integer_ratio, Decimal('inf'))
+ self.assertRaises(OverflowError,
+ Decimal.as_integer_ratio, Decimal('-inf'))
+ self.assertRaises(ValueError,
+ Decimal.as_integer_ratio, Decimal('-nan'))
+ self.assertRaises(ValueError,
+ Decimal.as_integer_ratio, Decimal('snan123'))
+
+ for exp in range(-4, 2):
+ for coeff in range(1000):
+ for sign in '+', '-':
+ d = Decimal('%s%dE%d' % (sign, coeff, exp))
+ pq = d.as_integer_ratio()
+ p, q = pq
+
+ # check return type
+ self.assertIsInstance(pq, tuple)
+ self.assertIsInstance(p, int)
+ self.assertIsInstance(q, int)
+
+ # check normalization: q should be positive;
+ # p should be relatively prime to q.
+ self.assertGreater(q, 0)
+ self.assertEqual(math.gcd(p, q), 1)
+
+ # check that p/q actually gives the correct value
+ self.assertEqual(Decimal(p) / Decimal(q), d)
+
def test_subclassing(self):
# Different behaviours when subclassing Decimal
Decimal = self.decimal.Decimal
diff --git a/Lib/test/test_deque.py b/Lib/test/test_deque.py
index f525429a17..4fd0cc7de5 100644
--- a/Lib/test/test_deque.py
+++ b/Lib/test/test_deque.py
@@ -289,7 +289,7 @@ class TestBasic(unittest.TestCase):
else:
self.assertEqual(d.index(element, start, stop), target)
- def test_insert_bug_24913(self):
+ def test_index_bug_24913(self):
d = deque('A' * 3)
with self.assertRaises(ValueError):
i = d.index("Hello world", 0, 4)
@@ -622,20 +622,22 @@ class TestBasic(unittest.TestCase):
self.assertEqual(list(d), list(e))
def test_pickle(self):
- d = deque(range(200))
- for i in range(pickle.HIGHEST_PROTOCOL + 1):
- s = pickle.dumps(d, i)
- e = pickle.loads(s)
- self.assertNotEqual(id(d), id(e))
- self.assertEqual(list(d), list(e))
-
-## def test_pickle_recursive(self):
-## d = deque('abc')
-## d.append(d)
-## for i in range(pickle.HIGHEST_PROTOCOL + 1):
-## e = pickle.loads(pickle.dumps(d, i))
-## self.assertNotEqual(id(d), id(e))
-## self.assertEqual(id(e), id(e[-1]))
+ for d in deque(range(200)), deque(range(200), 100):
+ for i in range(pickle.HIGHEST_PROTOCOL + 1):
+ s = pickle.dumps(d, i)
+ e = pickle.loads(s)
+ self.assertNotEqual(id(e), id(d))
+ self.assertEqual(list(e), list(d))
+ self.assertEqual(e.maxlen, d.maxlen)
+
+ def test_pickle_recursive(self):
+ for d in deque('abc'), deque('abc', 3):
+ d.append(d)
+ for i in range(pickle.HIGHEST_PROTOCOL + 1):
+ e = pickle.loads(pickle.dumps(d, i))
+ self.assertNotEqual(id(e), id(d))
+ self.assertEqual(id(e[-1]), id(e))
+ self.assertEqual(e.maxlen, d.maxlen)
def test_iterator_pickle(self):
orig = deque(range(200))
@@ -696,6 +698,15 @@ class TestBasic(unittest.TestCase):
self.assertNotEqual(id(d), id(e))
self.assertEqual(list(d), list(e))
+ for i in range(5):
+ for maxlen in range(-1, 6):
+ s = [random.random() for j in range(i)]
+ d = deque(s) if maxlen == -1 else deque(s, maxlen)
+ e = d.copy()
+ self.assertEqual(d, e)
+ self.assertEqual(d.maxlen, e.maxlen)
+ self.assertTrue(all(x is y for x, y in zip(d, e)))
+
def test_copy_method(self):
mut = [10]
d = deque([mut])
@@ -845,24 +856,26 @@ class TestSubclass(unittest.TestCase):
self.assertEqual(type(d), type(e))
self.assertEqual(list(d), list(e))
-## def test_pickle(self):
-## d = Deque('abc')
-## d.append(d)
-##
-## e = pickle.loads(pickle.dumps(d))
-## self.assertNotEqual(id(d), id(e))
-## self.assertEqual(type(d), type(e))
-## dd = d.pop()
-## ee = e.pop()
-## self.assertEqual(id(e), id(ee))
-## self.assertEqual(d, e)
-##
-## d.x = d
-## e = pickle.loads(pickle.dumps(d))
-## self.assertEqual(id(e), id(e.x))
-##
-## d = DequeWithBadIter('abc')
-## self.assertRaises(TypeError, pickle.dumps, d)
+ def test_pickle_recursive(self):
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ for d in Deque('abc'), Deque('abc', 3):
+ d.append(d)
+
+ e = pickle.loads(pickle.dumps(d, proto))
+ self.assertNotEqual(id(e), id(d))
+ self.assertEqual(type(e), type(d))
+ self.assertEqual(e.maxlen, d.maxlen)
+ dd = d.pop()
+ ee = e.pop()
+ self.assertEqual(id(ee), id(e))
+ self.assertEqual(e, d)
+
+ d.x = d
+ e = pickle.loads(pickle.dumps(d, proto))
+ self.assertEqual(id(e.x), id(e))
+
+ for d in DequeWithBadIter('abc'), DequeWithBadIter('abc', 2):
+ self.assertRaises(TypeError, pickle.dumps, d, proto)
def test_weakref(self):
d = deque('gallahad')
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index a130cecb89..0a5ecd5a0d 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -4738,11 +4738,8 @@ class PicklingTests(unittest.TestCase):
return (args, kwargs)
obj = C3()
for proto in protocols:
- if proto >= 4:
+ if proto >= 2:
self._check_reduce(proto, obj, args, kwargs)
- elif proto >= 2:
- with self.assertRaises(ValueError):
- obj.__reduce_ex__(proto)
class C4:
def __getnewargs_ex__(self):
@@ -5061,10 +5058,6 @@ class PicklingTests(unittest.TestCase):
kwargs = getattr(cls, 'KWARGS', {})
obj = cls(*cls.ARGS, **kwargs)
proto = pickle_copier.proto
- if 2 <= proto < 4 and hasattr(cls, '__getnewargs_ex__'):
- with self.assertRaises(ValueError):
- pickle_copier.dumps(obj, proto)
- continue
objcopy = pickle_copier.copy(obj)
self._assert_is_copy(obj, objcopy)
# For test classes that supports this, make sure we didn't go
diff --git a/Lib/test/test_devpoll.py b/Lib/test/test_devpoll.py
index 955618ae15..c133c811b1 100644
--- a/Lib/test/test_devpoll.py
+++ b/Lib/test/test_devpoll.py
@@ -5,9 +5,8 @@
import os
import random
import select
-import sys
import unittest
-from test.support import TESTFN, run_unittest, cpython_only
+from test.support import run_unittest, cpython_only
if not hasattr(select, 'devpoll') :
raise unittest.SkipTest('test works only on Solaris OS family')
diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py
index 6d68e761c6..6c4706636e 100644
--- a/Lib/test/test_dict.py
+++ b/Lib/test/test_dict.py
@@ -1,10 +1,12 @@
-import unittest
-from test import support
-
-import collections, random, string
+import collections
import collections.abc
-import gc, weakref
+import gc
import pickle
+import random
+import string
+import unittest
+import weakref
+from test import support
class DictTest(unittest.TestCase):
@@ -969,5 +971,6 @@ class Dict(dict):
class SubclassMappingTests(mapping_tests.BasicTestMappingProtocol):
type2test = Dict
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/test/test_dictcomps.py b/Lib/test/test_dictcomps.py
index 3c8b95cf32..0873071883 100644
--- a/Lib/test/test_dictcomps.py
+++ b/Lib/test/test_dictcomps.py
@@ -1,7 +1,5 @@
import unittest
-from test import support
-
# For scope testing.
g = "Global variable"
diff --git a/Lib/test/test_dictviews.py b/Lib/test/test_dictviews.py
index ab23ca1cf7..4c290ffaa1 100644
--- a/Lib/test/test_dictviews.py
+++ b/Lib/test/test_dictviews.py
@@ -1,3 +1,4 @@
+import collections
import copy
import pickle
import unittest
@@ -219,6 +220,27 @@ class DictSetTest(unittest.TestCase):
self.assertRaises((TypeError, pickle.PicklingError),
pickle.dumps, d.items(), proto)
+ def test_abc_registry(self):
+ d = dict(a=1)
+
+ self.assertIsInstance(d.keys(), collections.KeysView)
+ self.assertIsInstance(d.keys(), collections.MappingView)
+ self.assertIsInstance(d.keys(), collections.Set)
+ self.assertIsInstance(d.keys(), collections.Sized)
+ self.assertIsInstance(d.keys(), collections.Iterable)
+ self.assertIsInstance(d.keys(), collections.Container)
+
+ self.assertIsInstance(d.values(), collections.ValuesView)
+ self.assertIsInstance(d.values(), collections.MappingView)
+ self.assertIsInstance(d.values(), collections.Sized)
+
+ self.assertIsInstance(d.items(), collections.ItemsView)
+ self.assertIsInstance(d.items(), collections.MappingView)
+ self.assertIsInstance(d.items(), collections.Set)
+ self.assertIsInstance(d.items(), collections.Sized)
+ self.assertIsInstance(d.items(), collections.Iterable)
+ self.assertIsInstance(d.items(), collections.Container)
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py
index 0fd1348027..7e125ef59b 100644
--- a/Lib/test/test_dis.py
+++ b/Lib/test/test_dis.py
@@ -40,41 +40,41 @@ class _C:
dis_c_instance_method = """\
%3d 0 LOAD_FAST 1 (x)
- 3 LOAD_CONST 1 (1)
- 6 COMPARE_OP 2 (==)
- 9 LOAD_FAST 0 (self)
- 12 STORE_ATTR 0 (x)
- 15 LOAD_CONST 0 (None)
- 18 RETURN_VALUE
+ 2 LOAD_CONST 1 (1)
+ 4 COMPARE_OP 2 (==)
+ 6 LOAD_FAST 0 (self)
+ 8 STORE_ATTR 0 (x)
+ 10 LOAD_CONST 0 (None)
+ 12 RETURN_VALUE
""" % (_C.__init__.__code__.co_firstlineno + 1,)
dis_c_instance_method_bytes = """\
0 LOAD_FAST 1 (1)
- 3 LOAD_CONST 1 (1)
- 6 COMPARE_OP 2 (==)
- 9 LOAD_FAST 0 (0)
- 12 STORE_ATTR 0 (0)
- 15 LOAD_CONST 0 (0)
- 18 RETURN_VALUE
+ 2 LOAD_CONST 1 (1)
+ 4 COMPARE_OP 2 (==)
+ 6 LOAD_FAST 0 (0)
+ 8 STORE_ATTR 0 (0)
+ 10 LOAD_CONST 0 (0)
+ 12 RETURN_VALUE
"""
dis_c_class_method = """\
%3d 0 LOAD_FAST 1 (x)
- 3 LOAD_CONST 1 (1)
- 6 COMPARE_OP 2 (==)
- 9 LOAD_FAST 0 (cls)
- 12 STORE_ATTR 0 (x)
- 15 LOAD_CONST 0 (None)
- 18 RETURN_VALUE
+ 2 LOAD_CONST 1 (1)
+ 4 COMPARE_OP 2 (==)
+ 6 LOAD_FAST 0 (cls)
+ 8 STORE_ATTR 0 (x)
+ 10 LOAD_CONST 0 (None)
+ 12 RETURN_VALUE
""" % (_C.cm.__code__.co_firstlineno + 2,)
dis_c_static_method = """\
%3d 0 LOAD_FAST 0 (x)
- 3 LOAD_CONST 1 (1)
- 6 COMPARE_OP 2 (==)
- 9 STORE_FAST 0 (x)
- 12 LOAD_CONST 0 (None)
- 15 RETURN_VALUE
+ 2 LOAD_CONST 1 (1)
+ 4 COMPARE_OP 2 (==)
+ 6 STORE_FAST 0 (x)
+ 8 LOAD_CONST 0 (None)
+ 10 RETURN_VALUE
""" % (_C.sm.__code__.co_firstlineno + 2,)
# Class disassembling info has an extra newline at end.
@@ -95,23 +95,23 @@ def _f(a):
dis_f = """\
%3d 0 LOAD_GLOBAL 0 (print)
- 3 LOAD_FAST 0 (a)
- 6 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
- 9 POP_TOP
+ 2 LOAD_FAST 0 (a)
+ 4 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
+ 6 POP_TOP
-%3d 10 LOAD_CONST 1 (1)
- 13 RETURN_VALUE
+%3d 8 LOAD_CONST 1 (1)
+ 10 RETURN_VALUE
""" % (_f.__code__.co_firstlineno + 1,
_f.__code__.co_firstlineno + 2)
dis_f_co_code = """\
0 LOAD_GLOBAL 0 (0)
- 3 LOAD_FAST 0 (0)
- 6 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
- 9 POP_TOP
- 10 LOAD_CONST 1 (1)
- 13 RETURN_VALUE
+ 2 LOAD_FAST 0 (0)
+ 4 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
+ 6 POP_TOP
+ 8 LOAD_CONST 1 (1)
+ 10 RETURN_VALUE
"""
@@ -121,20 +121,20 @@ def bug708901():
pass
dis_bug708901 = """\
-%3d 0 SETUP_LOOP 23 (to 26)
- 3 LOAD_GLOBAL 0 (range)
- 6 LOAD_CONST 1 (1)
-
-%3d 9 LOAD_CONST 2 (10)
- 12 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
- 15 GET_ITER
- >> 16 FOR_ITER 6 (to 25)
- 19 STORE_FAST 0 (res)
-
-%3d 22 JUMP_ABSOLUTE 16
- >> 25 POP_BLOCK
- >> 26 LOAD_CONST 0 (None)
- 29 RETURN_VALUE
+%3d 0 SETUP_LOOP 18 (to 20)
+ 2 LOAD_GLOBAL 0 (range)
+ 4 LOAD_CONST 1 (1)
+
+%3d 6 LOAD_CONST 2 (10)
+ 8 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
+ 10 GET_ITER
+ >> 12 FOR_ITER 4 (to 18)
+ 14 STORE_FAST 0 (res)
+
+%3d 16 JUMP_ABSOLUTE 12
+ >> 18 POP_BLOCK
+ >> 20 LOAD_CONST 0 (None)
+ 22 RETURN_VALUE
""" % (bug708901.__code__.co_firstlineno + 1,
bug708901.__code__.co_firstlineno + 2,
bug708901.__code__.co_firstlineno + 3)
@@ -147,22 +147,22 @@ def bug1333982(x=[]):
dis_bug1333982 = """\
%3d 0 LOAD_CONST 1 (0)
- 3 POP_JUMP_IF_TRUE 35
- 6 LOAD_GLOBAL 0 (AssertionError)
- 9 LOAD_CONST 2 (<code object <listcomp> at 0x..., file "%s", line %d>)
- 12 LOAD_CONST 3 ('bug1333982.<locals>.<listcomp>')
- 15 MAKE_FUNCTION 0
- 18 LOAD_FAST 0 (x)
- 21 GET_ITER
+ 2 POP_JUMP_IF_TRUE 26
+ 4 LOAD_GLOBAL 0 (AssertionError)
+ 6 LOAD_CONST 2 (<code object <listcomp> at 0x..., file "%s", line %d>)
+ 8 LOAD_CONST 3 ('bug1333982.<locals>.<listcomp>')
+ 10 MAKE_FUNCTION 0
+ 12 LOAD_FAST 0 (x)
+ 14 GET_ITER
+ 16 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
+
+%3d 18 LOAD_CONST 4 (1)
+ 20 BINARY_ADD
22 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
+ 24 RAISE_VARARGS 1
-%3d 25 LOAD_CONST 4 (1)
- 28 BINARY_ADD
- 29 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
- 32 RAISE_VARARGS 1
-
-%3d >> 35 LOAD_CONST 0 (None)
- 38 RETURN_VALUE
+%3d >> 26 LOAD_CONST 0 (None)
+ 28 RETURN_VALUE
""" % (bug1333982.__code__.co_firstlineno + 1,
__file__,
bug1333982.__code__.co_firstlineno + 1,
@@ -171,19 +171,19 @@ dis_bug1333982 = """\
_BIG_LINENO_FORMAT = """\
%3d 0 LOAD_GLOBAL 0 (spam)
- 3 POP_TOP
+ 2 POP_TOP
4 LOAD_CONST 0 (None)
- 7 RETURN_VALUE
+ 6 RETURN_VALUE
"""
dis_module_expected_results = """\
Disassembly of f:
4 0 LOAD_CONST 0 (None)
- 3 RETURN_VALUE
+ 2 RETURN_VALUE
Disassembly of g:
5 0 LOAD_CONST 0 (None)
- 3 RETURN_VALUE
+ 2 RETURN_VALUE
"""
@@ -191,20 +191,20 @@ expr_str = "x + 1"
dis_expr_str = """\
1 0 LOAD_NAME 0 (x)
- 3 LOAD_CONST 0 (1)
- 6 BINARY_ADD
- 7 RETURN_VALUE
+ 2 LOAD_CONST 0 (1)
+ 4 BINARY_ADD
+ 6 RETURN_VALUE
"""
simple_stmt_str = "x = x + 1"
dis_simple_stmt_str = """\
1 0 LOAD_NAME 0 (x)
- 3 LOAD_CONST 0 (1)
- 6 BINARY_ADD
- 7 STORE_NAME 0 (x)
- 10 LOAD_CONST 1 (None)
- 13 RETURN_VALUE
+ 2 LOAD_CONST 0 (1)
+ 4 BINARY_ADD
+ 6 STORE_NAME 0 (x)
+ 8 LOAD_CONST 1 (None)
+ 10 RETURN_VALUE
"""
compound_stmt_str = """\
@@ -215,54 +215,54 @@ while 1:
dis_compound_stmt_str = """\
1 0 LOAD_CONST 0 (0)
- 3 STORE_NAME 0 (x)
-
- 2 6 SETUP_LOOP 14 (to 23)
-
- 3 >> 9 LOAD_NAME 0 (x)
- 12 LOAD_CONST 1 (1)
- 15 INPLACE_ADD
- 16 STORE_NAME 0 (x)
- 19 JUMP_ABSOLUTE 9
- 22 POP_BLOCK
- >> 23 LOAD_CONST 2 (None)
- 26 RETURN_VALUE
+ 2 STORE_NAME 0 (x)
+
+ 2 4 SETUP_LOOP 12 (to 18)
+
+ 3 >> 6 LOAD_NAME 0 (x)
+ 8 LOAD_CONST 1 (1)
+ 10 INPLACE_ADD
+ 12 STORE_NAME 0 (x)
+ 14 JUMP_ABSOLUTE 6
+ 16 POP_BLOCK
+ >> 18 LOAD_CONST 2 (None)
+ 20 RETURN_VALUE
"""
dis_traceback = """\
-%3d 0 SETUP_EXCEPT 12 (to 15)
+%3d 0 SETUP_EXCEPT 12 (to 14)
-%3d 3 LOAD_CONST 1 (1)
- 6 LOAD_CONST 2 (0)
- --> 9 BINARY_TRUE_DIVIDE
- 10 POP_TOP
- 11 POP_BLOCK
- 12 JUMP_FORWARD 46 (to 61)
+%3d 2 LOAD_CONST 1 (1)
+ 4 LOAD_CONST 2 (0)
+ --> 6 BINARY_TRUE_DIVIDE
+ 8 POP_TOP
+ 10 POP_BLOCK
+ 12 JUMP_FORWARD 40 (to 54)
-%3d >> 15 DUP_TOP
+%3d >> 14 DUP_TOP
16 LOAD_GLOBAL 0 (Exception)
- 19 COMPARE_OP 10 (exception match)
- 22 POP_JUMP_IF_FALSE 60
- 25 POP_TOP
- 26 STORE_FAST 0 (e)
- 29 POP_TOP
- 30 SETUP_FINALLY 14 (to 47)
-
-%3d 33 LOAD_FAST 0 (e)
- 36 LOAD_ATTR 1 (__traceback__)
- 39 STORE_FAST 1 (tb)
- 42 POP_BLOCK
- 43 POP_EXCEPT
- 44 LOAD_CONST 0 (None)
- >> 47 LOAD_CONST 0 (None)
- 50 STORE_FAST 0 (e)
- 53 DELETE_FAST 0 (e)
- 56 END_FINALLY
- 57 JUMP_FORWARD 1 (to 61)
- >> 60 END_FINALLY
-
-%3d >> 61 LOAD_FAST 1 (tb)
- 64 RETURN_VALUE
+ 18 COMPARE_OP 10 (exception match)
+ 20 POP_JUMP_IF_FALSE 52
+ 22 POP_TOP
+ 24 STORE_FAST 0 (e)
+ 26 POP_TOP
+ 28 SETUP_FINALLY 12 (to 42)
+
+%3d 30 LOAD_FAST 0 (e)
+ 32 LOAD_ATTR 1 (__traceback__)
+ 34 STORE_FAST 1 (tb)
+ 36 POP_BLOCK
+ 38 POP_EXCEPT
+ 40 LOAD_CONST 0 (None)
+ >> 42 LOAD_CONST 0 (None)
+ 44 STORE_FAST 0 (e)
+ 46 DELETE_FAST 0 (e)
+ 48 END_FINALLY
+ 50 JUMP_FORWARD 2 (to 54)
+ >> 52 END_FINALLY
+
+%3d >> 54 LOAD_FAST 1 (tb)
+ 56 RETURN_VALUE
""" % (TRACEBACK_CODE.co_firstlineno + 1,
TRACEBACK_CODE.co_firstlineno + 2,
TRACEBACK_CODE.co_firstlineno + 3,
@@ -650,170 +650,170 @@ expected_jumpy_line = 1
Instruction = dis.Instruction
expected_opinfo_outer = [
Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=3, argrepr='3', offset=0, starts_line=2, is_jump_target=False),
- Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=3, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_CLOSURE', opcode=135, arg=0, argval='a', argrepr='a', offset=6, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_CLOSURE', opcode=135, arg=1, argval='b', argrepr='b', offset=9, starts_line=None, is_jump_target=False),
- Instruction(opname='BUILD_TUPLE', opcode=102, arg=2, argval=2, argrepr='', offset=12, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_f, argrepr=repr(code_object_f), offset=15, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer.<locals>.f', argrepr="'outer.<locals>.f'", offset=18, starts_line=None, is_jump_target=False),
- Instruction(opname='MAKE_CLOSURE', opcode=134, arg=2, argval=2, argrepr='', offset=21, starts_line=None, is_jump_target=False),
- Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='f', argrepr='f', offset=24, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=27, starts_line=7, is_jump_target=False),
- Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='a', argrepr='a', offset=30, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='b', argrepr='b', offset=33, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval='', argrepr="''", offset=36, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval=1, argrepr='1', offset=39, starts_line=None, is_jump_target=False),
- Instruction(opname='BUILD_LIST', opcode=103, arg=0, argval=0, argrepr='', offset=42, starts_line=None, is_jump_target=False),
- Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=45, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval='Hello world!', argrepr="'Hello world!'", offset=48, starts_line=None, is_jump_target=False),
- Instruction(opname='CALL_FUNCTION', opcode=131, arg=7, argval=7, argrepr='7 positional, 0 keyword pair', offset=51, starts_line=None, is_jump_target=False),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=54, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=55, starts_line=8, is_jump_target=False),
- Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=58, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=2, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_CLOSURE', opcode=135, arg=0, argval='a', argrepr='a', offset=4, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_CLOSURE', opcode=135, arg=1, argval='b', argrepr='b', offset=6, starts_line=None, is_jump_target=False),
+ Instruction(opname='BUILD_TUPLE', opcode=102, arg=2, argval=2, argrepr='', offset=8, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_f, argrepr=repr(code_object_f), offset=10, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer.<locals>.f', argrepr="'outer.<locals>.f'", offset=12, starts_line=None, is_jump_target=False),
+ Instruction(opname='MAKE_CLOSURE', opcode=134, arg=2, argval=2, argrepr='', offset=14, starts_line=None, is_jump_target=False),
+ Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='f', argrepr='f', offset=16, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=18, starts_line=7, is_jump_target=False),
+ Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='a', argrepr='a', offset=20, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='b', argrepr='b', offset=22, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval='', argrepr="''", offset=24, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval=1, argrepr='1', offset=26, starts_line=None, is_jump_target=False),
+ Instruction(opname='BUILD_LIST', opcode=103, arg=0, argval=0, argrepr='', offset=28, starts_line=None, is_jump_target=False),
+ Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=30, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval='Hello world!', argrepr="'Hello world!'", offset=32, starts_line=None, is_jump_target=False),
+ Instruction(opname='CALL_FUNCTION', opcode=131, arg=7, argval=7, argrepr='7 positional, 0 keyword pair', offset=34, starts_line=None, is_jump_target=False),
+ Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=36, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=38, starts_line=8, is_jump_target=False),
+ Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=40, starts_line=None, is_jump_target=False),
]
expected_opinfo_f = [
Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=5, argrepr='5', offset=0, starts_line=3, is_jump_target=False),
- Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=6, argrepr='6', offset=3, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_CLOSURE', opcode=135, arg=2, argval='a', argrepr='a', offset=6, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_CLOSURE', opcode=135, arg=3, argval='b', argrepr='b', offset=9, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_CLOSURE', opcode=135, arg=0, argval='c', argrepr='c', offset=12, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_CLOSURE', opcode=135, arg=1, argval='d', argrepr='d', offset=15, starts_line=None, is_jump_target=False),
- Instruction(opname='BUILD_TUPLE', opcode=102, arg=4, argval=4, argrepr='', offset=18, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_inner, argrepr=repr(code_object_inner), offset=21, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer.<locals>.f.<locals>.inner', argrepr="'outer.<locals>.f.<locals>.inner'", offset=24, starts_line=None, is_jump_target=False),
- Instruction(opname='MAKE_CLOSURE', opcode=134, arg=2, argval=2, argrepr='', offset=27, starts_line=None, is_jump_target=False),
- Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='inner', argrepr='inner', offset=30, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=33, starts_line=5, is_jump_target=False),
- Instruction(opname='LOAD_DEREF', opcode=136, arg=2, argval='a', argrepr='a', offset=36, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_DEREF', opcode=136, arg=3, argval='b', argrepr='b', offset=39, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='c', argrepr='c', offset=42, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='d', argrepr='d', offset=45, starts_line=None, is_jump_target=False),
- Instruction(opname='CALL_FUNCTION', opcode=131, arg=4, argval=4, argrepr='4 positional, 0 keyword pair', offset=48, starts_line=None, is_jump_target=False),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=51, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=52, starts_line=6, is_jump_target=False),
- Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=55, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=6, argrepr='6', offset=2, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_CLOSURE', opcode=135, arg=2, argval='a', argrepr='a', offset=4, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_CLOSURE', opcode=135, arg=3, argval='b', argrepr='b', offset=6, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_CLOSURE', opcode=135, arg=0, argval='c', argrepr='c', offset=8, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_CLOSURE', opcode=135, arg=1, argval='d', argrepr='d', offset=10, starts_line=None, is_jump_target=False),
+ Instruction(opname='BUILD_TUPLE', opcode=102, arg=4, argval=4, argrepr='', offset=12, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_inner, argrepr=repr(code_object_inner), offset=14, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer.<locals>.f.<locals>.inner', argrepr="'outer.<locals>.f.<locals>.inner'", offset=16, starts_line=None, is_jump_target=False),
+ Instruction(opname='MAKE_CLOSURE', opcode=134, arg=2, argval=2, argrepr='', offset=18, starts_line=None, is_jump_target=False),
+ Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='inner', argrepr='inner', offset=20, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=22, starts_line=5, is_jump_target=False),
+ Instruction(opname='LOAD_DEREF', opcode=136, arg=2, argval='a', argrepr='a', offset=24, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_DEREF', opcode=136, arg=3, argval='b', argrepr='b', offset=26, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='c', argrepr='c', offset=28, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='d', argrepr='d', offset=30, starts_line=None, is_jump_target=False),
+ Instruction(opname='CALL_FUNCTION', opcode=131, arg=4, argval=4, argrepr='4 positional, 0 keyword pair', offset=32, starts_line=None, is_jump_target=False),
+ Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=34, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=36, starts_line=6, is_jump_target=False),
+ Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=38, starts_line=None, is_jump_target=False),
]
expected_opinfo_inner = [
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=0, starts_line=4, is_jump_target=False),
- Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='a', argrepr='a', offset=3, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='b', argrepr='b', offset=6, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_DEREF', opcode=136, arg=2, argval='c', argrepr='c', offset=9, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_DEREF', opcode=136, arg=3, argval='d', argrepr='d', offset=12, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='e', argrepr='e', offset=15, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='f', argrepr='f', offset=18, starts_line=None, is_jump_target=False),
- Instruction(opname='CALL_FUNCTION', opcode=131, arg=6, argval=6, argrepr='6 positional, 0 keyword pair', offset=21, starts_line=None, is_jump_target=False),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=24, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=25, starts_line=None, is_jump_target=False),
- Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=28, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='a', argrepr='a', offset=2, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='b', argrepr='b', offset=4, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_DEREF', opcode=136, arg=2, argval='c', argrepr='c', offset=6, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_DEREF', opcode=136, arg=3, argval='d', argrepr='d', offset=8, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='e', argrepr='e', offset=10, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='f', argrepr='f', offset=12, starts_line=None, is_jump_target=False),
+ Instruction(opname='CALL_FUNCTION', opcode=131, arg=6, argval=6, argrepr='6 positional, 0 keyword pair', offset=14, starts_line=None, is_jump_target=False),
+ Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=16, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=18, starts_line=None, is_jump_target=False),
+ Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=20, starts_line=None, is_jump_target=False),
]
expected_opinfo_jumpy = [
- Instruction(opname='SETUP_LOOP', opcode=120, arg=68, argval=71, argrepr='to 71', offset=0, starts_line=3, is_jump_target=False),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='range', argrepr='range', offset=3, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=10, argrepr='10', offset=6, starts_line=None, is_jump_target=False),
- Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=9, starts_line=None, is_jump_target=False),
- Instruction(opname='GET_ITER', opcode=68, arg=None, argval=None, argrepr='', offset=12, starts_line=None, is_jump_target=False),
- Instruction(opname='FOR_ITER', opcode=93, arg=44, argval=60, argrepr='to 60', offset=13, starts_line=None, is_jump_target=True),
- Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=16, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=19, starts_line=4, is_jump_target=False),
- Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=22, starts_line=None, is_jump_target=False),
- Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=25, starts_line=None, is_jump_target=False),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=28, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=29, starts_line=5, is_jump_target=False),
- Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=32, starts_line=None, is_jump_target=False),
- Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=35, starts_line=None, is_jump_target=False),
- Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=44, argval=44, argrepr='', offset=38, starts_line=None, is_jump_target=False),
- Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=13, argval=13, argrepr='', offset=41, starts_line=6, is_jump_target=False),
- Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=44, starts_line=7, is_jump_target=True),
- Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=47, starts_line=None, is_jump_target=False),
- Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=50, starts_line=None, is_jump_target=False),
- Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=13, argval=13, argrepr='', offset=53, starts_line=None, is_jump_target=False),
- Instruction(opname='BREAK_LOOP', opcode=80, arg=None, argval=None, argrepr='', offset=56, starts_line=8, is_jump_target=False),
- Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=13, argval=13, argrepr='', offset=57, starts_line=None, is_jump_target=False),
- Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=60, starts_line=None, is_jump_target=True),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=61, starts_line=10, is_jump_target=False),
- Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=64, starts_line=None, is_jump_target=False),
- Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=67, starts_line=None, is_jump_target=False),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=70, starts_line=None, is_jump_target=False),
- Instruction(opname='SETUP_LOOP', opcode=120, arg=68, argval=142, argrepr='to 142', offset=71, starts_line=11, is_jump_target=True),
- Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=74, starts_line=None, is_jump_target=True),
- Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=131, argval=131, argrepr='', offset=77, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=80, starts_line=12, is_jump_target=False),
- Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=83, starts_line=None, is_jump_target=False),
- Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=86, starts_line=None, is_jump_target=False),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=89, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=90, starts_line=13, is_jump_target=False),
- Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=93, starts_line=None, is_jump_target=False),
- Instruction(opname='INPLACE_SUBTRACT', opcode=56, arg=None, argval=None, argrepr='', offset=96, starts_line=None, is_jump_target=False),
- Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=97, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=100, starts_line=14, is_jump_target=False),
- Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=103, starts_line=None, is_jump_target=False),
- Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=106, starts_line=None, is_jump_target=False),
- Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=115, argval=115, argrepr='', offset=109, starts_line=None, is_jump_target=False),
- Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=74, argval=74, argrepr='', offset=112, starts_line=15, is_jump_target=False),
- Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=115, starts_line=16, is_jump_target=True),
- Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=118, starts_line=None, is_jump_target=False),
- Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=121, starts_line=None, is_jump_target=False),
- Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=74, argval=74, argrepr='', offset=124, starts_line=None, is_jump_target=False),
- Instruction(opname='BREAK_LOOP', opcode=80, arg=None, argval=None, argrepr='', offset=127, starts_line=17, is_jump_target=False),
- Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=74, argval=74, argrepr='', offset=128, starts_line=None, is_jump_target=False),
- Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=131, starts_line=None, is_jump_target=True),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=132, starts_line=19, is_jump_target=False),
- Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=135, starts_line=None, is_jump_target=False),
- Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=138, starts_line=None, is_jump_target=False),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=141, starts_line=None, is_jump_target=False),
- Instruction(opname='SETUP_FINALLY', opcode=122, arg=73, argval=218, argrepr='to 218', offset=142, starts_line=20, is_jump_target=True),
- Instruction(opname='SETUP_EXCEPT', opcode=121, arg=12, argval=160, argrepr='to 160', offset=145, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=148, starts_line=21, is_jump_target=False),
- Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=151, starts_line=None, is_jump_target=False),
- Instruction(opname='BINARY_TRUE_DIVIDE', opcode=27, arg=None, argval=None, argrepr='', offset=154, starts_line=None, is_jump_target=False),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=155, starts_line=None, is_jump_target=False),
- Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=156, starts_line=None, is_jump_target=False),
- Instruction(opname='JUMP_FORWARD', opcode=110, arg=28, argval=188, argrepr='to 188', offset=157, starts_line=None, is_jump_target=False),
- Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=160, starts_line=22, is_jump_target=True),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=2, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=161, starts_line=None, is_jump_target=False),
- Instruction(opname='COMPARE_OP', opcode=107, arg=10, argval='exception match', argrepr='exception match', offset=164, starts_line=None, is_jump_target=False),
- Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=187, argval=187, argrepr='', offset=167, starts_line=None, is_jump_target=False),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=170, starts_line=None, is_jump_target=False),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=171, starts_line=None, is_jump_target=False),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=172, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=173, starts_line=23, is_jump_target=False),
- Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=176, starts_line=None, is_jump_target=False),
- Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=179, starts_line=None, is_jump_target=False),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=182, starts_line=None, is_jump_target=False),
- Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=183, starts_line=None, is_jump_target=False),
- Instruction(opname='JUMP_FORWARD', opcode=110, arg=27, argval=214, argrepr='to 214', offset=184, starts_line=None, is_jump_target=False),
- Instruction(opname='END_FINALLY', opcode=88, arg=None, argval=None, argrepr='', offset=187, starts_line=None, is_jump_target=True),
- Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=188, starts_line=25, is_jump_target=True),
- Instruction(opname='SETUP_WITH', opcode=143, arg=17, argval=211, argrepr='to 211', offset=191, starts_line=None, is_jump_target=False),
- Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=194, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=197, starts_line=26, is_jump_target=False),
- Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Never reach this', argrepr="'Never reach this'", offset=200, starts_line=None, is_jump_target=False),
- Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=203, starts_line=None, is_jump_target=False),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=206, starts_line=None, is_jump_target=False),
- Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=207, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=208, starts_line=None, is_jump_target=False),
- Instruction(opname='WITH_CLEANUP_START', opcode=81, arg=None, argval=None, argrepr='', offset=211, starts_line=None, is_jump_target=True),
- Instruction(opname='WITH_CLEANUP_FINISH', opcode=82, arg=None, argval=None, argrepr='', offset=212, starts_line=None, is_jump_target=False),
- Instruction(opname='END_FINALLY', opcode=88, arg=None, argval=None, argrepr='', offset=213, starts_line=None, is_jump_target=False),
- Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=214, starts_line=None, is_jump_target=True),
- Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=215, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=218, starts_line=28, is_jump_target=True),
- Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=221, starts_line=None, is_jump_target=False),
- Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=224, starts_line=None, is_jump_target=False),
- Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=227, starts_line=None, is_jump_target=False),
- Instruction(opname='END_FINALLY', opcode=88, arg=None, argval=None, argrepr='', offset=228, starts_line=None, is_jump_target=False),
- Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=229, starts_line=None, is_jump_target=False),
- Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=232, starts_line=None, is_jump_target=False),
+ Instruction(opname='SETUP_LOOP', opcode=120, arg=52, argval=54, argrepr='to 54', offset=0, starts_line=3, is_jump_target=False),
+ Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='range', argrepr='range', offset=2, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=10, argrepr='10', offset=4, starts_line=None, is_jump_target=False),
+ Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=6, starts_line=None, is_jump_target=False),
+ Instruction(opname='GET_ITER', opcode=68, arg=None, argval=None, argrepr='', offset=8, starts_line=None, is_jump_target=False),
+ Instruction(opname='FOR_ITER', opcode=93, arg=32, argval=44, argrepr='to 44', offset=10, starts_line=None, is_jump_target=True),
+ Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=12, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=14, starts_line=4, is_jump_target=False),
+ Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=16, starts_line=None, is_jump_target=False),
+ Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=18, starts_line=None, is_jump_target=False),
+ Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=20, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=22, starts_line=5, is_jump_target=False),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=24, starts_line=None, is_jump_target=False),
+ Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=26, starts_line=None, is_jump_target=False),
+ Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=32, argval=32, argrepr='', offset=28, starts_line=None, is_jump_target=False),
+ Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=10, argval=10, argrepr='', offset=30, starts_line=6, is_jump_target=False),
+ Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=32, starts_line=7, is_jump_target=True),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=34, starts_line=None, is_jump_target=False),
+ Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=36, starts_line=None, is_jump_target=False),
+ Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=10, argval=10, argrepr='', offset=38, starts_line=None, is_jump_target=False),
+ Instruction(opname='BREAK_LOOP', opcode=80, arg=None, argval=None, argrepr='', offset=40, starts_line=8, is_jump_target=False),
+ Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=10, argval=10, argrepr='', offset=42, starts_line=None, is_jump_target=False),
+ Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=44, starts_line=None, is_jump_target=True),
+ Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=46, starts_line=10, is_jump_target=False),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=48, starts_line=None, is_jump_target=False),
+ Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=50, starts_line=None, is_jump_target=False),
+ Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=52, starts_line=None, is_jump_target=False),
+ Instruction(opname='SETUP_LOOP', opcode=120, arg=52, argval=108, argrepr='to 108', offset=54, starts_line=11, is_jump_target=True),
+ Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=56, starts_line=None, is_jump_target=True),
+ Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=98, argval=98, argrepr='', offset=58, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=60, starts_line=12, is_jump_target=False),
+ Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=62, starts_line=None, is_jump_target=False),
+ Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=64, starts_line=None, is_jump_target=False),
+ Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=66, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=68, starts_line=13, is_jump_target=False),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=70, starts_line=None, is_jump_target=False),
+ Instruction(opname='INPLACE_SUBTRACT', opcode=56, arg=None, argval=None, argrepr='', offset=72, starts_line=None, is_jump_target=False),
+ Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=74, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=76, starts_line=14, is_jump_target=False),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=78, starts_line=None, is_jump_target=False),
+ Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=80, starts_line=None, is_jump_target=False),
+ Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=86, argval=86, argrepr='', offset=82, starts_line=None, is_jump_target=False),
+ Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=56, argval=56, argrepr='', offset=84, starts_line=15, is_jump_target=False),
+ Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=86, starts_line=16, is_jump_target=True),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=88, starts_line=None, is_jump_target=False),
+ Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=90, starts_line=None, is_jump_target=False),
+ Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=56, argval=56, argrepr='', offset=92, starts_line=None, is_jump_target=False),
+ Instruction(opname='BREAK_LOOP', opcode=80, arg=None, argval=None, argrepr='', offset=94, starts_line=17, is_jump_target=False),
+ Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=56, argval=56, argrepr='', offset=96, starts_line=None, is_jump_target=False),
+ Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=98, starts_line=None, is_jump_target=True),
+ Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=100, starts_line=19, is_jump_target=False),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=102, starts_line=None, is_jump_target=False),
+ Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=104, starts_line=None, is_jump_target=False),
+ Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=106, starts_line=None, is_jump_target=False),
+ Instruction(opname='SETUP_FINALLY', opcode=122, arg=70, argval=180, argrepr='to 180', offset=108, starts_line=20, is_jump_target=True),
+ Instruction(opname='SETUP_EXCEPT', opcode=121, arg=12, argval=124, argrepr='to 124', offset=110, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=112, starts_line=21, is_jump_target=False),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=114, starts_line=None, is_jump_target=False),
+ Instruction(opname='BINARY_TRUE_DIVIDE', opcode=27, arg=None, argval=None, argrepr='', offset=116, starts_line=None, is_jump_target=False),
+ Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=118, starts_line=None, is_jump_target=False),
+ Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=120, starts_line=None, is_jump_target=False),
+ Instruction(opname='JUMP_FORWARD', opcode=110, arg=28, argval=152, argrepr='to 152', offset=122, starts_line=None, is_jump_target=False),
+ Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=124, starts_line=22, is_jump_target=True),
+ Instruction(opname='LOAD_GLOBAL', opcode=116, arg=2, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=126, starts_line=None, is_jump_target=False),
+ Instruction(opname='COMPARE_OP', opcode=107, arg=10, argval='exception match', argrepr='exception match', offset=128, starts_line=None, is_jump_target=False),
+ Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=150, argval=150, argrepr='', offset=130, starts_line=None, is_jump_target=False),
+ Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=132, starts_line=None, is_jump_target=False),
+ Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=134, starts_line=None, is_jump_target=False),
+ Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=136, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=138, starts_line=23, is_jump_target=False),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=140, starts_line=None, is_jump_target=False),
+ Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=142, starts_line=None, is_jump_target=False),
+ Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=144, starts_line=None, is_jump_target=False),
+ Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=146, starts_line=None, is_jump_target=False),
+ Instruction(opname='JUMP_FORWARD', opcode=110, arg=26, argval=176, argrepr='to 176', offset=148, starts_line=None, is_jump_target=False),
+ Instruction(opname='END_FINALLY', opcode=88, arg=None, argval=None, argrepr='', offset=150, starts_line=None, is_jump_target=True),
+ Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=152, starts_line=25, is_jump_target=True),
+ Instruction(opname='SETUP_WITH', opcode=143, arg=14, argval=170, argrepr='to 170', offset=154, starts_line=None, is_jump_target=False),
+ Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=156, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=158, starts_line=26, is_jump_target=False),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Never reach this', argrepr="'Never reach this'", offset=160, starts_line=None, is_jump_target=False),
+ Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=162, starts_line=None, is_jump_target=False),
+ Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=164, starts_line=None, is_jump_target=False),
+ Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=166, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=168, starts_line=None, is_jump_target=False),
+ Instruction(opname='WITH_CLEANUP_START', opcode=81, arg=None, argval=None, argrepr='', offset=170, starts_line=None, is_jump_target=True),
+ Instruction(opname='WITH_CLEANUP_FINISH', opcode=82, arg=None, argval=None, argrepr='', offset=172, starts_line=None, is_jump_target=False),
+ Instruction(opname='END_FINALLY', opcode=88, arg=None, argval=None, argrepr='', offset=174, starts_line=None, is_jump_target=False),
+ Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=176, starts_line=None, is_jump_target=True),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=178, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=180, starts_line=28, is_jump_target=True),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=182, starts_line=None, is_jump_target=False),
+ Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=184, starts_line=None, is_jump_target=False),
+ Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=186, starts_line=None, is_jump_target=False),
+ Instruction(opname='END_FINALLY', opcode=88, arg=None, argval=None, argrepr='', offset=188, starts_line=None, is_jump_target=False),
+ Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=190, starts_line=None, is_jump_target=False),
+ Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=192, starts_line=None, is_jump_target=False),
]
# One last piece of inspect fodder to check the default line number handling
def simple(): pass
expected_opinfo_simple = [
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=0, starts_line=simple.__code__.co_firstlineno, is_jump_target=False),
- Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=3, starts_line=None, is_jump_target=False)
+ Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=2, starts_line=None, is_jump_target=False)
]
diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py
index 29426a3185..2068fb70f8 100644
--- a/Lib/test/test_doctest.py
+++ b/Lib/test/test_doctest.py
@@ -1876,7 +1876,6 @@ if not hasattr(sys, 'gettrace') or not sys.gettrace():
To demonstrate this, we'll create a fake standard input that
captures our debugger input:
- >>> import tempfile
>>> real_stdin = sys.stdin
>>> sys.stdin = _FakeInput([
... 'print(x)', # print data defined by the example
@@ -1917,7 +1916,7 @@ if not hasattr(sys, 'gettrace') or not sys.gettrace():
... finally:
... sys.stdin = real_stdin
--Return--
- > <doctest test.test_doctest.test_pdb_set_trace[8]>(3)calls_set_trace()->None
+ > <doctest test.test_doctest.test_pdb_set_trace[7]>(3)calls_set_trace()->None
-> import pdb; pdb.set_trace()
(Pdb) print(y)
2
@@ -2804,7 +2803,6 @@ text files).
... _ = f.write(" 'abc def'\n")
... _ = f.write("\n")
... _ = f.write(' \"\"\"\n')
- ... import shutil
... rc1, out1, err1 = script_helper.assert_python_failure(
... '-m', 'doctest', fn, fn2, TERM='')
... rc2, out2, err2 = script_helper.assert_python_ok(
@@ -2948,12 +2946,11 @@ Invalid doctest option:
def test_main():
# Check the doctest cases in doctest itself:
ret = support.run_doctest(doctest, verbosity=True)
+
# Check the doctest cases defined here:
from test import test_doctest
support.run_doctest(test_doctest, verbosity=True)
-import sys, re, io
-
def test_coverage(coverdir):
trace = support.import_module('trace')
tracer = trace.Trace(ignoredirs=[sys.base_prefix, sys.base_exec_prefix,],
diff --git a/Lib/test/test_dynamic.py b/Lib/test/test_dynamic.py
index 5080ec9f79..3ae090fd66 100644
--- a/Lib/test/test_dynamic.py
+++ b/Lib/test/test_dynamic.py
@@ -1,7 +1,6 @@
# Test the most dynamic corner cases of Python's runtime semantics.
import builtins
-import contextlib
import unittest
from test.support import swap_item, swap_attr
diff --git a/Lib/test/test_eintr.py b/Lib/test/test_eintr.py
index aabad835a0..25f86d31de 100644
--- a/Lib/test/test_eintr.py
+++ b/Lib/test/test_eintr.py
@@ -1,7 +1,5 @@
import os
import signal
-import subprocess
-import sys
import unittest
from test import support
@@ -16,14 +14,8 @@ class EINTRTests(unittest.TestCase):
# Run the tester in a sub-process, to make sure there is only one
# thread (for reliable signal delivery).
tester = support.findfile("eintr_tester.py", subdir="eintrdata")
-
- if support.verbose:
- args = [sys.executable, tester]
- with subprocess.Popen(args) as proc:
- exitcode = proc.wait()
- self.assertEqual(exitcode, 0)
- else:
- script_helper.assert_python_ok(tester)
+ # use -u to try to get the full output if the test hangs or crash
+ script_helper.assert_python_ok("-u", tester)
if __name__ == "__main__":
diff --git a/Lib/test/test_email/__init__.py b/Lib/test/test_email/__init__.py
index d2f7d31934..16001596e4 100644
--- a/Lib/test/test_email/__init__.py
+++ b/Lib/test/test_email/__init__.py
@@ -1,5 +1,4 @@
import os
-import sys
import unittest
import collections
import email
diff --git a/Lib/test/test_email/test_asian_codecs.py b/Lib/test/test_email/test_asian_codecs.py
index f9cd7d9b4e..1e0caeeaed 100644
--- a/Lib/test/test_email/test_asian_codecs.py
+++ b/Lib/test/test_email/test_asian_codecs.py
@@ -3,7 +3,6 @@
# email package unit tests for (optional) Asian codecs
import unittest
-from test.support import run_unittest
from test.test_email import TestEmailBase
from email.charset import Charset
diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py
index 894b8003cd..af3fb85c56 100644
--- a/Lib/test/test_email/test_email.py
+++ b/Lib/test/test_email/test_email.py
@@ -3421,7 +3421,6 @@ Do you like this message?
class TestFeedParsers(TestEmailBase):
def parse(self, chunks):
- from email.feedparser import FeedParser
feedparser = FeedParser()
for chunk in chunks:
feedparser.feed(chunk)
diff --git a/Lib/test/test_email/test_headerregistry.py b/Lib/test/test_email/test_headerregistry.py
index 55ecdea9aa..af836dc972 100644
--- a/Lib/test/test_email/test_headerregistry.py
+++ b/Lib/test/test_email/test_headerregistry.py
@@ -1,7 +1,6 @@
import datetime
import textwrap
import unittest
-import types
from email import errors
from email import policy
from email.message import Message
diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py
index e970a264d7..b6cb00fcf4 100644
--- a/Lib/test/test_enum.py
+++ b/Lib/test/test_enum.py
@@ -6,6 +6,7 @@ from collections import OrderedDict
from enum import Enum, IntEnum, EnumMeta, unique
from io import StringIO
from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
+from test import support
# for pickle tests
try:
@@ -283,6 +284,28 @@ class TestEnum(unittest.TestCase):
class Wrong(Enum):
_any_name_ = 9
+ def test_bool(self):
+ # plain Enum members are always True
+ class Logic(Enum):
+ true = True
+ false = False
+ self.assertTrue(Logic.true)
+ self.assertTrue(Logic.false)
+ # unless overridden
+ class RealLogic(Enum):
+ true = True
+ false = False
+ def __bool__(self):
+ return bool(self._value_)
+ self.assertTrue(RealLogic.true)
+ self.assertFalse(RealLogic.false)
+ # mixed Enums depend on mixed-in type
+ class IntLogic(int, Enum):
+ true = 1
+ false = 0
+ self.assertTrue(IntLogic.true)
+ self.assertFalse(IntLogic.false)
+
def test_contains(self):
Season = self.Season
self.assertIn(Season.AUTUMN, Season)
@@ -1739,5 +1762,11 @@ class TestStdLib(unittest.TestCase):
if failed:
self.fail("result does not equal expected, see print above")
+
+class MiscTestCase(unittest.TestCase):
+ def test__all__(self):
+ support.check__all__(self, enum)
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/Lib/test/test_epoll.py b/Lib/test/test_epoll.py
index a7359e9c29..a7aff8a59e 100644
--- a/Lib/test/test_epoll.py
+++ b/Lib/test/test_epoll.py
@@ -28,7 +28,6 @@ import socket
import time
import unittest
-from test import support
if not hasattr(select, "epoll"):
raise unittest.SkipTest("test works only on Linux 2.6")
diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py
index 1562eecbd6..fc2d6d7bae 100644
--- a/Lib/test/test_faulthandler.py
+++ b/Lib/test/test_faulthandler.py
@@ -23,6 +23,7 @@ except ImportError:
_testcapi = None
TIMEOUT = 0.5
+MS_WINDOWS = (os.name == 'nt')
def expected_traceback(lineno1, lineno2, header, min_count=1):
regex = header
@@ -58,8 +59,9 @@ class FaultHandlerTests(unittest.TestCase):
pass_fds.append(fd)
with support.SuppressCrashReport():
process = script_helper.spawn_python('-c', code, pass_fds=pass_fds)
- stdout, stderr = process.communicate()
- exitcode = process.wait()
+ with process:
+ stdout, stderr = process.communicate()
+ exitcode = process.wait()
output = support.strip_python_stderr(stdout)
output = output.decode('ascii', 'backslashreplace')
if filename:
@@ -73,14 +75,11 @@ class FaultHandlerTests(unittest.TestCase):
with open(fd, "rb", closefd=False) as fp:
output = fp.read()
output = output.decode('ascii', 'backslashreplace')
- output = re.sub('Current thread 0x[0-9a-f]+',
- 'Current thread XXX',
- output)
return output.splitlines(), exitcode
- def check_fatal_error(self, code, line_number, name_regex,
- filename=None, all_threads=True, other_regex=None,
- fd=None):
+ def check_error(self, code, line_number, fatal_error, *,
+ filename=None, all_threads=True, other_regex=None,
+ fd=None, know_current_thread=True):
"""
Check that the fault handler for fatal errors is enabled and check the
traceback from the child process output.
@@ -88,19 +87,22 @@ class FaultHandlerTests(unittest.TestCase):
Raise an error if the output doesn't match the expected format.
"""
if all_threads:
- header = 'Current thread XXX (most recent call first)'
+ if know_current_thread:
+ header = 'Current thread 0x[0-9a-f]+'
+ else:
+ header = 'Thread 0x[0-9a-f]+'
else:
- header = 'Stack (most recent call first)'
+ header = 'Stack'
regex = """
- ^Fatal Python error: {name}
+ ^{fatal_error}
- {header}:
+ {header} \(most recent call first\):
File "<string>", line {lineno} in <module>
"""
regex = dedent(regex.format(
lineno=line_number,
- name=name_regex,
- header=re.escape(header))).strip()
+ fatal_error=fatal_error,
+ header=header)).strip()
if other_regex:
regex += '|' + other_regex
output, exitcode = self.get_output(code, filename=filename, fd=fd)
@@ -108,26 +110,56 @@ class FaultHandlerTests(unittest.TestCase):
self.assertRegex(output, regex)
self.assertNotEqual(exitcode, 0)
+ def check_fatal_error(self, code, line_number, name_regex, **kw):
+ fatal_error = 'Fatal Python error: %s' % name_regex
+ self.check_error(code, line_number, fatal_error, **kw)
+
+ def check_windows_exception(self, code, line_number, name_regex, **kw):
+ fatal_error = 'Windows fatal exception: %s' % name_regex
+ self.check_error(code, line_number, fatal_error, **kw)
+
@unittest.skipIf(sys.platform.startswith('aix'),
"the first page of memory is a mapped read-only on AIX")
def test_read_null(self):
+ if not MS_WINDOWS:
+ self.check_fatal_error("""
+ import faulthandler
+ faulthandler.enable()
+ faulthandler._read_null()
+ """,
+ 3,
+ # Issue #12700: Read NULL raises SIGILL on Mac OS X Lion
+ '(?:Segmentation fault'
+ '|Bus error'
+ '|Illegal instruction)')
+ else:
+ self.check_windows_exception("""
+ import faulthandler
+ faulthandler.enable()
+ faulthandler._read_null()
+ """,
+ 3,
+ 'access violation')
+
+ def test_sigsegv(self):
self.check_fatal_error("""
import faulthandler
faulthandler.enable()
- faulthandler._read_null()
+ faulthandler._sigsegv()
""",
3,
- # Issue #12700: Read NULL raises SIGILL on Mac OS X Lion
- '(?:Segmentation fault|Bus error|Illegal instruction)')
+ 'Segmentation fault')
- def test_sigsegv(self):
+ @unittest.skipIf(not HAVE_THREADS, 'need threads')
+ def test_fatal_error_c_thread(self):
self.check_fatal_error("""
import faulthandler
faulthandler.enable()
- faulthandler._sigsegv()
+ faulthandler._fatal_error_c_thread()
""",
3,
- 'Segmentation fault')
+ 'in new thread',
+ know_current_thread=False)
def test_sigabrt(self):
self.check_fatal_error("""
@@ -465,7 +497,7 @@ class FaultHandlerTests(unittest.TestCase):
File ".*threading.py", line [0-9]+ in _bootstrap_inner
File ".*threading.py", line [0-9]+ in _bootstrap
- Current thread XXX \(most recent call first\):
+ Current thread 0x[0-9a-f]+ \(most recent call first\):
File "<string>", line {lineno} in dump
File "<string>", line 28 in <module>$
"""
@@ -637,7 +669,7 @@ class FaultHandlerTests(unittest.TestCase):
trace = '\n'.join(trace)
if not unregister:
if all_threads:
- regex = 'Current thread XXX \(most recent call first\):\n'
+ regex = 'Current thread 0x[0-9a-f]+ \(most recent call first\):\n'
else:
regex = 'Stack \(most recent call first\):\n'
regex = expected_traceback(14, 32, regex)
@@ -696,6 +728,22 @@ class FaultHandlerTests(unittest.TestCase):
with self.check_stderr_none():
faulthandler.register(signal.SIGUSR1)
+ @unittest.skipUnless(MS_WINDOWS, 'specific to Windows')
+ def test_raise_exception(self):
+ for exc, name in (
+ ('EXCEPTION_ACCESS_VIOLATION', 'access violation'),
+ ('EXCEPTION_INT_DIVIDE_BY_ZERO', 'int divide by zero'),
+ ('EXCEPTION_STACK_OVERFLOW', 'stack overflow'),
+ ):
+ self.check_windows_exception(f"""
+ import faulthandler
+ faulthandler.enable()
+ faulthandler._raise_exception(faulthandler._{exc})
+ """,
+ 3,
+ name)
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/test/test_file.py b/Lib/test/test_file.py
index 4e392b770c..65be30f0b2 100644
--- a/Lib/test/test_file.py
+++ b/Lib/test/test_file.py
@@ -7,7 +7,7 @@ from weakref import proxy
import io
import _pyio as pyio
-from test.support import TESTFN, run_unittest
+from test.support import TESTFN
from collections import UserList
class AutoFileTests:
@@ -139,7 +139,7 @@ class OtherFileTests:
def testModeStrings(self):
# check invalid mode strings
- for mode in ("", "aU", "wU+"):
+ for mode in ("", "aU", "wU+", "U+", "+U", "rU+"):
try:
f = self.open(TESTFN, mode)
except ValueError:
diff --git a/Lib/test/test_fileinput.py b/Lib/test/test_fileinput.py
index 784bc92d23..565633fccc 100644
--- a/Lib/test/test_fileinput.py
+++ b/Lib/test/test_fileinput.py
@@ -22,8 +22,9 @@ except ImportError:
from io import BytesIO, StringIO
from fileinput import FileInput, hook_encoded
-from test.support import verbose, TESTFN, run_unittest, check_warnings
+from test.support import verbose, TESTFN, check_warnings
from test.support import unlink as safe_unlink
+from test import support
from unittest import mock
@@ -92,7 +93,11 @@ class BufferSizesTests(unittest.TestCase):
t2 = writeTmp(2, ["Line %s of file 2\n" % (i+1) for i in range(10)])
t3 = writeTmp(3, ["Line %s of file 3\n" % (i+1) for i in range(5)])
t4 = writeTmp(4, ["Line %s of file 4\n" % (i+1) for i in range(1)])
- self.buffer_size_test(t1, t2, t3, t4, bs, round)
+ if bs:
+ with self.assertWarns(DeprecationWarning):
+ self.buffer_size_test(t1, t2, t3, t4, bs, round)
+ else:
+ self.buffer_size_test(t1, t2, t3, t4, bs, round)
finally:
remove_tempfiles(t1, t2, t3, t4)
@@ -940,7 +945,8 @@ class Test_hook_encoded(unittest.TestCase):
def test(self):
encoding = object()
- result = fileinput.hook_encoded(encoding)
+ errors = object()
+ result = fileinput.hook_encoded(encoding, errors=errors)
fake_open = InvocationRecorder()
original_open = builtins.open
@@ -958,8 +964,26 @@ class Test_hook_encoded(unittest.TestCase):
self.assertIs(args[0], filename)
self.assertIs(args[1], mode)
self.assertIs(kwargs.pop('encoding'), encoding)
+ self.assertIs(kwargs.pop('errors'), errors)
self.assertFalse(kwargs)
+ def test_errors(self):
+ with open(TESTFN, 'wb') as f:
+ f.write(b'\x80abc')
+ self.addCleanup(safe_unlink, TESTFN)
+
+ def check(errors, expected_lines):
+ with FileInput(files=TESTFN, mode='r',
+ openhook=hook_encoded('utf-8', errors=errors)) as fi:
+ lines = list(fi)
+ self.assertEqual(lines, expected_lines)
+
+ check('ignore', ['abc'])
+ with self.assertRaises(UnicodeDecodeError):
+ check('strict', ['abc'])
+ check('replace', ['\ufffdabc'])
+ check('backslashreplace', ['\\x80abc'])
+
def test_modes(self):
with open(TESTFN, 'wb') as f:
# UTF-7 is a convenient, seldom used encoding
@@ -981,5 +1005,11 @@ class Test_hook_encoded(unittest.TestCase):
check('rb', ['A\n', 'B\r\n', 'C\r', 'D\u20ac'])
+class MiscTest(unittest.TestCase):
+
+ def test_all(self):
+ support.check__all__(self, fileinput)
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/test/test_float.py b/Lib/test/test_float.py
index cb1f6db8fc..427f044af4 100644
--- a/Lib/test/test_float.py
+++ b/Lib/test/test_float.py
@@ -1,6 +1,5 @@
import fractions
-import math
import operator
import os
import random
diff --git a/Lib/test/test_format.py b/Lib/test/test_format.py
index 9b13632591..9924fde13e 100644
--- a/Lib/test/test_format.py
+++ b/Lib/test/test_format.py
@@ -300,6 +300,8 @@ class FormatTest(unittest.TestCase):
testcommon(b"%c", 7, b"\x07")
testcommon(b"%c", b"Z", b"Z")
testcommon(b"%c", bytearray(b"Z"), b"Z")
+ testcommon(b"%5c", 65, b" A")
+ testcommon(b"%-5c", 65, b"A ")
# %b will insert a series of bytes, either from a type that supports
# the Py_buffer protocol, or something that has a __bytes__ method
class FakeBytes(object):
diff --git a/Lib/test/test_fractions.py b/Lib/test/test_fractions.py
index 1699852216..73d2dd3031 100644
--- a/Lib/test/test_fractions.py
+++ b/Lib/test/test_fractions.py
@@ -263,13 +263,13 @@ class FractionTest(unittest.TestCase):
nan = inf - inf
# bug 16469: error types should be consistent with float -> int
self.assertRaisesMessage(
- OverflowError, "Cannot convert inf to Fraction.",
+ OverflowError, "cannot convert Infinity to integer ratio",
F.from_float, inf)
self.assertRaisesMessage(
- OverflowError, "Cannot convert -inf to Fraction.",
+ OverflowError, "cannot convert Infinity to integer ratio",
F.from_float, -inf)
self.assertRaisesMessage(
- ValueError, "Cannot convert nan to Fraction.",
+ ValueError, "cannot convert NaN to integer ratio",
F.from_float, nan)
def testFromDecimal(self):
@@ -284,16 +284,16 @@ class FractionTest(unittest.TestCase):
# bug 16469: error types should be consistent with decimal -> int
self.assertRaisesMessage(
- OverflowError, "Cannot convert Infinity to Fraction.",
+ OverflowError, "cannot convert Infinity to integer ratio",
F.from_decimal, Decimal("inf"))
self.assertRaisesMessage(
- OverflowError, "Cannot convert -Infinity to Fraction.",
+ OverflowError, "cannot convert Infinity to integer ratio",
F.from_decimal, Decimal("-inf"))
self.assertRaisesMessage(
- ValueError, "Cannot convert NaN to Fraction.",
+ ValueError, "cannot convert NaN to integer ratio",
F.from_decimal, Decimal("nan"))
self.assertRaisesMessage(
- ValueError, "Cannot convert sNaN to Fraction.",
+ ValueError, "cannot convert NaN to integer ratio",
F.from_decimal, Decimal("snan"))
def testLimitDenominator(self):
diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py
new file mode 100644
index 0000000000..a82dedffe4
--- /dev/null
+++ b/Lib/test/test_fstring.py
@@ -0,0 +1,745 @@
+import ast
+import types
+import decimal
+import unittest
+
+a_global = 'global variable'
+
+# You could argue that I'm too strict in looking for specific error
+# values with assertRaisesRegex, but without it it's way too easy to
+# make a syntax error in the test strings. Especially with all of the
+# triple quotes, raw strings, backslashes, etc. I think it's a
+# worthwhile tradeoff. When I switched to this method, I found many
+# examples where I wasn't testing what I thought I was.
+
+class TestCase(unittest.TestCase):
+ def assertAllRaise(self, exception_type, regex, error_strings):
+ for str in error_strings:
+ with self.subTest(str=str):
+ with self.assertRaisesRegex(exception_type, regex):
+ eval(str)
+
+ def test__format__lookup(self):
+ # Make sure __format__ is looked up on the type, not the instance.
+ class X:
+ def __format__(self, spec):
+ return 'class'
+
+ x = X()
+
+ # Add a bound __format__ method to the 'y' instance, but not
+ # the 'x' instance.
+ y = X()
+ y.__format__ = types.MethodType(lambda self, spec: 'instance', y)
+
+ self.assertEqual(f'{y}', format(y))
+ self.assertEqual(f'{y}', 'class')
+ self.assertEqual(format(x), format(y))
+
+ # __format__ is not called this way, but still make sure it
+ # returns what we expect (so we can make sure we're bypassing
+ # it).
+ self.assertEqual(x.__format__(''), 'class')
+ self.assertEqual(y.__format__(''), 'instance')
+
+ # This is how __format__ is actually called.
+ self.assertEqual(type(x).__format__(x, ''), 'class')
+ self.assertEqual(type(y).__format__(y, ''), 'class')
+
+ def test_ast(self):
+ # Inspired by http://bugs.python.org/issue24975
+ class X:
+ def __init__(self):
+ self.called = False
+ def __call__(self):
+ self.called = True
+ return 4
+ x = X()
+ expr = """
+a = 10
+f'{a * x()}'"""
+ t = ast.parse(expr)
+ c = compile(t, '', 'exec')
+
+ # Make sure x was not called.
+ self.assertFalse(x.called)
+
+ # Actually run the code.
+ exec(c)
+
+ # Make sure x was called.
+ self.assertTrue(x.called)
+
+ def test_literal_eval(self):
+ # With no expressions, an f-string is okay.
+ self.assertEqual(ast.literal_eval("f'x'"), 'x')
+ self.assertEqual(ast.literal_eval("f'x' 'y'"), 'xy')
+
+ # But this should raise an error.
+ with self.assertRaisesRegex(ValueError, 'malformed node or string'):
+ ast.literal_eval("f'x{3}'")
+
+ # As should this, which uses a different ast node
+ with self.assertRaisesRegex(ValueError, 'malformed node or string'):
+ ast.literal_eval("f'{3}'")
+
+ def test_ast_compile_time_concat(self):
+ x = ['']
+
+ expr = """x[0] = 'foo' f'{3}'"""
+ t = ast.parse(expr)
+ c = compile(t, '', 'exec')
+ exec(c)
+ self.assertEqual(x[0], 'foo3')
+
+ def test_literal(self):
+ self.assertEqual(f'', '')
+ self.assertEqual(f'a', 'a')
+ self.assertEqual(f' ', ' ')
+ self.assertEqual(f'\N{GREEK CAPITAL LETTER DELTA}',
+ '\N{GREEK CAPITAL LETTER DELTA}')
+ self.assertEqual(f'\N{GREEK CAPITAL LETTER DELTA}',
+ '\u0394')
+ self.assertEqual(f'\N{True}', '\u22a8')
+ self.assertEqual(rf'\N{True}', r'\NTrue')
+
+ def test_escape_order(self):
+ # note that hex(ord('{')) == 0x7b, so this
+ # string becomes f'a{4*10}b'
+ self.assertEqual(f'a\u007b4*10}b', 'a40b')
+ self.assertEqual(f'a\x7b4*10}b', 'a40b')
+ self.assertEqual(f'a\x7b4*10\N{RIGHT CURLY BRACKET}b', 'a40b')
+ self.assertEqual(f'{"a"!\N{LATIN SMALL LETTER R}}', "'a'")
+ self.assertEqual(f'{10\x3a02X}', '0A')
+ self.assertEqual(f'{10:02\N{LATIN CAPITAL LETTER X}}', '0A')
+
+ self.assertAllRaise(SyntaxError, "f-string: single '}' is not allowed",
+ [r"""f'a{\u007b4*10}b'""", # mis-matched brackets
+ ])
+ self.assertAllRaise(SyntaxError, 'unexpected character after line continuation character',
+ [r"""f'{"a"\!r}'""",
+ r"""f'{a\!r}'""",
+ ])
+
+ def test_unterminated_string(self):
+ self.assertAllRaise(SyntaxError, 'f-string: unterminated string',
+ [r"""f'{"x'""",
+ r"""f'{"x}'""",
+ r"""f'{("x'""",
+ r"""f'{("x}'""",
+ ])
+
+ def test_mismatched_parens(self):
+ self.assertAllRaise(SyntaxError, 'f-string: mismatched',
+ ["f'{((}'",
+ ])
+
+ def test_double_braces(self):
+ self.assertEqual(f'{{', '{')
+ self.assertEqual(f'a{{', 'a{')
+ self.assertEqual(f'{{b', '{b')
+ self.assertEqual(f'a{{b', 'a{b')
+ self.assertEqual(f'}}', '}')
+ self.assertEqual(f'a}}', 'a}')
+ self.assertEqual(f'}}b', '}b')
+ self.assertEqual(f'a}}b', 'a}b')
+
+ self.assertEqual(f'{{{10}', '{10')
+ self.assertEqual(f'}}{10}', '}10')
+ self.assertEqual(f'}}{{{10}', '}{10')
+ self.assertEqual(f'}}a{{{10}', '}a{10')
+
+ self.assertEqual(f'{10}{{', '10{')
+ self.assertEqual(f'{10}}}', '10}')
+ self.assertEqual(f'{10}}}{{', '10}{')
+ self.assertEqual(f'{10}}}a{{' '}', '10}a{}')
+
+ # Inside of strings, don't interpret doubled brackets.
+ self.assertEqual(f'{"{{}}"}', '{{}}')
+
+ self.assertAllRaise(TypeError, 'unhashable type',
+ ["f'{ {{}} }'", # dict in a set
+ ])
+
+ def test_compile_time_concat(self):
+ x = 'def'
+ self.assertEqual('abc' f'## {x}ghi', 'abc## defghi')
+ self.assertEqual('abc' f'{x}' 'ghi', 'abcdefghi')
+ self.assertEqual('abc' f'{x}' 'gh' f'i{x:4}', 'abcdefghidef ')
+ self.assertEqual('{x}' f'{x}', '{x}def')
+ self.assertEqual('{x' f'{x}', '{xdef')
+ self.assertEqual('{x}' f'{x}', '{x}def')
+ self.assertEqual('{{x}}' f'{x}', '{{x}}def')
+ self.assertEqual('{{x' f'{x}', '{{xdef')
+ self.assertEqual('x}}' f'{x}', 'x}}def')
+ self.assertEqual(f'{x}' 'x}}', 'defx}}')
+ self.assertEqual(f'{x}' '', 'def')
+ self.assertEqual('' f'{x}' '', 'def')
+ self.assertEqual('' f'{x}', 'def')
+ self.assertEqual(f'{x}' '2', 'def2')
+ self.assertEqual('1' f'{x}' '2', '1def2')
+ self.assertEqual('1' f'{x}', '1def')
+ self.assertEqual(f'{x}' f'-{x}', 'def-def')
+ self.assertEqual('' f'', '')
+ self.assertEqual('' f'' '', '')
+ self.assertEqual('' f'' '' f'', '')
+ self.assertEqual(f'', '')
+ self.assertEqual(f'' '', '')
+ self.assertEqual(f'' '' f'', '')
+ self.assertEqual(f'' '' f'' '', '')
+
+ self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
+ ["f'{3' f'}'", # can't concat to get a valid f-string
+ ])
+
+ def test_comments(self):
+ # These aren't comments, since they're in strings.
+ d = {'#': 'hash'}
+ self.assertEqual(f'{"#"}', '#')
+ self.assertEqual(f'{d["#"]}', 'hash')
+
+ self.assertAllRaise(SyntaxError, "f-string cannot include '#'",
+ ["f'{1#}'", # error because the expression becomes "(1#)"
+ "f'{3(#)}'",
+ ])
+
+ def test_many_expressions(self):
+ # Create a string with many expressions in it. Note that
+ # because we have a space in here as a literal, we're actually
+ # going to use twice as many ast nodes: one for each literal
+ # plus one for each expression.
+ def build_fstr(n, extra=''):
+ return "f'" + ('{x} ' * n) + extra + "'"
+
+ x = 'X'
+ width = 1
+
+ # Test around 256.
+ for i in range(250, 260):
+ self.assertEqual(eval(build_fstr(i)), (x+' ')*i)
+
+ # Test concatenating 2 largs fstrings.
+ self.assertEqual(eval(build_fstr(255)*256), (x+' ')*(255*256))
+
+ s = build_fstr(253, '{x:{width}} ')
+ self.assertEqual(eval(s), (x+' ')*254)
+
+ # Test lots of expressions and constants, concatenated.
+ s = "f'{1}' 'x' 'y'" * 1024
+ self.assertEqual(eval(s), '1xy' * 1024)
+
+ def test_format_specifier_expressions(self):
+ width = 10
+ precision = 4
+ value = decimal.Decimal('12.34567')
+ self.assertEqual(f'result: {value:{width}.{precision}}', 'result: 12.35')
+ self.assertEqual(f'result: {value:{width!r}.{precision}}', 'result: 12.35')
+ self.assertEqual(f'result: {value:{width:0}.{precision:1}}', 'result: 12.35')
+ self.assertEqual(f'result: {value:{1}{0:0}.{precision:1}}', 'result: 12.35')
+ self.assertEqual(f'result: {value:{ 1}{ 0:0}.{ precision:1}}', 'result: 12.35')
+ self.assertEqual(f'{10:#{1}0x}', ' 0xa')
+ self.assertEqual(f'{10:{"#"}1{0}{"x"}}', ' 0xa')
+ self.assertEqual(f'{-10:-{"#"}1{0}x}', ' -0xa')
+ self.assertEqual(f'{-10:{"-"}#{1}0{"x"}}', ' -0xa')
+ self.assertEqual(f'{10:#{3 != {4:5} and width}x}', ' 0xa')
+
+ self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
+ ["""f'{"s"!r{":10"}}'""",
+
+ # This looks like a nested format spec.
+ ])
+
+ self.assertAllRaise(SyntaxError, "invalid syntax",
+ [# Invalid sytax inside a nested spec.
+ "f'{4:{/5}}'",
+ ])
+
+ self.assertAllRaise(SyntaxError, "f-string: expressions nested too deeply",
+ [# Can't nest format specifiers.
+ "f'result: {value:{width:{0}}.{precision:1}}'",
+ ])
+
+ self.assertAllRaise(SyntaxError, 'f-string: invalid conversion character',
+ [# No expansion inside conversion or for
+ # the : or ! itself.
+ """f'{"s"!{"r"}}'""",
+ ])
+
+ def test_side_effect_order(self):
+ class X:
+ def __init__(self):
+ self.i = 0
+ def __format__(self, spec):
+ self.i += 1
+ return str(self.i)
+
+ x = X()
+ self.assertEqual(f'{x} {x}', '1 2')
+
+ def test_missing_expression(self):
+ self.assertAllRaise(SyntaxError, 'f-string: empty expression not allowed',
+ ["f'{}'",
+ "f'{ }'"
+ "f' {} '",
+ "f'{!r}'",
+ "f'{ !r}'",
+ "f'{10:{ }}'",
+ "f' { } '",
+ r"f'{\n}'",
+ r"f'{\n \n}'",
+
+ # Catch the empty expression before the
+ # invalid conversion.
+ "f'{!x}'",
+ "f'{ !xr}'",
+ "f'{!x:}'",
+ "f'{!x:a}'",
+ "f'{ !xr:}'",
+ "f'{ !xr:a}'",
+
+ "f'{!}'",
+ "f'{:}'",
+
+ # We find the empty expression before the
+ # missing closing brace.
+ "f'{!'",
+ "f'{!s:'",
+ "f'{:'",
+ "f'{:x'",
+ ])
+
+ def test_parens_in_expressions(self):
+ self.assertEqual(f'{3,}', '(3,)')
+
+ # Add these because when an expression is evaluated, parens
+ # are added around it. But we shouldn't go from an invalid
+ # expression to a valid one. The added parens are just
+ # supposed to allow whitespace (including newlines).
+ self.assertAllRaise(SyntaxError, 'invalid syntax',
+ ["f'{,}'",
+ "f'{,}'", # this is (,), which is an error
+ ])
+
+ self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
+ ["f'{3)+(4}'",
+ ])
+
+ self.assertAllRaise(SyntaxError, 'EOL while scanning string literal',
+ ["f'{\n}'",
+ ])
+
+ def test_newlines_in_expressions(self):
+ self.assertEqual(f'{0}', '0')
+ self.assertEqual(f'{0\n}', '0')
+ self.assertEqual(f'{0\r}', '0')
+ self.assertEqual(f'{\n0\n}', '0')
+ self.assertEqual(f'{\r0\r}', '0')
+ self.assertEqual(f'{\n0\r}', '0')
+ self.assertEqual(f'{\n0}', '0')
+ self.assertEqual(f'{3+\n4}', '7')
+ self.assertEqual(f'{3+\\\n4}', '7')
+ self.assertEqual(rf'''{3+
+4}''', '7')
+ self.assertEqual(f'''{3+\
+4}''', '7')
+
+ self.assertAllRaise(SyntaxError, 'f-string: empty expression not allowed',
+ [r"f'{\n}'",
+ ])
+
+ def test_lambda(self):
+ x = 5
+ self.assertEqual(f'{(lambda y:x*y)("8")!r}', "'88888'")
+ self.assertEqual(f'{(lambda y:x*y)("8")!r:10}', "'88888' ")
+ self.assertEqual(f'{(lambda y:x*y)("8"):10}', "88888 ")
+
+ # lambda doesn't work without parens, because the colon
+ # makes the parser think it's a format_spec
+ self.assertAllRaise(SyntaxError, 'unexpected EOF while parsing',
+ ["f'{lambda x:x}'",
+ ])
+
+ def test_yield(self):
+ # Not terribly useful, but make sure the yield turns
+ # a function into a generator
+ def fn(y):
+ f'y:{yield y*2}'
+
+ g = fn(4)
+ self.assertEqual(next(g), 8)
+
+ def test_yield_send(self):
+ def fn(x):
+ yield f'x:{yield (lambda i: x * i)}'
+
+ g = fn(10)
+ the_lambda = next(g)
+ self.assertEqual(the_lambda(4), 40)
+ self.assertEqual(g.send('string'), 'x:string')
+
+ def test_expressions_with_triple_quoted_strings(self):
+ self.assertEqual(f"{'''x'''}", 'x')
+ self.assertEqual(f"{'''eric's'''}", "eric's")
+ self.assertEqual(f'{"""eric\'s"""}', "eric's")
+ self.assertEqual(f"{'''eric\"s'''}", 'eric"s')
+ self.assertEqual(f'{"""eric"s"""}', 'eric"s')
+
+ # Test concatenation within an expression
+ self.assertEqual(f'{"x" """eric"s""" "y"}', 'xeric"sy')
+ self.assertEqual(f'{"x" """eric"s"""}', 'xeric"s')
+ self.assertEqual(f'{"""eric"s""" "y"}', 'eric"sy')
+ self.assertEqual(f'{"""x""" """eric"s""" "y"}', 'xeric"sy')
+ self.assertEqual(f'{"""x""" """eric"s""" """y"""}', 'xeric"sy')
+ self.assertEqual(f'{r"""x""" """eric"s""" """y"""}', 'xeric"sy')
+
+ def test_multiple_vars(self):
+ x = 98
+ y = 'abc'
+ self.assertEqual(f'{x}{y}', '98abc')
+
+ self.assertEqual(f'X{x}{y}', 'X98abc')
+ self.assertEqual(f'{x}X{y}', '98Xabc')
+ self.assertEqual(f'{x}{y}X', '98abcX')
+
+ self.assertEqual(f'X{x}Y{y}', 'X98Yabc')
+ self.assertEqual(f'X{x}{y}Y', 'X98abcY')
+ self.assertEqual(f'{x}X{y}Y', '98XabcY')
+
+ self.assertEqual(f'X{x}Y{y}Z', 'X98YabcZ')
+
+ def test_closure(self):
+ def outer(x):
+ def inner():
+ return f'x:{x}'
+ return inner
+
+ self.assertEqual(outer('987')(), 'x:987')
+ self.assertEqual(outer(7)(), 'x:7')
+
+ def test_arguments(self):
+ y = 2
+ def f(x, width):
+ return f'x={x*y:{width}}'
+
+ self.assertEqual(f('foo', 10), 'x=foofoo ')
+ x = 'bar'
+ self.assertEqual(f(10, 10), 'x= 20')
+
+ def test_locals(self):
+ value = 123
+ self.assertEqual(f'v:{value}', 'v:123')
+
+ def test_missing_variable(self):
+ with self.assertRaises(NameError):
+ f'v:{value}'
+
+ def test_missing_format_spec(self):
+ class O:
+ def __format__(self, spec):
+ if not spec:
+ return '*'
+ return spec
+
+ self.assertEqual(f'{O():x}', 'x')
+ self.assertEqual(f'{O()}', '*')
+ self.assertEqual(f'{O():}', '*')
+
+ self.assertEqual(f'{3:}', '3')
+ self.assertEqual(f'{3!s:}', '3')
+
+ def test_global(self):
+ self.assertEqual(f'g:{a_global}', 'g:global variable')
+ self.assertEqual(f'g:{a_global!r}', "g:'global variable'")
+
+ a_local = 'local variable'
+ self.assertEqual(f'g:{a_global} l:{a_local}',
+ 'g:global variable l:local variable')
+ self.assertEqual(f'g:{a_global!r}',
+ "g:'global variable'")
+ self.assertEqual(f'g:{a_global} l:{a_local!r}',
+ "g:global variable l:'local variable'")
+
+ self.assertIn("module 'unittest' from", f'{unittest}')
+
+ def test_shadowed_global(self):
+ a_global = 'really a local'
+ self.assertEqual(f'g:{a_global}', 'g:really a local')
+ self.assertEqual(f'g:{a_global!r}', "g:'really a local'")
+
+ a_local = 'local variable'
+ self.assertEqual(f'g:{a_global} l:{a_local}',
+ 'g:really a local l:local variable')
+ self.assertEqual(f'g:{a_global!r}',
+ "g:'really a local'")
+ self.assertEqual(f'g:{a_global} l:{a_local!r}',
+ "g:really a local l:'local variable'")
+
+ def test_call(self):
+ def foo(x):
+ return 'x=' + str(x)
+
+ self.assertEqual(f'{foo(10)}', 'x=10')
+
+ def test_nested_fstrings(self):
+ y = 5
+ self.assertEqual(f'{f"{0}"*3}', '000')
+ self.assertEqual(f'{f"{y}"*3}', '555')
+ self.assertEqual(f'{f"{\'x\'}"*3}', 'xxx')
+
+ self.assertEqual(f"{r'x' f'{\"s\"}'}", 'xs')
+ self.assertEqual(f"{r'x'rf'{\"s\"}'}", 'xs')
+
+ def test_invalid_string_prefixes(self):
+ self.assertAllRaise(SyntaxError, 'unexpected EOF while parsing',
+ ["fu''",
+ "uf''",
+ "Fu''",
+ "fU''",
+ "Uf''",
+ "uF''",
+ "ufr''",
+ "urf''",
+ "fur''",
+ "fru''",
+ "rfu''",
+ "ruf''",
+ "FUR''",
+ "Fur''",
+ ])
+
+ def test_leading_trailing_spaces(self):
+ self.assertEqual(f'{ 3}', '3')
+ self.assertEqual(f'{ 3}', '3')
+ self.assertEqual(f'{\t3}', '3')
+ self.assertEqual(f'{\t\t3}', '3')
+ self.assertEqual(f'{3 }', '3')
+ self.assertEqual(f'{3 }', '3')
+ self.assertEqual(f'{3\t}', '3')
+ self.assertEqual(f'{3\t\t}', '3')
+
+ self.assertEqual(f'expr={ {x: y for x, y in [(1, 2), ]}}',
+ 'expr={1: 2}')
+ self.assertEqual(f'expr={ {x: y for x, y in [(1, 2), ]} }',
+ 'expr={1: 2}')
+
+ def test_character_name(self):
+ self.assertEqual(f'{4}\N{GREEK CAPITAL LETTER DELTA}{3}',
+ '4\N{GREEK CAPITAL LETTER DELTA}3')
+ self.assertEqual(f'{{}}\N{GREEK CAPITAL LETTER DELTA}{3}',
+ '{}\N{GREEK CAPITAL LETTER DELTA}3')
+
+ def test_not_equal(self):
+ # There's a special test for this because there's a special
+ # case in the f-string parser to look for != as not ending an
+ # expression. Normally it would, while looking for !s or !r.
+
+ self.assertEqual(f'{3!=4}', 'True')
+ self.assertEqual(f'{3!=4:}', 'True')
+ self.assertEqual(f'{3!=4!s}', 'True')
+ self.assertEqual(f'{3!=4!s:.3}', 'Tru')
+
+ def test_conversions(self):
+ self.assertEqual(f'{3.14:10.10}', ' 3.14')
+ self.assertEqual(f'{3.14!s:10.10}', '3.14 ')
+ self.assertEqual(f'{3.14!r:10.10}', '3.14 ')
+ self.assertEqual(f'{3.14!a:10.10}', '3.14 ')
+
+ self.assertEqual(f'{"a"}', 'a')
+ self.assertEqual(f'{"a"!r}', "'a'")
+ self.assertEqual(f'{"a"!a}', "'a'")
+
+ # Not a conversion.
+ self.assertEqual(f'{"a!r"}', "a!r")
+
+ # Not a conversion, but show that ! is allowed in a format spec.
+ self.assertEqual(f'{3.14:!<10.10}', '3.14!!!!!!')
+
+ self.assertEqual(f'{"\N{GREEK CAPITAL LETTER DELTA}"}', '\u0394')
+ self.assertEqual(f'{"\N{GREEK CAPITAL LETTER DELTA}"!r}', "'\u0394'")
+ self.assertEqual(f'{"\N{GREEK CAPITAL LETTER DELTA}"!a}', "'\\u0394'")
+
+ self.assertAllRaise(SyntaxError, 'f-string: invalid conversion character',
+ ["f'{3!g}'",
+ "f'{3!A}'",
+ "f'{3!A}'",
+ "f'{3!A}'",
+ "f'{3!!}'",
+ "f'{3!:}'",
+ "f'{3!\N{GREEK CAPITAL LETTER DELTA}}'",
+ "f'{3! s}'", # no space before conversion char
+ "f'{x!\\x00:.<10}'",
+ ])
+
+ self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
+ ["f'{x!s{y}}'",
+ "f'{3!ss}'",
+ "f'{3!ss:}'",
+ "f'{3!ss:s}'",
+ ])
+
+ def test_assignment(self):
+ self.assertAllRaise(SyntaxError, 'invalid syntax',
+ ["f'' = 3",
+ "f'{0}' = x",
+ "f'{x}' = x",
+ ])
+
+ def test_del(self):
+ self.assertAllRaise(SyntaxError, 'invalid syntax',
+ ["del f''",
+ "del '' f''",
+ ])
+
+ def test_mismatched_braces(self):
+ self.assertAllRaise(SyntaxError, "f-string: single '}' is not allowed",
+ ["f'{{}'",
+ "f'{{}}}'",
+ "f'}'",
+ "f'x}'",
+ "f'x}x'",
+
+ # Can't have { or } in a format spec.
+ "f'{3:}>10}'",
+ r"f'{3:\\}>10}'",
+ "f'{3:}}>10}'",
+ ])
+
+ self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
+ ["f'{3:{{>10}'",
+ "f'{3'",
+ "f'{3!'",
+ "f'{3:'",
+ "f'{3!s'",
+ "f'{3!s:'",
+ "f'{3!s:3'",
+ "f'x{'",
+ "f'x{x'",
+ "f'{3:s'",
+ "f'{{{'",
+ "f'{{}}{'",
+ "f'{'",
+ ])
+
+ self.assertAllRaise(SyntaxError, 'invalid syntax',
+ [r"f'{3:\\{>10}'",
+ ])
+
+ # But these are just normal strings.
+ self.assertEqual(f'{"{"}', '{')
+ self.assertEqual(f'{"}"}', '}')
+ self.assertEqual(f'{3:{"}"}>10}', '}}}}}}}}}3')
+ self.assertEqual(f'{2:{"{"}>10}', '{{{{{{{{{2')
+
+ def test_if_conditional(self):
+ # There's special logic in compile.c to test if the
+ # conditional for an if (and while) are constants. Exercise
+ # that code.
+
+ def test_fstring(x, expected):
+ flag = 0
+ if f'{x}':
+ flag = 1
+ else:
+ flag = 2
+ self.assertEqual(flag, expected)
+
+ def test_concat_empty(x, expected):
+ flag = 0
+ if '' f'{x}':
+ flag = 1
+ else:
+ flag = 2
+ self.assertEqual(flag, expected)
+
+ def test_concat_non_empty(x, expected):
+ flag = 0
+ if ' ' f'{x}':
+ flag = 1
+ else:
+ flag = 2
+ self.assertEqual(flag, expected)
+
+ test_fstring('', 2)
+ test_fstring(' ', 1)
+
+ test_concat_empty('', 2)
+ test_concat_empty(' ', 1)
+
+ test_concat_non_empty('', 1)
+ test_concat_non_empty(' ', 1)
+
+ def test_empty_format_specifier(self):
+ x = 'test'
+ self.assertEqual(f'{x}', 'test')
+ self.assertEqual(f'{x:}', 'test')
+ self.assertEqual(f'{x!s:}', 'test')
+ self.assertEqual(f'{x!r:}', "'test'")
+
+ def test_str_format_differences(self):
+ d = {'a': 'string',
+ 0: 'integer',
+ }
+ a = 0
+ self.assertEqual(f'{d[0]}', 'integer')
+ self.assertEqual(f'{d["a"]}', 'string')
+ self.assertEqual(f'{d[a]}', 'integer')
+ self.assertEqual('{d[a]}'.format(d=d), 'string')
+ self.assertEqual('{d[0]}'.format(d=d), 'integer')
+
+ def test_invalid_expressions(self):
+ self.assertAllRaise(SyntaxError, 'invalid syntax',
+ [r"f'{a[4)}'",
+ r"f'{a(4]}'",
+ ])
+
+ def test_errors(self):
+ # see issue 26287
+ self.assertAllRaise(TypeError, 'non-empty',
+ [r"f'{(lambda: 0):x}'",
+ r"f'{(0,):x}'",
+ ])
+ self.assertAllRaise(ValueError, 'Unknown format code',
+ [r"f'{1000:j}'",
+ r"f'{1000:j}'",
+ ])
+
+ def test_loop(self):
+ for i in range(1000):
+ self.assertEqual(f'i:{i}', 'i:' + str(i))
+
+ def test_dict(self):
+ d = {'"': 'dquote',
+ "'": 'squote',
+ 'foo': 'bar',
+ }
+ self.assertEqual(f'{d["\'"]}', 'squote')
+ self.assertEqual(f"{d['\"']}", 'dquote')
+
+ self.assertEqual(f'''{d["'"]}''', 'squote')
+ self.assertEqual(f"""{d['"']}""", 'dquote')
+
+ self.assertEqual(f'{d["foo"]}', 'bar')
+ self.assertEqual(f"{d['foo']}", 'bar')
+ self.assertEqual(f'{d[\'foo\']}', 'bar')
+ self.assertEqual(f"{d[\"foo\"]}", 'bar')
+
+ def test_escaped_quotes(self):
+ d = {'"': 'a',
+ "'": 'b'}
+
+ self.assertEqual(fr"{d['\"']}", 'a')
+ self.assertEqual(fr'{d["\'"]}', 'b')
+ self.assertEqual(fr"{'\"'}", '"')
+ self.assertEqual(fr'{"\'"}', "'")
+ self.assertEqual(f'{"\\"3"}', '"3')
+
+ self.assertAllRaise(SyntaxError, 'f-string: unterminated string',
+ [r'''f'{"""\\}' ''', # Backslash at end of expression
+ ])
+ self.assertAllRaise(SyntaxError, 'unexpected character after line continuation',
+ [r"rf'{3\}'",
+ ])
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py
index aef66da98a..9d8de211df 100644
--- a/Lib/test/test_ftplib.py
+++ b/Lib/test/test_ftplib.py
@@ -1049,10 +1049,19 @@ class TestTimeouts(TestCase):
ftp.close()
+class MiscTestCase(TestCase):
+ def test__all__(self):
+ blacklist = {'MSG_OOB', 'FTP_PORT', 'MAXLINE', 'CRLF', 'B_CRLF',
+ 'Error', 'parse150', 'parse227', 'parse229', 'parse257',
+ 'print_line', 'ftpcp', 'test'}
+ support.check__all__(self, ftplib, blacklist=blacklist)
+
+
def test_main():
tests = [TestFTPClass, TestTimeouts,
TestIPv6Environment,
- TestTLS_FTPClassMixin, TestTLS_FTPClass]
+ TestTLS_FTPClassMixin, TestTLS_FTPClass,
+ MiscTestCase]
thread_info = support.threading_setup()
try:
diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py
index 9abe984330..9cf115d42b 100644
--- a/Lib/test/test_functools.py
+++ b/Lib/test/test_functools.py
@@ -1516,7 +1516,7 @@ class TestSingleDispatch(unittest.TestCase):
m = mro(D, bases)
self.assertEqual(m, [D, c.MutableSequence, c.Sequence,
c.defaultdict, dict, c.MutableMapping,
- c.Mapping, c.Sized, c.Iterable, c.Container,
+ c.Mapping, c.Sized, c.Reversible, c.Iterable, c.Container,
object])
# Container and Callable are registered on different base classes and
diff --git a/Lib/test/test_gc.py b/Lib/test/test_gc.py
index 1f0867d379..872ca62b5e 100644
--- a/Lib/test/test_gc.py
+++ b/Lib/test/test_gc.py
@@ -682,7 +682,6 @@ class GCTests(unittest.TestCase):
# Create a reference cycle through the __main__ module and check
# it gets collected at interpreter shutdown.
code = """if 1:
- import weakref
class C:
def __del__(self):
print('__del__ called')
@@ -696,7 +695,6 @@ class GCTests(unittest.TestCase):
# Same as above, but with a non-__main__ module.
with temp_dir() as script_dir:
module = """if 1:
- import weakref
class C:
def __del__(self):
print('__del__ called')
diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py
index cd7d2925f4..730b628b58 100644
--- a/Lib/test/test_gdb.py
+++ b/Lib/test/test_gdb.py
@@ -5,7 +5,6 @@
import os
import re
-import pprint
import subprocess
import sys
import sysconfig
@@ -176,6 +175,7 @@ class DebuggerTests(unittest.TestCase):
args = ['--eval-command=%s' % cmd for cmd in commands]
args += ["--args",
sys.executable]
+ args.extend(subprocess._args_from_interpreter_flags())
if not import_site:
# -S suppresses the default 'import site'
@@ -291,7 +291,9 @@ class PrettyPrintTests(DebuggerTests):
'Verify the pretty-printing of dictionaries'
self.assertGdbRepr({})
self.assertGdbRepr({'foo': 'bar'}, "{'foo': 'bar'}")
- self.assertGdbRepr({'foo': 'bar', 'douglas': 42}, "{'douglas': 42, 'foo': 'bar'}")
+ # PYTHONHASHSEED is need to get the exact item order
+ if not sys.flags.ignore_environment:
+ self.assertGdbRepr({'foo': 'bar', 'douglas': 42}, "{'douglas': 42, 'foo': 'bar'}")
def test_lists(self):
'Verify the pretty-printing of lists'
@@ -354,9 +356,12 @@ class PrettyPrintTests(DebuggerTests):
'Verify the pretty-printing of sets'
if (gdb_major_version, gdb_minor_version) < (7, 3):
self.skipTest("pretty-printing of sets needs gdb 7.3 or later")
- self.assertGdbRepr(set(), 'set()')
- self.assertGdbRepr(set(['a', 'b']), "{'a', 'b'}")
- self.assertGdbRepr(set([4, 5, 6]), "{4, 5, 6}")
+ self.assertGdbRepr(set(), "set()")
+ self.assertGdbRepr(set(['a']), "{'a'}")
+ # PYTHONHASHSEED is need to get the exact frozenset item order
+ if not sys.flags.ignore_environment:
+ self.assertGdbRepr(set(['a', 'b']), "{'a', 'b'}")
+ self.assertGdbRepr(set([4, 5, 6]), "{4, 5, 6}")
# Ensure that we handle sets containing the "dummy" key value,
# which happens on deletion:
@@ -369,9 +374,12 @@ id(s)''')
'Verify the pretty-printing of frozensets'
if (gdb_major_version, gdb_minor_version) < (7, 3):
self.skipTest("pretty-printing of frozensets needs gdb 7.3 or later")
- self.assertGdbRepr(frozenset(), 'frozenset()')
- self.assertGdbRepr(frozenset(['a', 'b']), "frozenset({'a', 'b'})")
- self.assertGdbRepr(frozenset([4, 5, 6]), "frozenset({4, 5, 6})")
+ self.assertGdbRepr(frozenset(), "frozenset()")
+ self.assertGdbRepr(frozenset(['a']), "frozenset({'a'})")
+ # PYTHONHASHSEED is need to get the exact frozenset item order
+ if not sys.flags.ignore_environment:
+ self.assertGdbRepr(frozenset(['a', 'b']), "frozenset({'a', 'b'})")
+ self.assertGdbRepr(frozenset([4, 5, 6]), "frozenset({4, 5, 6})")
def test_exceptions(self):
# Test a RuntimeError
@@ -500,6 +508,10 @@ id(foo)''')
def test_builtins_help(self):
'Ensure that the new-style class _Helper in site.py can be handled'
+
+ if sys.flags.no_site:
+ self.skipTest("need site module, but -S option was used")
+
# (this was the issue causing tracebacks in
# http://bugs.python.org/issue8032#msg100537 )
gdb_repr, gdb_output = self.get_gdb_repr('id(__builtins__.help)', import_site=True)
diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py
index 3f82462478..f4b33afe14 100644
--- a/Lib/test/test_generators.py
+++ b/Lib/test/test_generators.py
@@ -245,11 +245,11 @@ class ExceptionTest(unittest.TestCase):
yield
with self.assertRaises(StopIteration), \
- self.assertWarnsRegex(PendingDeprecationWarning, "StopIteration"):
+ self.assertWarnsRegex(DeprecationWarning, "StopIteration"):
next(gen())
- with self.assertRaisesRegex(PendingDeprecationWarning,
+ with self.assertRaisesRegex(DeprecationWarning,
"generator .* raised StopIteration"), \
warnings.catch_warnings():
@@ -268,7 +268,7 @@ class ExceptionTest(unittest.TestCase):
g = f()
self.assertEqual(next(g), 1)
- with self.assertWarnsRegex(PendingDeprecationWarning, "StopIteration"):
+ with self.assertWarnsRegex(DeprecationWarning, "StopIteration"):
with self.assertRaises(StopIteration):
next(g)
diff --git a/Lib/test/test_genericpath.py b/Lib/test/test_genericpath.py
index 86fc2de753..9c28a6872b 100644
--- a/Lib/test/test_genericpath.py
+++ b/Lib/test/test_genericpath.py
@@ -10,11 +10,9 @@ import warnings
from test import support
-def safe_rmdir(dirname):
- try:
- os.rmdir(dirname)
- except OSError:
- pass
+def create_file(filename, data=b'foo'):
+ with open(filename, 'xb', 0) as fp:
+ fp.write(data)
class GenericTest:
@@ -97,52 +95,47 @@ class GenericTest:
self.assertNotEqual(s1[n:n+1], s2[n:n+1])
def test_getsize(self):
- f = open(support.TESTFN, "wb")
- try:
- f.write(b"foo")
- f.close()
- self.assertEqual(self.pathmodule.getsize(support.TESTFN), 3)
- finally:
- if not f.closed:
- f.close()
- support.unlink(support.TESTFN)
+ filename = support.TESTFN
+ self.addCleanup(support.unlink, filename)
- def test_time(self):
- f = open(support.TESTFN, "wb")
- try:
- f.write(b"foo")
- f.close()
- f = open(support.TESTFN, "ab")
+ create_file(filename, b'Hello')
+ self.assertEqual(self.pathmodule.getsize(filename), 5)
+ os.remove(filename)
+
+ create_file(filename, b'Hello World!')
+ self.assertEqual(self.pathmodule.getsize(filename), 12)
+
+ def test_filetime(self):
+ filename = support.TESTFN
+ self.addCleanup(support.unlink, filename)
+
+ create_file(filename, b'foo')
+
+ with open(filename, "ab", 0) as f:
f.write(b"bar")
- f.close()
- f = open(support.TESTFN, "rb")
- d = f.read()
- f.close()
- self.assertEqual(d, b"foobar")
-
- self.assertLessEqual(
- self.pathmodule.getctime(support.TESTFN),
- self.pathmodule.getmtime(support.TESTFN)
- )
- finally:
- if not f.closed:
- f.close()
- support.unlink(support.TESTFN)
+
+ with open(filename, "rb", 0) as f:
+ data = f.read()
+ self.assertEqual(data, b"foobar")
+
+ self.assertLessEqual(
+ self.pathmodule.getctime(filename),
+ self.pathmodule.getmtime(filename)
+ )
def test_exists(self):
- self.assertIs(self.pathmodule.exists(support.TESTFN), False)
- f = open(support.TESTFN, "wb")
- try:
+ filename = support.TESTFN
+ self.addCleanup(support.unlink, filename)
+
+ self.assertIs(self.pathmodule.exists(filename), False)
+
+ with open(filename, "xb") as f:
f.write(b"foo")
- f.close()
- self.assertIs(self.pathmodule.exists(support.TESTFN), True)
- if not self.pathmodule == genericpath:
- self.assertIs(self.pathmodule.lexists(support.TESTFN),
- True)
- finally:
- if not f.close():
- f.close()
- support.unlink(support.TESTFN)
+
+ self.assertIs(self.pathmodule.exists(filename), True)
+
+ if not self.pathmodule == genericpath:
+ self.assertIs(self.pathmodule.lexists(filename), True)
@unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()")
def test_exists_fd(self):
@@ -154,53 +147,66 @@ class GenericTest:
os.close(w)
self.assertFalse(self.pathmodule.exists(r))
- def test_isdir(self):
- self.assertIs(self.pathmodule.isdir(support.TESTFN), False)
- f = open(support.TESTFN, "wb")
- try:
- f.write(b"foo")
- f.close()
- self.assertIs(self.pathmodule.isdir(support.TESTFN), False)
- os.remove(support.TESTFN)
- os.mkdir(support.TESTFN)
- self.assertIs(self.pathmodule.isdir(support.TESTFN), True)
- os.rmdir(support.TESTFN)
- finally:
- if not f.close():
- f.close()
- support.unlink(support.TESTFN)
- safe_rmdir(support.TESTFN)
-
- def test_isfile(self):
- self.assertIs(self.pathmodule.isfile(support.TESTFN), False)
- f = open(support.TESTFN, "wb")
- try:
- f.write(b"foo")
- f.close()
- self.assertIs(self.pathmodule.isfile(support.TESTFN), True)
- os.remove(support.TESTFN)
- os.mkdir(support.TESTFN)
- self.assertIs(self.pathmodule.isfile(support.TESTFN), False)
- os.rmdir(support.TESTFN)
- finally:
- if not f.close():
- f.close()
- support.unlink(support.TESTFN)
- safe_rmdir(support.TESTFN)
+ def test_isdir_file(self):
+ filename = support.TESTFN
+ self.addCleanup(support.unlink, filename)
+ self.assertIs(self.pathmodule.isdir(filename), False)
+
+ create_file(filename)
+ self.assertIs(self.pathmodule.isdir(filename), False)
+
+ def test_isdir_dir(self):
+ filename = support.TESTFN
+ self.addCleanup(support.rmdir, filename)
+ self.assertIs(self.pathmodule.isdir(filename), False)
+
+ os.mkdir(filename)
+ self.assertIs(self.pathmodule.isdir(filename), True)
+
+ def test_isfile_file(self):
+ filename = support.TESTFN
+ self.addCleanup(support.unlink, filename)
+ self.assertIs(self.pathmodule.isfile(filename), False)
- @staticmethod
- def _create_file(filename):
- with open(filename, 'wb') as f:
- f.write(b'foo')
+ create_file(filename)
+ self.assertIs(self.pathmodule.isfile(filename), True)
+
+ def test_isfile_dir(self):
+ filename = support.TESTFN
+ self.addCleanup(support.rmdir, filename)
+ self.assertIs(self.pathmodule.isfile(filename), False)
+
+ os.mkdir(filename)
+ self.assertIs(self.pathmodule.isfile(filename), False)
def test_samefile(self):
- try:
- test_fn = support.TESTFN + "1"
- self._create_file(test_fn)
- self.assertTrue(self.pathmodule.samefile(test_fn, test_fn))
- self.assertRaises(TypeError, self.pathmodule.samefile)
- finally:
- os.remove(test_fn)
+ file1 = support.TESTFN
+ file2 = support.TESTFN + "2"
+ self.addCleanup(support.unlink, file1)
+ self.addCleanup(support.unlink, file2)
+
+ create_file(file1)
+ self.assertTrue(self.pathmodule.samefile(file1, file1))
+
+ create_file(file2)
+ self.assertFalse(self.pathmodule.samefile(file1, file2))
+
+ self.assertRaises(TypeError, self.pathmodule.samefile)
+
+ def _test_samefile_on_link_func(self, func):
+ test_fn1 = support.TESTFN
+ test_fn2 = support.TESTFN + "2"
+ self.addCleanup(support.unlink, test_fn1)
+ self.addCleanup(support.unlink, test_fn2)
+
+ create_file(test_fn1)
+
+ func(test_fn1, test_fn2)
+ self.assertTrue(self.pathmodule.samefile(test_fn1, test_fn2))
+ os.remove(test_fn2)
+
+ create_file(test_fn2)
+ self.assertFalse(self.pathmodule.samefile(test_fn1, test_fn2))
@support.skip_unless_symlink
def test_samefile_on_symlink(self):
@@ -209,31 +215,37 @@ class GenericTest:
def test_samefile_on_link(self):
self._test_samefile_on_link_func(os.link)
- def _test_samefile_on_link_func(self, func):
- try:
- test_fn1 = support.TESTFN + "1"
- test_fn2 = support.TESTFN + "2"
- self._create_file(test_fn1)
+ def test_samestat(self):
+ test_fn1 = support.TESTFN
+ test_fn2 = support.TESTFN + "2"
+ self.addCleanup(support.unlink, test_fn1)
+ self.addCleanup(support.unlink, test_fn2)
- func(test_fn1, test_fn2)
- self.assertTrue(self.pathmodule.samefile(test_fn1, test_fn2))
- os.remove(test_fn2)
+ create_file(test_fn1)
+ stat1 = os.stat(test_fn1)
+ self.assertTrue(self.pathmodule.samestat(stat1, os.stat(test_fn1)))
- self._create_file(test_fn2)
- self.assertFalse(self.pathmodule.samefile(test_fn1, test_fn2))
- finally:
- os.remove(test_fn1)
- os.remove(test_fn2)
+ create_file(test_fn2)
+ stat2 = os.stat(test_fn2)
+ self.assertFalse(self.pathmodule.samestat(stat1, stat2))
- def test_samestat(self):
- try:
- test_fn = support.TESTFN + "1"
- self._create_file(test_fn)
- test_fns = [test_fn]*2
- stats = map(os.stat, test_fns)
- self.assertTrue(self.pathmodule.samestat(*stats))
- finally:
- os.remove(test_fn)
+ self.assertRaises(TypeError, self.pathmodule.samestat)
+
+ def _test_samestat_on_link_func(self, func):
+ test_fn1 = support.TESTFN + "1"
+ test_fn2 = support.TESTFN + "2"
+ self.addCleanup(support.unlink, test_fn1)
+ self.addCleanup(support.unlink, test_fn2)
+
+ create_file(test_fn1)
+ func(test_fn1, test_fn2)
+ self.assertTrue(self.pathmodule.samestat(os.stat(test_fn1),
+ os.stat(test_fn2)))
+ os.remove(test_fn2)
+
+ create_file(test_fn2)
+ self.assertFalse(self.pathmodule.samestat(os.stat(test_fn1),
+ os.stat(test_fn2)))
@support.skip_unless_symlink
def test_samestat_on_symlink(self):
@@ -242,31 +254,17 @@ class GenericTest:
def test_samestat_on_link(self):
self._test_samestat_on_link_func(os.link)
- def _test_samestat_on_link_func(self, func):
- try:
- test_fn1 = support.TESTFN + "1"
- test_fn2 = support.TESTFN + "2"
- self._create_file(test_fn1)
- test_fns = (test_fn1, test_fn2)
- func(*test_fns)
- stats = map(os.stat, test_fns)
- self.assertTrue(self.pathmodule.samestat(*stats))
- os.remove(test_fn2)
-
- self._create_file(test_fn2)
- stats = map(os.stat, test_fns)
- self.assertFalse(self.pathmodule.samestat(*stats))
-
- self.assertRaises(TypeError, self.pathmodule.samestat)
- finally:
- os.remove(test_fn1)
- os.remove(test_fn2)
-
def test_sameopenfile(self):
- fname = support.TESTFN + "1"
- with open(fname, "wb") as a, open(fname, "wb") as b:
- self.assertTrue(self.pathmodule.sameopenfile(
- a.fileno(), b.fileno()))
+ filename = support.TESTFN
+ self.addCleanup(support.unlink, filename)
+ create_file(filename)
+
+ with open(filename, "rb", 0) as fp1:
+ fd1 = fp1.fileno()
+ with open(filename, "rb", 0) as fp2:
+ fd2 = fp2.fileno()
+ self.assertTrue(self.pathmodule.sameopenfile(fd1, fd2))
+
class TestGenericTest(GenericTest, unittest.TestCase):
# Issue 16852: GenericTest can't inherit from unittest.TestCase
diff --git a/Lib/test/test_getargs2.py b/Lib/test/test_getargs2.py
index 984aac7d91..8a51e0bf8c 100644
--- a/Lib/test/test_getargs2.py
+++ b/Lib/test/test_getargs2.py
@@ -474,7 +474,7 @@ class Tuple_TestCase(unittest.TestCase):
ret = get_args(*TupleSubclass([1, 2]))
self.assertEqual(ret, (1, 2))
- self.assertIsInstance(ret, tuple)
+ self.assertIs(type(ret), tuple)
ret = get_args()
self.assertIn(ret, ((), None))
@@ -512,7 +512,7 @@ class Keywords_TestCase(unittest.TestCase):
ret = get_kwargs(**DictSubclass({'a': 1, 'b': 2}))
self.assertEqual(ret, {'a': 1, 'b': 2})
- self.assertIsInstance(ret, dict)
+ self.assertIs(type(ret), dict)
ret = get_kwargs()
self.assertIn(ret, ({}, None))
@@ -822,10 +822,10 @@ class String_TestCase(unittest.TestCase):
self.assertEqual(getargs_es_hash('abc\xe9', 'latin1', buf), b'abc\xe9')
self.assertEqual(buf, bytearray(b'abc\xe9\x00'))
buf = bytearray(b'x'*4)
- self.assertRaises(TypeError, getargs_es_hash, 'abc\xe9', 'latin1', buf)
+ self.assertRaises(ValueError, getargs_es_hash, 'abc\xe9', 'latin1', buf)
self.assertEqual(buf, bytearray(b'x'*4))
buf = bytearray()
- self.assertRaises(TypeError, getargs_es_hash, 'abc\xe9', 'latin1', buf)
+ self.assertRaises(ValueError, getargs_es_hash, 'abc\xe9', 'latin1', buf)
def test_et_hash(self):
from _testcapi import getargs_et_hash
@@ -848,10 +848,10 @@ class String_TestCase(unittest.TestCase):
self.assertEqual(getargs_et_hash('abc\xe9', 'latin1', buf), b'abc\xe9')
self.assertEqual(buf, bytearray(b'abc\xe9\x00'))
buf = bytearray(b'x'*4)
- self.assertRaises(TypeError, getargs_et_hash, 'abc\xe9', 'latin1', buf)
+ self.assertRaises(ValueError, getargs_et_hash, 'abc\xe9', 'latin1', buf)
self.assertEqual(buf, bytearray(b'x'*4))
buf = bytearray()
- self.assertRaises(TypeError, getargs_et_hash, 'abc\xe9', 'latin1', buf)
+ self.assertRaises(ValueError, getargs_et_hash, 'abc\xe9', 'latin1', buf)
def test_u(self):
from _testcapi import getargs_u
diff --git a/Lib/test/test_gettext.py b/Lib/test/test_gettext.py
index de610c752a..d345baa26b 100644
--- a/Lib/test/test_gettext.py
+++ b/Lib/test/test_gettext.py
@@ -1,6 +1,5 @@
import os
import base64
-import shutil
import gettext
import unittest
@@ -440,6 +439,12 @@ class GettextCacheTestCase(GettextBaseTest):
self.assertEqual(t.__class__, DummyGNUTranslations)
+class MiscTestCase(unittest.TestCase):
+ def test__all__(self):
+ blacklist = {'c2py', 'ENOENT'}
+ support.check__all__(self, gettext, blacklist=blacklist)
+
+
def test_main():
support.run_unittest(__name__)
diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py
index d68cc7da7c..331f48c54d 100644
--- a/Lib/test/test_grammar.py
+++ b/Lib/test/test_grammar.py
@@ -295,6 +295,10 @@ class GrammarTests(unittest.TestCase):
pos2key2dict(1,2,k2=100,tokwarg1=100,tokwarg2=200)
pos2key2dict(1,2,tokwarg1=100,tokwarg2=200, k2=100)
+ self.assertRaises(SyntaxError, eval, "def f(*): pass")
+ self.assertRaises(SyntaxError, eval, "def f(*,): pass")
+ self.assertRaises(SyntaxError, eval, "def f(*, **kwds): pass")
+
# keyword arguments after *arglist
def f(*args, **kwargs):
return args, kwargs
@@ -352,6 +356,23 @@ class GrammarTests(unittest.TestCase):
check_syntax_error(self, "f(*g(1=2))")
check_syntax_error(self, "f(**g(1=2))")
+ # Check trailing commas are permitted in funcdef argument list
+ def f(a,): pass
+ def f(*args,): pass
+ def f(**kwds,): pass
+ def f(a, *args,): pass
+ def f(a, **kwds,): pass
+ def f(*args, b,): pass
+ def f(*, b,): pass
+ def f(*args, **kwds,): pass
+ def f(a, *args, b,): pass
+ def f(a, *, b,): pass
+ def f(a, *args, **kwds,): pass
+ def f(*args, b, **kwds,): pass
+ def f(*, b, **kwds,): pass
+ def f(a, *args, b, **kwds,): pass
+ def f(a, *, b, **kwds,): pass
+
def test_lambdef(self):
### lambdef: 'lambda' [varargslist] ':' test
l1 = lambda : 0
@@ -370,6 +391,23 @@ class GrammarTests(unittest.TestCase):
self.assertEqual(l6(1,2), 1+2+20)
self.assertEqual(l6(1,2,k=10), 1+2+10)
+ # check that trailing commas are permitted
+ l10 = lambda a,: 0
+ l11 = lambda *args,: 0
+ l12 = lambda **kwds,: 0
+ l13 = lambda a, *args,: 0
+ l14 = lambda a, **kwds,: 0
+ l15 = lambda *args, b,: 0
+ l16 = lambda *, b,: 0
+ l17 = lambda *args, **kwds,: 0
+ l18 = lambda a, *args, b,: 0
+ l19 = lambda a, *, b,: 0
+ l20 = lambda a, *args, **kwds,: 0
+ l21 = lambda *args, b, **kwds,: 0
+ l22 = lambda *, b, **kwds,: 0
+ l23 = lambda a, *args, b, **kwds,: 0
+ l24 = lambda a, *, b, **kwds,: 0
+
### stmt: simple_stmt | compound_stmt
# Tested below
diff --git a/Lib/test/test_grp.py b/Lib/test/test_grp.py
index 272b08615d..69095a3fb9 100644
--- a/Lib/test/test_grp.py
+++ b/Lib/test/test_grp.py
@@ -92,5 +92,15 @@ class GroupDatabaseTestCase(unittest.TestCase):
self.assertRaises(KeyError, grp.getgrgid, fakegid)
+ def test_noninteger_gid(self):
+ entries = grp.getgrall()
+ if not entries:
+ self.skipTest('no groups')
+ # Choose an existent gid.
+ gid = entries[0][2]
+ self.assertWarns(DeprecationWarning, grp.getgrgid, float(gid))
+ self.assertWarns(DeprecationWarning, grp.getgrgid, str(gid))
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/test/test_heapq.py b/Lib/test/test_heapq.py
index b7e8259f8d..2f8c648d84 100644
--- a/Lib/test/test_heapq.py
+++ b/Lib/test/test_heapq.py
@@ -1,6 +1,5 @@
"""Unittests for heapq."""
-import sys
import random
import unittest
diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py
index 98826b5a60..067e13f107 100644
--- a/Lib/test/test_hmac.py
+++ b/Lib/test/test_hmac.py
@@ -3,7 +3,6 @@ import hmac
import hashlib
import unittest
import warnings
-from test import support
def ignore_warning(func):
diff --git a/Lib/test/test_htmlparser.py b/Lib/test/test_htmlparser.py
index 11420b2c84..a7f53d382e 100644
--- a/Lib/test/test_htmlparser.py
+++ b/Lib/test/test_htmlparser.py
@@ -3,7 +3,6 @@
import html.parser
import pprint
import unittest
-from test import support
class EventCollector(html.parser.HTMLParser):
diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py
index 1fffdb1a7b..9b96a29737 100644
--- a/Lib/test/test_httpservers.py
+++ b/Lib/test/test_httpservers.py
@@ -18,6 +18,7 @@ import urllib.parse
import html
import http.client
import tempfile
+import time
from io import BytesIO
import unittest
@@ -344,7 +345,7 @@ class SimpleHTTPServerTestCase(BaseTestCase):
quotedname = urllib.parse.quote(filename, errors='surrogatepass')
self.assertIn(('href="%s"' % quotedname)
.encode(enc, 'surrogateescape'), body)
- self.assertIn(('>%s<' % html.escape(filename))
+ self.assertIn(('>%s<' % html.escape(filename, quote=False))
.encode(enc, 'surrogateescape'), body)
response = self.request(self.base_url + '/' + quotedname)
self.check_status_and_reason(response, HTTPStatus.OK,
@@ -422,6 +423,27 @@ class SimpleHTTPServerTestCase(BaseTestCase):
self.assertEqual(response.getheader("Location"),
self.tempdir_name + "/?hi=1")
+ def test_html_escape_filename(self):
+ filename = '<test&>.txt'
+ fullpath = os.path.join(self.tempdir, filename)
+
+ try:
+ open(fullpath, 'w').close()
+ except OSError:
+ raise unittest.SkipTest('Can not create file %s on current file '
+ 'system' % filename)
+
+ try:
+ response = self.request(self.base_url + '/')
+ body = self.check_status_and_reason(response, HTTPStatus.OK)
+ enc = response.headers.get_content_charset()
+ finally:
+ os.unlink(fullpath) # avoid affecting test_undecodable_filename
+
+ self.assertIsNotNone(enc)
+ html_text = '>%s<' % html.escape(filename, quote=False)
+ self.assertIn(html_text.encode(enc), body)
+
cgi_file1 = """\
#!%s
@@ -872,7 +894,7 @@ class BaseHTTPRequestHandlerTestCase(unittest.TestCase):
# Issue #6791: same for headers
result = self.send_typical_request(
b'GET / HTTP/1.1\r\nX-Foo: bar' + b'r' * 65537 + b'\r\n\r\n')
- self.assertEqual(result[0], b'HTTP/1.1 400 Line too long\r\n')
+ self.assertEqual(result[0], b'HTTP/1.1 431 Line too long\r\n')
self.assertFalse(self.handler.get_called)
self.assertEqual(self.handler.requestline, 'GET / HTTP/1.1')
@@ -883,6 +905,13 @@ class BaseHTTPRequestHandlerTestCase(unittest.TestCase):
self.assertFalse(self.handler.get_called)
self.assertEqual(self.handler.requestline, 'GET / HTTP/1.1')
+ def test_html_escape_on_error(self):
+ result = self.send_typical_request(
+ b'<script>alert("hello")</script> / HTTP/1.1')
+ result = b''.join(result)
+ text = '<script>alert("hello")</script>'
+ self.assertIn(html.escape(text, quote=False).encode('ascii'), result)
+
def test_close_connection(self):
# handle_one_request() should be repeatedly called until
# it sets close_connection
@@ -898,6 +927,19 @@ class BaseHTTPRequestHandlerTestCase(unittest.TestCase):
self.handler.handle()
self.assertRaises(StopIteration, next, close_values)
+ def test_date_time_string(self):
+ now = time.time()
+ # this is the old code that formats the timestamp
+ year, month, day, hh, mm, ss, wd, y, z = time.gmtime(now)
+ expected = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (
+ self.handler.weekdayname[wd],
+ day,
+ self.handler.monthname[month],
+ year, hh, mm, ss
+ )
+ self.assertEqual(self.handler.date_time_string(timestamp=now), expected)
+
+
class SimpleHTTPRequestHandlerTestCase(unittest.TestCase):
""" Test url parsing """
def setUp(self):
diff --git a/Lib/test/test_idle.py b/Lib/test/test_idle.py
index 141e89e493..0b34e97ccc 100644
--- a/Lib/test/test_idle.py
+++ b/Lib/test/test_idle.py
@@ -1,5 +1,4 @@
import unittest
-from test import support
from test.support import import_module
# Skip test if _thread or _tkinter wasn't built or idlelib was deleted.
diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py
index 07157f52d6..8e4990b3cf 100644
--- a/Lib/test/test_imaplib.py
+++ b/Lib/test/test_imaplib.py
@@ -243,6 +243,55 @@ class ThreadedNetworkedTests(unittest.TestCase):
client.shutdown()
@reap_threads
+ def test_bracket_flags(self):
+
+ # This violates RFC 3501, which disallows ']' characters in tag names,
+ # but imaplib has allowed producing such tags forever, other programs
+ # also produce them (eg: OtherInbox's Organizer app as of 20140716),
+ # and Gmail, for example, accepts them and produces them. So we
+ # support them. See issue #21815.
+
+ class BracketFlagHandler(SimpleIMAPHandler):
+
+ def handle(self):
+ self.flags = ['Answered', 'Flagged', 'Deleted', 'Seen', 'Draft']
+ super().handle()
+
+ def cmd_AUTHENTICATE(self, tag, args):
+ self._send_textline('+')
+ self.server.response = yield
+ self._send_tagged(tag, 'OK', 'FAKEAUTH successful')
+
+ def cmd_SELECT(self, tag, args):
+ flag_msg = ' \\'.join(self.flags)
+ self._send_line(('* FLAGS (%s)' % flag_msg).encode('ascii'))
+ self._send_line(b'* 2 EXISTS')
+ self._send_line(b'* 0 RECENT')
+ msg = ('* OK [PERMANENTFLAGS %s \\*)] Flags permitted.'
+ % flag_msg)
+ self._send_line(msg.encode('ascii'))
+ self._send_tagged(tag, 'OK', '[READ-WRITE] SELECT completed.')
+
+ def cmd_STORE(self, tag, args):
+ new_flags = args[2].strip('(').strip(')').split()
+ self.flags.extend(new_flags)
+ flags_msg = '(FLAGS (%s))' % ' \\'.join(self.flags)
+ msg = '* %s FETCH %s' % (args[0], flags_msg)
+ self._send_line(msg.encode('ascii'))
+ self._send_tagged(tag, 'OK', 'STORE completed.')
+
+ with self.reaped_pair(BracketFlagHandler) as (server, client):
+ code, data = client.authenticate('MYAUTH', lambda x: b'fake')
+ self.assertEqual(code, 'OK')
+ self.assertEqual(server.response, b'ZmFrZQ==\r\n')
+ client.select('test')
+ typ, [data] = client.store(b'1', "+FLAGS", "[test]")
+ self.assertIn(b'[test]', data)
+ client.select('test')
+ typ, [data] = client.response('PERMANENTFLAGS')
+ self.assertIn(b'[test]', data)
+
+ @reap_threads
def test_issue5949(self):
class EOFHandler(socketserver.StreamRequestHandler):
diff --git a/Lib/test/test_imp.py b/Lib/test/test_imp.py
index ee9ee1ad8c..4ece365410 100644
--- a/Lib/test/test_imp.py
+++ b/Lib/test/test_imp.py
@@ -6,13 +6,12 @@ import importlib
import importlib.util
import os
import os.path
-import shutil
import sys
from test import support
import unittest
import warnings
with warnings.catch_warnings():
- warnings.simplefilter('ignore', PendingDeprecationWarning)
+ warnings.simplefilter('ignore', DeprecationWarning)
import imp
diff --git a/Lib/test/test_importlib/extension/test_case_sensitivity.py b/Lib/test/test_importlib/extension/test_case_sensitivity.py
index 706c3e4b87..b74e900391 100644
--- a/Lib/test/test_importlib/extension/test_case_sensitivity.py
+++ b/Lib/test/test_importlib/extension/test_case_sensitivity.py
@@ -1,5 +1,4 @@
from importlib import _bootstrap_external
-import sys
from test import support
import unittest
@@ -8,8 +7,6 @@ from .. import util
machinery = util.import_importlib('importlib.machinery')
-# XXX find_spec tests
-
@unittest.skipIf(util.EXTENSIONS.filename is None, '_testcapi not available')
@util.case_insensitive_tests
class ExtensionModuleCaseSensitivityTest:
diff --git a/Lib/test/test_importlib/extension/test_finder.py b/Lib/test/test_importlib/extension/test_finder.py
index 71bf67febd..c9b4a3772c 100644
--- a/Lib/test/test_importlib/extension/test_finder.py
+++ b/Lib/test/test_importlib/extension/test_finder.py
@@ -6,7 +6,6 @@ machinery = util.import_importlib('importlib.machinery')
import unittest
import warnings
-# XXX find_spec tests
class FinderTests(abc.FinderTests):
diff --git a/Lib/test/test_importlib/extension/test_path_hook.py b/Lib/test/test_importlib/extension/test_path_hook.py
index 8f4b8bb161..a4b5a64aae 100644
--- a/Lib/test/test_importlib/extension/test_path_hook.py
+++ b/Lib/test/test_importlib/extension/test_path_hook.py
@@ -2,8 +2,6 @@ from .. import util
machinery = util.import_importlib('importlib.machinery')
-import collections
-import sys
import unittest
diff --git a/Lib/test/test_importlib/frozen/test_loader.py b/Lib/test/test_importlib/frozen/test_loader.py
index 603c7d7b19..29ecff1774 100644
--- a/Lib/test/test_importlib/frozen/test_loader.py
+++ b/Lib/test/test_importlib/frozen/test_loader.py
@@ -3,8 +3,6 @@ from .. import util
machinery = util.import_importlib('importlib.machinery')
-
-import sys
from test.support import captured_stdout
import types
import unittest
diff --git a/Lib/test/test_importlib/import_/test___package__.py b/Lib/test/test_importlib/import_/test___package__.py
index c7d3a2a204..7f64548748 100644
--- a/Lib/test/test_importlib/import_/test___package__.py
+++ b/Lib/test/test_importlib/import_/test___package__.py
@@ -5,6 +5,7 @@ of using the typical __path__/__name__ test).
"""
import unittest
+import warnings
from .. import util
@@ -33,31 +34,50 @@ class Using__package__:
"""
- def test_using___package__(self):
- # [__package__]
+ def import_module(self, globals_):
with self.mock_modules('pkg.__init__', 'pkg.fake') as importer:
with util.import_state(meta_path=[importer]):
self.__import__('pkg.fake')
module = self.__import__('',
- globals={'__package__': 'pkg.fake'},
- fromlist=['attr'], level=2)
+ globals=globals_,
+ fromlist=['attr'], level=2)
+ return module
+
+ def test_using___package__(self):
+ # [__package__]
+ module = self.import_module({'__package__': 'pkg.fake'})
self.assertEqual(module.__name__, 'pkg')
- def test_using___name__(self, package_as_None=False):
+ def test_using___name__(self):
# [__name__]
- globals_ = {'__name__': 'pkg.fake', '__path__': []}
- if package_as_None:
- globals_['__package__'] = None
- with self.mock_modules('pkg.__init__', 'pkg.fake') as importer:
- with util.import_state(meta_path=[importer]):
- self.__import__('pkg.fake')
- module = self.__import__('', globals= globals_,
- fromlist=['attr'], level=2)
- self.assertEqual(module.__name__, 'pkg')
+ with warnings.catch_warnings():
+ warnings.simplefilter("ignore")
+ module = self.import_module({'__name__': 'pkg.fake',
+ '__path__': []})
+ self.assertEqual(module.__name__, 'pkg')
+
+ def test_warn_when_using___name__(self):
+ with self.assertWarns(ImportWarning):
+ self.import_module({'__name__': 'pkg.fake', '__path__': []})
def test_None_as___package__(self):
# [None]
- self.test_using___name__(package_as_None=True)
+ with warnings.catch_warnings():
+ warnings.simplefilter("ignore")
+ module = self.import_module({
+ '__name__': 'pkg.fake', '__path__': [], '__package__': None })
+ self.assertEqual(module.__name__, 'pkg')
+
+ def test_spec_fallback(self):
+ # If __package__ isn't defined, fall back on __spec__.parent.
+ module = self.import_module({'__spec__': FakeSpec('pkg.fake')})
+ self.assertEqual(module.__name__, 'pkg')
+
+ def test_warn_when_package_and_spec_disagree(self):
+ # Raise an ImportWarning if __package__ != __spec__.parent.
+ with self.assertWarns(ImportWarning):
+ self.import_module({'__package__': 'pkg.fake',
+ '__spec__': FakeSpec('pkg.fakefake')})
def test_bad__package__(self):
globals = {'__package__': '<not real>'}
@@ -70,6 +90,11 @@ class Using__package__:
self.__import__('', globals, {}, ['relimport'], 1)
+class FakeSpec:
+ def __init__(self, parent):
+ self.parent = parent
+
+
class Using__package__PEP302(Using__package__):
mock_modules = util.mock_modules
diff --git a/Lib/test/test_importlib/import_/test_packages.py b/Lib/test/test_importlib/import_/test_packages.py
index 3755b84a1a..24396044a5 100644
--- a/Lib/test/test_importlib/import_/test_packages.py
+++ b/Lib/test/test_importlib/import_/test_packages.py
@@ -1,7 +1,6 @@
from .. import util
import sys
import unittest
-import importlib
from test import support
diff --git a/Lib/test/test_importlib/import_/test_path.py b/Lib/test/test_importlib/import_/test_path.py
index b32a876f89..7aa26b0eee 100644
--- a/Lib/test/test_importlib/import_/test_path.py
+++ b/Lib/test/test_importlib/import_/test_path.py
@@ -16,11 +16,14 @@ class FinderTests:
"""Tests for PathFinder."""
+ find = None
+ check_found = None
+
def test_failure(self):
# Test None returned upon not finding a suitable loader.
module = '<test module>'
with util.import_state():
- self.assertIsNone(self.machinery.PathFinder.find_module(module))
+ self.assertIsNone(self.find(module))
def test_sys_path(self):
# Test that sys.path is used when 'path' is None.
@@ -30,8 +33,8 @@ class FinderTests:
importer = util.mock_spec(module)
with util.import_state(path_importer_cache={path: importer},
path=[path]):
- loader = self.machinery.PathFinder.find_module(module)
- self.assertIs(loader, importer)
+ found = self.find(module)
+ self.check_found(found, importer)
def test_path(self):
# Test that 'path' is used when set.
@@ -40,8 +43,8 @@ class FinderTests:
path = '<test path>'
importer = util.mock_spec(module)
with util.import_state(path_importer_cache={path: importer}):
- loader = self.machinery.PathFinder.find_module(module, [path])
- self.assertIs(loader, importer)
+ found = self.find(module, [path])
+ self.check_found(found, importer)
def test_empty_list(self):
# An empty list should not count as asking for sys.path.
@@ -50,7 +53,7 @@ class FinderTests:
importer = util.mock_spec(module)
with util.import_state(path_importer_cache={path: importer},
path=[path]):
- self.assertIsNone(self.machinery.PathFinder.find_module('module', []))
+ self.assertIsNone(self.find('module', []))
def test_path_hooks(self):
# Test that sys.path_hooks is used.
@@ -60,8 +63,8 @@ class FinderTests:
importer = util.mock_spec(module)
hook = util.mock_path_hook(path, importer=importer)
with util.import_state(path_hooks=[hook]):
- loader = self.machinery.PathFinder.find_module(module, [path])
- self.assertIs(loader, importer)
+ found = self.find(module, [path])
+ self.check_found(found, importer)
self.assertIn(path, sys.path_importer_cache)
self.assertIs(sys.path_importer_cache[path], importer)
@@ -73,7 +76,7 @@ class FinderTests:
path=[path_entry]):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
- self.assertIsNone(self.machinery.PathFinder.find_module('os'))
+ self.assertIsNone(self.find('os'))
self.assertIsNone(sys.path_importer_cache[path_entry])
self.assertEqual(len(w), 1)
self.assertTrue(issubclass(w[-1].category, ImportWarning))
@@ -85,8 +88,8 @@ class FinderTests:
importer = util.mock_spec(module)
hook = util.mock_path_hook(os.getcwd(), importer=importer)
with util.import_state(path=[path], path_hooks=[hook]):
- loader = self.machinery.PathFinder.find_module(module)
- self.assertIs(loader, importer)
+ found = self.find(module)
+ self.check_found(found, importer)
self.assertIn(os.getcwd(), sys.path_importer_cache)
def test_None_on_sys_path(self):
@@ -182,16 +185,33 @@ class FinderTests:
self.assertIsNone(self.machinery.PathFinder.find_spec('whatever'))
+class FindModuleTests(FinderTests):
+ def find(self, *args, **kwargs):
+ return self.machinery.PathFinder.find_module(*args, **kwargs)
+ def check_found(self, found, importer):
+ self.assertIs(found, importer)
+
+
+(Frozen_FindModuleTests,
+ Source_FindModuleTests
+) = util.test_both(FindModuleTests, importlib=importlib, machinery=machinery)
-(Frozen_FinderTests,
- Source_FinderTests
- ) = util.test_both(FinderTests, importlib=importlib, machinery=machinery)
+class FindSpecTests(FinderTests):
+ def find(self, *args, **kwargs):
+ return self.machinery.PathFinder.find_spec(*args, **kwargs)
+ def check_found(self, found, importer):
+ self.assertIs(found.loader, importer)
+
+
+(Frozen_FindSpecTests,
+ Source_FindSpecTests
+ ) = util.test_both(FindSpecTests, importlib=importlib, machinery=machinery)
class PathEntryFinderTests:
- def test_finder_with_failing_find_module(self):
+ def test_finder_with_failing_find_spec(self):
# PathEntryFinder with find_module() defined should work.
# Issue #20763.
class Finder:
@@ -209,6 +229,24 @@ class PathEntryFinderTests:
path_hooks=[Finder]):
self.machinery.PathFinder.find_spec('importlib')
+ def test_finder_with_failing_find_module(self):
+ # PathEntryFinder with find_module() defined should work.
+ # Issue #20763.
+ class Finder:
+ path_location = 'test_finder_with_find_module'
+ def __init__(self, path):
+ if path != self.path_location:
+ raise ImportError
+
+ @staticmethod
+ def find_module(fullname):
+ return None
+
+
+ with util.import_state(path=[Finder.path_location]+sys.path[:],
+ path_hooks=[Finder]):
+ self.machinery.PathFinder.find_module('importlib')
+
(Frozen_PEFTests,
Source_PEFTests
diff --git a/Lib/test/test_importlib/import_/test_relative_imports.py b/Lib/test/test_importlib/import_/test_relative_imports.py
index 3bb819f906..8a95a32109 100644
--- a/Lib/test/test_importlib/import_/test_relative_imports.py
+++ b/Lib/test/test_importlib/import_/test_relative_imports.py
@@ -1,7 +1,8 @@
"""Test relative imports (PEP 328)."""
from .. import util
-import sys
import unittest
+import warnings
+
class RelativeImports:
@@ -65,9 +66,11 @@ class RelativeImports:
uncache_names.append(name[:-len('.__init__')])
with util.mock_spec(*create) as importer:
with util.import_state(meta_path=[importer]):
- for global_ in globals_:
- with util.uncache(*uncache_names):
- callback(global_)
+ with warnings.catch_warnings():
+ warnings.simplefilter("ignore")
+ for global_ in globals_:
+ with util.uncache(*uncache_names):
+ callback(global_)
def test_module_from_module(self):
@@ -204,11 +207,18 @@ class RelativeImports:
def test_relative_import_no_globals(self):
# No globals for a relative import is an error.
- with self.assertRaises(KeyError):
- self.__import__('sys', level=1)
+ with warnings.catch_warnings():
+ warnings.simplefilter("ignore")
+ with self.assertRaises(KeyError):
+ self.__import__('sys', level=1)
+
+ def test_relative_import_no_package(self):
+ with self.assertRaises(ImportError):
+ self.__import__('a', {'__package__': '', '__spec__': None},
+ level=1)
def test_relative_import_no_package_exists_absolute(self):
- with self.assertRaises(SystemError):
+ with self.assertRaises(ImportError):
self.__import__('sys', {'__package__': '', '__spec__': None},
level=1)
diff --git a/Lib/test/test_importlib/regrtest.py b/Lib/test/test_importlib/regrtest.py
deleted file mode 100644
index a5be11fd4e..0000000000
--- a/Lib/test/test_importlib/regrtest.py
+++ /dev/null
@@ -1,17 +0,0 @@
-"""Run Python's standard test suite using importlib.__import__.
-
-Tests known to fail because of assumptions that importlib (properly)
-invalidates are automatically skipped if the entire test suite is run.
-Otherwise all command-line options valid for test.regrtest are also valid for
-this script.
-
-"""
-import importlib
-import sys
-from test import regrtest
-
-if __name__ == '__main__':
- __builtins__.__import__ = importlib.__import__
- sys.path_importer_cache.clear()
-
- regrtest.main(quiet=True, verbose2=True)
diff --git a/Lib/test/test_importlib/source/test_case_sensitivity.py b/Lib/test/test_importlib/source/test_case_sensitivity.py
index c274b3823f..0d6c388a57 100644
--- a/Lib/test/test_importlib/source/test_case_sensitivity.py
+++ b/Lib/test/test_importlib/source/test_case_sensitivity.py
@@ -5,7 +5,6 @@ importlib = util.import_importlib('importlib')
machinery = util.import_importlib('importlib.machinery')
import os
-import sys
from test import support as test_support
import unittest
diff --git a/Lib/test/test_importlib/source/test_file_loader.py b/Lib/test/test_importlib/source/test_file_loader.py
index 73f4c62070..a151149f31 100644
--- a/Lib/test/test_importlib/source/test_file_loader.py
+++ b/Lib/test/test_importlib/source/test_file_loader.py
@@ -217,7 +217,7 @@ class SimpleTest(abc.LoaderTests):
# PEP 302
with warnings.catch_warnings():
warnings.simplefilter('ignore', DeprecationWarning)
- mod = loader.load_module('_temp') # XXX
+ mod = loader.load_module('_temp')
# Sanity checks.
self.assertEqual(mod.__cached__, compiled)
self.assertEqual(mod.x, 5)
@@ -245,12 +245,7 @@ class SimpleTest(abc.LoaderTests):
class BadBytecodeTest:
def import_(self, file, module_name):
- loader = self.loader(module_name, file)
- with warnings.catch_warnings():
- warnings.simplefilter('ignore', DeprecationWarning)
- # XXX Change to use exec_module().
- module = loader.load_module(module_name)
- self.assertIn(module_name, sys.modules)
+ raise NotImplementedError
def manipulate_bytecode(self, name, mapping, manipulator, *,
del_source=False):
diff --git a/Lib/test/test_importlib/source/test_path_hook.py b/Lib/test/test_importlib/source/test_path_hook.py
index e6a2415bda..795d436c3b 100644
--- a/Lib/test/test_importlib/source/test_path_hook.py
+++ b/Lib/test/test_importlib/source/test_path_hook.py
@@ -16,10 +16,19 @@ class PathHookTest:
def test_success(self):
with util.create_modules('dummy') as mapping:
self.assertTrue(hasattr(self.path_hook()(mapping['.root']),
- 'find_module'))
+ 'find_spec'))
+
+ def test_success_legacy(self):
+ with util.create_modules('dummy') as mapping:
+ self.assertTrue(hasattr(self.path_hook()(mapping['.root']),
+ 'find_module'))
def test_empty_string(self):
# The empty string represents the cwd.
+ self.assertTrue(hasattr(self.path_hook()(''), 'find_spec'))
+
+ def test_empty_string_legacy(self):
+ # The empty string represents the cwd.
self.assertTrue(hasattr(self.path_hook()(''), 'find_module'))
diff --git a/Lib/test/test_importlib/source/test_source_encoding.py b/Lib/test/test_importlib/source/test_source_encoding.py
index 1e0771b19d..980855fe1a 100644
--- a/Lib/test/test_importlib/source/test_source_encoding.py
+++ b/Lib/test/test_importlib/source/test_source_encoding.py
@@ -5,7 +5,6 @@ machinery = util.import_importlib('importlib.machinery')
import codecs
import importlib.util
import re
-import sys
import types
# Because sys.path gets essentially blanked, need to have unicodedata already
# imported for the parser to use.
diff --git a/Lib/test/test_importlib/test_abc.py b/Lib/test/test_importlib/test_abc.py
index d4bf9153e9..c86248047f 100644
--- a/Lib/test/test_importlib/test_abc.py
+++ b/Lib/test/test_importlib/test_abc.py
@@ -207,6 +207,10 @@ class LoaderDefaultsTests(ABCTestHarness):
SPLIT = make_abc_subclasses(Loader)
+ def test_create_module(self):
+ spec = 'a spec'
+ self.assertIsNone(self.ins.create_module(spec))
+
def test_load_module(self):
with self.assertRaises(ImportError):
self.ins.load_module('something')
@@ -519,6 +523,12 @@ class InspectLoaderLoadModuleTests:
support.unload(self.module_name)
self.addCleanup(support.unload, self.module_name)
+ def load(self, loader):
+ spec = self.util.spec_from_loader(self.module_name, loader)
+ with warnings.catch_warnings():
+ warnings.simplefilter('ignore', DeprecationWarning)
+ return self.init._bootstrap._load_unlocked(spec)
+
def mock_get_code(self):
return mock.patch.object(self.InspectLoaderSubclass, 'get_code')
@@ -528,9 +538,7 @@ class InspectLoaderLoadModuleTests:
mocked_get_code.side_effect = ImportError
with self.assertRaises(ImportError):
loader = self.InspectLoaderSubclass()
- with warnings.catch_warnings():
- warnings.simplefilter('ignore', DeprecationWarning)
- loader.load_module(self.module_name)
+ self.load(loader)
def test_get_code_None(self):
# If get_code() returns None, raise ImportError.
@@ -538,7 +546,7 @@ class InspectLoaderLoadModuleTests:
mocked_get_code.return_value = None
with self.assertRaises(ImportError):
loader = self.InspectLoaderSubclass()
- loader.load_module(self.module_name)
+ self.load(loader)
def test_module_returned(self):
# The loaded module should be returned.
@@ -546,14 +554,16 @@ class InspectLoaderLoadModuleTests:
with self.mock_get_code() as mocked_get_code:
mocked_get_code.return_value = code
loader = self.InspectLoaderSubclass()
- module = loader.load_module(self.module_name)
+ module = self.load(loader)
self.assertEqual(module, sys.modules[self.module_name])
(Frozen_ILLoadModuleTests,
Source_ILLoadModuleTests
) = test_util.test_both(InspectLoaderLoadModuleTests,
- InspectLoaderSubclass=SPLIT_IL)
+ InspectLoaderSubclass=SPLIT_IL,
+ init=init,
+ util=util)
##### ExecutionLoader concrete methods #########################################
diff --git a/Lib/test/test_importlib/test_api.py b/Lib/test/test_importlib/test_api.py
index 6bc3c564a5..b0a94aaff5 100644
--- a/Lib/test/test_importlib/test_api.py
+++ b/Lib/test/test_importlib/test_api.py
@@ -99,9 +99,7 @@ class ImportModuleTests:
class FindLoaderTests:
- class FakeMetaFinder:
- @staticmethod
- def find_module(name, path=None): return name, path
+ FakeMetaFinder = None
def test_sys_modules(self):
# If a module with __loader__ is in sys.modules, then return it.
@@ -171,9 +169,30 @@ class FindLoaderTests:
self.assertIsNone(self.init.find_loader('nevergoingtofindthismodule'))
-(Frozen_FindLoaderTests,
- Source_FindLoaderTests
- ) = test_util.test_both(FindLoaderTests, init=init)
+class FindLoaderPEP451Tests(FindLoaderTests):
+
+ class FakeMetaFinder:
+ @staticmethod
+ def find_spec(name, path=None, target=None):
+ return machinery['Source'].ModuleSpec(name, (name, path))
+
+
+(Frozen_FindLoaderPEP451Tests,
+ Source_FindLoaderPEP451Tests
+ ) = test_util.test_both(FindLoaderPEP451Tests, init=init)
+
+
+class FindLoaderPEP302Tests(FindLoaderTests):
+
+ class FakeMetaFinder:
+ @staticmethod
+ def find_module(name, path=None):
+ return name, path
+
+
+(Frozen_FindLoaderPEP302Tests,
+ Source_FindLoaderPEP302Tests
+ ) = test_util.test_both(FindLoaderPEP302Tests, init=init)
class ReloadTests:
diff --git a/Lib/test/test_importlib/test_locks.py b/Lib/test/test_importlib/test_locks.py
index df0af12d38..b2aadff289 100644
--- a/Lib/test/test_importlib/test_locks.py
+++ b/Lib/test/test_importlib/test_locks.py
@@ -3,7 +3,6 @@ from . import util as test_util
init = test_util.import_importlib('importlib')
import sys
-import time
import unittest
import weakref
diff --git a/Lib/test/test_importlib/test_namespace_pkgs.py b/Lib/test/test_importlib/test_namespace_pkgs.py
index 6639612631..e37d8a18f4 100644
--- a/Lib/test/test_importlib/test_namespace_pkgs.py
+++ b/Lib/test/test_importlib/test_namespace_pkgs.py
@@ -1,13 +1,10 @@
import contextlib
-import importlib.abc
-import importlib.machinery
+import importlib
import os
import sys
-import types
import unittest
from test.test_importlib import util
-from test.support import run_unittest
# needed tests:
#
@@ -71,6 +68,7 @@ class NamespacePackageTest(unittest.TestCase):
# TODO: will we ever want to pass exc_info to __exit__?
self.ctx.__exit__(None, None, None)
+
class SingleNamespacePackage(NamespacePackageTest):
paths = ['portion1']
@@ -87,7 +85,7 @@ class SingleNamespacePackage(NamespacePackageTest):
self.assertEqual(repr(foo), "<module 'foo' (namespace)>")
-class DynamicPatheNamespacePackage(NamespacePackageTest):
+class DynamicPathNamespacePackage(NamespacePackageTest):
paths = ['portion1']
def test_dynamic_path(self):
@@ -289,5 +287,35 @@ class ModuleAndNamespacePackageInSameDir(NamespacePackageTest):
self.assertEqual(a_test.attr, 'in module')
+class ReloadTests(NamespacePackageTest):
+ paths = ['portion1']
+
+ def test_simple_package(self):
+ import foo.one
+ foo = importlib.reload(foo)
+ self.assertEqual(foo.one.attr, 'portion1 foo one')
+
+ def test_cant_import_other(self):
+ import foo
+ with self.assertRaises(ImportError):
+ import foo.two
+ foo = importlib.reload(foo)
+ with self.assertRaises(ImportError):
+ import foo.two
+
+ def test_dynamic_path(self):
+ import foo.one
+ with self.assertRaises(ImportError):
+ import foo.two
+
+ # Now modify sys.path and reload.
+ sys.path.append(os.path.join(self.root, 'portion2'))
+ foo = importlib.reload(foo)
+
+ # And make sure foo.two is now importable
+ import foo.two
+ self.assertEqual(foo.two.attr, 'portion2 foo two')
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/test/test_importlib/test_windows.py b/Lib/test/test_importlib/test_windows.py
index c893bcf565..005b685cc0 100644
--- a/Lib/test/test_importlib/test_windows.py
+++ b/Lib/test/test_importlib/test_windows.py
@@ -40,7 +40,7 @@ def setup_module(machinery, name, path=None):
else:
root = machinery.WindowsRegistryFinder.REGISTRY_KEY
key = root.format(fullname=name,
- sys_version=sys.version[:3])
+ sys_version='%d.%d' % sys.version_info[:2])
try:
with temp_module(name, "a = 1") as location:
subkey = CreateKey(HKEY_CURRENT_USER, key)
diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
index 671e05a7b5..76cebcc221 100644
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -30,6 +30,7 @@ from test.support import MISSING_C_DOCSTRINGS, cpython_only
from test.support.script_helper import assert_python_ok, assert_python_failure
from test import inspect_fodder as mod
from test import inspect_fodder2 as mod2
+from test import support
from test.test_import import _ready_to_import
@@ -38,7 +39,7 @@ from test.test_import import _ready_to_import
# ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode,
# isbuiltin, isroutine, isgenerator, isgeneratorfunction, getmembers,
# getdoc, getfile, getmodule, getsourcefile, getcomments, getsource,
-# getclasstree, getargspec, getargvalues, formatargspec, formatargvalues,
+# getclasstree, getargvalues, formatargspec, formatargvalues,
# currentframe, stack, trace, isdatadescriptor
# NOTE: There are some additional tests relating to interaction with
@@ -400,7 +401,7 @@ class TestRetrievingSourceCode(GetSourceBase):
self.assertEqual(normcase(inspect.getsourcefile(mod.spam)), modfile)
self.assertEqual(normcase(inspect.getsourcefile(git.abuse)), modfile)
fn = "_non_existing_filename_used_for_sourcefile_test.py"
- co = compile("None", fn, "exec")
+ co = compile("x=1", fn, "exec")
self.assertEqual(inspect.getsourcefile(co), None)
linecache.cache[co.co_filename] = (1, None, "None", co.co_filename)
try:
@@ -3543,14 +3544,14 @@ class TestMain(unittest.TestCase):
def test_details(self):
module = importlib.import_module('unittest')
- rc, out, err = assert_python_ok('-m', 'inspect',
+ args = support.optim_args_from_interpreter_flags()
+ rc, out, err = assert_python_ok(*args, '-m', 'inspect',
'unittest', '--details')
output = out.decode()
# Just a quick sanity check on the output
self.assertIn(module.__name__, output)
self.assertIn(module.__file__, output)
- if not sys.flags.optimize:
- self.assertIn(module.__cached__, output)
+ self.assertIn(module.__cached__, output)
self.assertEqual(err, b'')
diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
index 73231981ad..53e776d910 100644
--- a/Lib/test/test_io.py
+++ b/Lib/test/test_io.py
@@ -496,7 +496,11 @@ class IOTest(unittest.TestCase):
def test_open_handles_NUL_chars(self):
fn_with_NUL = 'foo\0bar'
self.assertRaises(ValueError, self.open, fn_with_NUL, 'w')
- self.assertRaises(ValueError, self.open, bytes(fn_with_NUL, 'ascii'), 'w')
+
+ bytes_fn = bytes(fn_with_NUL, 'ascii')
+ with warnings.catch_warnings():
+ warnings.simplefilter("ignore", DeprecationWarning)
+ self.assertRaises(ValueError, self.open, bytes_fn, 'w')
def test_raw_file_io(self):
with self.open(support.TESTFN, "wb", buffering=0) as f:
@@ -3228,8 +3232,7 @@ class CTextIOWrapperTest(TextIOWrapperTest):
class PyTextIOWrapperTest(TextIOWrapperTest):
io = pyio
- #shutdown_error = "LookupError: unknown encoding: ascii"
- shutdown_error = "TypeError: 'NoneType' object is not iterable"
+ shutdown_error = "LookupError: unknown encoding: ascii"
class IncrementalNewlineDecoderTest(unittest.TestCase):
diff --git a/Lib/test/test_iterlen.py b/Lib/test/test_iterlen.py
index 152f5fc0cb..41c9752e55 100644
--- a/Lib/test/test_iterlen.py
+++ b/Lib/test/test_iterlen.py
@@ -42,7 +42,6 @@ enumerate(iter('abc')).
"""
import unittest
-from test import support
from itertools import repeat
from collections import deque
from operator import length_hint
diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py
index f940852ce1..945c58d5d0 100644
--- a/Lib/test/test_itertools.py
+++ b/Lib/test/test_itertools.py
@@ -4,7 +4,6 @@ from itertools import *
import weakref
from decimal import Decimal
from fractions import Fraction
-import sys
import operator
import random
import copy
@@ -613,6 +612,56 @@ class TestBasicOps(unittest.TestCase):
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
self.pickletest(proto, cycle('abc'))
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ # test with partial consumed input iterable
+ it = iter('abcde')
+ c = cycle(it)
+ _ = [next(c) for i in range(2)] # consume 2 of 5 inputs
+ p = pickle.dumps(c, proto)
+ d = pickle.loads(p) # rebuild the cycle object
+ self.assertEqual(take(20, d), list('cdeabcdeabcdeabcdeab'))
+
+ # test with completely consumed input iterable
+ it = iter('abcde')
+ c = cycle(it)
+ _ = [next(c) for i in range(7)] # consume 7 of 5 inputs
+ p = pickle.dumps(c, proto)
+ d = pickle.loads(p) # rebuild the cycle object
+ self.assertEqual(take(20, d), list('cdeabcdeabcdeabcdeab'))
+
+ def test_cycle_setstate(self):
+ # Verify both modes for restoring state
+
+ # Mode 0 is efficient. It uses an incompletely consumed input
+ # iterator to build a cycle object and then passes in state with
+ # a list of previously consumed values. There is no data
+ # overlap between the two.
+ c = cycle('defg')
+ c.__setstate__((list('abc'), 0))
+ self.assertEqual(take(20, c), list('defgabcdefgabcdefgab'))
+
+ # Mode 1 is inefficient. It starts with a cycle object built
+ # from an iterator over the remaining elements in a partial
+ # cycle and then passes in state with all of the previously
+ # seen values (this overlaps values included in the iterator).
+ c = cycle('defg')
+ c.__setstate__((list('abcdefg'), 1))
+ self.assertEqual(take(20, c), list('defgabcdefgabcdefgab'))
+
+ # The first argument to setstate needs to be a tuple
+ with self.assertRaises(SystemError):
+ cycle('defg').__setstate__([list('abcdefg'), 0])
+
+ # The first argument in the setstate tuple must be a list
+ with self.assertRaises(TypeError):
+ c = cycle('defg')
+ c.__setstate__((dict.fromkeys('defg'), 0))
+ take(20, c)
+
+ # The first argument in the setstate tuple must be a list
+ with self.assertRaises(TypeError):
+ cycle('defg').__setstate__((list('abcdefg'), 'x'))
+
def test_groupby(self):
# Check whether it accepts arguments correctly
self.assertEqual([], list(groupby([])))
diff --git a/Lib/test/test_json/__init__.py b/Lib/test/test_json/__init__.py
index 0807e6fb4f..bac370dadf 100644
--- a/Lib/test/test_json/__init__.py
+++ b/Lib/test/test_json/__init__.py
@@ -1,5 +1,4 @@
import os
-import sys
import json
import doctest
import unittest
diff --git a/Lib/test/test_json/test_fail.py b/Lib/test/test_json/test_fail.py
index 95ff5b8d1e..7910521021 100644
--- a/Lib/test/test_json/test_fail.py
+++ b/Lib/test/test_json/test_fail.py
@@ -1,5 +1,4 @@
from test.test_json import PyTest, CTest
-import re
# 2007-10-05
JSONDOCS = [
diff --git a/Lib/test/test_kqueue.py b/Lib/test/test_kqueue.py
index f822024aa0..9f49886878 100644
--- a/Lib/test/test_kqueue.py
+++ b/Lib/test/test_kqueue.py
@@ -5,7 +5,6 @@ import errno
import os
import select
import socket
-import sys
import time
import unittest
diff --git a/Lib/test/test_linecache.py b/Lib/test/test_linecache.py
index 47e2eddfb1..375d9c4213 100644
--- a/Lib/test/test_linecache.py
+++ b/Lib/test/test_linecache.py
@@ -3,6 +3,8 @@
import linecache
import unittest
import os.path
+import tempfile
+import tokenize
from test import support
@@ -10,8 +12,6 @@ FILENAME = linecache.__file__
NONEXISTENT_FILENAME = FILENAME + '.missing'
INVALID_NAME = '!@$)(!@#_1'
EMPTY = ''
-TESTS = 'inspect_fodder inspect_fodder2 mapping_tests'
-TESTS = TESTS.split()
TEST_PATH = os.path.dirname(__file__)
MODULES = "linecache abc".split()
MODULE_PATH = os.path.dirname(FILENAME)
@@ -37,6 +37,65 @@ def f():
return 3''' # No ending newline
+class TempFile:
+
+ def setUp(self):
+ super().setUp()
+ with tempfile.NamedTemporaryFile(delete=False) as fp:
+ self.file_name = fp.name
+ fp.write(self.file_byte_string)
+ self.addCleanup(support.unlink, self.file_name)
+
+
+class GetLineTestsGoodData(TempFile):
+ # file_list = ['list\n', 'of\n', 'good\n', 'strings\n']
+
+ def setUp(self):
+ self.file_byte_string = ''.join(self.file_list).encode('utf-8')
+ super().setUp()
+
+ def test_getline(self):
+ with tokenize.open(self.file_name) as fp:
+ for index, line in enumerate(fp):
+ if not line.endswith('\n'):
+ line += '\n'
+
+ cached_line = linecache.getline(self.file_name, index + 1)
+ self.assertEqual(line, cached_line)
+
+ def test_getlines(self):
+ lines = linecache.getlines(self.file_name)
+ self.assertEqual(lines, self.file_list)
+
+
+class GetLineTestsBadData(TempFile):
+ # file_byte_string = b'Bad data goes here'
+
+ def test_getline(self):
+ self.assertRaises((SyntaxError, UnicodeDecodeError),
+ linecache.getline, self.file_name, 1)
+
+ def test_getlines(self):
+ self.assertRaises((SyntaxError, UnicodeDecodeError),
+ linecache.getlines, self.file_name)
+
+
+class EmptyFile(GetLineTestsGoodData, unittest.TestCase):
+ file_list = []
+
+
+class SingleEmptyLine(GetLineTestsGoodData, unittest.TestCase):
+ file_list = ['\n']
+
+
+class GoodUnicode(GetLineTestsGoodData, unittest.TestCase):
+ file_list = ['á\n', 'b\n', 'abcdef\n', 'ááááá\n']
+
+
+class BadUnicode(GetLineTestsBadData, unittest.TestCase):
+ file_byte_string = b'\x80abc'
+
+
class LineCacheTests(unittest.TestCase):
def test_getline(self):
@@ -53,13 +112,6 @@ class LineCacheTests(unittest.TestCase):
self.assertEqual(getline(EMPTY, 1), EMPTY)
self.assertEqual(getline(INVALID_NAME, 1), EMPTY)
- # Check whether lines correspond to those from file iteration
- for entry in TESTS:
- filename = os.path.join(TEST_PATH, entry) + '.py'
- with open(filename) as file:
- for index, line in enumerate(file):
- self.assertEqual(line, getline(filename, index + 1))
-
# Check module loading
for entry in MODULES:
filename = os.path.join(MODULE_PATH, entry) + '.py'
@@ -80,12 +132,13 @@ class LineCacheTests(unittest.TestCase):
def test_clearcache(self):
cached = []
- for entry in TESTS:
- filename = os.path.join(TEST_PATH, entry) + '.py'
+ for entry in MODULES:
+ filename = os.path.join(MODULE_PATH, entry) + '.py'
cached.append(filename)
linecache.getline(filename, 1)
# Are all files cached?
+ self.assertNotEqual(cached, [])
cached_empty = [fn for fn in cached if fn not in linecache.cache]
self.assertEqual(cached_empty, [])
diff --git a/Lib/test/test_list.py b/Lib/test/test_list.py
index 8f82ab5297..aee62dca1c 100644
--- a/Lib/test/test_list.py
+++ b/Lib/test/test_list.py
@@ -1,5 +1,5 @@
import sys
-from test import support, list_tests
+from test import list_tests
import pickle
import unittest
diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py
index 95575bf56a..9c4344f99a 100644
--- a/Lib/test/test_logging.py
+++ b/Lib/test/test_logging.py
@@ -4159,6 +4159,17 @@ class NTEventLogHandlerTest(BaseTest):
msg = 'Record not found in event log, went back %d records' % GO_BACK
self.assertTrue(found, msg=msg)
+
+class MiscTestCase(unittest.TestCase):
+ def test__all__(self):
+ blacklist = {'logThreads', 'logMultiprocessing',
+ 'logProcesses', 'currentframe',
+ 'PercentStyle', 'StrFormatStyle', 'StringTemplateStyle',
+ 'Filterer', 'PlaceHolder', 'Manager', 'RootLogger',
+ 'root'}
+ support.check__all__(self, logging, blacklist=blacklist)
+
+
# Set the locale to the platform-dependent default. I have no idea
# why the test does this, but in any case we save the current locale
# first and restore it at the end.
@@ -4175,7 +4186,8 @@ def test_main():
RotatingFileHandlerTest, LastResortTest, LogRecordTest,
ExceptionTest, SysLogHandlerTest, HTTPHandlerTest,
NTEventLogHandlerTest, TimedRotatingFileHandlerTest,
- UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest)
+ UnixSocketHandlerTest, UnixDatagramHandlerTest, UnixSysLogHandlerTest,
+ MiscTestCase)
if __name__ == "__main__":
test_main()
diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py
index b2d008b101..f0dd0749f7 100644
--- a/Lib/test/test_long.py
+++ b/Lib/test/test_long.py
@@ -689,6 +689,20 @@ class LongTest(unittest.TestCase):
self.assertRaises(OverflowError, int, float('-inf'))
self.assertRaises(ValueError, int, float('nan'))
+ def test_mod_division(self):
+ with self.assertRaises(ZeroDivisionError):
+ _ = 1 % 0
+
+ self.assertEqual(13 % 10, 3)
+ self.assertEqual(-13 % 10, 7)
+ self.assertEqual(13 % -10, -7)
+ self.assertEqual(-13 % -10, -3)
+
+ self.assertEqual(12 % 4, 0)
+ self.assertEqual(-12 % 4, 0)
+ self.assertEqual(12 % -4, 0)
+ self.assertEqual(-12 % -4, 0)
+
def test_true_division(self):
huge = 1 << 40000
mhuge = -huge
@@ -723,6 +737,25 @@ class LongTest(unittest.TestCase):
for zero in ["huge / 0", "mhuge / 0"]:
self.assertRaises(ZeroDivisionError, eval, zero, namespace)
+ def test_floordiv(self):
+ with self.assertRaises(ZeroDivisionError):
+ _ = 1 // 0
+
+ self.assertEqual(2 // 3, 0)
+ self.assertEqual(2 // -3, -1)
+ self.assertEqual(-2 // 3, -1)
+ self.assertEqual(-2 // -3, 0)
+
+ self.assertEqual(-11 // -3, 3)
+ self.assertEqual(-11 // 3, -4)
+ self.assertEqual(11 // -3, -4)
+ self.assertEqual(11 // 3, 3)
+
+ self.assertEqual(-12 // -3, 4)
+ self.assertEqual(-12 // 3, -4)
+ self.assertEqual(12 // -3, -4)
+ self.assertEqual(12 // 3, 4)
+
def check_truediv(self, a, b, skip_small=True):
"""Verify that the result of a/b is correctly rounded, by
comparing it with a pure Python implementation of correctly
diff --git a/Lib/test/test_macpath.py b/Lib/test/test_macpath.py
index 80bec7a799..0698ff5f6b 100644
--- a/Lib/test/test_macpath.py
+++ b/Lib/test/test_macpath.py
@@ -1,5 +1,5 @@
import macpath
-from test import support, test_genericpath
+from test import test_genericpath
import unittest
diff --git a/Lib/test/test_mailbox.py b/Lib/test/test_mailbox.py
index 0991f74f84..1f30fa6e8f 100644
--- a/Lib/test/test_mailbox.py
+++ b/Lib/test/test_mailbox.py
@@ -7,17 +7,12 @@ import email
import email.message
import re
import io
-import shutil
import tempfile
from test import support
import unittest
import textwrap
import mailbox
import glob
-try:
- import fcntl
-except ImportError:
- pass
class TestBase:
diff --git a/Lib/test/test_mailcap.py b/Lib/test/test_mailcap.py
index 22b2fcc4a7..623fadb8ed 100644
--- a/Lib/test/test_mailcap.py
+++ b/Lib/test/test_mailcap.py
@@ -1,6 +1,5 @@
import mailcap
import os
-import shutil
import test.support
import unittest
diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py
index c7def9a599..b378ffea00 100644
--- a/Lib/test/test_marshal.py
+++ b/Lib/test/test_marshal.py
@@ -135,6 +135,13 @@ class ContainerTestCase(unittest.TestCase, HelperMixin):
for constructor in (set, frozenset):
self.helper(constructor(self.d.keys()))
+ @support.cpython_only
+ def test_empty_frozenset_singleton(self):
+ # marshal.loads() must reuse the empty frozenset singleton
+ obj = frozenset()
+ obj2 = marshal.loads(marshal.dumps(obj))
+ self.assertIs(obj2, obj)
+
class BufferTestCase(unittest.TestCase, HelperMixin):
diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py
index 6c7b99d2d2..d0bc79065f 100644
--- a/Lib/test/test_math.py
+++ b/Lib/test/test_math.py
@@ -6,7 +6,6 @@ from test import support
import unittest
import math
import os
-import platform
import sys
import struct
import sysconfig
diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py
index b365d84865..bbb4070148 100644
--- a/Lib/test/test_mmap.py
+++ b/Lib/test/test_mmap.py
@@ -713,6 +713,14 @@ class MmapTests(unittest.TestCase):
gc_collect()
self.assertIs(wr(), None)
+ def test_write_returning_the_number_of_bytes_written(self):
+ mm = mmap.mmap(-1, 16)
+ self.assertEqual(mm.write(b""), 0)
+ self.assertEqual(mm.write(b"x"), 1)
+ self.assertEqual(mm.write(b"yz"), 2)
+ self.assertEqual(mm.write(b"python"), 6)
+
+
class LargeMmapTests(unittest.TestCase):
def setUp(self):
diff --git a/Lib/test/test_msilib.py b/Lib/test/test_msilib.py
index 8ef334fdb3..f656f7234e 100644
--- a/Lib/test/test_msilib.py
+++ b/Lib/test/test_msilib.py
@@ -1,6 +1,5 @@
""" Test suite for the code in msilib """
import unittest
-import os
from test.support import import_module
msilib = import_module('msilib')
diff --git a/Lib/test/test_multibytecodec.py b/Lib/test/test_multibytecodec.py
index 8d7a213c16..01a1cd3c69 100644
--- a/Lib/test/test_multibytecodec.py
+++ b/Lib/test/test_multibytecodec.py
@@ -5,7 +5,7 @@
from test import support
from test.support import TESTFN
-import unittest, io, codecs, sys, os
+import unittest, io, codecs, sys
import _multibytecodec
ALL_CJKENCODINGS = [
diff --git a/Lib/test/test_multiprocessing_main_handling.py b/Lib/test/test_multiprocessing_main_handling.py
index 52273ea22d..2e15cd8a6b 100644
--- a/Lib/test/test_multiprocessing_main_handling.py
+++ b/Lib/test/test_multiprocessing_main_handling.py
@@ -6,7 +6,6 @@ support.import_module('_multiprocessing')
import importlib
import importlib.machinery
-import zipimport
import unittest
import sys
import os
@@ -15,7 +14,7 @@ import py_compile
from test.support.script_helper import (
make_pkg, make_script, make_zip_pkg, make_zip_script,
- assert_python_ok, assert_python_failure, spawn_python, kill_python)
+ assert_python_ok)
# Look up which start methods are available to test
import multiprocessing
diff --git a/Lib/test/test_nis.py b/Lib/test/test_nis.py
index 387a4e7856..21074c6810 100644
--- a/Lib/test/test_nis.py
+++ b/Lib/test/test_nis.py
@@ -1,6 +1,5 @@
from test import support
import unittest
-import sys
# Skip test if nis module does not exist.
nis = support.import_module('nis')
diff --git a/Lib/test/test_normalization.py b/Lib/test/test_normalization.py
index 30fa612645..5b590e1af3 100644
--- a/Lib/test/test_normalization.py
+++ b/Lib/test/test_normalization.py
@@ -3,7 +3,6 @@ import unittest
from http.client import HTTPException
import sys
-import os
from unicodedata import normalize, unidata_version
TESTDATAFILE = "NormalizationTest.txt"
diff --git a/Lib/test/test_operator.py b/Lib/test/test_operator.py
index b5ba97625f..6254091e78 100644
--- a/Lib/test/test_operator.py
+++ b/Lib/test/test_operator.py
@@ -120,63 +120,63 @@ class OperatorTestCase:
operator = self.module
self.assertRaises(TypeError, operator.add)
self.assertRaises(TypeError, operator.add, None, None)
- self.assertTrue(operator.add(3, 4) == 7)
+ self.assertEqual(operator.add(3, 4), 7)
def test_bitwise_and(self):
operator = self.module
self.assertRaises(TypeError, operator.and_)
self.assertRaises(TypeError, operator.and_, None, None)
- self.assertTrue(operator.and_(0xf, 0xa) == 0xa)
+ self.assertEqual(operator.and_(0xf, 0xa), 0xa)
def test_concat(self):
operator = self.module
self.assertRaises(TypeError, operator.concat)
self.assertRaises(TypeError, operator.concat, None, None)
- self.assertTrue(operator.concat('py', 'thon') == 'python')
- self.assertTrue(operator.concat([1, 2], [3, 4]) == [1, 2, 3, 4])
- self.assertTrue(operator.concat(Seq1([5, 6]), Seq1([7])) == [5, 6, 7])
- self.assertTrue(operator.concat(Seq2([5, 6]), Seq2([7])) == [5, 6, 7])
+ self.assertEqual(operator.concat('py', 'thon'), 'python')
+ self.assertEqual(operator.concat([1, 2], [3, 4]), [1, 2, 3, 4])
+ self.assertEqual(operator.concat(Seq1([5, 6]), Seq1([7])), [5, 6, 7])
+ self.assertEqual(operator.concat(Seq2([5, 6]), Seq2([7])), [5, 6, 7])
self.assertRaises(TypeError, operator.concat, 13, 29)
def test_countOf(self):
operator = self.module
self.assertRaises(TypeError, operator.countOf)
self.assertRaises(TypeError, operator.countOf, None, None)
- self.assertTrue(operator.countOf([1, 2, 1, 3, 1, 4], 3) == 1)
- self.assertTrue(operator.countOf([1, 2, 1, 3, 1, 4], 5) == 0)
+ self.assertEqual(operator.countOf([1, 2, 1, 3, 1, 4], 3), 1)
+ self.assertEqual(operator.countOf([1, 2, 1, 3, 1, 4], 5), 0)
def test_delitem(self):
operator = self.module
a = [4, 3, 2, 1]
self.assertRaises(TypeError, operator.delitem, a)
self.assertRaises(TypeError, operator.delitem, a, None)
- self.assertTrue(operator.delitem(a, 1) is None)
- self.assertTrue(a == [4, 2, 1])
+ self.assertIsNone(operator.delitem(a, 1))
+ self.assertEqual(a, [4, 2, 1])
def test_floordiv(self):
operator = self.module
self.assertRaises(TypeError, operator.floordiv, 5)
self.assertRaises(TypeError, operator.floordiv, None, None)
- self.assertTrue(operator.floordiv(5, 2) == 2)
+ self.assertEqual(operator.floordiv(5, 2), 2)
def test_truediv(self):
operator = self.module
self.assertRaises(TypeError, operator.truediv, 5)
self.assertRaises(TypeError, operator.truediv, None, None)
- self.assertTrue(operator.truediv(5, 2) == 2.5)
+ self.assertEqual(operator.truediv(5, 2), 2.5)
def test_getitem(self):
operator = self.module
a = range(10)
self.assertRaises(TypeError, operator.getitem)
self.assertRaises(TypeError, operator.getitem, a, None)
- self.assertTrue(operator.getitem(a, 2) == 2)
+ self.assertEqual(operator.getitem(a, 2), 2)
def test_indexOf(self):
operator = self.module
self.assertRaises(TypeError, operator.indexOf)
self.assertRaises(TypeError, operator.indexOf, None, None)
- self.assertTrue(operator.indexOf([4, 3, 2, 1], 3) == 1)
+ self.assertEqual(operator.indexOf([4, 3, 2, 1], 3), 1)
self.assertRaises(ValueError, operator.indexOf, [4, 3, 2, 1], 0)
def test_invert(self):
@@ -189,21 +189,21 @@ class OperatorTestCase:
operator = self.module
self.assertRaises(TypeError, operator.lshift)
self.assertRaises(TypeError, operator.lshift, None, 42)
- self.assertTrue(operator.lshift(5, 1) == 10)
- self.assertTrue(operator.lshift(5, 0) == 5)
+ self.assertEqual(operator.lshift(5, 1), 10)
+ self.assertEqual(operator.lshift(5, 0), 5)
self.assertRaises(ValueError, operator.lshift, 2, -1)
def test_mod(self):
operator = self.module
self.assertRaises(TypeError, operator.mod)
self.assertRaises(TypeError, operator.mod, None, 42)
- self.assertTrue(operator.mod(5, 2) == 1)
+ self.assertEqual(operator.mod(5, 2), 1)
def test_mul(self):
operator = self.module
self.assertRaises(TypeError, operator.mul)
self.assertRaises(TypeError, operator.mul, None, None)
- self.assertTrue(operator.mul(5, 2) == 10)
+ self.assertEqual(operator.mul(5, 2), 10)
def test_matmul(self):
operator = self.module
@@ -227,7 +227,7 @@ class OperatorTestCase:
operator = self.module
self.assertRaises(TypeError, operator.or_)
self.assertRaises(TypeError, operator.or_, None, None)
- self.assertTrue(operator.or_(0xa, 0x5) == 0xf)
+ self.assertEqual(operator.or_(0xa, 0x5), 0xf)
def test_pos(self):
operator = self.module
@@ -250,8 +250,8 @@ class OperatorTestCase:
operator = self.module
self.assertRaises(TypeError, operator.rshift)
self.assertRaises(TypeError, operator.rshift, None, 42)
- self.assertTrue(operator.rshift(5, 1) == 2)
- self.assertTrue(operator.rshift(5, 0) == 5)
+ self.assertEqual(operator.rshift(5, 1), 2)
+ self.assertEqual(operator.rshift(5, 0), 5)
self.assertRaises(ValueError, operator.rshift, 2, -1)
def test_contains(self):
@@ -266,15 +266,15 @@ class OperatorTestCase:
a = list(range(3))
self.assertRaises(TypeError, operator.setitem, a)
self.assertRaises(TypeError, operator.setitem, a, None, None)
- self.assertTrue(operator.setitem(a, 0, 2) is None)
- self.assertTrue(a == [2, 1, 2])
+ self.assertIsNone(operator.setitem(a, 0, 2))
+ self.assertEqual(a, [2, 1, 2])
self.assertRaises(IndexError, operator.setitem, a, 4, 2)
def test_sub(self):
operator = self.module
self.assertRaises(TypeError, operator.sub)
self.assertRaises(TypeError, operator.sub, None, None)
- self.assertTrue(operator.sub(5, 2) == 3)
+ self.assertEqual(operator.sub(5, 2), 3)
def test_truth(self):
operator = self.module
@@ -292,7 +292,7 @@ class OperatorTestCase:
operator = self.module
self.assertRaises(TypeError, operator.xor)
self.assertRaises(TypeError, operator.xor, None, None)
- self.assertTrue(operator.xor(0xb, 0xc) == 0x7)
+ self.assertEqual(operator.xor(0xb, 0xc), 0x7)
def test_is(self):
operator = self.module
diff --git a/Lib/test/test_optparse.py b/Lib/test/test_optparse.py
index 7621c24305..91a0319a73 100644
--- a/Lib/test/test_optparse.py
+++ b/Lib/test/test_optparse.py
@@ -16,6 +16,7 @@ from io import StringIO
from test import support
+import optparse
from optparse import make_option, Option, \
TitledHelpFormatter, OptionParser, OptionGroup, \
SUPPRESS_USAGE, OptionError, OptionConflictError, \
@@ -1650,6 +1651,12 @@ class TestParseNumber(BaseTest):
"option -l: invalid integer value: '0x12x'")
+class MiscTestCase(unittest.TestCase):
+ def test__all__(self):
+ blacklist = {'check_builtin', 'AmbiguousOptionError', 'NO_DEFAULT'}
+ support.check__all__(self, optparse, blacklist=blacklist)
+
+
def test_main():
support.run_unittest(__name__)
diff --git a/Lib/test/test_ordered_dict.py b/Lib/test/test_ordered_dict.py
index 901d4b2ad2..6fbc1b4132 100644
--- a/Lib/test/test_ordered_dict.py
+++ b/Lib/test/test_ordered_dict.py
@@ -298,9 +298,11 @@ class OrderedDictTests:
# do not save instance dictionary if not needed
pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
od = OrderedDict(pairs)
+ self.assertIsInstance(od.__dict__, dict)
self.assertIsNone(od.__reduce__()[2])
od.x = 10
- self.assertIsNotNone(od.__reduce__()[2])
+ self.assertEqual(od.__dict__['x'], 10)
+ self.assertEqual(od.__reduce__()[2], {'x': 10})
def test_pickle_recursive(self):
OrderedDict = self.OrderedDict
@@ -403,6 +405,14 @@ class OrderedDictTests:
od = OrderedDict(**d)
self.assertGreater(sys.getsizeof(od), sys.getsizeof(d))
+ def test_views(self):
+ OrderedDict = self.OrderedDict
+ # See http://bugs.python.org/issue24286
+ s = 'the quick brown fox jumped over a lazy dog yesterday before dawn'.split()
+ od = OrderedDict.fromkeys(s)
+ self.assertEqual(od.keys(), dict(od).keys())
+ self.assertEqual(od.items(), dict(od).items())
+
def test_override_update(self):
OrderedDict = self.OrderedDict
# Verify that subclasses can override update() without breaking __init__()
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
index 874f9e4c90..01404ff4f6 100644
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -15,7 +15,6 @@ import locale
import mmap
import os
import pickle
-import platform
import re
import shutil
import signal
@@ -66,6 +65,7 @@ except ImportError:
from test.support.script_helper import assert_python_ok
+
root_in_posix = False
if hasattr(os, 'geteuid'):
root_in_posix = (os.geteuid() == 0)
@@ -82,6 +82,28 @@ else:
# Issue #14110: Some tests fail on FreeBSD if the user is in the wheel group.
HAVE_WHEEL_GROUP = sys.platform.startswith('freebsd') and os.getgid() == 0
+
+@contextlib.contextmanager
+def ignore_deprecation_warnings(msg_regex, quiet=False):
+ with support.check_warnings((msg_regex, DeprecationWarning), quiet=quiet):
+ yield
+
+
+@contextlib.contextmanager
+def bytes_filename_warn(expected):
+ msg = 'The Windows bytes API has been deprecated'
+ if os.name == 'nt':
+ with ignore_deprecation_warnings(msg, quiet=not expected):
+ yield
+ else:
+ yield
+
+
+def create_file(filename, content=b'content'):
+ with open(filename, "xb", 0) as fp:
+ fp.write(content)
+
+
# Tests creating TESTFN
class FileTests(unittest.TestCase):
def setUp(self):
@@ -140,9 +162,8 @@ class FileTests(unittest.TestCase):
"needs INT_MAX < PY_SSIZE_T_MAX")
@support.bigmemtest(size=INT_MAX + 10, memuse=1, dry_run=False)
def test_large_read(self, size):
- with open(support.TESTFN, "wb") as fp:
- fp.write(b'test')
self.addCleanup(support.unlink, support.TESTFN)
+ create_file(support.TESTFN, b'test')
# Issue #21932: Make sure that os.read() does not raise an
# OverflowError for size larger than INT_MAX
@@ -199,11 +220,12 @@ class FileTests(unittest.TestCase):
def test_replace(self):
TESTFN2 = support.TESTFN + ".2"
- with open(support.TESTFN, 'w') as f:
- f.write("1")
- with open(TESTFN2, 'w') as f:
- f.write("2")
- self.addCleanup(os.unlink, TESTFN2)
+ self.addCleanup(support.unlink, support.TESTFN)
+ self.addCleanup(support.unlink, TESTFN2)
+
+ create_file(support.TESTFN, b"1")
+ create_file(TESTFN2, b"2")
+
os.replace(support.TESTFN, TESTFN2)
self.assertRaises(FileNotFoundError, os.stat, support.TESTFN)
with open(TESTFN2, 'r') as f:
@@ -226,15 +248,9 @@ class FileTests(unittest.TestCase):
# Test attributes on return values from os.*stat* family.
class StatAttributeTests(unittest.TestCase):
def setUp(self):
- os.mkdir(support.TESTFN)
- self.fname = os.path.join(support.TESTFN, "f1")
- f = open(self.fname, 'wb')
- f.write(b"ABC")
- f.close()
-
- def tearDown(self):
- os.unlink(self.fname)
- os.rmdir(support.TESTFN)
+ self.fname = support.TESTFN
+ self.addCleanup(support.unlink, self.fname)
+ create_file(self.fname, b"ABC")
@unittest.skipUnless(hasattr(os, 'stat'), 'test needs os.stat()')
def check_stat_attributes(self, fname):
@@ -310,8 +326,7 @@ class StatAttributeTests(unittest.TestCase):
fname = self.fname.encode(sys.getfilesystemencoding())
except UnicodeEncodeError:
self.skipTest("cannot encode %a for the filesystem" % self.fname)
- with warnings.catch_warnings():
- warnings.simplefilter("ignore", DeprecationWarning)
+ with bytes_filename_warn(True):
self.check_stat_attributes(fname)
def test_stat_result_pickle(self):
@@ -426,7 +441,11 @@ class StatAttributeTests(unittest.TestCase):
0)
# test directory st_file_attributes (FILE_ATTRIBUTE_DIRECTORY set)
- result = os.stat(support.TESTFN)
+ dirname = support.TESTFN + "dir"
+ os.mkdir(dirname)
+ self.addCleanup(os.rmdir, dirname)
+
+ result = os.stat(dirname)
self.check_file_attributes(result)
self.assertEqual(
result.st_file_attributes & stat.FILE_ATTRIBUTE_DIRECTORY,
@@ -440,19 +459,14 @@ class UtimeTests(unittest.TestCase):
self.addCleanup(support.rmtree, self.dirname)
os.mkdir(self.dirname)
- with open(self.fname, 'wb') as fp:
- fp.write(b"ABC")
+ create_file(self.fname)
def restore_float_times(state):
- with warnings.catch_warnings():
- warnings.simplefilter("ignore", DeprecationWarning)
-
+ with ignore_deprecation_warnings('stat_float_times'):
os.stat_float_times(state)
# ensure that st_atime and st_mtime are float
- with warnings.catch_warnings():
- warnings.simplefilter("ignore", DeprecationWarning)
-
+ with ignore_deprecation_warnings('stat_float_times'):
old_float_times = os.stat_float_times(-1)
self.addCleanup(restore_float_times, old_float_times)
@@ -544,7 +558,7 @@ class UtimeTests(unittest.TestCase):
"fd support for utime required for this test.")
def test_utime_fd(self):
def set_time(filename, ns):
- with open(filename, 'wb') as fp:
+ with open(filename, 'wb', 0) as fp:
# use a file descriptor to test futimens(timespec)
# or futimes(timeval)
os.utime(fp.fileno(), ns=ns)
@@ -798,6 +812,7 @@ class WalkTests(unittest.TestCase):
def setUp(self):
join = os.path.join
+ self.addCleanup(support.rmtree, support.TESTFN)
# Build:
# TESTFN/
@@ -830,9 +845,8 @@ class WalkTests(unittest.TestCase):
os.makedirs(t2_path)
for path in tmp1_path, tmp2_path, tmp3_path, tmp4_path:
- f = open(path, "w")
- f.write("I'm " + path + " and proud of it. Blame test_os.\n")
- f.close()
+ with open(path, "x") as f:
+ f.write("I'm " + path + " and proud of it. Blame test_os.\n")
if support.can_symlink():
os.symlink(os.path.abspath(t2_path), self.link_path)
@@ -878,7 +892,7 @@ class WalkTests(unittest.TestCase):
# Walk bottom-up.
all = list(self.walk(self.walk_path, topdown=False))
- self.assertEqual(len(all), 4)
+ self.assertEqual(len(all), 4, all)
# We can't know which order SUB1 and SUB2 will appear in.
# Not flipped: SUB11, SUB1, SUB2, TESTFN
# flipped: SUB2, SUB11, SUB1, TESTFN
@@ -908,22 +922,6 @@ class WalkTests(unittest.TestCase):
else:
self.fail("Didn't follow symlink with followlinks=True")
- def tearDown(self):
- # Tear everything down. This is a decent use for bottom-up on
- # Windows, which doesn't have a recursive delete command. The
- # (not so) subtlety is that rmdir will fail unless the dir's
- # kids are removed first, so bottom up is essential.
- for root, dirs, files in os.walk(support.TESTFN, topdown=False):
- for name in files:
- os.remove(os.path.join(root, name))
- for name in dirs:
- dirname = os.path.join(root, name)
- if not os.path.islink(dirname):
- os.rmdir(dirname)
- else:
- os.remove(dirname)
- os.rmdir(support.TESTFN)
-
def test_walk_bad_dir(self):
# Walk top-down.
errors = []
@@ -1006,27 +1004,13 @@ class FwalkTests(WalkTests):
self.addCleanup(os.close, newfd)
self.assertEqual(newfd, minfd)
- def tearDown(self):
- # cleanup
- for root, dirs, files, rootfd in os.fwalk(support.TESTFN, topdown=False):
- for name in files:
- os.unlink(name, dir_fd=rootfd)
- for name in dirs:
- st = os.stat(name, dir_fd=rootfd, follow_symlinks=False)
- if stat.S_ISDIR(st.st_mode):
- os.rmdir(name, dir_fd=rootfd)
- else:
- os.unlink(name, dir_fd=rootfd)
- os.rmdir(support.TESTFN)
-
class BytesWalkTests(WalkTests):
"""Tests for os.walk() with bytes."""
def setUp(self):
super().setUp()
self.stack = contextlib.ExitStack()
if os.name == 'nt':
- self.stack.enter_context(warnings.catch_warnings())
- warnings.simplefilter("ignore", DeprecationWarning)
+ self.stack.enter_context(bytes_filename_warn(False))
def tearDown(self):
self.stack.close()
@@ -1203,8 +1187,7 @@ class RemoveDirsTests(unittest.TestCase):
os.mkdir(dira)
dirb = os.path.join(dira, 'dirb')
os.mkdir(dirb)
- with open(os.path.join(dira, 'file.txt'), 'w') as f:
- f.write('text')
+ create_file(os.path.join(dira, 'file.txt'))
os.removedirs(dirb)
self.assertFalse(os.path.exists(dirb))
self.assertTrue(os.path.exists(dira))
@@ -1215,8 +1198,7 @@ class RemoveDirsTests(unittest.TestCase):
os.mkdir(dira)
dirb = os.path.join(dira, 'dirb')
os.mkdir(dirb)
- with open(os.path.join(dirb, 'file.txt'), 'w') as f:
- f.write('text')
+ create_file(os.path.join(dirb, 'file.txt'))
with self.assertRaises(OSError):
os.removedirs(dirb)
self.assertTrue(os.path.exists(dirb))
@@ -1226,7 +1208,7 @@ class RemoveDirsTests(unittest.TestCase):
class DevNullTests(unittest.TestCase):
def test_devnull(self):
- with open(os.devnull, 'wb') as f:
+ with open(os.devnull, 'wb', 0) as f:
f.write(b'hello')
f.close()
with open(os.devnull, 'rb') as f:
@@ -1313,9 +1295,9 @@ class URandomFDTests(unittest.TestCase):
def test_urandom_fd_reopened(self):
# Issue #21207: urandom() should detect its fd to /dev/urandom
# changed to something else, and reopen it.
- with open(support.TESTFN, 'wb') as f:
- f.write(b"x" * 256)
- self.addCleanup(os.unlink, support.TESTFN)
+ self.addCleanup(support.unlink, support.TESTFN)
+ create_file(support.TESTFN, b"x" * 256)
+
code = """if 1:
import os
import sys
@@ -1444,6 +1426,18 @@ class ExecTests(unittest.TestCase):
@unittest.skipUnless(sys.platform == "win32", "Win32 specific tests")
class Win32ErrorTests(unittest.TestCase):
+ def setUp(self):
+ try:
+ os.stat(support.TESTFN)
+ except FileNotFoundError:
+ exists = False
+ except OSError as exc:
+ exists = True
+ self.fail("file %s must not exist; os.stat failed with %s"
+ % (support.TESTFN, exc))
+ else:
+ self.fail("file %s must not exist" % support.TESTFN)
+
def test_rename(self):
self.assertRaises(OSError, os.rename, support.TESTFN, support.TESTFN+".bak")
@@ -1454,12 +1448,10 @@ class Win32ErrorTests(unittest.TestCase):
self.assertRaises(OSError, os.chdir, support.TESTFN)
def test_mkdir(self):
- f = open(support.TESTFN, "w")
- try:
+ self.addCleanup(support.unlink, support.TESTFN)
+
+ with open(support.TESTFN, "x") as f:
self.assertRaises(OSError, os.mkdir, support.TESTFN)
- finally:
- f.close()
- os.unlink(support.TESTFN)
def test_utime(self):
self.assertRaises(OSError, os.utime, support.TESTFN, None)
@@ -1467,6 +1459,7 @@ class Win32ErrorTests(unittest.TestCase):
def test_chmod(self):
self.assertRaises(OSError, os.chmod, support.TESTFN, 0)
+
class TestInvalidFD(unittest.TestCase):
singles = ["fchdir", "dup", "fdopen", "fdatasync", "fstat",
"fstatvfs", "fsync", "tcgetpgrp", "ttyname"]
@@ -1578,11 +1571,9 @@ class LinkTests(unittest.TestCase):
os.unlink(file)
def _test_link(self, file1, file2):
- with open(file1, "w") as f1:
- f1.write("test")
+ create_file(file1)
- with warnings.catch_warnings():
- warnings.simplefilter("ignore", DeprecationWarning)
+ with bytes_filename_warn(False):
os.link(file1, file2)
with open(file1, "r") as f1, open(file2, "r") as f2:
self.assertTrue(os.path.sameopenfile(f1.fileno(), f2.fileno()))
@@ -1874,10 +1865,12 @@ class Win32ListdirTests(unittest.TestCase):
self.assertEqual(
sorted(os.listdir(support.TESTFN)),
self.created_paths)
+
# bytes
- self.assertEqual(
- sorted(os.listdir(os.fsencode(support.TESTFN))),
- [os.fsencode(path) for path in self.created_paths])
+ with bytes_filename_warn(False):
+ self.assertEqual(
+ sorted(os.listdir(os.fsencode(support.TESTFN))),
+ [os.fsencode(path) for path in self.created_paths])
def test_listdir_extended_path(self):
"""Test when the path starts with '\\\\?\\'."""
@@ -1887,11 +1880,13 @@ class Win32ListdirTests(unittest.TestCase):
self.assertEqual(
sorted(os.listdir(path)),
self.created_paths)
+
# bytes
- path = b'\\\\?\\' + os.fsencode(os.path.abspath(support.TESTFN))
- self.assertEqual(
- sorted(os.listdir(path)),
- [os.fsencode(path) for path in self.created_paths])
+ with bytes_filename_warn(False):
+ path = b'\\\\?\\' + os.fsencode(os.path.abspath(support.TESTFN))
+ self.assertEqual(
+ sorted(os.listdir(path)),
+ [os.fsencode(path) for path in self.created_paths])
@unittest.skipUnless(sys.platform == "win32", "Win32 specific tests")
@@ -1966,51 +1961,45 @@ class Win32SymlinkTests(unittest.TestCase):
self.assertNotEqual(os.lstat(link), os.stat(link))
bytes_link = os.fsencode(link)
- with warnings.catch_warnings():
- warnings.simplefilter("ignore", DeprecationWarning)
+ with bytes_filename_warn(True):
self.assertEqual(os.stat(bytes_link), os.stat(target))
+ with bytes_filename_warn(True):
self.assertNotEqual(os.lstat(bytes_link), os.stat(bytes_link))
def test_12084(self):
level1 = os.path.abspath(support.TESTFN)
level2 = os.path.join(level1, "level2")
level3 = os.path.join(level2, "level3")
- try:
- os.mkdir(level1)
- os.mkdir(level2)
- os.mkdir(level3)
+ self.addCleanup(support.rmtree, level1)
- file1 = os.path.abspath(os.path.join(level1, "file1"))
+ os.mkdir(level1)
+ os.mkdir(level2)
+ os.mkdir(level3)
- with open(file1, "w") as f:
- f.write("file1")
+ file1 = os.path.abspath(os.path.join(level1, "file1"))
+ create_file(file1)
- orig_dir = os.getcwd()
- try:
- os.chdir(level2)
- link = os.path.join(level2, "link")
- os.symlink(os.path.relpath(file1), "link")
- self.assertIn("link", os.listdir(os.getcwd()))
-
- # Check os.stat calls from the same dir as the link
- self.assertEqual(os.stat(file1), os.stat("link"))
-
- # Check os.stat calls from a dir below the link
- os.chdir(level1)
- self.assertEqual(os.stat(file1),
- os.stat(os.path.relpath(link)))
-
- # Check os.stat calls from a dir above the link
- os.chdir(level3)
- self.assertEqual(os.stat(file1),
- os.stat(os.path.relpath(link)))
- finally:
- os.chdir(orig_dir)
- except OSError as err:
- self.fail(err)
+ orig_dir = os.getcwd()
+ try:
+ os.chdir(level2)
+ link = os.path.join(level2, "link")
+ os.symlink(os.path.relpath(file1), "link")
+ self.assertIn("link", os.listdir(os.getcwd()))
+
+ # Check os.stat calls from the same dir as the link
+ self.assertEqual(os.stat(file1), os.stat("link"))
+
+ # Check os.stat calls from a dir below the link
+ os.chdir(level1)
+ self.assertEqual(os.stat(file1),
+ os.stat(os.path.relpath(link)))
+
+ # Check os.stat calls from a dir above the link
+ os.chdir(level3)
+ self.assertEqual(os.stat(file1),
+ os.stat(os.path.relpath(link)))
finally:
- os.remove(file1)
- shutil.rmtree(level1)
+ os.chdir(orig_dir)
@unittest.skipUnless(sys.platform == "win32", "Win32 specific tests")
@@ -2146,8 +2135,8 @@ class ProgramPriorityTests(unittest.TestCase):
try:
new_prio = os.getpriority(os.PRIO_PROCESS, os.getpid())
if base >= 19 and new_prio <= 19:
- raise unittest.SkipTest(
- "unable to reliably test setpriority at current nice level of %s" % base)
+ raise unittest.SkipTest("unable to reliably test setpriority "
+ "at current nice level of %s" % base)
else:
self.assertEqual(new_prio, base + 1)
finally:
@@ -2257,8 +2246,7 @@ class TestSendfile(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.key = support.threading_setup()
- with open(support.TESTFN, "wb") as f:
- f.write(cls.DATA)
+ create_file(support.TESTFN, cls.DATA)
@classmethod
def tearDownClass(cls):
@@ -2408,10 +2396,11 @@ class TestSendfile(unittest.TestCase):
def test_trailers(self):
TESTFN2 = support.TESTFN + "2"
file_data = b"abcdef"
- with open(TESTFN2, 'wb') as f:
- f.write(file_data)
- with open(TESTFN2, 'rb')as f:
- self.addCleanup(os.remove, TESTFN2)
+
+ self.addCleanup(support.unlink, TESTFN2)
+ create_file(TESTFN2, file_data)
+
+ with open(TESTFN2, 'rb') as f:
os.sendfile(self.sockno, f.fileno(), 0, len(file_data),
trailers=[b"1234"])
self.client.close()
@@ -2434,35 +2423,37 @@ class TestSendfile(unittest.TestCase):
def supports_extended_attributes():
if not hasattr(os, "setxattr"):
return False
+
try:
- with open(support.TESTFN, "wb") as fp:
+ with open(support.TESTFN, "xb", 0) as fp:
try:
os.setxattr(fp.fileno(), b"user.test", b"")
except OSError:
return False
finally:
support.unlink(support.TESTFN)
- # Kernels < 2.6.39 don't respect setxattr flags.
- kernel_version = platform.release()
- m = re.match("2.6.(\d{1,2})", kernel_version)
- return m is None or int(m.group(1)) >= 39
+
+ return True
@unittest.skipUnless(supports_extended_attributes(),
"no non-broken extended attribute support")
+# Kernels < 2.6.39 don't respect setxattr flags.
+@support.requires_linux_version(2, 6, 39)
class ExtendedAttributeTests(unittest.TestCase):
- def tearDown(self):
- support.unlink(support.TESTFN)
-
def _check_xattrs_str(self, s, getxattr, setxattr, removexattr, listxattr, **kwargs):
fn = support.TESTFN
- open(fn, "wb").close()
+ self.addCleanup(support.unlink, fn)
+ create_file(fn)
+
with self.assertRaises(OSError) as cm:
getxattr(fn, s("user.test"), **kwargs)
self.assertEqual(cm.exception.errno, errno.ENODATA)
+
init_xattr = listxattr(fn)
self.assertIsInstance(init_xattr, list)
+
setxattr(fn, s("user.test"), b"", **kwargs)
xattr = set(init_xattr)
xattr.add("user.test")
@@ -2470,19 +2461,24 @@ class ExtendedAttributeTests(unittest.TestCase):
self.assertEqual(getxattr(fn, b"user.test", **kwargs), b"")
setxattr(fn, s("user.test"), b"hello", os.XATTR_REPLACE, **kwargs)
self.assertEqual(getxattr(fn, b"user.test", **kwargs), b"hello")
+
with self.assertRaises(OSError) as cm:
setxattr(fn, s("user.test"), b"bye", os.XATTR_CREATE, **kwargs)
self.assertEqual(cm.exception.errno, errno.EEXIST)
+
with self.assertRaises(OSError) as cm:
setxattr(fn, s("user.test2"), b"bye", os.XATTR_REPLACE, **kwargs)
self.assertEqual(cm.exception.errno, errno.ENODATA)
+
setxattr(fn, s("user.test2"), b"foo", os.XATTR_CREATE, **kwargs)
xattr.add("user.test2")
self.assertEqual(set(listxattr(fn)), xattr)
removexattr(fn, s("user.test"), **kwargs)
+
with self.assertRaises(OSError) as cm:
getxattr(fn, s("user.test"), **kwargs)
self.assertEqual(cm.exception.errno, errno.ENODATA)
+
xattr.remove("user.test")
self.assertEqual(set(listxattr(fn)), xattr)
self.assertEqual(getxattr(fn, s("user.test2"), **kwargs), b"foo")
@@ -2495,11 +2491,11 @@ class ExtendedAttributeTests(unittest.TestCase):
self.assertEqual(set(listxattr(fn)), set(init_xattr) | set(many))
def _check_xattrs(self, *args, **kwargs):
- def make_bytes(s):
- return bytes(s, "ascii")
self._check_xattrs_str(str, *args, **kwargs)
support.unlink(support.TESTFN)
- self._check_xattrs_str(make_bytes, *args, **kwargs)
+
+ self._check_xattrs_str(os.fsencode, *args, **kwargs)
+ support.unlink(support.TESTFN)
def test_simple(self):
self._check_xattrs(os.getxattr, os.setxattr, os.removexattr,
@@ -2514,10 +2510,10 @@ class ExtendedAttributeTests(unittest.TestCase):
with open(path, "rb") as fp:
return os.getxattr(fp.fileno(), *args)
def setxattr(path, *args):
- with open(path, "wb") as fp:
+ with open(path, "wb", 0) as fp:
os.setxattr(fp.fileno(), *args)
def removexattr(path, *args):
- with open(path, "wb") as fp:
+ with open(path, "wb", 0) as fp:
os.removexattr(fp.fileno(), *args)
def listxattr(path, *args):
with open(path, "rb") as fp:
@@ -2530,36 +2526,39 @@ class Win32DeprecatedBytesAPI(unittest.TestCase):
def test_deprecated(self):
import nt
filename = os.fsencode(support.TESTFN)
- with warnings.catch_warnings():
- warnings.simplefilter("error", DeprecationWarning)
- for func, *args in (
- (nt._getfullpathname, filename),
- (nt._isdir, filename),
- (os.access, filename, os.R_OK),
- (os.chdir, filename),
- (os.chmod, filename, 0o777),
- (os.getcwdb,),
- (os.link, filename, filename),
- (os.listdir, filename),
- (os.lstat, filename),
- (os.mkdir, filename),
- (os.open, filename, os.O_RDONLY),
- (os.rename, filename, filename),
- (os.rmdir, filename),
- (os.startfile, filename),
- (os.stat, filename),
- (os.unlink, filename),
- (os.utime, filename),
- ):
- self.assertRaises(DeprecationWarning, func, *args)
+ for func, *args in (
+ (nt._getfullpathname, filename),
+ (nt._isdir, filename),
+ (os.access, filename, os.R_OK),
+ (os.chdir, filename),
+ (os.chmod, filename, 0o777),
+ (os.getcwdb,),
+ (os.link, filename, filename),
+ (os.listdir, filename),
+ (os.lstat, filename),
+ (os.mkdir, filename),
+ (os.open, filename, os.O_RDONLY),
+ (os.rename, filename, filename),
+ (os.rmdir, filename),
+ (os.startfile, filename),
+ (os.stat, filename),
+ (os.unlink, filename),
+ (os.utime, filename),
+ ):
+ with bytes_filename_warn(True):
+ try:
+ func(*args)
+ except OSError:
+ # ignore OSError, we only care about DeprecationWarning
+ pass
@support.skip_unless_symlink
def test_symlink(self):
+ self.addCleanup(support.unlink, support.TESTFN)
+
filename = os.fsencode(support.TESTFN)
- with warnings.catch_warnings():
- warnings.simplefilter("error", DeprecationWarning)
- self.assertRaises(DeprecationWarning,
- os.symlink, filename, filename)
+ with bytes_filename_warn(True):
+ os.symlink(filename, filename)
@unittest.skipUnless(hasattr(os, 'get_terminal_size'), "requires os.get_terminal_size")
@@ -2697,7 +2696,8 @@ class OSErrorTests(unittest.TestCase):
for filenames, func, *func_args in funcs:
for name in filenames:
try:
- func(name, *func_args)
+ with bytes_filename_warn(False):
+ func(name, *func_args)
except OSError as err:
self.assertIs(err.filename, name)
else:
@@ -2820,6 +2820,8 @@ class ExportsTests(unittest.TestCase):
class TestScandir(unittest.TestCase):
+ check_no_resource_warning = support.check_no_resource_warning
+
def setUp(self):
self.path = os.path.realpath(support.TESTFN)
self.addCleanup(support.rmtree, self.path)
@@ -2827,8 +2829,7 @@ class TestScandir(unittest.TestCase):
def create_file(self, name="file.txt"):
filename = os.path.join(self.path, name)
- with open(filename, "wb") as fp:
- fp.write(b'python')
+ create_file(filename, b'python')
return filename
def get_entries(self, names):
@@ -3010,7 +3011,8 @@ class TestScandir(unittest.TestCase):
def test_bytes(self):
if os.name == "nt":
# On Windows, os.scandir(bytes) must raise an exception
- self.assertRaises(TypeError, os.scandir, b'.')
+ with bytes_filename_warn(True):
+ self.assertRaises(TypeError, os.scandir, b'.')
return
self.create_file("file.txt")
@@ -3042,6 +3044,56 @@ class TestScandir(unittest.TestCase):
for obj in [1234, 1.234, {}, []]:
self.assertRaises(TypeError, os.scandir, obj)
+ def test_close(self):
+ self.create_file("file.txt")
+ self.create_file("file2.txt")
+ iterator = os.scandir(self.path)
+ next(iterator)
+ iterator.close()
+ # multiple closes
+ iterator.close()
+ with self.check_no_resource_warning():
+ del iterator
+
+ def test_context_manager(self):
+ self.create_file("file.txt")
+ self.create_file("file2.txt")
+ with os.scandir(self.path) as iterator:
+ next(iterator)
+ with self.check_no_resource_warning():
+ del iterator
+
+ def test_context_manager_close(self):
+ self.create_file("file.txt")
+ self.create_file("file2.txt")
+ with os.scandir(self.path) as iterator:
+ next(iterator)
+ iterator.close()
+
+ def test_context_manager_exception(self):
+ self.create_file("file.txt")
+ self.create_file("file2.txt")
+ with self.assertRaises(ZeroDivisionError):
+ with os.scandir(self.path) as iterator:
+ next(iterator)
+ 1/0
+ with self.check_no_resource_warning():
+ del iterator
+
+ def test_resource_warning(self):
+ self.create_file("file.txt")
+ self.create_file("file2.txt")
+ iterator = os.scandir(self.path)
+ next(iterator)
+ with self.assertWarns(ResourceWarning):
+ del iterator
+ support.gc_collect()
+ # exhausted iterator
+ iterator = os.scandir(self.path)
+ list(iterator)
+ with self.check_no_resource_warning():
+ del iterator
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/test/test_parser.py b/Lib/test/test_parser.py
index 3d301b4924..72692067fe 100644
--- a/Lib/test/test_parser.py
+++ b/Lib/test/test_parser.py
@@ -1,6 +1,5 @@
import parser
import unittest
-import sys
import operator
import struct
from test import support
diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py
index fa96d9f882..fbbd448f65 100644
--- a/Lib/test/test_pathlib.py
+++ b/Lib/test/test_pathlib.py
@@ -1474,14 +1474,14 @@ class _BasePathTest(object):
self.assertEqual(set(p.glob("dirA/../file*")), { P(BASE, "dirA/../fileA") })
self.assertEqual(set(p.glob("../xyzzy")), set())
- def _check_resolve_relative(self, p, expected):
- q = p.resolve()
- self.assertEqual(q, expected)
- def _check_resolve_absolute(self, p, expected):
+ def _check_resolve(self, p, expected):
q = p.resolve()
self.assertEqual(q, expected)
+ # this can be used to check both relative and absolute resolutions
+ _check_resolve_relative = _check_resolve_absolute = _check_resolve
+
@with_symlinks
def test_resolve_common(self):
P = self.cls
diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py
index 45ba5a9685..a63ccd83ca 100644
--- a/Lib/test/test_pdb.py
+++ b/Lib/test/test_pdb.py
@@ -558,7 +558,6 @@ def test_pdb_continue_in_bottomframe():
def pdb_invoke(method, arg):
"""Run pdb.method(arg)."""
- import pdb
getattr(pdb.Pdb(nosigint=True), method)(arg)
diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py
index 41e5091fab..b0336407c3 100644
--- a/Lib/test/test_peepholer.py
+++ b/Lib/test/test_peepholer.py
@@ -1,9 +1,8 @@
import dis
import re
import sys
-from io import StringIO
+import textwrap
import unittest
-from math import copysign
from test.bytecode_helper import BytecodeTestCase
@@ -30,22 +29,25 @@ class TestTranforms(BytecodeTestCase):
def test_global_as_constant(self):
# LOAD_GLOBAL None/True/False --> LOAD_CONST None/True/False
- def f(x):
- None
- None
+ def f():
+ x = None
+ x = None
return x
- def g(x):
- True
+ def g():
+ x = True
return x
- def h(x):
- False
+ def h():
+ x = False
return x
+
for func, elem in ((f, None), (g, True), (h, False)):
self.assertNotInBytecode(func, 'LOAD_GLOBAL')
self.assertInBytecode(func, 'LOAD_CONST', elem)
+
def f():
'Adding a docstring made this test fail in Py2.5.0'
return None
+
self.assertNotInBytecode(f, 'LOAD_GLOBAL')
self.assertInBytecode(f, 'LOAD_CONST', None)
diff --git a/Lib/test/test_pep3151.py b/Lib/test/test_pep3151.py
index 7b0d465425..8649596790 100644
--- a/Lib/test/test_pep3151.py
+++ b/Lib/test/test_pep3151.py
@@ -2,7 +2,6 @@ import builtins
import os
import select
import socket
-import sys
import unittest
import errno
from errno import EEXIST
diff --git a/Lib/test/test_pep352.py b/Lib/test/test_pep352.py
index 7c98c460b9..27d514fe2e 100644
--- a/Lib/test/test_pep352.py
+++ b/Lib/test/test_pep352.py
@@ -1,6 +1,5 @@
import unittest
import builtins
-import warnings
import os
from platform import system as platform_system
diff --git a/Lib/test/test_pickle.py b/Lib/test/test_pickle.py
index ee7a667d06..e2ba1ad77a 100644
--- a/Lib/test/test_pickle.py
+++ b/Lib/test/test_pickle.py
@@ -33,8 +33,6 @@ class PyUnpicklerTests(AbstractUnpickleTests):
unpickler = pickle._Unpickler
bad_stack_errors = (IndexError,)
- bad_mark_errors = (IndexError, pickle.UnpicklingError,
- TypeError, AttributeError, EOFError)
truncated_errors = (pickle.UnpicklingError, EOFError,
AttributeError, ValueError,
struct.error, IndexError, ImportError)
@@ -69,8 +67,6 @@ class InMemoryPickleTests(AbstractPickleTests, AbstractUnpickleTests,
pickler = pickle._Pickler
unpickler = pickle._Unpickler
bad_stack_errors = (pickle.UnpicklingError, IndexError)
- bad_mark_errors = (pickle.UnpicklingError, IndexError,
- TypeError, AttributeError, EOFError)
truncated_errors = (pickle.UnpicklingError, EOFError,
AttributeError, ValueError,
struct.error, IndexError, ImportError)
@@ -132,7 +128,6 @@ if has_c_implementation:
class CUnpicklerTests(PyUnpicklerTests):
unpickler = _pickle.Unpickler
bad_stack_errors = (pickle.UnpicklingError,)
- bad_mark_errors = (EOFError,)
truncated_errors = (pickle.UnpicklingError, EOFError,
AttributeError, ValueError)
diff --git a/Lib/test/test_pickletools.py b/Lib/test/test_pickletools.py
index bbe6875545..86bebfa026 100644
--- a/Lib/test/test_pickletools.py
+++ b/Lib/test/test_pickletools.py
@@ -1,9 +1,9 @@
-import struct
import pickle
import pickletools
from test import support
from test.pickletester import AbstractPickleTests
from test.pickletester import AbstractPickleModuleTests
+import unittest
class OptimizedPickleTests(AbstractPickleTests, AbstractPickleModuleTests):
@@ -59,8 +59,40 @@ class OptimizedPickleTests(AbstractPickleTests, AbstractPickleModuleTests):
self.assertNotIn(pickle.BINPUT, pickled2)
+class MiscTestCase(unittest.TestCase):
+ def test__all__(self):
+ blacklist = {'bytes_types',
+ 'UP_TO_NEWLINE', 'TAKEN_FROM_ARGUMENT1',
+ 'TAKEN_FROM_ARGUMENT4', 'TAKEN_FROM_ARGUMENT4U',
+ 'TAKEN_FROM_ARGUMENT8U', 'ArgumentDescriptor',
+ 'read_uint1', 'read_uint2', 'read_int4', 'read_uint4',
+ 'read_uint8', 'read_stringnl', 'read_stringnl_noescape',
+ 'read_stringnl_noescape_pair', 'read_string1',
+ 'read_string4', 'read_bytes1', 'read_bytes4',
+ 'read_bytes8', 'read_unicodestringnl',
+ 'read_unicodestring1', 'read_unicodestring4',
+ 'read_unicodestring8', 'read_decimalnl_short',
+ 'read_decimalnl_long', 'read_floatnl', 'read_float8',
+ 'read_long1', 'read_long4',
+ 'uint1', 'uint2', 'int4', 'uint4', 'uint8', 'stringnl',
+ 'stringnl_noescape', 'stringnl_noescape_pair', 'string1',
+ 'string4', 'bytes1', 'bytes4', 'bytes8',
+ 'unicodestringnl', 'unicodestring1', 'unicodestring4',
+ 'unicodestring8', 'decimalnl_short', 'decimalnl_long',
+ 'floatnl', 'float8', 'long1', 'long4',
+ 'StackObject',
+ 'pyint', 'pylong', 'pyinteger_or_bool', 'pybool', 'pyfloat',
+ 'pybytes_or_str', 'pystring', 'pybytes', 'pyunicode',
+ 'pynone', 'pytuple', 'pylist', 'pydict', 'pyset',
+ 'pyfrozenset', 'anyobject', 'markobject', 'stackslice',
+ 'OpcodeInfo', 'opcodes', 'code2op',
+ }
+ support.check__all__(self, pickletools, blacklist=blacklist)
+
+
def test_main():
support.run_unittest(OptimizedPickleTests)
+ support.run_unittest(MiscTestCase)
support.run_doctest(pickletools)
diff --git a/Lib/test/test_pipes.py b/Lib/test/test_pipes.py
index 6a7b45fb46..ad01d08481 100644
--- a/Lib/test/test_pipes.py
+++ b/Lib/test/test_pipes.py
@@ -2,6 +2,7 @@ import pipes
import os
import string
import unittest
+import shutil
from test.support import TESTFN, run_unittest, unlink, reap_children
if os.name != 'posix':
@@ -18,6 +19,8 @@ class SimplePipeTests(unittest.TestCase):
unlink(f)
def testSimplePipe1(self):
+ if shutil.which('tr') is None:
+ self.skipTest('tr is not available')
t = pipes.Template()
t.append(s_command, pipes.STDIN_STDOUT)
f = t.open(TESTFN, 'w')
@@ -27,6 +30,8 @@ class SimplePipeTests(unittest.TestCase):
self.assertEqual(f.read(), 'HELLO WORLD #1')
def testSimplePipe2(self):
+ if shutil.which('tr') is None:
+ self.skipTest('tr is not available')
with open(TESTFN, 'w') as f:
f.write('hello world #2')
t = pipes.Template()
@@ -36,6 +41,8 @@ class SimplePipeTests(unittest.TestCase):
self.assertEqual(f.read(), 'HELLO WORLD #2')
def testSimplePipe3(self):
+ if shutil.which('tr') is None:
+ self.skipTest('tr is not available')
with open(TESTFN, 'w') as f:
f.write('hello world #2')
t = pipes.Template()
diff --git a/Lib/test/test_plistlib.py b/Lib/test/test_plistlib.py
index 16114f9f6f..662ed904b0 100644
--- a/Lib/test/test_plistlib.py
+++ b/Lib/test/test_plistlib.py
@@ -7,7 +7,6 @@ import datetime
import codecs
import binascii
import collections
-import struct
from test import support
from io import BytesIO
diff --git a/Lib/test/test_poplib.py b/Lib/test/test_poplib.py
index bceeb93ad1..7b9606d359 100644
--- a/Lib/test/test_poplib.py
+++ b/Lib/test/test_poplib.py
@@ -8,7 +8,6 @@ import asyncore
import asynchat
import socket
import os
-import time
import errno
from unittest import TestCase, skipUnless
diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py
index 2a59c38174..6a1c82917a 100644
--- a/Lib/test/test_posix.py
+++ b/Lib/test/test_posix.py
@@ -11,7 +11,6 @@ import time
import os
import platform
import pwd
-import shutil
import stat
import tempfile
import unittest
@@ -411,7 +410,7 @@ class PosixTester(unittest.TestCase):
self.assertTrue(posix.stat(bytearray(os.fsencode(support.TESTFN))))
self.assertRaisesRegex(TypeError,
- 'can\'t specify None for path argument',
+ 'should be string, bytes or integer, not',
posix.stat, None)
self.assertRaisesRegex(TypeError,
'should be string, bytes or integer, not',
@@ -863,9 +862,9 @@ class PosixTester(unittest.TestCase):
self.assertEqual(s1, s2)
s2 = posix.stat(support.TESTFN, dir_fd=None)
self.assertEqual(s1, s2)
- self.assertRaisesRegex(TypeError, 'should be integer, not',
+ self.assertRaisesRegex(TypeError, 'should be integer or None, not',
posix.stat, support.TESTFN, dir_fd=posix.getcwd())
- self.assertRaisesRegex(TypeError, 'should be integer, not',
+ self.assertRaisesRegex(TypeError, 'should be integer or None, not',
posix.stat, support.TESTFN, dir_fd=float(f))
self.assertRaises(OverflowError,
posix.stat, support.TESTFN, dir_fd=10**20)
diff --git a/Lib/test/test_posixpath.py b/Lib/test/test_posixpath.py
index acf110204c..4ff445d400 100644
--- a/Lib/test/test_posixpath.py
+++ b/Lib/test/test_posixpath.py
@@ -1,7 +1,5 @@
-import itertools
import os
import posixpath
-import sys
import unittest
import warnings
from posixpath import realpath, abspath, dirname, basename
diff --git a/Lib/test/test_pow.py b/Lib/test/test_pow.py
index 6feac409bd..ce99fe6410 100644
--- a/Lib/test/test_pow.py
+++ b/Lib/test/test_pow.py
@@ -1,4 +1,4 @@
-import test.support, unittest
+import unittest
class PowTest(unittest.TestCase):
diff --git a/Lib/test/test_pty.py b/Lib/test/test_pty.py
index ef5e99ee26..15f88e4fcd 100644
--- a/Lib/test/test_pty.py
+++ b/Lib/test/test_pty.py
@@ -277,7 +277,6 @@ class SmallPtyTests(unittest.TestCase):
socketpair = self._socketpair()
masters = [s.fileno() for s in socketpair]
- os.close(masters[1])
socketpair[1].close()
os.close(write_to_stdin_fd)
diff --git a/Lib/test/test_pulldom.py b/Lib/test/test_pulldom.py
index 1932c6bb99..3d89e3adda 100644
--- a/Lib/test/test_pulldom.py
+++ b/Lib/test/test_pulldom.py
@@ -1,6 +1,5 @@
import io
import unittest
-import sys
import xml.sax
from xml.sax.xmlreader import AttributesImpl
diff --git a/Lib/test/test_pyclbr.py b/Lib/test/test_pyclbr.py
index 6ffbbbda27..06c10c17af 100644
--- a/Lib/test/test_pyclbr.py
+++ b/Lib/test/test_pyclbr.py
@@ -156,7 +156,7 @@ class PyclbrTest(TestCase):
# These were once about the 10 longest modules
cm('random', ignore=('Random',)) # from _random import Random as CoreGenerator
cm('cgi', ignore=('log',)) # set with = in module
- cm('pickle')
+ cm('pickle', ignore=('partial',))
cm('aifc', ignore=('openfp', '_aifc_params')) # set with = in module
cm('sre_parse', ignore=('dump', 'groups')) # from sre_constants import *; property
cm('pdb')
diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py
index f284779ba4..083ba2ea90 100644
--- a/Lib/test/test_pydoc.py
+++ b/Lib/test/test_pydoc.py
@@ -841,6 +841,22 @@ class TestDescriptions(unittest.TestCase):
self.assertEqual(self._get_summary_line(t.wrap),
"wrap(text) method of textwrap.TextWrapper instance")
+ def test_field_order_for_named_tuples(self):
+ Person = namedtuple('Person', ['nickname', 'firstname', 'agegroup'])
+ s = pydoc.render_doc(Person)
+ self.assertLess(s.index('nickname'), s.index('firstname'))
+ self.assertLess(s.index('firstname'), s.index('agegroup'))
+
+ class NonIterableFields:
+ _fields = None
+
+ class NonHashableFields:
+ _fields = [[]]
+
+ # Make sure these doesn't fail
+ pydoc.render_doc(NonIterableFields)
+ pydoc.render_doc(NonHashableFields)
+
@requires_docstrings
def test_bound_builtin_method(self):
s = StringIO()
diff --git a/Lib/test/test_quopri.py b/Lib/test/test_quopri.py
index 7cac013446..715544c8a9 100644
--- a/Lib/test/test_quopri.py
+++ b/Lib/test/test_quopri.py
@@ -1,6 +1,6 @@
import unittest
-import sys, os, io, subprocess
+import sys, io, subprocess
import quopri
diff --git a/Lib/test/test_range.py b/Lib/test/test_range.py
index 106c732dd9..e03b570dab 100644
--- a/Lib/test/test_range.py
+++ b/Lib/test/test_range.py
@@ -1,6 +1,6 @@
# Python test set -- built-in functions
-import test.support, unittest
+import unittest
import sys
import pickle
import itertools
diff --git a/Lib/test/test_readline.py b/Lib/test/test_readline.py
index 35330ab076..c1864efaab 100644
--- a/Lib/test/test_readline.py
+++ b/Lib/test/test_readline.py
@@ -1,7 +1,12 @@
"""
Very minimal unittests for parts of the readline module.
"""
+from contextlib import ExitStack
+from errno import EIO
import os
+import selectors
+import subprocess
+import sys
import tempfile
import unittest
from test.support import import_module, unlink
@@ -96,6 +101,65 @@ class TestReadline(unittest.TestCase):
TERM='xterm-256color')
self.assertEqual(stdout, b'')
+ auto_history_script = """\
+import readline
+readline.set_auto_history({})
+input()
+print("History length:", readline.get_current_history_length())
+"""
+
+ def test_auto_history_enabled(self):
+ output = run_pty(self.auto_history_script.format(True))
+ self.assertIn(b"History length: 1\r\n", output)
+
+ def test_auto_history_disabled(self):
+ output = run_pty(self.auto_history_script.format(False))
+ self.assertIn(b"History length: 0\r\n", output)
+
+
+def run_pty(script, input=b"dummy input\r"):
+ pty = import_module('pty')
+ output = bytearray()
+ [master, slave] = pty.openpty()
+ args = (sys.executable, '-c', script)
+ proc = subprocess.Popen(args, stdin=slave, stdout=slave, stderr=slave)
+ os.close(slave)
+ with ExitStack() as cleanup:
+ cleanup.enter_context(proc)
+ def terminate(proc):
+ try:
+ proc.terminate()
+ except ProcessLookupError:
+ # Workaround for Open/Net BSD bug (Issue 16762)
+ pass
+ cleanup.callback(terminate, proc)
+ cleanup.callback(os.close, master)
+ # Avoid using DefaultSelector and PollSelector. Kqueue() does not
+ # work with pseudo-terminals on OS X < 10.9 (Issue 20365) and Open
+ # BSD (Issue 20667). Poll() does not work with OS X 10.6 or 10.4
+ # either (Issue 20472). Hopefully the file descriptor is low enough
+ # to use with select().
+ sel = cleanup.enter_context(selectors.SelectSelector())
+ sel.register(master, selectors.EVENT_READ | selectors.EVENT_WRITE)
+ os.set_blocking(master, False)
+ while True:
+ for [_, events] in sel.select():
+ if events & selectors.EVENT_READ:
+ try:
+ chunk = os.read(master, 0x10000)
+ except OSError as err:
+ # Linux raises EIO when the slave is closed
+ if err.errno != EIO:
+ raise
+ chunk = b""
+ if not chunk:
+ return output
+ output.extend(chunk)
+ if events & selectors.EVENT_WRITE:
+ input = input[os.write(master, input):]
+ if not input:
+ sel.modify(master, selectors.EVENT_READ)
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py
index a398a4f836..c11408df7f 100644
--- a/Lib/test/test_regrtest.py
+++ b/Lib/test/test_regrtest.py
@@ -1,21 +1,48 @@
"""
Tests of regrtest.py.
+
+Note: test_regrtest cannot be run twice in parallel.
"""
-import argparse
+import contextlib
import faulthandler
-import getopt
+import io
import os.path
+import platform
+import re
+import subprocess
+import sys
+import sysconfig
+import tempfile
+import textwrap
import unittest
-from test import regrtest, support
+from test import libregrtest
+from test import support
-class ParseArgsTestCase(unittest.TestCase):
- """Test regrtest's argument parsing."""
+Py_DEBUG = hasattr(sys, 'getobjects')
+ROOT_DIR = os.path.join(os.path.dirname(__file__), '..', '..')
+ROOT_DIR = os.path.abspath(os.path.normpath(ROOT_DIR))
+
+TEST_INTERRUPTED = textwrap.dedent("""
+ from signal import SIGINT
+ try:
+ from _testcapi import raise_signal
+ raise_signal(SIGINT)
+ except ImportError:
+ import os
+ os.kill(os.getpid(), SIGINT)
+ """)
+
+
+class ParseArgsTestCase(unittest.TestCase):
+ """
+ Test regrtest's argument parsing, function _parse_args().
+ """
def checkError(self, args, msg):
with support.captured_stderr() as err, self.assertRaises(SystemExit):
- regrtest._parse_args(args)
+ libregrtest._parse_args(args)
self.assertIn(msg, err.getvalue())
def test_help(self):
@@ -23,82 +50,82 @@ class ParseArgsTestCase(unittest.TestCase):
with self.subTest(opt=opt):
with support.captured_stdout() as out, \
self.assertRaises(SystemExit):
- regrtest._parse_args([opt])
+ libregrtest._parse_args([opt])
self.assertIn('Run Python regression tests.', out.getvalue())
@unittest.skipUnless(hasattr(faulthandler, 'dump_traceback_later'),
"faulthandler.dump_traceback_later() required")
def test_timeout(self):
- ns = regrtest._parse_args(['--timeout', '4.2'])
+ ns = libregrtest._parse_args(['--timeout', '4.2'])
self.assertEqual(ns.timeout, 4.2)
self.checkError(['--timeout'], 'expected one argument')
self.checkError(['--timeout', 'foo'], 'invalid float value')
def test_wait(self):
- ns = regrtest._parse_args(['--wait'])
+ ns = libregrtest._parse_args(['--wait'])
self.assertTrue(ns.wait)
def test_slaveargs(self):
- ns = regrtest._parse_args(['--slaveargs', '[[], {}]'])
+ ns = libregrtest._parse_args(['--slaveargs', '[[], {}]'])
self.assertEqual(ns.slaveargs, '[[], {}]')
self.checkError(['--slaveargs'], 'expected one argument')
def test_start(self):
for opt in '-S', '--start':
with self.subTest(opt=opt):
- ns = regrtest._parse_args([opt, 'foo'])
+ ns = libregrtest._parse_args([opt, 'foo'])
self.assertEqual(ns.start, 'foo')
self.checkError([opt], 'expected one argument')
def test_verbose(self):
- ns = regrtest._parse_args(['-v'])
+ ns = libregrtest._parse_args(['-v'])
self.assertEqual(ns.verbose, 1)
- ns = regrtest._parse_args(['-vvv'])
+ ns = libregrtest._parse_args(['-vvv'])
self.assertEqual(ns.verbose, 3)
- ns = regrtest._parse_args(['--verbose'])
+ ns = libregrtest._parse_args(['--verbose'])
self.assertEqual(ns.verbose, 1)
- ns = regrtest._parse_args(['--verbose'] * 3)
+ ns = libregrtest._parse_args(['--verbose'] * 3)
self.assertEqual(ns.verbose, 3)
- ns = regrtest._parse_args([])
+ ns = libregrtest._parse_args([])
self.assertEqual(ns.verbose, 0)
def test_verbose2(self):
for opt in '-w', '--verbose2':
with self.subTest(opt=opt):
- ns = regrtest._parse_args([opt])
+ ns = libregrtest._parse_args([opt])
self.assertTrue(ns.verbose2)
def test_verbose3(self):
for opt in '-W', '--verbose3':
with self.subTest(opt=opt):
- ns = regrtest._parse_args([opt])
+ ns = libregrtest._parse_args([opt])
self.assertTrue(ns.verbose3)
def test_quiet(self):
for opt in '-q', '--quiet':
with self.subTest(opt=opt):
- ns = regrtest._parse_args([opt])
+ ns = libregrtest._parse_args([opt])
self.assertTrue(ns.quiet)
self.assertEqual(ns.verbose, 0)
def test_slow(self):
for opt in '-o', '--slow':
with self.subTest(opt=opt):
- ns = regrtest._parse_args([opt])
+ ns = libregrtest._parse_args([opt])
self.assertTrue(ns.print_slow)
def test_header(self):
- ns = regrtest._parse_args(['--header'])
+ ns = libregrtest._parse_args(['--header'])
self.assertTrue(ns.header)
def test_randomize(self):
for opt in '-r', '--randomize':
with self.subTest(opt=opt):
- ns = regrtest._parse_args([opt])
+ ns = libregrtest._parse_args([opt])
self.assertTrue(ns.randomize)
def test_randseed(self):
- ns = regrtest._parse_args(['--randseed', '12345'])
+ ns = libregrtest._parse_args(['--randseed', '12345'])
self.assertEqual(ns.random_seed, 12345)
self.assertTrue(ns.randomize)
self.checkError(['--randseed'], 'expected one argument')
@@ -107,7 +134,7 @@ class ParseArgsTestCase(unittest.TestCase):
def test_fromfile(self):
for opt in '-f', '--fromfile':
with self.subTest(opt=opt):
- ns = regrtest._parse_args([opt, 'foo'])
+ ns = libregrtest._parse_args([opt, 'foo'])
self.assertEqual(ns.fromfile, 'foo')
self.checkError([opt], 'expected one argument')
self.checkError([opt, 'foo', '-s'], "don't go together")
@@ -115,42 +142,42 @@ class ParseArgsTestCase(unittest.TestCase):
def test_exclude(self):
for opt in '-x', '--exclude':
with self.subTest(opt=opt):
- ns = regrtest._parse_args([opt])
+ ns = libregrtest._parse_args([opt])
self.assertTrue(ns.exclude)
def test_single(self):
for opt in '-s', '--single':
with self.subTest(opt=opt):
- ns = regrtest._parse_args([opt])
+ ns = libregrtest._parse_args([opt])
self.assertTrue(ns.single)
self.checkError([opt, '-f', 'foo'], "don't go together")
def test_match(self):
for opt in '-m', '--match':
with self.subTest(opt=opt):
- ns = regrtest._parse_args([opt, 'pattern'])
+ ns = libregrtest._parse_args([opt, 'pattern'])
self.assertEqual(ns.match_tests, 'pattern')
self.checkError([opt], 'expected one argument')
def test_failfast(self):
for opt in '-G', '--failfast':
with self.subTest(opt=opt):
- ns = regrtest._parse_args([opt, '-v'])
+ ns = libregrtest._parse_args([opt, '-v'])
self.assertTrue(ns.failfast)
- ns = regrtest._parse_args([opt, '-W'])
+ ns = libregrtest._parse_args([opt, '-W'])
self.assertTrue(ns.failfast)
self.checkError([opt], '-G/--failfast needs either -v or -W')
def test_use(self):
for opt in '-u', '--use':
with self.subTest(opt=opt):
- ns = regrtest._parse_args([opt, 'gui,network'])
+ ns = libregrtest._parse_args([opt, 'gui,network'])
self.assertEqual(ns.use_resources, ['gui', 'network'])
- ns = regrtest._parse_args([opt, 'gui,none,network'])
+ ns = libregrtest._parse_args([opt, 'gui,none,network'])
self.assertEqual(ns.use_resources, ['network'])
- expected = list(regrtest.RESOURCE_NAMES)
+ expected = list(libregrtest.RESOURCE_NAMES)
expected.remove('gui')
- ns = regrtest._parse_args([opt, 'all,-gui'])
+ ns = libregrtest._parse_args([opt, 'all,-gui'])
self.assertEqual(ns.use_resources, expected)
self.checkError([opt], 'expected one argument')
self.checkError([opt, 'foo'], 'invalid resource')
@@ -158,31 +185,31 @@ class ParseArgsTestCase(unittest.TestCase):
def test_memlimit(self):
for opt in '-M', '--memlimit':
with self.subTest(opt=opt):
- ns = regrtest._parse_args([opt, '4G'])
+ ns = libregrtest._parse_args([opt, '4G'])
self.assertEqual(ns.memlimit, '4G')
self.checkError([opt], 'expected one argument')
def test_testdir(self):
- ns = regrtest._parse_args(['--testdir', 'foo'])
+ ns = libregrtest._parse_args(['--testdir', 'foo'])
self.assertEqual(ns.testdir, os.path.join(support.SAVEDCWD, 'foo'))
self.checkError(['--testdir'], 'expected one argument')
def test_runleaks(self):
for opt in '-L', '--runleaks':
with self.subTest(opt=opt):
- ns = regrtest._parse_args([opt])
+ ns = libregrtest._parse_args([opt])
self.assertTrue(ns.runleaks)
def test_huntrleaks(self):
for opt in '-R', '--huntrleaks':
with self.subTest(opt=opt):
- ns = regrtest._parse_args([opt, ':'])
+ ns = libregrtest._parse_args([opt, ':'])
self.assertEqual(ns.huntrleaks, (5, 4, 'reflog.txt'))
- ns = regrtest._parse_args([opt, '6:'])
+ ns = libregrtest._parse_args([opt, '6:'])
self.assertEqual(ns.huntrleaks, (6, 4, 'reflog.txt'))
- ns = regrtest._parse_args([opt, ':3'])
+ ns = libregrtest._parse_args([opt, ':3'])
self.assertEqual(ns.huntrleaks, (5, 3, 'reflog.txt'))
- ns = regrtest._parse_args([opt, '6:3:leaks.log'])
+ ns = libregrtest._parse_args([opt, '6:3:leaks.log'])
self.assertEqual(ns.huntrleaks, (6, 3, 'leaks.log'))
self.checkError([opt], 'expected one argument')
self.checkError([opt, '6'],
@@ -193,24 +220,23 @@ class ParseArgsTestCase(unittest.TestCase):
def test_multiprocess(self):
for opt in '-j', '--multiprocess':
with self.subTest(opt=opt):
- ns = regrtest._parse_args([opt, '2'])
+ ns = libregrtest._parse_args([opt, '2'])
self.assertEqual(ns.use_mp, 2)
self.checkError([opt], 'expected one argument')
self.checkError([opt, 'foo'], 'invalid int value')
self.checkError([opt, '2', '-T'], "don't go together")
self.checkError([opt, '2', '-l'], "don't go together")
- self.checkError([opt, '2', '-M', '4G'], "don't go together")
def test_coverage(self):
for opt in '-T', '--coverage':
with self.subTest(opt=opt):
- ns = regrtest._parse_args([opt])
+ ns = libregrtest._parse_args([opt])
self.assertTrue(ns.trace)
def test_coverdir(self):
for opt in '-D', '--coverdir':
with self.subTest(opt=opt):
- ns = regrtest._parse_args([opt, 'foo'])
+ ns = libregrtest._parse_args([opt, 'foo'])
self.assertEqual(ns.coverdir,
os.path.join(support.SAVEDCWD, 'foo'))
self.checkError([opt], 'expected one argument')
@@ -218,13 +244,13 @@ class ParseArgsTestCase(unittest.TestCase):
def test_nocoverdir(self):
for opt in '-N', '--nocoverdir':
with self.subTest(opt=opt):
- ns = regrtest._parse_args([opt])
+ ns = libregrtest._parse_args([opt])
self.assertIsNone(ns.coverdir)
def test_threshold(self):
for opt in '-t', '--threshold':
with self.subTest(opt=opt):
- ns = regrtest._parse_args([opt, '1000'])
+ ns = libregrtest._parse_args([opt, '1000'])
self.assertEqual(ns.threshold, 1000)
self.checkError([opt], 'expected one argument')
self.checkError([opt, 'foo'], 'invalid int value')
@@ -232,13 +258,16 @@ class ParseArgsTestCase(unittest.TestCase):
def test_nowindows(self):
for opt in '-n', '--nowindows':
with self.subTest(opt=opt):
- ns = regrtest._parse_args([opt])
+ with contextlib.redirect_stderr(io.StringIO()) as stderr:
+ ns = libregrtest._parse_args([opt])
self.assertTrue(ns.nowindows)
+ err = stderr.getvalue()
+ self.assertIn('the --nowindows (-n) option is deprecated', err)
def test_forever(self):
for opt in '-F', '--forever':
with self.subTest(opt=opt):
- ns = regrtest._parse_args([opt])
+ ns = libregrtest._parse_args([opt])
self.assertTrue(ns.forever)
@@ -246,30 +275,503 @@ class ParseArgsTestCase(unittest.TestCase):
self.checkError(['--xxx'], 'usage:')
def test_long_option__partial(self):
- ns = regrtest._parse_args(['--qui'])
+ ns = libregrtest._parse_args(['--qui'])
self.assertTrue(ns.quiet)
self.assertEqual(ns.verbose, 0)
def test_two_options(self):
- ns = regrtest._parse_args(['--quiet', '--exclude'])
+ ns = libregrtest._parse_args(['--quiet', '--exclude'])
self.assertTrue(ns.quiet)
self.assertEqual(ns.verbose, 0)
self.assertTrue(ns.exclude)
def test_option_with_empty_string_value(self):
- ns = regrtest._parse_args(['--start', ''])
+ ns = libregrtest._parse_args(['--start', ''])
self.assertEqual(ns.start, '')
def test_arg(self):
- ns = regrtest._parse_args(['foo'])
+ ns = libregrtest._parse_args(['foo'])
self.assertEqual(ns.args, ['foo'])
def test_option_and_arg(self):
- ns = regrtest._parse_args(['--quiet', 'foo'])
+ ns = libregrtest._parse_args(['--quiet', 'foo'])
self.assertTrue(ns.quiet)
self.assertEqual(ns.verbose, 0)
self.assertEqual(ns.args, ['foo'])
+class BaseTestCase(unittest.TestCase):
+ TEST_UNIQUE_ID = 1
+ TESTNAME_PREFIX = 'test_regrtest_'
+ TESTNAME_REGEX = r'test_[a-zA-Z0-9_]+'
+
+ def setUp(self):
+ self.testdir = os.path.realpath(os.path.dirname(__file__))
+
+ self.tmptestdir = tempfile.mkdtemp()
+ self.addCleanup(support.rmtree, self.tmptestdir)
+
+ def create_test(self, name=None, code=''):
+ if not name:
+ name = 'noop%s' % BaseTestCase.TEST_UNIQUE_ID
+ BaseTestCase.TEST_UNIQUE_ID += 1
+
+ # test_regrtest cannot be run twice in parallel because
+ # of setUp() and create_test()
+ name = self.TESTNAME_PREFIX + name
+ path = os.path.join(self.tmptestdir, name + '.py')
+
+ self.addCleanup(support.unlink, path)
+ # Use 'x' mode to ensure that we do not override existing tests
+ try:
+ with open(path, 'x', encoding='utf-8') as fp:
+ fp.write(code)
+ except PermissionError as exc:
+ if not sysconfig.is_python_build():
+ self.skipTest("cannot write %s: %s" % (path, exc))
+ raise
+ return name
+
+ def regex_search(self, regex, output):
+ match = re.search(regex, output, re.MULTILINE)
+ if not match:
+ self.fail("%r not found in %r" % (regex, output))
+ return match
+
+ def check_line(self, output, regex):
+ regex = re.compile(r'^' + regex, re.MULTILINE)
+ self.assertRegex(output, regex)
+
+ def parse_executed_tests(self, output):
+ regex = (r'^[0-9]+:[0-9]+:[0-9]+ \[ *[0-9]+(?:/ *[0-9]+)?\] (%s)'
+ % self.TESTNAME_REGEX)
+ parser = re.finditer(regex, output, re.MULTILINE)
+ return list(match.group(1) for match in parser)
+
+ def check_executed_tests(self, output, tests, skipped=(), failed=(),
+ omitted=(), randomize=False):
+ if isinstance(tests, str):
+ tests = [tests]
+ if isinstance(skipped, str):
+ skipped = [skipped]
+ if isinstance(failed, str):
+ failed = [failed]
+ if isinstance(omitted, str):
+ omitted = [omitted]
+ ntest = len(tests)
+ nskipped = len(skipped)
+ nfailed = len(failed)
+ nomitted = len(omitted)
+
+ executed = self.parse_executed_tests(output)
+ if randomize:
+ self.assertEqual(set(executed), set(tests), output)
+ else:
+ self.assertEqual(executed, tests, output)
+
+ def plural(count):
+ return 's' if count != 1 else ''
+
+ def list_regex(line_format, tests):
+ count = len(tests)
+ names = ' '.join(sorted(tests))
+ regex = line_format % (count, plural(count))
+ regex = r'%s:\n %s$' % (regex, names)
+ return regex
+
+ if skipped:
+ regex = list_regex('%s test%s skipped', skipped)
+ self.check_line(output, regex)
+
+ if failed:
+ regex = list_regex('%s test%s failed', failed)
+ self.check_line(output, regex)
+
+ if omitted:
+ regex = list_regex('%s test%s omitted', omitted)
+ self.check_line(output, regex)
+
+ good = ntest - nskipped - nfailed - nomitted
+ if good:
+ regex = r'%s test%s OK\.$' % (good, plural(good))
+ if not skipped and not failed and good > 1:
+ regex = 'All %s' % regex
+ self.check_line(output, regex)
+
+ def parse_random_seed(self, output):
+ match = self.regex_search(r'Using random seed ([0-9]+)', output)
+ randseed = int(match.group(1))
+ self.assertTrue(0 <= randseed <= 10000000, randseed)
+ return randseed
+
+ def run_command(self, args, input=None, exitcode=0, **kw):
+ if not input:
+ input = ''
+ if 'stderr' not in kw:
+ kw['stderr'] = subprocess.PIPE
+ proc = subprocess.run(args,
+ universal_newlines=True,
+ input=input,
+ stdout=subprocess.PIPE,
+ **kw)
+ if proc.returncode != exitcode:
+ msg = ("Command %s failed with exit code %s\n"
+ "\n"
+ "stdout:\n"
+ "---\n"
+ "%s\n"
+ "---\n"
+ % (str(args), proc.returncode, proc.stdout))
+ if proc.stderr:
+ msg += ("\n"
+ "stderr:\n"
+ "---\n"
+ "%s"
+ "---\n"
+ % proc.stderr)
+ self.fail(msg)
+ return proc
+
+
+ def run_python(self, args, **kw):
+ args = [sys.executable, '-X', 'faulthandler', '-I', *args]
+ proc = self.run_command(args, **kw)
+ return proc.stdout
+
+
+class ProgramsTestCase(BaseTestCase):
+ """
+ Test various ways to run the Python test suite. Use options close
+ to options used on the buildbot.
+ """
+
+ NTEST = 4
+
+ def setUp(self):
+ super().setUp()
+
+ # Create NTEST tests doing nothing
+ self.tests = [self.create_test() for index in range(self.NTEST)]
+
+ self.python_args = ['-Wd', '-E', '-bb']
+ self.regrtest_args = ['-uall', '-rwW',
+ '--testdir=%s' % self.tmptestdir]
+ if hasattr(faulthandler, 'dump_traceback_later'):
+ self.regrtest_args.extend(('--timeout', '3600', '-j4'))
+ if sys.platform == 'win32':
+ self.regrtest_args.append('-n')
+
+ def check_output(self, output):
+ self.parse_random_seed(output)
+ self.check_executed_tests(output, self.tests, randomize=True)
+
+ def run_tests(self, args):
+ output = self.run_python(args)
+ self.check_output(output)
+
+ def test_script_regrtest(self):
+ # Lib/test/regrtest.py
+ script = os.path.join(self.testdir, 'regrtest.py')
+
+ args = [*self.python_args, script, *self.regrtest_args, *self.tests]
+ self.run_tests(args)
+
+ def test_module_test(self):
+ # -m test
+ args = [*self.python_args, '-m', 'test',
+ *self.regrtest_args, *self.tests]
+ self.run_tests(args)
+
+ def test_module_regrtest(self):
+ # -m test.regrtest
+ args = [*self.python_args, '-m', 'test.regrtest',
+ *self.regrtest_args, *self.tests]
+ self.run_tests(args)
+
+ def test_module_autotest(self):
+ # -m test.autotest
+ args = [*self.python_args, '-m', 'test.autotest',
+ *self.regrtest_args, *self.tests]
+ self.run_tests(args)
+
+ def test_module_from_test_autotest(self):
+ # from test import autotest
+ code = 'from test import autotest'
+ args = [*self.python_args, '-c', code,
+ *self.regrtest_args, *self.tests]
+ self.run_tests(args)
+
+ def test_script_autotest(self):
+ # Lib/test/autotest.py
+ script = os.path.join(self.testdir, 'autotest.py')
+ args = [*self.python_args, script, *self.regrtest_args, *self.tests]
+ self.run_tests(args)
+
+ @unittest.skipUnless(sysconfig.is_python_build(),
+ 'run_tests.py script is not installed')
+ def test_tools_script_run_tests(self):
+ # Tools/scripts/run_tests.py
+ script = os.path.join(ROOT_DIR, 'Tools', 'scripts', 'run_tests.py')
+ args = [script, *self.regrtest_args, *self.tests]
+ self.run_tests(args)
+
+ def run_batch(self, *args):
+ proc = self.run_command(args)
+ self.check_output(proc.stdout)
+
+ @unittest.skipUnless(sysconfig.is_python_build(),
+ 'test.bat script is not installed')
+ @unittest.skipUnless(sys.platform == 'win32', 'Windows only')
+ def test_tools_buildbot_test(self):
+ # Tools\buildbot\test.bat
+ script = os.path.join(ROOT_DIR, 'Tools', 'buildbot', 'test.bat')
+ test_args = ['--testdir=%s' % self.tmptestdir]
+ if platform.architecture()[0] == '64bit':
+ test_args.append('-x64') # 64-bit build
+ if not Py_DEBUG:
+ test_args.append('+d') # Release build, use python.exe
+ self.run_batch(script, *test_args, *self.tests)
+
+ @unittest.skipUnless(sys.platform == 'win32', 'Windows only')
+ def test_pcbuild_rt(self):
+ # PCbuild\rt.bat
+ script = os.path.join(ROOT_DIR, r'PCbuild\rt.bat')
+ rt_args = ["-q"] # Quick, don't run tests twice
+ if platform.architecture()[0] == '64bit':
+ rt_args.append('-x64') # 64-bit build
+ if Py_DEBUG:
+ rt_args.append('-d') # Debug build, use python_d.exe
+ self.run_batch(script, *rt_args, *self.regrtest_args, *self.tests)
+
+
+class ArgsTestCase(BaseTestCase):
+ """
+ Test arguments of the Python test suite.
+ """
+
+ def run_tests(self, *testargs, **kw):
+ cmdargs = ['-m', 'test', '--testdir=%s' % self.tmptestdir, *testargs]
+ return self.run_python(cmdargs, **kw)
+
+ def test_failing_test(self):
+ # test a failing test
+ code = textwrap.dedent("""
+ import unittest
+
+ class FailingTest(unittest.TestCase):
+ def test_failing(self):
+ self.fail("bug")
+ """)
+ test_ok = self.create_test('ok')
+ test_failing = self.create_test('failing', code=code)
+ tests = [test_ok, test_failing]
+
+ output = self.run_tests(*tests, exitcode=1)
+ self.check_executed_tests(output, tests, failed=test_failing)
+
+ def test_resources(self):
+ # test -u command line option
+ tests = {}
+ for resource in ('audio', 'network'):
+ code = 'from test import support\nsupport.requires(%r)' % resource
+ tests[resource] = self.create_test(resource, code)
+ test_names = sorted(tests.values())
+
+ # -u all: 2 resources enabled
+ output = self.run_tests('-u', 'all', *test_names)
+ self.check_executed_tests(output, test_names)
+
+ # -u audio: 1 resource enabled
+ output = self.run_tests('-uaudio', *test_names)
+ self.check_executed_tests(output, test_names,
+ skipped=tests['network'])
+
+ # no option: 0 resources enabled
+ output = self.run_tests(*test_names)
+ self.check_executed_tests(output, test_names,
+ skipped=test_names)
+
+ def test_random(self):
+ # test -r and --randseed command line option
+ code = textwrap.dedent("""
+ import random
+ print("TESTRANDOM: %s" % random.randint(1, 1000))
+ """)
+ test = self.create_test('random', code)
+
+ # first run to get the output with the random seed
+ output = self.run_tests('-r', test)
+ randseed = self.parse_random_seed(output)
+ match = self.regex_search(r'TESTRANDOM: ([0-9]+)', output)
+ test_random = int(match.group(1))
+
+ # try to reproduce with the random seed
+ output = self.run_tests('-r', '--randseed=%s' % randseed, test)
+ randseed2 = self.parse_random_seed(output)
+ self.assertEqual(randseed2, randseed)
+
+ match = self.regex_search(r'TESTRANDOM: ([0-9]+)', output)
+ test_random2 = int(match.group(1))
+ self.assertEqual(test_random2, test_random)
+
+ def test_fromfile(self):
+ # test --fromfile
+ tests = [self.create_test() for index in range(5)]
+
+ # Write the list of files using a format similar to regrtest output:
+ # [1/2] test_1
+ # [2/2] test_2
+ filename = support.TESTFN
+ self.addCleanup(support.unlink, filename)
+
+ # test format '0:00:00 [2/7] test_opcodes -- test_grammar took 0 sec'
+ with open(filename, "w") as fp:
+ previous = None
+ for index, name in enumerate(tests, 1):
+ line = ("00:00:%02i [%s/%s] %s"
+ % (index, index, len(tests), name))
+ if previous:
+ line += " -- %s took 0 sec" % previous
+ print(line, file=fp)
+ previous = name
+
+ output = self.run_tests('--fromfile', filename)
+ self.check_executed_tests(output, tests)
+
+ # test format '[2/7] test_opcodes'
+ with open(filename, "w") as fp:
+ for index, name in enumerate(tests, 1):
+ print("[%s/%s] %s" % (index, len(tests), name), file=fp)
+
+ output = self.run_tests('--fromfile', filename)
+ self.check_executed_tests(output, tests)
+
+ # test format 'test_opcodes'
+ with open(filename, "w") as fp:
+ for name in tests:
+ print(name, file=fp)
+
+ output = self.run_tests('--fromfile', filename)
+ self.check_executed_tests(output, tests)
+
+ def test_interrupted(self):
+ code = TEST_INTERRUPTED
+ test = self.create_test('sigint', code=code)
+ output = self.run_tests(test, exitcode=1)
+ self.check_executed_tests(output, test, omitted=test)
+
+ def test_slow(self):
+ # test --slow
+ tests = [self.create_test() for index in range(3)]
+ output = self.run_tests("--slow", *tests)
+ self.check_executed_tests(output, tests)
+ regex = ('10 slowest tests:\n'
+ '(?:%s: [0-9]+\.[0-9]+s\n){%s}'
+ % (self.TESTNAME_REGEX, len(tests)))
+ self.check_line(output, regex)
+
+ def test_slow_interrupted(self):
+ # Issue #25373: test --slow with an interrupted test
+ code = TEST_INTERRUPTED
+ test = self.create_test("sigint", code=code)
+
+ for multiprocessing in (False, True):
+ if multiprocessing:
+ args = ("--slow", "-j2", test)
+ else:
+ args = ("--slow", test)
+ output = self.run_tests(*args, exitcode=1)
+ self.check_executed_tests(output, test, omitted=test)
+ regex = ('10 slowest tests:\n')
+ self.check_line(output, regex)
+ self.check_line(output, 'Test suite interrupted by signal SIGINT.')
+
+ def test_coverage(self):
+ # test --coverage
+ test = self.create_test('coverage')
+ output = self.run_tests("--coverage", test)
+ self.check_executed_tests(output, [test])
+ regex = ('lines +cov% +module +\(path\)\n'
+ '(?: *[0-9]+ *[0-9]{1,2}% *[^ ]+ +\([^)]+\)+)+')
+ self.check_line(output, regex)
+
+ def test_wait(self):
+ # test --wait
+ test = self.create_test('wait')
+ output = self.run_tests("--wait", test, input='key')
+ self.check_line(output, 'Press any key to continue')
+
+ def test_forever(self):
+ # test --forever
+ code = textwrap.dedent("""
+ import builtins
+ import unittest
+
+ class ForeverTester(unittest.TestCase):
+ def test_run(self):
+ # Store the state in the builtins module, because the test
+ # module is reload at each run
+ if 'RUN' in builtins.__dict__:
+ builtins.__dict__['RUN'] += 1
+ if builtins.__dict__['RUN'] >= 3:
+ self.fail("fail at the 3rd runs")
+ else:
+ builtins.__dict__['RUN'] = 1
+ """)
+ test = self.create_test('forever', code=code)
+ output = self.run_tests('--forever', test, exitcode=1)
+ self.check_executed_tests(output, [test]*3, failed=test)
+
+ @unittest.skipUnless(Py_DEBUG, 'need a debug build')
+ def test_huntrleaks_fd_leak(self):
+ # test --huntrleaks for file descriptor leak
+ code = textwrap.dedent("""
+ import os
+ import unittest
+
+ # Issue #25306: Disable popups and logs to stderr on assertion
+ # failures in MSCRT
+ try:
+ import msvcrt
+ msvcrt.CrtSetReportMode
+ except (ImportError, AttributeError):
+ # no Windows, o release build
+ pass
+ else:
+ for m in [msvcrt.CRT_WARN, msvcrt.CRT_ERROR, msvcrt.CRT_ASSERT]:
+ msvcrt.CrtSetReportMode(m, 0)
+
+ class FDLeakTest(unittest.TestCase):
+ def test_leak(self):
+ fd = os.open(__file__, os.O_RDONLY)
+ # bug: never cloes the file descriptor
+ """)
+ test = self.create_test('huntrleaks', code=code)
+
+ filename = 'reflog.txt'
+ self.addCleanup(support.unlink, filename)
+ output = self.run_tests('--huntrleaks', '3:3:', test,
+ exitcode=1,
+ stderr=subprocess.STDOUT)
+ self.check_executed_tests(output, [test], failed=test)
+
+ line = 'beginning 6 repetitions\n123456\n......\n'
+ self.check_line(output, re.escape(line))
+
+ line2 = '%s leaked [1, 1, 1] file descriptors, sum=3\n' % test
+ self.check_line(output, re.escape(line2))
+
+ with open(filename) as fp:
+ reflog = fp.read()
+ self.assertEqual(reflog, line2)
+
+ def test_list_tests(self):
+ # test --list-tests
+ tests = [self.create_test() for i in range(5)]
+ output = self.run_tests('--list-tests', *tests)
+ self.assertEqual(output.rstrip().splitlines(),
+ tests)
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/Lib/test/test_richcmp.py b/Lib/test/test_richcmp.py
index 1582caad97..58729a9fea 100644
--- a/Lib/test/test_richcmp.py
+++ b/Lib/test/test_richcmp.py
@@ -253,6 +253,31 @@ class MiscTest(unittest.TestCase):
self.assertTrue(a != b)
self.assertTrue(a < b)
+ def test_exception_message(self):
+ class Spam:
+ pass
+
+ tests = [
+ (lambda: 42 < None, r"'<' .* of 'int' and 'NoneType'"),
+ (lambda: None < 42, r"'<' .* of 'NoneType' and 'int'"),
+ (lambda: 42 > None, r"'>' .* of 'int' and 'NoneType'"),
+ (lambda: "foo" < None, r"'<' .* of 'str' and 'NoneType'"),
+ (lambda: "foo" >= 666, r"'>=' .* of 'str' and 'int'"),
+ (lambda: 42 <= None, r"'<=' .* of 'int' and 'NoneType'"),
+ (lambda: 42 >= None, r"'>=' .* of 'int' and 'NoneType'"),
+ (lambda: 42 < [], r"'<' .* of 'int' and 'list'"),
+ (lambda: () > [], r"'>' .* of 'tuple' and 'list'"),
+ (lambda: None >= None, r"'>=' .* of 'NoneType' and 'NoneType'"),
+ (lambda: Spam() < 42, r"'<' .* of 'Spam' and 'int'"),
+ (lambda: 42 < Spam(), r"'<' .* of 'int' and 'Spam'"),
+ (lambda: Spam() <= Spam(), r"'<=' .* of 'Spam' and 'Spam'"),
+ ]
+ for i, test in enumerate(tests):
+ with self.subTest(test=i):
+ with self.assertRaisesRegex(TypeError, test[1]):
+ test[0]()
+
+
class DictTest(unittest.TestCase):
def test_dicts(self):
diff --git a/Lib/test/test_rlcompleter.py b/Lib/test/test_rlcompleter.py
index 853e77330a..0dc1080ca3 100644
--- a/Lib/test/test_rlcompleter.py
+++ b/Lib/test/test_rlcompleter.py
@@ -1,11 +1,12 @@
import unittest
-import unittest.mock
+from unittest.mock import patch
import builtins
import rlcompleter
class CompleteMe:
""" Trivial class used in testing rlcompleter.Completer. """
spam = 1
+ _ham = 2
class TestRlcompleter(unittest.TestCase):
@@ -52,18 +53,32 @@ class TestRlcompleter(unittest.TestCase):
['str.{}('.format(x) for x in dir(str)
if x.startswith('s')])
self.assertEqual(self.stdcompleter.attr_matches('tuple.foospamegg'), [])
+ expected = sorted({'None.%s%s' % (x, '(' if x != '__doc__' else '')
+ for x in dir(None)})
+ self.assertEqual(self.stdcompleter.attr_matches('None.'), expected)
+ self.assertEqual(self.stdcompleter.attr_matches('None._'), expected)
+ self.assertEqual(self.stdcompleter.attr_matches('None.__'), expected)
# test with a customized namespace
self.assertEqual(self.completer.attr_matches('CompleteMe.sp'),
['CompleteMe.spam'])
self.assertEqual(self.completer.attr_matches('Completeme.egg'), [])
+ self.assertEqual(self.completer.attr_matches('CompleteMe.'),
+ ['CompleteMe.mro(', 'CompleteMe.spam'])
+ self.assertEqual(self.completer.attr_matches('CompleteMe._'),
+ ['CompleteMe._ham'])
+ matches = self.completer.attr_matches('CompleteMe.__')
+ for x in matches:
+ self.assertTrue(x.startswith('CompleteMe.__'), x)
+ self.assertIn('CompleteMe.__name__', matches)
+ self.assertIn('CompleteMe.__new__(', matches)
- CompleteMe.me = CompleteMe
- self.assertEqual(self.completer.attr_matches('CompleteMe.me.me.sp'),
- ['CompleteMe.me.me.spam'])
- self.assertEqual(self.completer.attr_matches('egg.s'),
- ['egg.{}('.format(x) for x in dir(str)
- if x.startswith('s')])
+ with patch.object(CompleteMe, "me", CompleteMe, create=True):
+ self.assertEqual(self.completer.attr_matches('CompleteMe.me.me.sp'),
+ ['CompleteMe.me.me.spam'])
+ self.assertEqual(self.completer.attr_matches('egg.s'),
+ ['egg.{}('.format(x) for x in dir(str)
+ if x.startswith('s')])
def test_excessive_getattr(self):
# Ensure getattr() is invoked no more than once per attribute
@@ -78,14 +93,27 @@ class TestRlcompleter(unittest.TestCase):
self.assertEqual(completer.complete('f.b', 0), 'f.bar')
self.assertEqual(f.calls, 1)
+ def test_uncreated_attr(self):
+ # Attributes like properties and slots should be completed even when
+ # they haven't been created on an instance
+ class Foo:
+ __slots__ = ("bar",)
+ completer = rlcompleter.Completer(dict(f=Foo()))
+ self.assertEqual(completer.complete('f.', 0), 'f.bar')
+
@unittest.mock.patch('rlcompleter._readline_available', False)
def test_complete(self):
completer = rlcompleter.Completer()
self.assertEqual(completer.complete('', 0), '\t')
- self.assertEqual(completer.complete('a', 0), 'and')
- self.assertEqual(completer.complete('a', 1), 'as')
- self.assertEqual(completer.complete('as', 2), 'assert')
- self.assertEqual(completer.complete('an', 0), 'and')
+ self.assertEqual(completer.complete('a', 0), 'and ')
+ self.assertEqual(completer.complete('a', 1), 'as ')
+ self.assertEqual(completer.complete('as', 2), 'assert ')
+ self.assertEqual(completer.complete('an', 0), 'and ')
+ self.assertEqual(completer.complete('pa', 0), 'pass')
+ self.assertEqual(completer.complete('Fa', 0), 'False')
+ self.assertEqual(completer.complete('el', 0), 'elif ')
+ self.assertEqual(completer.complete('el', 1), 'else')
+ self.assertEqual(completer.complete('tr', 0), 'try:')
def test_duplicate_globals(self):
namespace = {
@@ -98,9 +126,10 @@ class TestRlcompleter(unittest.TestCase):
completer = rlcompleter.Completer(namespace)
self.assertEqual(completer.complete('False', 0), 'False')
self.assertIsNone(completer.complete('False', 1)) # No duplicates
- self.assertEqual(completer.complete('assert', 0), 'assert')
+ # Space or colon added due to being a reserved keyword
+ self.assertEqual(completer.complete('assert', 0), 'assert ')
self.assertIsNone(completer.complete('assert', 1))
- self.assertEqual(completer.complete('try', 0), 'try')
+ self.assertEqual(completer.complete('try', 0), 'try:')
self.assertIsNone(completer.complete('try', 1))
# No opening bracket "(" because we overrode the built-in class
self.assertEqual(completer.complete('memoryview', 0), 'memoryview')
diff --git a/Lib/test/test_robotparser.py b/Lib/test/test_robotparser.py
index d01266f330..76f4f7c614 100644
--- a/Lib/test/test_robotparser.py
+++ b/Lib/test/test_robotparser.py
@@ -1,8 +1,7 @@
import io
import unittest
import urllib.robotparser
-from urllib.error import URLError, HTTPError
-from urllib.request import urlopen
+from collections import namedtuple
from test import support
from http.server import BaseHTTPRequestHandler, HTTPServer
try:
@@ -12,7 +11,8 @@ except ImportError:
class RobotTestCase(unittest.TestCase):
- def __init__(self, index=None, parser=None, url=None, good=None, agent=None):
+ def __init__(self, index=None, parser=None, url=None, good=None,
+ agent=None, request_rate=None, crawl_delay=None):
# workaround to make unittest discovery work (see #17066)
if not isinstance(index, int):
return
@@ -25,6 +25,8 @@ class RobotTestCase(unittest.TestCase):
self.url = url
self.good = good
self.agent = agent
+ self.request_rate = request_rate
+ self.crawl_delay = crawl_delay
def runTest(self):
if isinstance(self.url, tuple):
@@ -34,6 +36,18 @@ class RobotTestCase(unittest.TestCase):
agent = self.agent
if self.good:
self.assertTrue(self.parser.can_fetch(agent, url))
+ self.assertEqual(self.parser.crawl_delay(agent), self.crawl_delay)
+ # if we have actual values for request rate
+ if self.request_rate and self.parser.request_rate(agent):
+ self.assertEqual(
+ self.parser.request_rate(agent).requests,
+ self.request_rate.requests
+ )
+ self.assertEqual(
+ self.parser.request_rate(agent).seconds,
+ self.request_rate.seconds
+ )
+ self.assertEqual(self.parser.request_rate(agent), self.request_rate)
else:
self.assertFalse(self.parser.can_fetch(agent, url))
@@ -43,15 +57,17 @@ class RobotTestCase(unittest.TestCase):
tests = unittest.TestSuite()
def RobotTest(index, robots_txt, good_urls, bad_urls,
- agent="test_robotparser"):
+ request_rate, crawl_delay, agent="test_robotparser"):
lines = io.StringIO(robots_txt).readlines()
parser = urllib.robotparser.RobotFileParser()
parser.parse(lines)
for url in good_urls:
- tests.addTest(RobotTestCase(index, parser, url, 1, agent))
+ tests.addTest(RobotTestCase(index, parser, url, 1, agent,
+ request_rate, crawl_delay))
for url in bad_urls:
- tests.addTest(RobotTestCase(index, parser, url, 0, agent))
+ tests.addTest(RobotTestCase(index, parser, url, 0, agent,
+ request_rate, crawl_delay))
# Examples from http://www.robotstxt.org/wc/norobots.html (fetched 2002)
@@ -65,14 +81,18 @@ Disallow: /foo.html
good = ['/','/test.html']
bad = ['/cyberworld/map/index.html','/tmp/xxx','/foo.html']
+request_rate = None
+crawl_delay = None
-RobotTest(1, doc, good, bad)
+RobotTest(1, doc, good, bad, request_rate, crawl_delay)
# 2.
doc = """
# robots.txt for http://www.example.com/
User-agent: *
+Crawl-delay: 1
+Request-rate: 3/15
Disallow: /cyberworld/map/ # This is an infinite virtual URL space
# Cybermapper knows where to go.
@@ -83,8 +103,10 @@ Disallow:
good = ['/','/test.html',('cybermapper','/cyberworld/map/index.html')]
bad = ['/cyberworld/map/index.html']
+request_rate = None # The parameters should be equal to None since they
+crawl_delay = None # don't apply to the cybermapper user agent
-RobotTest(2, doc, good, bad)
+RobotTest(2, doc, good, bad, request_rate, crawl_delay)
# 3.
doc = """
@@ -95,14 +117,18 @@ Disallow: /
good = []
bad = ['/cyberworld/map/index.html','/','/tmp/']
+request_rate = None
+crawl_delay = None
-RobotTest(3, doc, good, bad)
+RobotTest(3, doc, good, bad, request_rate, crawl_delay)
# Examples from http://www.robotstxt.org/wc/norobots-rfc.html (fetched 2002)
# 4.
doc = """
User-agent: figtree
+Crawl-delay: 3
+Request-rate: 9/30
Disallow: /tmp
Disallow: /a%3cd.html
Disallow: /a%2fb.html
@@ -115,8 +141,17 @@ bad = ['/tmp','/tmp.html','/tmp/a.html',
'/~joe/index.html'
]
-RobotTest(4, doc, good, bad, 'figtree')
-RobotTest(5, doc, good, bad, 'FigTree Robot libwww-perl/5.04')
+request_rate = namedtuple('req_rate', 'requests seconds')
+request_rate.requests = 9
+request_rate.seconds = 30
+crawl_delay = 3
+request_rate_bad = None # not actually tested, but we still need to parse it
+crawl_delay_bad = None # in order to accommodate the input parameters
+
+
+RobotTest(4, doc, good, bad, request_rate, crawl_delay, 'figtree' )
+RobotTest(5, doc, good, bad, request_rate_bad, crawl_delay_bad,
+ 'FigTree Robot libwww-perl/5.04')
# 6.
doc = """
@@ -125,14 +160,18 @@ Disallow: /tmp/
Disallow: /a%3Cd.html
Disallow: /a/b.html
Disallow: /%7ejoe/index.html
+Crawl-delay: 3
+Request-rate: 9/banana
"""
good = ['/tmp',] # XFAIL: '/a%2fb.html'
bad = ['/tmp/','/tmp/a.html',
'/a%3cd.html','/a%3Cd.html',"/a/b.html",
'/%7Ejoe/index.html']
+crawl_delay = 3
+request_rate = None # since request rate has invalid syntax, return None
-RobotTest(6, doc, good, bad)
+RobotTest(6, doc, good, bad, None, None)
# From bug report #523041
@@ -140,12 +179,16 @@ RobotTest(6, doc, good, bad)
doc = """
User-Agent: *
Disallow: /.
+Crawl-delay: pears
"""
good = ['/foo.html']
-bad = [] # Bug report says "/" should be denied, but that is not in the RFC
+bad = [] # bug report says "/" should be denied, but that is not in the RFC
+
+crawl_delay = None # since crawl delay has invalid syntax, return None
+request_rate = None
-RobotTest(7, doc, good, bad)
+RobotTest(7, doc, good, bad, crawl_delay, request_rate)
# From Google: http://www.google.com/support/webmasters/bin/answer.py?hl=en&answer=40364
@@ -154,12 +197,15 @@ doc = """
User-agent: Googlebot
Allow: /folder1/myfile.html
Disallow: /folder1/
+Request-rate: whale/banana
"""
good = ['/folder1/myfile.html']
bad = ['/folder1/anotherfile.html']
+crawl_delay = None
+request_rate = None # invalid syntax, return none
-RobotTest(8, doc, good, bad, agent="Googlebot")
+RobotTest(8, doc, good, bad, crawl_delay, request_rate, agent="Googlebot")
# 9. This file is incorrect because "Googlebot" is a substring of
# "Googlebot-Mobile", so test 10 works just like test 9.
@@ -174,12 +220,12 @@ Allow: /
good = []
bad = ['/something.jpg']
-RobotTest(9, doc, good, bad, agent="Googlebot")
+RobotTest(9, doc, good, bad, None, None, agent="Googlebot")
good = []
bad = ['/something.jpg']
-RobotTest(10, doc, good, bad, agent="Googlebot-Mobile")
+RobotTest(10, doc, good, bad, None, None, agent="Googlebot-Mobile")
# 11. Get the order correct.
doc = """
@@ -193,12 +239,12 @@ Disallow: /
good = []
bad = ['/something.jpg']
-RobotTest(11, doc, good, bad, agent="Googlebot")
+RobotTest(11, doc, good, bad, None, None, agent="Googlebot")
good = ['/something.jpg']
bad = []
-RobotTest(12, doc, good, bad, agent="Googlebot-Mobile")
+RobotTest(12, doc, good, bad, None, None, agent="Googlebot-Mobile")
# 13. Google also got the order wrong in #8. You need to specify the
@@ -212,7 +258,7 @@ Disallow: /folder1/
good = ['/folder1/myfile.html']
bad = ['/folder1/anotherfile.html']
-RobotTest(13, doc, good, bad, agent="googlebot")
+RobotTest(13, doc, good, bad, None, None, agent="googlebot")
# 14. For issue #6325 (query string support)
@@ -224,7 +270,7 @@ Disallow: /some/path?name=value
good = ['/some/path']
bad = ['/some/path?name=value']
-RobotTest(14, doc, good, bad)
+RobotTest(14, doc, good, bad, None, None)
# 15. For issue #4108 (obey first * entry)
doc = """
@@ -238,7 +284,7 @@ Disallow: /another/path
good = ['/another/path']
bad = ['/some/path']
-RobotTest(15, doc, good, bad)
+RobotTest(15, doc, good, bad, None, None)
# 16. Empty query (issue #17403). Normalizing the url first.
doc = """
@@ -250,7 +296,7 @@ Disallow: /another/path?
good = ['/some/path?']
bad = ['/another/path?']
-RobotTest(16, doc, good, bad)
+RobotTest(16, doc, good, bad, None, None)
class RobotHandler(BaseHTTPRequestHandler):
diff --git a/Lib/test/test_sched.py b/Lib/test/test_sched.py
index fe8e785092..f86f599afc 100644
--- a/Lib/test/test_sched.py
+++ b/Lib/test/test_sched.py
@@ -2,7 +2,6 @@ import queue
import sched
import time
import unittest
-from test import support
try:
import threading
except ImportError:
diff --git a/Lib/test/test_secrets.py b/Lib/test/test_secrets.py
new file mode 100644
index 0000000000..4c65cf00cd
--- /dev/null
+++ b/Lib/test/test_secrets.py
@@ -0,0 +1,123 @@
+"""Test the secrets module.
+
+As most of the functions in secrets are thin wrappers around functions
+defined elsewhere, we don't need to test them exhaustively.
+"""
+
+
+import secrets
+import unittest
+import string
+
+
+# === Unit tests ===
+
+class Compare_Digest_Tests(unittest.TestCase):
+ """Test secrets.compare_digest function."""
+
+ def test_equal(self):
+ # Test compare_digest functionality with equal (byte/text) strings.
+ for s in ("a", "bcd", "xyz123"):
+ a = s*100
+ b = s*100
+ self.assertTrue(secrets.compare_digest(a, b))
+ self.assertTrue(secrets.compare_digest(a.encode('utf-8'), b.encode('utf-8')))
+
+ def test_unequal(self):
+ # Test compare_digest functionality with unequal (byte/text) strings.
+ self.assertFalse(secrets.compare_digest("abc", "abcd"))
+ self.assertFalse(secrets.compare_digest(b"abc", b"abcd"))
+ for s in ("x", "mn", "a1b2c3"):
+ a = s*100 + "q"
+ b = s*100 + "k"
+ self.assertFalse(secrets.compare_digest(a, b))
+ self.assertFalse(secrets.compare_digest(a.encode('utf-8'), b.encode('utf-8')))
+
+ def test_bad_types(self):
+ # Test that compare_digest raises with mixed types.
+ a = 'abcde'
+ b = a.encode('utf-8')
+ assert isinstance(a, str)
+ assert isinstance(b, bytes)
+ self.assertRaises(TypeError, secrets.compare_digest, a, b)
+ self.assertRaises(TypeError, secrets.compare_digest, b, a)
+
+ def test_bool(self):
+ # Test that compare_digest returns a bool.
+ self.assertIsInstance(secrets.compare_digest("abc", "abc"), bool)
+ self.assertIsInstance(secrets.compare_digest("abc", "xyz"), bool)
+
+
+class Random_Tests(unittest.TestCase):
+ """Test wrappers around SystemRandom methods."""
+
+ def test_randbits(self):
+ # Test randbits.
+ errmsg = "randbits(%d) returned %d"
+ for numbits in (3, 12, 30):
+ for i in range(6):
+ n = secrets.randbits(numbits)
+ self.assertTrue(0 <= n < 2**numbits, errmsg % (numbits, n))
+
+ def test_choice(self):
+ # Test choice.
+ items = [1, 2, 4, 8, 16, 32, 64]
+ for i in range(10):
+ self.assertTrue(secrets.choice(items) in items)
+
+ def test_randbelow(self):
+ # Test randbelow.
+ for i in range(2, 10):
+ self.assertIn(secrets.randbelow(i), range(i))
+ self.assertRaises(ValueError, secrets.randbelow, 0)
+
+
+class Token_Tests(unittest.TestCase):
+ """Test token functions."""
+
+ def test_token_defaults(self):
+ # Test that token_* functions handle default size correctly.
+ for func in (secrets.token_bytes, secrets.token_hex,
+ secrets.token_urlsafe):
+ with self.subTest(func=func):
+ name = func.__name__
+ try:
+ func()
+ except TypeError:
+ self.fail("%s cannot be called with no argument" % name)
+ try:
+ func(None)
+ except TypeError:
+ self.fail("%s cannot be called with None" % name)
+ size = secrets.DEFAULT_ENTROPY
+ self.assertEqual(len(secrets.token_bytes(None)), size)
+ self.assertEqual(len(secrets.token_hex(None)), 2*size)
+
+ def test_token_bytes(self):
+ # Test token_bytes.
+ for n in (1, 8, 17, 100):
+ with self.subTest(n=n):
+ self.assertIsInstance(secrets.token_bytes(n), bytes)
+ self.assertEqual(len(secrets.token_bytes(n)), n)
+
+ def test_token_hex(self):
+ # Test token_hex.
+ for n in (1, 12, 25, 90):
+ with self.subTest(n=n):
+ s = secrets.token_hex(n)
+ self.assertIsInstance(s, str)
+ self.assertEqual(len(s), 2*n)
+ self.assertTrue(all(c in string.hexdigits for c in s))
+
+ def test_token_urlsafe(self):
+ # Test token_urlsafe.
+ legal = string.ascii_letters + string.digits + '-_'
+ for n in (1, 11, 28, 76):
+ with self.subTest(n=n):
+ s = secrets.token_urlsafe(n)
+ self.assertIsInstance(s, str)
+ self.assertTrue(all(c in legal for c in s))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Lib/test/test_set.py b/Lib/test/test_set.py
index 1a49edf231..49abfb3e71 100644
--- a/Lib/test/test_set.py
+++ b/Lib/test/test_set.py
@@ -6,10 +6,11 @@ import operator
import copy
import pickle
from random import randrange, shuffle
-import sys
import warnings
import collections
import collections.abc
+import itertools
+import string
class PassThru(Exception):
pass
@@ -714,6 +715,28 @@ class TestFrozenSet(TestJointOps, unittest.TestCase):
addhashvalue(hash(frozenset([e for e, m in elemmasks if m&i])))
self.assertEqual(len(hashvalues), 2**n)
+ def letter_range(n):
+ return string.ascii_letters[:n]
+
+ def zf_range(n):
+ # https://en.wikipedia.org/wiki/Set-theoretic_definition_of_natural_numbers
+ nums = [frozenset()]
+ for i in range(n-1):
+ num = frozenset(nums)
+ nums.append(num)
+ return nums[:n]
+
+ def powerset(s):
+ for i in range(len(s)+1):
+ yield from map(frozenset, itertools.combinations(s, i))
+
+ for n in range(18):
+ t = 2 ** n
+ mask = t - 1
+ for nums in (range, letter_range, zf_range):
+ u = len({h & mask for h in map(hash, powerset(nums(n)))})
+ self.assertGreater(4*u, t)
+
class FrozenSetSubclass(frozenset):
pass
diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py
index 1b80ff0963..ab42ed70cc 100644
--- a/Lib/test/test_signal.py
+++ b/Lib/test/test_signal.py
@@ -22,29 +22,6 @@ except ImportError:
_testcapi = None
-class HandlerBCalled(Exception):
- pass
-
-
-def exit_subprocess():
- """Use os._exit(0) to exit the current subprocess.
-
- Otherwise, the test catches the SystemExit and continues executing
- in parallel with the original test, so you wind up with an
- exponential number of tests running concurrently.
- """
- os._exit(0)
-
-
-def ignoring_eintr(__func, *args, **kwargs):
- try:
- return __func(*args, **kwargs)
- except OSError as e:
- if e.errno != errno.EINTR:
- raise
- return None
-
-
class GenericTests(unittest.TestCase):
@unittest.skipIf(threading is None, "test needs threading module")
@@ -63,145 +40,6 @@ class GenericTests(unittest.TestCase):
@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
-class InterProcessSignalTests(unittest.TestCase):
- MAX_DURATION = 20 # Entire test should last at most 20 sec.
-
- def setUp(self):
- self.using_gc = gc.isenabled()
- gc.disable()
-
- def tearDown(self):
- if self.using_gc:
- gc.enable()
-
- def format_frame(self, frame, limit=None):
- return ''.join(traceback.format_stack(frame, limit=limit))
-
- def handlerA(self, signum, frame):
- self.a_called = True
-
- def handlerB(self, signum, frame):
- self.b_called = True
- raise HandlerBCalled(signum, self.format_frame(frame))
-
- def wait(self, child):
- """Wait for child to finish, ignoring EINTR."""
- while True:
- try:
- child.wait()
- return
- except OSError as e:
- if e.errno != errno.EINTR:
- raise
-
- def run_test(self):
- # Install handlers. This function runs in a sub-process, so we
- # don't worry about re-setting the default handlers.
- signal.signal(signal.SIGHUP, self.handlerA)
- signal.signal(signal.SIGUSR1, self.handlerB)
- signal.signal(signal.SIGUSR2, signal.SIG_IGN)
- signal.signal(signal.SIGALRM, signal.default_int_handler)
-
- # Variables the signals will modify:
- self.a_called = False
- self.b_called = False
-
- # Let the sub-processes know who to send signals to.
- pid = os.getpid()
-
- child = ignoring_eintr(subprocess.Popen, ['kill', '-HUP', str(pid)])
- if child:
- self.wait(child)
- if not self.a_called:
- time.sleep(1) # Give the signal time to be delivered.
- self.assertTrue(self.a_called)
- self.assertFalse(self.b_called)
- self.a_called = False
-
- # Make sure the signal isn't delivered while the previous
- # Popen object is being destroyed, because __del__ swallows
- # exceptions.
- del child
- try:
- child = subprocess.Popen(['kill', '-USR1', str(pid)])
- # This wait should be interrupted by the signal's exception.
- self.wait(child)
- time.sleep(1) # Give the signal time to be delivered.
- self.fail('HandlerBCalled exception not raised')
- except HandlerBCalled:
- self.assertTrue(self.b_called)
- self.assertFalse(self.a_called)
-
- child = ignoring_eintr(subprocess.Popen, ['kill', '-USR2', str(pid)])
- if child:
- self.wait(child) # Nothing should happen.
-
- try:
- signal.alarm(1)
- # The race condition in pause doesn't matter in this case,
- # since alarm is going to raise a KeyboardException, which
- # will skip the call.
- signal.pause()
- # But if another signal arrives before the alarm, pause
- # may return early.
- time.sleep(1)
- except KeyboardInterrupt:
- pass
- except:
- self.fail("Some other exception woke us from pause: %s" %
- traceback.format_exc())
- else:
- self.fail("pause returned of its own accord, and the signal"
- " didn't arrive after another second.")
-
- # Issue 3864, unknown if this affects earlier versions of freebsd also
- @unittest.skipIf(sys.platform=='freebsd6',
- 'inter process signals not reliable (do not mix well with threading) '
- 'on freebsd6')
- def test_main(self):
- # This function spawns a child process to insulate the main
- # test-running process from all the signals. It then
- # communicates with that child process over a pipe and
- # re-raises information about any exceptions the child
- # raises. The real work happens in self.run_test().
- os_done_r, os_done_w = os.pipe()
- with closing(os.fdopen(os_done_r, 'rb')) as done_r, \
- closing(os.fdopen(os_done_w, 'wb')) as done_w:
- child = os.fork()
- if child == 0:
- # In the child process; run the test and report results
- # through the pipe.
- try:
- done_r.close()
- # Have to close done_w again here because
- # exit_subprocess() will skip the enclosing with block.
- with closing(done_w):
- try:
- self.run_test()
- except:
- pickle.dump(traceback.format_exc(), done_w)
- else:
- pickle.dump(None, done_w)
- except:
- print('Uh oh, raised from pickle.')
- traceback.print_exc()
- finally:
- exit_subprocess()
-
- done_w.close()
- # Block for up to MAX_DURATION seconds for the test to finish.
- r, w, x = select.select([done_r], [], [], self.MAX_DURATION)
- if done_r in r:
- tb = pickle.load(done_r)
- if tb:
- self.fail(tb)
- else:
- os.kill(child, signal.SIGKILL)
- self.fail('Test deadlocked after %d seconds.' %
- self.MAX_DURATION)
-
-
-@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
class PosixTests(unittest.TestCase):
def trivial_signal_handler(self, *args):
pass
@@ -224,6 +62,15 @@ class PosixTests(unittest.TestCase):
signal.signal(signal.SIGHUP, hup)
self.assertEqual(signal.getsignal(signal.SIGHUP), hup)
+ # Issue 3864, unknown if this affects earlier versions of freebsd also
+ @unittest.skipIf(sys.platform=='freebsd6',
+ 'inter process signals not reliable (do not mix well with threading) '
+ 'on freebsd6')
+ def test_interprocess_signal(self):
+ dirname = os.path.dirname(__file__)
+ script = os.path.join(dirname, 'signalinterproctester.py')
+ assert_python_ok(script)
+
@unittest.skipUnless(sys.platform == "win32", "Windows specific")
class WindowsSignalTests(unittest.TestCase):
diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py
index da20a3d21a..f698927f37 100644
--- a/Lib/test/test_site.py
+++ b/Lib/test/test_site.py
@@ -75,7 +75,7 @@ class HelperFunctionsTests(unittest.TestCase):
def test_init_pathinfo(self):
dir_set = site._init_pathinfo()
for entry in [site.makepath(path)[1] for path in sys.path
- if path and os.path.isdir(path)]:
+ if path and os.path.exists(path)]:
self.assertIn(entry, dir_set,
"%s from sys.path not found in set returned "
"by _init_pathinfo(): %s" % (entry, dir_set))
@@ -243,13 +243,14 @@ class HelperFunctionsTests(unittest.TestCase):
self.assertEqual(len(dirs), 2)
wanted = os.path.join('/Library',
sysconfig.get_config_var("PYTHONFRAMEWORK"),
- sys.version[:3],
+ '%d.%d' % sys.version_info[:2],
'site-packages')
self.assertEqual(dirs[1], wanted)
elif os.sep == '/':
# OS X non-framwework builds, Linux, FreeBSD, etc
self.assertEqual(len(dirs), 1)
- wanted = os.path.join('xoxo', 'lib', 'python' + sys.version[:3],
+ wanted = os.path.join('xoxo', 'lib',
+ 'python%d.%d' % sys.version_info[:2],
'site-packages')
self.assertEqual(dirs[0], wanted)
else:
diff --git a/Lib/test/test_smtpd.py b/Lib/test/test_smtpd.py
index 88dbfdf6f0..d92c9b3b02 100644
--- a/Lib/test/test_smtpd.py
+++ b/Lib/test/test_smtpd.py
@@ -53,10 +53,6 @@ class SMTPDServerTest(unittest.TestCase):
write_line(b'DATA')
self.assertRaises(NotImplementedError, write_line, b'spam\r\n.\r\n')
- def test_decode_data_default_warns(self):
- with self.assertWarns(DeprecationWarning):
- smtpd.SMTPServer((support.HOST, 0), ('b', 0))
-
def test_decode_data_and_enable_SMTPUTF8_raises(self):
self.assertRaises(
ValueError,
@@ -108,10 +104,9 @@ class DebuggingServerTest(unittest.TestCase):
"""))
def test_process_message_with_decode_data_false(self):
- server = smtpd.DebuggingServer((support.HOST, 0), ('b', 0),
- decode_data=False)
+ server = smtpd.DebuggingServer((support.HOST, 0), ('b', 0))
conn, addr = server.accept()
- channel = smtpd.SMTPChannel(server, conn, addr, decode_data=False)
+ channel = smtpd.SMTPChannel(server, conn, addr)
with support.captured_stdout() as s:
self.send_data(channel, b'From: test\n\nh\xc3\xa9llo\xff\n')
stdout = s.getvalue()
@@ -175,13 +170,11 @@ class TestFamilyDetection(unittest.TestCase):
@unittest.skipUnless(support.IPV6_ENABLED, "IPv6 not enabled")
def test_socket_uses_IPv6(self):
- server = smtpd.SMTPServer((support.HOSTv6, 0), (support.HOST, 0),
- decode_data=False)
+ server = smtpd.SMTPServer((support.HOSTv6, 0), (support.HOST, 0))
self.assertEqual(server.socket.family, socket.AF_INET6)
def test_socket_uses_IPv4(self):
- server = smtpd.SMTPServer((support.HOST, 0), (support.HOSTv6, 0),
- decode_data=False)
+ server = smtpd.SMTPServer((support.HOST, 0), (support.HOSTv6, 0))
self.assertEqual(server.socket.family, socket.AF_INET)
@@ -204,18 +197,18 @@ class TestRcptOptionParsing(unittest.TestCase):
channel.handle_read()
def test_params_rejected(self):
- server = DummyServer((support.HOST, 0), ('b', 0), decode_data=False)
+ server = DummyServer((support.HOST, 0), ('b', 0))
conn, addr = server.accept()
- channel = smtpd.SMTPChannel(server, conn, addr, decode_data=False)
+ channel = smtpd.SMTPChannel(server, conn, addr)
self.write_line(channel, b'EHLO example')
self.write_line(channel, b'MAIL from: <foo@example.com> size=20')
self.write_line(channel, b'RCPT to: <foo@example.com> foo=bar')
self.assertEqual(channel.socket.last, self.error_response)
def test_nothing_accepted(self):
- server = DummyServer((support.HOST, 0), ('b', 0), decode_data=False)
+ server = DummyServer((support.HOST, 0), ('b', 0))
conn, addr = server.accept()
- channel = smtpd.SMTPChannel(server, conn, addr, decode_data=False)
+ channel = smtpd.SMTPChannel(server, conn, addr)
self.write_line(channel, b'EHLO example')
self.write_line(channel, b'MAIL from: <foo@example.com> size=20')
self.write_line(channel, b'RCPT to: <foo@example.com>')
@@ -257,9 +250,9 @@ class TestMailOptionParsing(unittest.TestCase):
self.assertEqual(channel.socket.last, b'250 OK\r\n')
def test_with_decode_data_false(self):
- server = DummyServer((support.HOST, 0), ('b', 0), decode_data=False)
+ server = DummyServer((support.HOST, 0), ('b', 0))
conn, addr = server.accept()
- channel = smtpd.SMTPChannel(server, conn, addr, decode_data=False)
+ channel = smtpd.SMTPChannel(server, conn, addr)
self.write_line(channel, b'EHLO example')
for line in [
b'MAIL from: <foo@example.com> size=20 SMTPUTF8',
@@ -765,13 +758,6 @@ class SMTPDChannelTest(unittest.TestCase):
with support.check_warnings(('', DeprecationWarning)):
self.channel._SMTPChannel__addr = 'spam'
- def test_decode_data_default_warning(self):
- with self.assertWarns(DeprecationWarning):
- server = DummyServer((support.HOST, 0), ('b', 0))
- conn, addr = self.server.accept()
- with self.assertWarns(DeprecationWarning):
- smtpd.SMTPChannel(server, conn, addr)
-
@unittest.skipUnless(support.IPV6_ENABLED, "IPv6 not enabled")
class SMTPDChannelIPv6Test(SMTPDChannelTest):
def setUp(self):
@@ -845,12 +831,9 @@ class SMTPDChannelWithDecodeDataFalse(unittest.TestCase):
smtpd.socket = asyncore.socket = mock_socket
self.old_debugstream = smtpd.DEBUGSTREAM
self.debug = smtpd.DEBUGSTREAM = io.StringIO()
- self.server = DummyServer((support.HOST, 0), ('b', 0),
- decode_data=False)
+ self.server = DummyServer((support.HOST, 0), ('b', 0))
conn, addr = self.server.accept()
- # Set decode_data to False
- self.channel = smtpd.SMTPChannel(self.server, conn, addr,
- decode_data=False)
+ self.channel = smtpd.SMTPChannel(self.server, conn, addr)
def tearDown(self):
asyncore.close_all()
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index c151a50dcb..1ddd6044b9 100644
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -13,7 +13,6 @@ import queue
import sys
import os
import array
-import platform
import contextlib
from weakref import proxy
import signal
@@ -1161,6 +1160,17 @@ class GeneralModuleTests(unittest.TestCase):
sock.close()
self.assertRaises(OSError, sock.send, b"spam")
+ def testCloseException(self):
+ sock = socket.socket()
+ socket.socket(fileno=sock.fileno()).close()
+ try:
+ sock.close()
+ except OSError as err:
+ # Winsock apparently raises ENOTSOCK
+ self.assertIn(err.errno, (errno.EBADF, errno.ENOTSOCK))
+ else:
+ self.fail("close() should raise EBADF/ENOTSOCK")
+
def testNewAttributes(self):
# testing .family, .type and .protocol
@@ -2823,6 +2833,7 @@ class SCMRightsTest(SendrecvmsgServerTimeoutBase):
nbytes = self.sendmsgToServer([msg])
self.assertEqual(nbytes, len(msg))
+ @unittest.skipIf(sys.platform == "darwin", "see issue #24725")
def testFDPassEmpty(self):
# Try to pass an empty FD array. Can receive either no array
# or an empty array.
diff --git a/Lib/test/test_socketserver.py b/Lib/test/test_socketserver.py
index 0d0f86fca4..01ac12b949 100644
--- a/Lib/test/test_socketserver.py
+++ b/Lib/test/test_socketserver.py
@@ -7,8 +7,6 @@ import os
import select
import signal
import socket
-import select
-import errno
import tempfile
import unittest
import socketserver
@@ -58,6 +56,7 @@ if HAVE_UNIX_SOCKETS:
@contextlib.contextmanager
def simple_subprocess(testcase):
+ """Tests that a custom child process is not waited on (Issue 1540386)"""
pid = os.fork()
if pid == 0:
# Don't raise an exception; it would be caught by the test harness.
@@ -103,7 +102,6 @@ class SocketServerTest(unittest.TestCase):
class MyServer(svrcls):
def handle_error(self, request, client_address):
self.close_request(request)
- self.server_close()
raise
class MyHandler(hdlrbase):
@@ -279,6 +277,103 @@ class SocketServerTest(unittest.TestCase):
socketserver.TCPServer((HOST, -1),
socketserver.StreamRequestHandler)
+ def test_context_manager(self):
+ with socketserver.TCPServer((HOST, 0),
+ socketserver.StreamRequestHandler) as server:
+ pass
+ self.assertEqual(-1, server.socket.fileno())
+
+
+class ErrorHandlerTest(unittest.TestCase):
+ """Test that the servers pass normal exceptions from the handler to
+ handle_error(), and that exiting exceptions like SystemExit and
+ KeyboardInterrupt are not passed."""
+
+ def tearDown(self):
+ test.support.unlink(test.support.TESTFN)
+
+ def test_sync_handled(self):
+ BaseErrorTestServer(ValueError)
+ self.check_result(handled=True)
+
+ def test_sync_not_handled(self):
+ with self.assertRaises(SystemExit):
+ BaseErrorTestServer(SystemExit)
+ self.check_result(handled=False)
+
+ @unittest.skipUnless(threading, 'Threading required for this test.')
+ def test_threading_handled(self):
+ ThreadingErrorTestServer(ValueError)
+ self.check_result(handled=True)
+
+ @unittest.skipUnless(threading, 'Threading required for this test.')
+ def test_threading_not_handled(self):
+ ThreadingErrorTestServer(SystemExit)
+ self.check_result(handled=False)
+
+ @requires_forking
+ def test_forking_handled(self):
+ ForkingErrorTestServer(ValueError)
+ self.check_result(handled=True)
+
+ @requires_forking
+ def test_forking_not_handled(self):
+ ForkingErrorTestServer(SystemExit)
+ self.check_result(handled=False)
+
+ def check_result(self, handled):
+ with open(test.support.TESTFN) as log:
+ expected = 'Handler called\n' + 'Error handled\n' * handled
+ self.assertEqual(log.read(), expected)
+
+
+class BaseErrorTestServer(socketserver.TCPServer):
+ def __init__(self, exception):
+ self.exception = exception
+ super().__init__((HOST, 0), BadHandler)
+ with socket.create_connection(self.server_address):
+ pass
+ try:
+ self.handle_request()
+ finally:
+ self.server_close()
+ self.wait_done()
+
+ def handle_error(self, request, client_address):
+ with open(test.support.TESTFN, 'a') as log:
+ log.write('Error handled\n')
+
+ def wait_done(self):
+ pass
+
+
+class BadHandler(socketserver.BaseRequestHandler):
+ def handle(self):
+ with open(test.support.TESTFN, 'a') as log:
+ log.write('Handler called\n')
+ raise self.server.exception('Test error')
+
+
+class ThreadingErrorTestServer(socketserver.ThreadingMixIn,
+ BaseErrorTestServer):
+ def __init__(self, *pos, **kw):
+ self.done = threading.Event()
+ super().__init__(*pos, **kw)
+
+ def shutdown_request(self, *pos, **kw):
+ super().shutdown_request(*pos, **kw)
+ self.done.set()
+
+ def wait_done(self):
+ self.done.wait()
+
+
+class ForkingErrorTestServer(socketserver.ForkingMixIn, BaseErrorTestServer):
+ def wait_done(self):
+ [child] = self.active_children
+ os.waitpid(child, 0)
+ self.active_children.clear()
+
class MiscTestCase(unittest.TestCase):
diff --git a/Lib/test/test_sort.py b/Lib/test/test_sort.py
index a5d0ebfd5a..98ccab5c39 100644
--- a/Lib/test/test_sort.py
+++ b/Lib/test/test_sort.py
@@ -1,6 +1,5 @@
from test import support
import random
-import sys
import unittest
from functools import cmp_to_key
diff --git a/Lib/test/test_spwd.py b/Lib/test/test_spwd.py
index bea7ab1ba5..e893f3a847 100644
--- a/Lib/test/test_spwd.py
+++ b/Lib/test/test_spwd.py
@@ -56,5 +56,20 @@ class TestSpwdRoot(unittest.TestCase):
self.assertRaises(TypeError, spwd.getspnam, bytes_name)
+@unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() != 0,
+ 'non-root user required')
+class TestSpwdNonRoot(unittest.TestCase):
+
+ def test_getspnam_exception(self):
+ name = 'bin'
+ try:
+ with self.assertRaises(PermissionError) as cm:
+ spwd.getspnam(name)
+ except KeyError as exc:
+ self.skipTest("spwd entry %r doesn't exist: %s" % (name, exc))
+ else:
+ self.assertEqual(str(cm.exception), '[Errno 13] Permission denied')
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
index 645ec8d100..00d437a951 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -21,6 +21,13 @@ import functools
ssl = support.import_module("ssl")
+try:
+ import threading
+except ImportError:
+ _have_threads = False
+else:
+ _have_threads = True
+
PROTOCOLS = sorted(ssl._PROTOCOL_NAMES)
HOST = support.HOST
@@ -53,10 +60,10 @@ CRLFILE = data_file("revocation.crl")
# Two keys and certs signed by the same CA (for SNI tests)
SIGNED_CERTFILE = data_file("keycert3.pem")
SIGNED_CERTFILE2 = data_file("keycert4.pem")
-SIGNING_CA = data_file("pycacert.pem")
+# Same certificate as pycacert.pem, but without extra text in file
+SIGNING_CA = data_file("capath", "ceff1710.0")
REMOTE_HOST = "self-signed.pythontest.net"
-REMOTE_ROOT_CERT = data_file("selfsigned_pythontestdotnet.pem")
EMPTYCERT = data_file("nullcert.pem")
BADCERT = data_file("badcert.pem")
@@ -328,7 +335,7 @@ class BasicSocketTests(unittest.TestCase):
wr = weakref.ref(ss)
with support.check_warnings(("", ResourceWarning)):
del ss
- self.assertEqual(wr(), None)
+ self.assertEqual(wr(), None)
def test_wrapped_unconnected(self):
# Methods on an unconnected SSLSocket propagate the original
@@ -783,6 +790,22 @@ class BasicSocketTests(unittest.TestCase):
self.cert_time_ok("Feb 9 00:00:00 2007 GMT", 1170979200.0)
self.cert_time_fail(local_february_name() + " 9 00:00:00 2007 GMT")
+ def test_connect_ex_error(self):
+ server = socket.socket(socket.AF_INET)
+ self.addCleanup(server.close)
+ port = support.bind_port(server) # Reserve port but don't listen
+ s = ssl.wrap_socket(socket.socket(socket.AF_INET),
+ cert_reqs=ssl.CERT_REQUIRED)
+ self.addCleanup(s.close)
+ rc = s.connect_ex((HOST, port))
+ # Issue #19919: Windows machines or VMs hosted on Windows
+ # machines sometimes return EWOULDBLOCK.
+ errors = (
+ errno.ECONNREFUSED, errno.EHOSTUNREACH, errno.ETIMEDOUT,
+ errno.EWOULDBLOCK,
+ )
+ self.assertIn(rc, errors)
+
class ContextTests(unittest.TestCase):
@@ -1368,140 +1391,103 @@ class MemoryBIOTests(unittest.TestCase):
self.assertRaises(TypeError, bio.write, 1)
-class NetworkedTests(unittest.TestCase):
+@unittest.skipUnless(_have_threads, "Needs threading module")
+class SimpleBackgroundTests(unittest.TestCase):
- def test_connect(self):
- with support.transient_internet(REMOTE_HOST):
- s = ssl.wrap_socket(socket.socket(socket.AF_INET),
- cert_reqs=ssl.CERT_NONE)
- try:
- s.connect((REMOTE_HOST, 443))
- self.assertEqual({}, s.getpeercert())
- finally:
- s.close()
+ """Tests that connect to a simple server running in the background"""
- # this should fail because we have no verification certs
- s = ssl.wrap_socket(socket.socket(socket.AF_INET),
- cert_reqs=ssl.CERT_REQUIRED)
- self.assertRaisesRegex(ssl.SSLError, "certificate verify failed",
- s.connect, (REMOTE_HOST, 443))
- s.close()
+ def setUp(self):
+ server = ThreadedEchoServer(SIGNED_CERTFILE)
+ self.server_addr = (HOST, server.port)
+ server.__enter__()
+ self.addCleanup(server.__exit__, None, None, None)
- # this should succeed because we specify the root cert
- s = ssl.wrap_socket(socket.socket(socket.AF_INET),
- cert_reqs=ssl.CERT_REQUIRED,
- ca_certs=REMOTE_ROOT_CERT)
- try:
- s.connect((REMOTE_HOST, 443))
- self.assertTrue(s.getpeercert())
- finally:
- s.close()
+ def test_connect(self):
+ with ssl.wrap_socket(socket.socket(socket.AF_INET),
+ cert_reqs=ssl.CERT_NONE) as s:
+ s.connect(self.server_addr)
+ self.assertEqual({}, s.getpeercert())
+
+ # this should succeed because we specify the root cert
+ with ssl.wrap_socket(socket.socket(socket.AF_INET),
+ cert_reqs=ssl.CERT_REQUIRED,
+ ca_certs=SIGNING_CA) as s:
+ s.connect(self.server_addr)
+ self.assertTrue(s.getpeercert())
+
+ def test_connect_fail(self):
+ # This should fail because we have no verification certs. Connection
+ # failure crashes ThreadedEchoServer, so run this in an independent
+ # test method.
+ s = ssl.wrap_socket(socket.socket(socket.AF_INET),
+ cert_reqs=ssl.CERT_REQUIRED)
+ self.addCleanup(s.close)
+ self.assertRaisesRegex(ssl.SSLError, "certificate verify failed",
+ s.connect, self.server_addr)
def test_connect_ex(self):
# Issue #11326: check connect_ex() implementation
- with support.transient_internet(REMOTE_HOST):
- s = ssl.wrap_socket(socket.socket(socket.AF_INET),
- cert_reqs=ssl.CERT_REQUIRED,
- ca_certs=REMOTE_ROOT_CERT)
- try:
- self.assertEqual(0, s.connect_ex((REMOTE_HOST, 443)))
- self.assertTrue(s.getpeercert())
- finally:
- s.close()
+ s = ssl.wrap_socket(socket.socket(socket.AF_INET),
+ cert_reqs=ssl.CERT_REQUIRED,
+ ca_certs=SIGNING_CA)
+ self.addCleanup(s.close)
+ self.assertEqual(0, s.connect_ex(self.server_addr))
+ self.assertTrue(s.getpeercert())
def test_non_blocking_connect_ex(self):
# Issue #11326: non-blocking connect_ex() should allow handshake
# to proceed after the socket gets ready.
- with support.transient_internet(REMOTE_HOST):
- s = ssl.wrap_socket(socket.socket(socket.AF_INET),
- cert_reqs=ssl.CERT_REQUIRED,
- ca_certs=REMOTE_ROOT_CERT,
- do_handshake_on_connect=False)
+ s = ssl.wrap_socket(socket.socket(socket.AF_INET),
+ cert_reqs=ssl.CERT_REQUIRED,
+ ca_certs=SIGNING_CA,
+ do_handshake_on_connect=False)
+ self.addCleanup(s.close)
+ s.setblocking(False)
+ rc = s.connect_ex(self.server_addr)
+ # EWOULDBLOCK under Windows, EINPROGRESS elsewhere
+ self.assertIn(rc, (0, errno.EINPROGRESS, errno.EWOULDBLOCK))
+ # Wait for connect to finish
+ select.select([], [s], [], 5.0)
+ # Non-blocking handshake
+ while True:
try:
- s.setblocking(False)
- rc = s.connect_ex((REMOTE_HOST, 443))
- # EWOULDBLOCK under Windows, EINPROGRESS elsewhere
- self.assertIn(rc, (0, errno.EINPROGRESS, errno.EWOULDBLOCK))
- # Wait for connect to finish
+ s.do_handshake()
+ break
+ except ssl.SSLWantReadError:
+ select.select([s], [], [], 5.0)
+ except ssl.SSLWantWriteError:
select.select([], [s], [], 5.0)
- # Non-blocking handshake
- while True:
- try:
- s.do_handshake()
- break
- except ssl.SSLWantReadError:
- select.select([s], [], [], 5.0)
- except ssl.SSLWantWriteError:
- select.select([], [s], [], 5.0)
- # SSL established
- self.assertTrue(s.getpeercert())
- finally:
- s.close()
-
- def test_timeout_connect_ex(self):
- # Issue #12065: on a timeout, connect_ex() should return the original
- # errno (mimicking the behaviour of non-SSL sockets).
- with support.transient_internet(REMOTE_HOST):
- s = ssl.wrap_socket(socket.socket(socket.AF_INET),
- cert_reqs=ssl.CERT_REQUIRED,
- ca_certs=REMOTE_ROOT_CERT,
- do_handshake_on_connect=False)
- try:
- s.settimeout(0.0000001)
- rc = s.connect_ex((REMOTE_HOST, 443))
- if rc == 0:
- self.skipTest("REMOTE_HOST responded too quickly")
- self.assertIn(rc, (errno.EAGAIN, errno.EWOULDBLOCK))
- finally:
- s.close()
-
- def test_connect_ex_error(self):
- with support.transient_internet(REMOTE_HOST):
- s = ssl.wrap_socket(socket.socket(socket.AF_INET),
- cert_reqs=ssl.CERT_REQUIRED,
- ca_certs=REMOTE_ROOT_CERT)
- try:
- rc = s.connect_ex((REMOTE_HOST, 444))
- # Issue #19919: Windows machines or VMs hosted on Windows
- # machines sometimes return EWOULDBLOCK.
- errors = (
- errno.ECONNREFUSED, errno.EHOSTUNREACH, errno.ETIMEDOUT,
- errno.EWOULDBLOCK,
- )
- self.assertIn(rc, errors)
- finally:
- s.close()
+ # SSL established
+ self.assertTrue(s.getpeercert())
def test_connect_with_context(self):
- with support.transient_internet(REMOTE_HOST):
- # Same as test_connect, but with a separately created context
- ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
- s = ctx.wrap_socket(socket.socket(socket.AF_INET))
- s.connect((REMOTE_HOST, 443))
- try:
- self.assertEqual({}, s.getpeercert())
- finally:
- s.close()
- # Same with a server hostname
- s = ctx.wrap_socket(socket.socket(socket.AF_INET),
- server_hostname=REMOTE_HOST)
- s.connect((REMOTE_HOST, 443))
- s.close()
- # This should fail because we have no verification certs
- ctx.verify_mode = ssl.CERT_REQUIRED
- s = ctx.wrap_socket(socket.socket(socket.AF_INET))
- self.assertRaisesRegex(ssl.SSLError, "certificate verify failed",
- s.connect, (REMOTE_HOST, 443))
- s.close()
- # This should succeed because we specify the root cert
- ctx.load_verify_locations(REMOTE_ROOT_CERT)
- s = ctx.wrap_socket(socket.socket(socket.AF_INET))
- s.connect((REMOTE_HOST, 443))
- try:
- cert = s.getpeercert()
- self.assertTrue(cert)
- finally:
- s.close()
+ # Same as test_connect, but with a separately created context
+ ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
+ with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
+ s.connect(self.server_addr)
+ self.assertEqual({}, s.getpeercert())
+ # Same with a server hostname
+ with ctx.wrap_socket(socket.socket(socket.AF_INET),
+ server_hostname="dummy") as s:
+ s.connect(self.server_addr)
+ ctx.verify_mode = ssl.CERT_REQUIRED
+ # This should succeed because we specify the root cert
+ ctx.load_verify_locations(SIGNING_CA)
+ with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
+ s.connect(self.server_addr)
+ cert = s.getpeercert()
+ self.assertTrue(cert)
+
+ def test_connect_with_context_fail(self):
+ # This should fail because we have no verification certs. Connection
+ # failure crashes ThreadedEchoServer, so run this in an independent
+ # test method.
+ ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
+ ctx.verify_mode = ssl.CERT_REQUIRED
+ s = ctx.wrap_socket(socket.socket(socket.AF_INET))
+ self.addCleanup(s.close)
+ self.assertRaisesRegex(ssl.SSLError, "certificate verify failed",
+ s.connect, self.server_addr)
def test_connect_capath(self):
# Verify server certificates using the `capath` argument
@@ -1509,198 +1495,130 @@ class NetworkedTests(unittest.TestCase):
# OpenSSL 0.9.8n and 1.0.0, as a result the capath directory must
# contain both versions of each certificate (same content, different
# filename) for this test to be portable across OpenSSL releases.
- with support.transient_internet(REMOTE_HOST):
- ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
- ctx.verify_mode = ssl.CERT_REQUIRED
- ctx.load_verify_locations(capath=CAPATH)
- s = ctx.wrap_socket(socket.socket(socket.AF_INET))
- s.connect((REMOTE_HOST, 443))
- try:
- cert = s.getpeercert()
- self.assertTrue(cert)
- finally:
- s.close()
- # Same with a bytes `capath` argument
- ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
- ctx.verify_mode = ssl.CERT_REQUIRED
- ctx.load_verify_locations(capath=BYTES_CAPATH)
- s = ctx.wrap_socket(socket.socket(socket.AF_INET))
- s.connect((REMOTE_HOST, 443))
- try:
- cert = s.getpeercert()
- self.assertTrue(cert)
- finally:
- s.close()
+ ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
+ ctx.verify_mode = ssl.CERT_REQUIRED
+ ctx.load_verify_locations(capath=CAPATH)
+ with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
+ s.connect(self.server_addr)
+ cert = s.getpeercert()
+ self.assertTrue(cert)
+ # Same with a bytes `capath` argument
+ ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
+ ctx.verify_mode = ssl.CERT_REQUIRED
+ ctx.load_verify_locations(capath=BYTES_CAPATH)
+ with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
+ s.connect(self.server_addr)
+ cert = s.getpeercert()
+ self.assertTrue(cert)
def test_connect_cadata(self):
- with open(REMOTE_ROOT_CERT) as f:
+ with open(SIGNING_CA) as f:
pem = f.read()
der = ssl.PEM_cert_to_DER_cert(pem)
- with support.transient_internet(REMOTE_HOST):
- ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
- ctx.verify_mode = ssl.CERT_REQUIRED
- ctx.load_verify_locations(cadata=pem)
- with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
- s.connect((REMOTE_HOST, 443))
- cert = s.getpeercert()
- self.assertTrue(cert)
+ ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
+ ctx.verify_mode = ssl.CERT_REQUIRED
+ ctx.load_verify_locations(cadata=pem)
+ with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
+ s.connect(self.server_addr)
+ cert = s.getpeercert()
+ self.assertTrue(cert)
- # same with DER
- ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
- ctx.verify_mode = ssl.CERT_REQUIRED
- ctx.load_verify_locations(cadata=der)
- with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
- s.connect((REMOTE_HOST, 443))
- cert = s.getpeercert()
- self.assertTrue(cert)
+ # same with DER
+ ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
+ ctx.verify_mode = ssl.CERT_REQUIRED
+ ctx.load_verify_locations(cadata=der)
+ with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
+ s.connect(self.server_addr)
+ cert = s.getpeercert()
+ self.assertTrue(cert)
@unittest.skipIf(os.name == "nt", "Can't use a socket as a file under Windows")
def test_makefile_close(self):
# Issue #5238: creating a file-like object with makefile() shouldn't
# delay closing the underlying "real socket" (here tested with its
# file descriptor, hence skipping the test under Windows).
- with support.transient_internet(REMOTE_HOST):
- ss = ssl.wrap_socket(socket.socket(socket.AF_INET))
- ss.connect((REMOTE_HOST, 443))
- fd = ss.fileno()
- f = ss.makefile()
- f.close()
- # The fd is still open
+ ss = ssl.wrap_socket(socket.socket(socket.AF_INET))
+ ss.connect(self.server_addr)
+ fd = ss.fileno()
+ f = ss.makefile()
+ f.close()
+ # The fd is still open
+ os.read(fd, 0)
+ # Closing the SSL socket should close the fd too
+ ss.close()
+ gc.collect()
+ with self.assertRaises(OSError) as e:
os.read(fd, 0)
- # Closing the SSL socket should close the fd too
- ss.close()
- gc.collect()
- with self.assertRaises(OSError) as e:
- os.read(fd, 0)
- self.assertEqual(e.exception.errno, errno.EBADF)
+ self.assertEqual(e.exception.errno, errno.EBADF)
def test_non_blocking_handshake(self):
- with support.transient_internet(REMOTE_HOST):
- s = socket.socket(socket.AF_INET)
- s.connect((REMOTE_HOST, 443))
- s.setblocking(False)
- s = ssl.wrap_socket(s,
- cert_reqs=ssl.CERT_NONE,
- do_handshake_on_connect=False)
- count = 0
- while True:
- try:
- count += 1
- s.do_handshake()
- break
- except ssl.SSLWantReadError:
- select.select([s], [], [])
- except ssl.SSLWantWriteError:
- select.select([], [s], [])
- s.close()
- if support.verbose:
- sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
+ s = socket.socket(socket.AF_INET)
+ s.connect(self.server_addr)
+ s.setblocking(False)
+ s = ssl.wrap_socket(s,
+ cert_reqs=ssl.CERT_NONE,
+ do_handshake_on_connect=False)
+ self.addCleanup(s.close)
+ count = 0
+ while True:
+ try:
+ count += 1
+ s.do_handshake()
+ break
+ except ssl.SSLWantReadError:
+ select.select([s], [], [])
+ except ssl.SSLWantWriteError:
+ select.select([], [s], [])
+ if support.verbose:
+ sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
def test_get_server_certificate(self):
- def _test_get_server_certificate(host, port, cert=None):
- with support.transient_internet(host):
- pem = ssl.get_server_certificate((host, port))
- if not pem:
- self.fail("No server certificate on %s:%s!" % (host, port))
-
- try:
- pem = ssl.get_server_certificate((host, port),
- ca_certs=CERTFILE)
- except ssl.SSLError as x:
- #should fail
- if support.verbose:
- sys.stdout.write("%s\n" % x)
- else:
- self.fail("Got server certificate %s for %s:%s!" % (pem, host, port))
-
- pem = ssl.get_server_certificate((host, port),
- ca_certs=cert)
- if not pem:
- self.fail("No server certificate on %s:%s!" % (host, port))
- if support.verbose:
- sys.stdout.write("\nVerified certificate for %s:%s is\n%s\n" % (host, port ,pem))
+ _test_get_server_certificate(self, *self.server_addr, cert=SIGNING_CA)
- _test_get_server_certificate(REMOTE_HOST, 443, REMOTE_ROOT_CERT)
- if support.IPV6_ENABLED:
- _test_get_server_certificate('ipv6.google.com', 443)
+ def test_get_server_certificate_fail(self):
+ # Connection failure crashes ThreadedEchoServer, so run this in an
+ # independent test method
+ _test_get_server_certificate_fail(self, *self.server_addr)
def test_ciphers(self):
- remote = (REMOTE_HOST, 443)
- with support.transient_internet(remote[0]):
- with ssl.wrap_socket(socket.socket(socket.AF_INET),
- cert_reqs=ssl.CERT_NONE, ciphers="ALL") as s:
- s.connect(remote)
- with ssl.wrap_socket(socket.socket(socket.AF_INET),
- cert_reqs=ssl.CERT_NONE, ciphers="DEFAULT") as s:
- s.connect(remote)
- # Error checking can happen at instantiation or when connecting
- with self.assertRaisesRegex(ssl.SSLError, "No cipher can be selected"):
- with socket.socket(socket.AF_INET) as sock:
- s = ssl.wrap_socket(sock,
- cert_reqs=ssl.CERT_NONE, ciphers="^$:,;?*'dorothyx")
- s.connect(remote)
-
- def test_algorithms(self):
- # Issue #8484: all algorithms should be available when verifying a
- # certificate.
- # SHA256 was added in OpenSSL 0.9.8
- if ssl.OPENSSL_VERSION_INFO < (0, 9, 8, 0, 15):
- self.skipTest("SHA256 not available on %r" % ssl.OPENSSL_VERSION)
- # sha256.tbs-internet.com needs SNI to use the correct certificate
- if not ssl.HAS_SNI:
- self.skipTest("SNI needed for this test")
- # https://sha2.hboeck.de/ was used until 2011-01-08 (no route to host)
- remote = ("sha256.tbs-internet.com", 443)
- sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem")
- with support.transient_internet("sha256.tbs-internet.com"):
- ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
- ctx.verify_mode = ssl.CERT_REQUIRED
- ctx.load_verify_locations(sha256_cert)
- s = ctx.wrap_socket(socket.socket(socket.AF_INET),
- server_hostname="sha256.tbs-internet.com")
- try:
- s.connect(remote)
- if support.verbose:
- sys.stdout.write("\nCipher with %r is %r\n" %
- (remote, s.cipher()))
- sys.stdout.write("Certificate is:\n%s\n" %
- pprint.pformat(s.getpeercert()))
- finally:
- s.close()
+ with ssl.wrap_socket(socket.socket(socket.AF_INET),
+ cert_reqs=ssl.CERT_NONE, ciphers="ALL") as s:
+ s.connect(self.server_addr)
+ with ssl.wrap_socket(socket.socket(socket.AF_INET),
+ cert_reqs=ssl.CERT_NONE, ciphers="DEFAULT") as s:
+ s.connect(self.server_addr)
+ # Error checking can happen at instantiation or when connecting
+ with self.assertRaisesRegex(ssl.SSLError, "No cipher can be selected"):
+ with socket.socket(socket.AF_INET) as sock:
+ s = ssl.wrap_socket(sock,
+ cert_reqs=ssl.CERT_NONE, ciphers="^$:,;?*'dorothyx")
+ s.connect(self.server_addr)
def test_get_ca_certs_capath(self):
# capath certs are loaded on request
- with support.transient_internet(REMOTE_HOST):
- ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
- ctx.verify_mode = ssl.CERT_REQUIRED
- ctx.load_verify_locations(capath=CAPATH)
- self.assertEqual(ctx.get_ca_certs(), [])
- s = ctx.wrap_socket(socket.socket(socket.AF_INET))
- s.connect((REMOTE_HOST, 443))
- try:
- cert = s.getpeercert()
- self.assertTrue(cert)
- finally:
- s.close()
- self.assertEqual(len(ctx.get_ca_certs()), 1)
+ ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
+ ctx.verify_mode = ssl.CERT_REQUIRED
+ ctx.load_verify_locations(capath=CAPATH)
+ self.assertEqual(ctx.get_ca_certs(), [])
+ with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s:
+ s.connect(self.server_addr)
+ cert = s.getpeercert()
+ self.assertTrue(cert)
+ self.assertEqual(len(ctx.get_ca_certs()), 1)
@needs_sni
def test_context_setget(self):
# Check that the context of a connected socket can be replaced.
- with support.transient_internet(REMOTE_HOST):
- ctx1 = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
- ctx2 = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
- s = socket.socket(socket.AF_INET)
- with ctx1.wrap_socket(s) as ss:
- ss.connect((REMOTE_HOST, 443))
- self.assertIs(ss.context, ctx1)
- self.assertIs(ss._sslobj.context, ctx1)
- ss.context = ctx2
- self.assertIs(ss.context, ctx2)
- self.assertIs(ss._sslobj.context, ctx2)
-
-
-class NetworkedBIOTests(unittest.TestCase):
+ ctx1 = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
+ ctx2 = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
+ s = socket.socket(socket.AF_INET)
+ with ctx1.wrap_socket(s) as ss:
+ ss.connect(self.server_addr)
+ self.assertIs(ss.context, ctx1)
+ self.assertIs(ss._sslobj.context, ctx1)
+ ss.context = ctx2
+ self.assertIs(ss.context, ctx2)
+ self.assertIs(ss._sslobj.context, ctx2)
def ssl_io_loop(self, sock, incoming, outgoing, func, *args, **kwargs):
# A simple IO loop. Call func(*args) depending on the error we get
@@ -1736,64 +1654,128 @@ class NetworkedBIOTests(unittest.TestCase):
% (count, func.__name__))
return ret
- def test_handshake(self):
+ def test_bio_handshake(self):
+ sock = socket.socket(socket.AF_INET)
+ self.addCleanup(sock.close)
+ sock.connect(self.server_addr)
+ incoming = ssl.MemoryBIO()
+ outgoing = ssl.MemoryBIO()
+ ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
+ ctx.verify_mode = ssl.CERT_REQUIRED
+ ctx.load_verify_locations(SIGNING_CA)
+ ctx.check_hostname = True
+ sslobj = ctx.wrap_bio(incoming, outgoing, False, 'localhost')
+ self.assertIs(sslobj._sslobj.owner, sslobj)
+ self.assertIsNone(sslobj.cipher())
+ self.assertIsNone(sslobj.shared_ciphers())
+ self.assertRaises(ValueError, sslobj.getpeercert)
+ if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES:
+ self.assertIsNone(sslobj.get_channel_binding('tls-unique'))
+ self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake)
+ self.assertTrue(sslobj.cipher())
+ self.assertIsNone(sslobj.shared_ciphers())
+ self.assertTrue(sslobj.getpeercert())
+ if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES:
+ self.assertTrue(sslobj.get_channel_binding('tls-unique'))
+ try:
+ self.ssl_io_loop(sock, incoming, outgoing, sslobj.unwrap)
+ except ssl.SSLSyscallError:
+ # If the server shuts down the TCP connection without sending a
+ # secure shutdown message, this is reported as SSL_ERROR_SYSCALL
+ pass
+ self.assertRaises(ssl.SSLError, sslobj.write, b'foo')
+
+ def test_bio_read_write_data(self):
+ sock = socket.socket(socket.AF_INET)
+ self.addCleanup(sock.close)
+ sock.connect(self.server_addr)
+ incoming = ssl.MemoryBIO()
+ outgoing = ssl.MemoryBIO()
+ ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
+ ctx.verify_mode = ssl.CERT_NONE
+ sslobj = ctx.wrap_bio(incoming, outgoing, False)
+ self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake)
+ req = b'FOO\n'
+ self.ssl_io_loop(sock, incoming, outgoing, sslobj.write, req)
+ buf = self.ssl_io_loop(sock, incoming, outgoing, sslobj.read, 1024)
+ self.assertEqual(buf, b'foo\n')
+ self.ssl_io_loop(sock, incoming, outgoing, sslobj.unwrap)
+
+
+class NetworkedTests(unittest.TestCase):
+
+ def test_timeout_connect_ex(self):
+ # Issue #12065: on a timeout, connect_ex() should return the original
+ # errno (mimicking the behaviour of non-SSL sockets).
with support.transient_internet(REMOTE_HOST):
- sock = socket.socket(socket.AF_INET)
- sock.connect((REMOTE_HOST, 443))
- incoming = ssl.MemoryBIO()
- outgoing = ssl.MemoryBIO()
- ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
+ s = ssl.wrap_socket(socket.socket(socket.AF_INET),
+ cert_reqs=ssl.CERT_REQUIRED,
+ do_handshake_on_connect=False)
+ self.addCleanup(s.close)
+ s.settimeout(0.0000001)
+ rc = s.connect_ex((REMOTE_HOST, 443))
+ if rc == 0:
+ self.skipTest("REMOTE_HOST responded too quickly")
+ self.assertIn(rc, (errno.EAGAIN, errno.EWOULDBLOCK))
+
+ @unittest.skipUnless(support.IPV6_ENABLED, 'Needs IPv6')
+ def test_get_server_certificate_ipv6(self):
+ with support.transient_internet('ipv6.google.com'):
+ _test_get_server_certificate(self, 'ipv6.google.com', 443)
+ _test_get_server_certificate_fail(self, 'ipv6.google.com', 443)
+
+ def test_algorithms(self):
+ # Issue #8484: all algorithms should be available when verifying a
+ # certificate.
+ # SHA256 was added in OpenSSL 0.9.8
+ if ssl.OPENSSL_VERSION_INFO < (0, 9, 8, 0, 15):
+ self.skipTest("SHA256 not available on %r" % ssl.OPENSSL_VERSION)
+ # sha256.tbs-internet.com needs SNI to use the correct certificate
+ if not ssl.HAS_SNI:
+ self.skipTest("SNI needed for this test")
+ # https://sha2.hboeck.de/ was used until 2011-01-08 (no route to host)
+ remote = ("sha256.tbs-internet.com", 443)
+ sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem")
+ with support.transient_internet("sha256.tbs-internet.com"):
+ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
ctx.verify_mode = ssl.CERT_REQUIRED
- ctx.load_verify_locations(REMOTE_ROOT_CERT)
- ctx.check_hostname = True
- sslobj = ctx.wrap_bio(incoming, outgoing, False, REMOTE_HOST)
- self.assertIs(sslobj._sslobj.owner, sslobj)
- self.assertIsNone(sslobj.cipher())
- self.assertIsNone(sslobj.shared_ciphers())
- self.assertRaises(ValueError, sslobj.getpeercert)
- if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES:
- self.assertIsNone(sslobj.get_channel_binding('tls-unique'))
- self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake)
- self.assertTrue(sslobj.cipher())
- self.assertIsNone(sslobj.shared_ciphers())
- self.assertTrue(sslobj.getpeercert())
- if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES:
- self.assertTrue(sslobj.get_channel_binding('tls-unique'))
+ ctx.load_verify_locations(sha256_cert)
+ s = ctx.wrap_socket(socket.socket(socket.AF_INET),
+ server_hostname="sha256.tbs-internet.com")
try:
- self.ssl_io_loop(sock, incoming, outgoing, sslobj.unwrap)
- except ssl.SSLSyscallError:
- # self-signed.pythontest.net probably shuts down the TCP
- # connection without sending a secure shutdown message, and
- # this is reported as SSL_ERROR_SYSCALL
- pass
- self.assertRaises(ssl.SSLError, sslobj.write, b'foo')
- sock.close()
+ s.connect(remote)
+ if support.verbose:
+ sys.stdout.write("\nCipher with %r is %r\n" %
+ (remote, s.cipher()))
+ sys.stdout.write("Certificate is:\n%s\n" %
+ pprint.pformat(s.getpeercert()))
+ finally:
+ s.close()
- def test_read_write_data(self):
- with support.transient_internet(REMOTE_HOST):
- sock = socket.socket(socket.AF_INET)
- sock.connect((REMOTE_HOST, 443))
- incoming = ssl.MemoryBIO()
- outgoing = ssl.MemoryBIO()
- ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
- ctx.verify_mode = ssl.CERT_NONE
- sslobj = ctx.wrap_bio(incoming, outgoing, False)
- self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake)
- req = b'GET / HTTP/1.0\r\n\r\n'
- self.ssl_io_loop(sock, incoming, outgoing, sslobj.write, req)
- buf = self.ssl_io_loop(sock, incoming, outgoing, sslobj.read, 1024)
- self.assertEqual(buf[:5], b'HTTP/')
- self.ssl_io_loop(sock, incoming, outgoing, sslobj.unwrap)
- sock.close()
+def _test_get_server_certificate(test, host, port, cert=None):
+ pem = ssl.get_server_certificate((host, port))
+ if not pem:
+ test.fail("No server certificate on %s:%s!" % (host, port))
-try:
- import threading
-except ImportError:
- _have_threads = False
-else:
- _have_threads = True
+ pem = ssl.get_server_certificate((host, port), ca_certs=cert)
+ if not pem:
+ test.fail("No server certificate on %s:%s!" % (host, port))
+ if support.verbose:
+ sys.stdout.write("\nVerified certificate for %s:%s is\n%s\n" % (host, port ,pem))
+def _test_get_server_certificate_fail(test, host, port):
+ try:
+ pem = ssl.get_server_certificate((host, port), ca_certs=CERTFILE)
+ except ssl.SSLError as x:
+ #should fail
+ if support.verbose:
+ sys.stdout.write("%s\n" % x)
+ else:
+ test.fail("Got server certificate %s for %s:%s!" % (pem, host, port))
+
+
+if _have_threads:
from test.ssl_servers import make_https_server
class ThreadedEchoServer(threading.Thread):
@@ -1881,6 +1863,15 @@ else:
if not stripped:
# eof, so quit this handler
self.running = False
+ try:
+ self.sock = self.sslconn.unwrap()
+ except OSError:
+ # Many tests shut the TCP connection down
+ # without an SSL shutdown. This causes
+ # unwrap() to raise OSError with errno=0!
+ pass
+ else:
+ self.sslconn = None
self.close()
elif stripped == b'over':
if support.verbose and self.server.connectionchatty:
@@ -2718,12 +2709,13 @@ else:
count, addr = s.recvfrom_into(b)
return b[:count]
- # (name, method, whether to expect success, *args)
+ # (name, method, expect success?, *args, return value func)
send_methods = [
- ('send', s.send, True, []),
- ('sendto', s.sendto, False, ["some.address"]),
- ('sendall', s.sendall, True, []),
+ ('send', s.send, True, [], len),
+ ('sendto', s.sendto, False, ["some.address"], len),
+ ('sendall', s.sendall, True, [], lambda x: None),
]
+ # (name, method, whether to expect success, *args)
recv_methods = [
('recv', s.recv, True, []),
('recvfrom', s.recvfrom, False, ["some.address"]),
@@ -2732,10 +2724,13 @@ else:
]
data_prefix = "PREFIX_"
- for meth_name, send_meth, expect_success, args in send_methods:
+ for (meth_name, send_meth, expect_success, args,
+ ret_val_meth) in send_methods:
indata = (data_prefix + meth_name).encode('ascii')
try:
- send_meth(indata, *args)
+ ret = send_meth(indata, *args)
+ msg = "sending with {}".format(meth_name)
+ self.assertEqual(ret, ret_val_meth(indata), msg=msg)
outdata = s.read()
if outdata != indata.lower():
self.fail(
@@ -3360,18 +3355,20 @@ def test_main(verbose=False):
pass
for filename in [
- CERTFILE, REMOTE_ROOT_CERT, BYTES_CERTFILE,
+ CERTFILE, BYTES_CERTFILE,
ONLYCERT, ONLYKEY, BYTES_ONLYCERT, BYTES_ONLYKEY,
SIGNED_CERTFILE, SIGNED_CERTFILE2, SIGNING_CA,
BADCERT, BADKEY, EMPTYCERT]:
if not os.path.exists(filename):
raise support.TestFailed("Can't read certificate file %r" % filename)
- tests = [ContextTests, BasicSocketTests, SSLErrorTests, MemoryBIOTests]
+ tests = [
+ ContextTests, BasicSocketTests, SSLErrorTests, MemoryBIOTests,
+ SimpleBackgroundTests,
+ ]
if support.is_resource_enabled('network'):
tests.append(NetworkedTests)
- tests.append(NetworkedBIOTests)
if _have_threads:
thread_info = support.threading_setup()
diff --git a/Lib/test/test_statistics.py b/Lib/test/test_statistics.py
index 0089ae8dc6..5275cb681d 100644
--- a/Lib/test/test_statistics.py
+++ b/Lib/test/test_statistics.py
@@ -702,9 +702,9 @@ class ExactRatioTest(unittest.TestCase):
def test_decimal(self):
D = Decimal
_exact_ratio = statistics._exact_ratio
- self.assertEqual(_exact_ratio(D("0.125")), (125, 1000))
- self.assertEqual(_exact_ratio(D("12.345")), (12345, 1000))
- self.assertEqual(_exact_ratio(D("-1.98")), (-198, 100))
+ self.assertEqual(_exact_ratio(D("0.125")), (1, 8))
+ self.assertEqual(_exact_ratio(D("12.345")), (2469, 200))
+ self.assertEqual(_exact_ratio(D("-1.98")), (-99, 50))
def test_inf(self):
INF = float("INF")
@@ -743,18 +743,18 @@ class ExactRatioTest(unittest.TestCase):
class DecimalToRatioTest(unittest.TestCase):
- # Test _decimal_to_ratio private function.
+ # Test _exact_ratio private function.
def test_infinity(self):
# Test that INFs are handled correctly.
inf = Decimal('INF')
- self.assertEqual(statistics._decimal_to_ratio(inf), (inf, None))
- self.assertEqual(statistics._decimal_to_ratio(-inf), (-inf, None))
+ self.assertEqual(statistics._exact_ratio(inf), (inf, None))
+ self.assertEqual(statistics._exact_ratio(-inf), (-inf, None))
def test_nan(self):
# Test that NANs are handled correctly.
for nan in (Decimal('NAN'), Decimal('sNAN')):
- num, den = statistics._decimal_to_ratio(nan)
+ num, den = statistics._exact_ratio(nan)
# Because NANs always compare non-equal, we cannot use assertEqual.
# Nor can we use an identity test, as we don't guarantee anything
# about the object identity.
@@ -767,30 +767,30 @@ class DecimalToRatioTest(unittest.TestCase):
for d in numbers:
# First test positive decimals.
assert d > 0
- num, den = statistics._decimal_to_ratio(d)
+ num, den = statistics._exact_ratio(d)
self.assertGreaterEqual(num, 0)
self.assertGreater(den, 0)
# Then test negative decimals.
- num, den = statistics._decimal_to_ratio(-d)
+ num, den = statistics._exact_ratio(-d)
self.assertLessEqual(num, 0)
self.assertGreater(den, 0)
def test_negative_exponent(self):
# Test result when the exponent is negative.
- t = statistics._decimal_to_ratio(Decimal("0.1234"))
- self.assertEqual(t, (1234, 10000))
+ t = statistics._exact_ratio(Decimal("0.1234"))
+ self.assertEqual(t, (617, 5000))
def test_positive_exponent(self):
# Test results when the exponent is positive.
- t = statistics._decimal_to_ratio(Decimal("1.234e7"))
+ t = statistics._exact_ratio(Decimal("1.234e7"))
self.assertEqual(t, (12340000, 1))
def test_regression_20536(self):
# Regression test for issue 20536.
# See http://bugs.python.org/issue20536
- t = statistics._decimal_to_ratio(Decimal("1e2"))
+ t = statistics._exact_ratio(Decimal("1e2"))
self.assertEqual(t, (100, 1))
- t = statistics._decimal_to_ratio(Decimal("1.47e5"))
+ t = statistics._exact_ratio(Decimal("1.47e5"))
self.assertEqual(t, (147000, 1))
diff --git a/Lib/test/test_strptime.py b/Lib/test/test_strptime.py
index 85126e6e53..8c8f97ba50 100644
--- a/Lib/test/test_strptime.py
+++ b/Lib/test/test_strptime.py
@@ -5,7 +5,6 @@ import time
import locale
import re
import os
-import sys
from test import support
from datetime import date as datetime_date
@@ -153,8 +152,8 @@ class TimeRETests(unittest.TestCase):
"'%s' using '%s'; group 'a' = '%s', group 'b' = %s'" %
(found.string, found.re.pattern, found.group('a'),
found.group('b')))
- for directive in ('a','A','b','B','c','d','H','I','j','m','M','p','S',
- 'U','w','W','x','X','y','Y','Z','%'):
+ for directive in ('a','A','b','B','c','d','G','H','I','j','m','M','p',
+ 'S','u','U','V','w','W','x','X','y','Y','Z','%'):
compiled = self.time_re.compile("%" + directive)
found = compiled.match(time.strftime("%" + directive))
self.assertTrue(found, "Matching failed on '%s' using '%s' regex" %
@@ -219,6 +218,26 @@ class StrptimeTests(unittest.TestCase):
else:
self.fail("'%s' did not raise ValueError" % bad_format)
+ # Ambiguous or incomplete cases using ISO year/week/weekday directives
+ # 1. ISO week (%V) is specified, but the year is specified with %Y
+ # instead of %G
+ with self.assertRaises(ValueError):
+ _strptime._strptime("1999 50", "%Y %V")
+ # 2. ISO year (%G) and ISO week (%V) are specified, but weekday is not
+ with self.assertRaises(ValueError):
+ _strptime._strptime("1999 51", "%G %V")
+ # 3. ISO year (%G) and weekday are specified, but ISO week (%V) is not
+ for w in ('A', 'a', 'w', 'u'):
+ with self.assertRaises(ValueError):
+ _strptime._strptime("1999 51","%G %{}".format(w))
+ # 4. ISO year is specified alone (e.g. time.strptime('2015', '%G'))
+ with self.assertRaises(ValueError):
+ _strptime._strptime("2015", "%G")
+ # 5. Julian/ordinal day (%j) is specified with %G, but not %Y
+ with self.assertRaises(ValueError):
+ _strptime._strptime("1999 256", "%G %j")
+
+
def test_strptime_exception_context(self):
# check that this doesn't chain exceptions needlessly (see #17572)
with self.assertRaises(ValueError) as e:
@@ -290,7 +309,7 @@ class StrptimeTests(unittest.TestCase):
def test_weekday(self):
# Test weekday directives
- for directive in ('A', 'a', 'w'):
+ for directive in ('A', 'a', 'w', 'u'):
self.helper(directive,6)
def test_julian(self):
@@ -457,16 +476,20 @@ class CalculationTests(unittest.TestCase):
# Should be able to infer date if given year, week of year (%U or %W)
# and day of the week
def test_helper(ymd_tuple, test_reason):
- for directive in ('W', 'U'):
- format_string = "%%Y %%%s %%w" % directive
- dt_date = datetime_date(*ymd_tuple)
- strp_input = dt_date.strftime(format_string)
- strp_output = _strptime._strptime_time(strp_input, format_string)
- self.assertTrue(strp_output[:3] == ymd_tuple,
- "%s(%s) test failed w/ '%s': %s != %s (%s != %s)" %
- (test_reason, directive, strp_input,
- strp_output[:3], ymd_tuple,
- strp_output[7], dt_date.timetuple()[7]))
+ for year_week_format in ('%Y %W', '%Y %U', '%G %V'):
+ for weekday_format in ('%w', '%u', '%a', '%A'):
+ format_string = year_week_format + ' ' + weekday_format
+ with self.subTest(test_reason,
+ date=ymd_tuple,
+ format=format_string):
+ dt_date = datetime_date(*ymd_tuple)
+ strp_input = dt_date.strftime(format_string)
+ strp_output = _strptime._strptime_time(strp_input,
+ format_string)
+ msg = "%r: %s != %s" % (strp_input,
+ strp_output[7],
+ dt_date.timetuple()[7])
+ self.assertEqual(strp_output[:3], ymd_tuple, msg)
test_helper((1901, 1, 3), "week 0")
test_helper((1901, 1, 8), "common case")
test_helper((1901, 1, 13), "day on Sunday")
@@ -498,33 +521,48 @@ class CalculationTests(unittest.TestCase):
self.assertEqual(_strptime._strptime_time(value, format)[:-1], expected)
check('2015 0 0', '%Y %U %w', 2014, 12, 28, 0, 0, 0, 6, 362)
check('2015 0 0', '%Y %W %w', 2015, 1, 4, 0, 0, 0, 6, 4)
+ check('2015 1 1', '%G %V %u', 2014, 12, 29, 0, 0, 0, 0, 363)
check('2015 0 1', '%Y %U %w', 2014, 12, 29, 0, 0, 0, 0, 363)
check('2015 0 1', '%Y %W %w', 2014, 12, 29, 0, 0, 0, 0, 363)
+ check('2015 1 2', '%G %V %u', 2014, 12, 30, 0, 0, 0, 1, 364)
check('2015 0 2', '%Y %U %w', 2014, 12, 30, 0, 0, 0, 1, 364)
check('2015 0 2', '%Y %W %w', 2014, 12, 30, 0, 0, 0, 1, 364)
+ check('2015 1 3', '%G %V %u', 2014, 12, 31, 0, 0, 0, 2, 365)
check('2015 0 3', '%Y %U %w', 2014, 12, 31, 0, 0, 0, 2, 365)
check('2015 0 3', '%Y %W %w', 2014, 12, 31, 0, 0, 0, 2, 365)
+ check('2015 1 4', '%G %V %u', 2015, 1, 1, 0, 0, 0, 3, 1)
check('2015 0 4', '%Y %U %w', 2015, 1, 1, 0, 0, 0, 3, 1)
check('2015 0 4', '%Y %W %w', 2015, 1, 1, 0, 0, 0, 3, 1)
+ check('2015 1 5', '%G %V %u', 2015, 1, 2, 0, 0, 0, 4, 2)
check('2015 0 5', '%Y %U %w', 2015, 1, 2, 0, 0, 0, 4, 2)
check('2015 0 5', '%Y %W %w', 2015, 1, 2, 0, 0, 0, 4, 2)
+ check('2015 1 6', '%G %V %u', 2015, 1, 3, 0, 0, 0, 5, 3)
check('2015 0 6', '%Y %U %w', 2015, 1, 3, 0, 0, 0, 5, 3)
check('2015 0 6', '%Y %W %w', 2015, 1, 3, 0, 0, 0, 5, 3)
+ check('2015 1 7', '%G %V %u', 2015, 1, 4, 0, 0, 0, 6, 4)
check('2009 0 0', '%Y %U %w', 2008, 12, 28, 0, 0, 0, 6, 363)
check('2009 0 0', '%Y %W %w', 2009, 1, 4, 0, 0, 0, 6, 4)
+ check('2009 1 1', '%G %V %u', 2008, 12, 29, 0, 0, 0, 0, 364)
check('2009 0 1', '%Y %U %w', 2008, 12, 29, 0, 0, 0, 0, 364)
check('2009 0 1', '%Y %W %w', 2008, 12, 29, 0, 0, 0, 0, 364)
+ check('2009 1 2', '%G %V %u', 2008, 12, 30, 0, 0, 0, 1, 365)
check('2009 0 2', '%Y %U %w', 2008, 12, 30, 0, 0, 0, 1, 365)
check('2009 0 2', '%Y %W %w', 2008, 12, 30, 0, 0, 0, 1, 365)
+ check('2009 1 3', '%G %V %u', 2008, 12, 31, 0, 0, 0, 2, 366)
check('2009 0 3', '%Y %U %w', 2008, 12, 31, 0, 0, 0, 2, 366)
check('2009 0 3', '%Y %W %w', 2008, 12, 31, 0, 0, 0, 2, 366)
+ check('2009 1 4', '%G %V %u', 2009, 1, 1, 0, 0, 0, 3, 1)
check('2009 0 4', '%Y %U %w', 2009, 1, 1, 0, 0, 0, 3, 1)
check('2009 0 4', '%Y %W %w', 2009, 1, 1, 0, 0, 0, 3, 1)
+ check('2009 1 5', '%G %V %u', 2009, 1, 2, 0, 0, 0, 4, 2)
check('2009 0 5', '%Y %U %w', 2009, 1, 2, 0, 0, 0, 4, 2)
check('2009 0 5', '%Y %W %w', 2009, 1, 2, 0, 0, 0, 4, 2)
+ check('2009 1 6', '%G %V %u', 2009, 1, 3, 0, 0, 0, 5, 3)
check('2009 0 6', '%Y %U %w', 2009, 1, 3, 0, 0, 0, 5, 3)
check('2009 0 6', '%Y %W %w', 2009, 1, 3, 0, 0, 0, 5, 3)
+ check('2009 1 7', '%G %V %u', 2009, 1, 4, 0, 0, 0, 6, 4)
+
class CacheTests(unittest.TestCase):
"""Test that caching works properly."""
diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py
index 9c7aa93f04..a8f0a64e96 100644
--- a/Lib/test/test_subprocess.py
+++ b/Lib/test/test_subprocess.py
@@ -1,19 +1,15 @@
import unittest
-from test.support import script_helper
from test import support
import subprocess
import sys
import signal
import io
-import locale
import os
import errno
import tempfile
import time
-import re
import selectors
import sysconfig
-import warnings
import select
import shutil
import gc
@@ -447,8 +443,8 @@ class ProcessTestCase(BaseTestCase):
p = subprocess.Popen([sys.executable, "-c",
'import sys; sys.stdout.write("orange")'],
stdout=subprocess.PIPE)
- self.addCleanup(p.stdout.close)
- self.assertEqual(p.stdout.read(), b"orange")
+ with p:
+ self.assertEqual(p.stdout.read(), b"orange")
def test_stdout_filedes(self):
# stdout is set to open file descriptor
@@ -478,8 +474,8 @@ class ProcessTestCase(BaseTestCase):
p = subprocess.Popen([sys.executable, "-c",
'import sys; sys.stderr.write("strawberry")'],
stderr=subprocess.PIPE)
- self.addCleanup(p.stderr.close)
- self.assertStderrEqual(p.stderr.read(), b"strawberry")
+ with p:
+ self.assertStderrEqual(p.stderr.read(), b"strawberry")
def test_stderr_filedes(self):
# stderr is set to open file descriptor
@@ -534,8 +530,8 @@ class ProcessTestCase(BaseTestCase):
'sys.stderr.write("orange")'],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
- self.addCleanup(p.stdout.close)
- self.assertStderrEqual(p.stdout.read(), b"appleorange")
+ with p:
+ self.assertStderrEqual(p.stdout.read(), b"appleorange")
def test_stdout_stderr_file(self):
# capture stdout and stderr to the same open file
@@ -793,18 +789,19 @@ class ProcessTestCase(BaseTestCase):
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
universal_newlines=1)
- p.stdin.write("line1\n")
- p.stdin.flush()
- self.assertEqual(p.stdout.readline(), "line1\n")
- p.stdin.write("line3\n")
- p.stdin.close()
- self.addCleanup(p.stdout.close)
- self.assertEqual(p.stdout.readline(),
- "line2\n")
- self.assertEqual(p.stdout.read(6),
- "line3\n")
- self.assertEqual(p.stdout.read(),
- "line4\nline5\nline6\nline7\nline8")
+ with p:
+ p.stdin.write("line1\n")
+ p.stdin.flush()
+ self.assertEqual(p.stdout.readline(), "line1\n")
+ p.stdin.write("line3\n")
+ p.stdin.close()
+ self.addCleanup(p.stdout.close)
+ self.assertEqual(p.stdout.readline(),
+ "line2\n")
+ self.assertEqual(p.stdout.read(6),
+ "line3\n")
+ self.assertEqual(p.stdout.read(),
+ "line4\nline5\nline6\nline7\nline8")
def test_universal_newlines_communicate(self):
# universal newlines through communicate()
@@ -1438,8 +1435,8 @@ class POSIXProcessTestCase(BaseTestCase):
'sys.stdout.write(os.getenv("FRUIT"))'],
stdout=subprocess.PIPE,
preexec_fn=lambda: os.putenv("FRUIT", "apple"))
- self.addCleanup(p.stdout.close)
- self.assertEqual(p.stdout.read(), b"apple")
+ with p:
+ self.assertEqual(p.stdout.read(), b"apple")
def test_preexec_exception(self):
def raise_it():
@@ -1587,8 +1584,8 @@ class POSIXProcessTestCase(BaseTestCase):
p = subprocess.Popen(["echo $FRUIT"], shell=1,
stdout=subprocess.PIPE,
env=newenv)
- self.addCleanup(p.stdout.close)
- self.assertEqual(p.stdout.read().strip(b" \t\r\n\f"), b"apple")
+ with p:
+ self.assertEqual(p.stdout.read().strip(b" \t\r\n\f"), b"apple")
def test_shell_string(self):
# Run command through the shell (string)
@@ -1597,8 +1594,8 @@ class POSIXProcessTestCase(BaseTestCase):
p = subprocess.Popen("echo $FRUIT", shell=1,
stdout=subprocess.PIPE,
env=newenv)
- self.addCleanup(p.stdout.close)
- self.assertEqual(p.stdout.read().strip(b" \t\r\n\f"), b"apple")
+ with p:
+ self.assertEqual(p.stdout.read().strip(b" \t\r\n\f"), b"apple")
def test_call_string(self):
# call() function with string argument on UNIX
@@ -1630,8 +1627,8 @@ class POSIXProcessTestCase(BaseTestCase):
for sh in shells:
p = subprocess.Popen("echo $0", executable=sh, shell=True,
stdout=subprocess.PIPE)
- self.addCleanup(p.stdout.close)
- self.assertEqual(p.stdout.read().strip(), bytes(sh, 'ascii'))
+ with p:
+ self.assertEqual(p.stdout.read().strip(), bytes(sh, 'ascii'))
def _kill_process(self, method, *args):
# Do not inherit file handles from the parent.
@@ -2289,7 +2286,9 @@ class POSIXProcessTestCase(BaseTestCase):
self.addCleanup(p.stderr.close)
ident = id(p)
pid = p.pid
- del p
+ with support.check_warnings(('', ResourceWarning)):
+ p = None
+
# check that p is in the active processes list
self.assertIn(ident, [id(o) for o in subprocess._active])
@@ -2308,7 +2307,9 @@ class POSIXProcessTestCase(BaseTestCase):
self.addCleanup(p.stderr.close)
ident = id(p)
pid = p.pid
- del p
+ with support.check_warnings(('', ResourceWarning)):
+ p = None
+
os.kill(pid, signal.SIGKILL)
# check that p is in the active processes list
self.assertIn(ident, [id(o) for o in subprocess._active])
@@ -2454,8 +2455,8 @@ class Win32ProcessTestCase(BaseTestCase):
p = subprocess.Popen(["set"], shell=1,
stdout=subprocess.PIPE,
env=newenv)
- self.addCleanup(p.stdout.close)
- self.assertIn(b"physalis", p.stdout.read())
+ with p:
+ self.assertIn(b"physalis", p.stdout.read())
def test_shell_string(self):
# Run command through the shell (string)
@@ -2464,8 +2465,8 @@ class Win32ProcessTestCase(BaseTestCase):
p = subprocess.Popen("set", shell=1,
stdout=subprocess.PIPE,
env=newenv)
- self.addCleanup(p.stdout.close)
- self.assertIn(b"physalis", p.stdout.read())
+ with p:
+ self.assertIn(b"physalis", p.stdout.read())
def test_call_string(self):
# call() function with string argument on Windows
@@ -2484,16 +2485,14 @@ class Win32ProcessTestCase(BaseTestCase):
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)
- getattr(p, method)(*args)
- _, stderr = p.communicate()
- self.assertStderrEqual(stderr, b'')
- returncode = p.wait()
+ with p:
+ # Wait for the interpreter to be completely initialized before
+ # sending any signal.
+ p.stdout.read(1)
+ getattr(p, method)(*args)
+ _, stderr = p.communicate()
+ self.assertStderrEqual(stderr, b'')
+ returncode = p.wait()
self.assertNotEqual(returncode, 0)
def _kill_dead_process(self, method, *args):
@@ -2506,19 +2505,17 @@ class Win32ProcessTestCase(BaseTestCase):
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()
+ with p:
+ # 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):
@@ -2561,8 +2558,7 @@ class MiscTests(unittest.TestCase):
def test__all__(self):
"""Ensure that __all__ is populated properly."""
- # STARTUPINFO added to __all__ in 3.6
- intentionally_excluded = {"list2cmdline", "STARTUPINFO", "Handle"}
+ intentionally_excluded = {"list2cmdline", "Handle"}
exported = set(subprocess.__all__)
possible_exports = set()
import types
@@ -2607,11 +2603,11 @@ class CommandsWithSpaces (BaseTestCase):
def with_spaces(self, *args, **kwargs):
kwargs['stdout'] = subprocess.PIPE
p = subprocess.Popen(*args, **kwargs)
- self.addCleanup(p.stdout.close)
- self.assertEqual(
- p.stdout.read ().decode("mbcs"),
- "2 [%r, 'ab cd']" % self.fname
- )
+ with p:
+ self.assertEqual(
+ p.stdout.read ().decode("mbcs"),
+ "2 [%r, 'ab cd']" % self.fname
+ )
def test_shell_string_with_spaces(self):
# call() function with string argument with spaces on Windows
diff --git a/Lib/test/test_sunau.py b/Lib/test/test_sunau.py
index 0f4134e982..bc1f46c0eb 100644
--- a/Lib/test/test_sunau.py
+++ b/Lib/test/test_sunau.py
@@ -1,4 +1,3 @@
-from test.support import TESTFN
import unittest
from test import audiotests
from audioop import byteswap
diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py
index 2c00417414..269d9bf2b6 100644
--- a/Lib/test/test_support.py
+++ b/Lib/test/test_support.py
@@ -9,13 +9,11 @@ import errno
from test import support
TESTFN = support.TESTFN
-TESTDIRN = os.path.basename(tempfile.mkdtemp(dir='.'))
class TestSupport(unittest.TestCase):
def setUp(self):
support.unlink(TESTFN)
- support.rmtree(TESTDIRN)
tearDown = setUp
def test_import_module(self):
@@ -48,6 +46,10 @@ class TestSupport(unittest.TestCase):
support.unlink(TESTFN)
def test_rmtree(self):
+ TESTDIRN = os.path.basename(tempfile.mkdtemp(dir='.'))
+ self.addCleanup(support.rmtree, TESTDIRN)
+ support.rmtree(TESTDIRN)
+
os.mkdir(TESTDIRN)
os.mkdir(os.path.join(TESTDIRN, TESTDIRN))
support.rmtree(TESTDIRN)
@@ -228,7 +230,8 @@ class TestSupport(unittest.TestCase):
def test_check_syntax_error(self):
support.check_syntax_error(self, "def class")
- self.assertRaises(AssertionError, support.check_syntax_error, self, "1")
+ with self.assertRaises(AssertionError):
+ support.check_syntax_error(self, "x=1")
def test_CleanImport(self):
import importlib
@@ -312,6 +315,28 @@ class TestSupport(unittest.TestCase):
self.OtherClass, self.RefClass, ignore=ignore)
self.assertEqual(set(), missing_items)
+ def test_check__all__(self):
+ extra = {'tempdir'}
+ blacklist = {'template'}
+ support.check__all__(self,
+ tempfile,
+ extra=extra,
+ blacklist=blacklist)
+
+ extra = {'TextTestResult', 'installHandler'}
+ blacklist = {'load_tests', "TestProgram", "BaseTestSuite"}
+
+ support.check__all__(self,
+ unittest,
+ ("unittest.result", "unittest.case",
+ "unittest.suite", "unittest.loader",
+ "unittest.main", "unittest.runner",
+ "unittest.signals"),
+ extra=extra,
+ blacklist=blacklist)
+
+ self.assertRaises(AssertionError, support.check__all__, self, unittest)
+
# XXX -follows a list of untested API
# make_legacy_pyc
# is_resource_enabled
diff --git a/Lib/test/test_symbol.py b/Lib/test/test_symbol.py
new file mode 100644
index 0000000000..c1306f5432
--- /dev/null
+++ b/Lib/test/test_symbol.py
@@ -0,0 +1,54 @@
+import unittest
+from test import support
+import os
+import sys
+import subprocess
+
+
+SYMBOL_FILE = support.findfile('symbol.py')
+GRAMMAR_FILE = os.path.join(os.path.dirname(__file__),
+ '..', '..', 'Include', 'graminit.h')
+TEST_PY_FILE = 'symbol_test.py'
+
+
+class TestSymbolGeneration(unittest.TestCase):
+
+ def _copy_file_without_generated_symbols(self, source_file, dest_file):
+ with open(source_file) as fp:
+ lines = fp.readlines()
+ with open(dest_file, 'w') as fp:
+ fp.writelines(lines[:lines.index("#--start constants--\n") + 1])
+ fp.writelines(lines[lines.index("#--end constants--\n"):])
+
+ def _generate_symbols(self, grammar_file, target_symbol_py_file):
+ proc = subprocess.Popen([sys.executable,
+ SYMBOL_FILE,
+ grammar_file,
+ target_symbol_py_file], stderr=subprocess.PIPE)
+ stderr = proc.communicate()[1]
+ return proc.returncode, stderr
+
+ def compare_files(self, file1, file2):
+ with open(file1) as fp:
+ lines1 = fp.readlines()
+ with open(file2) as fp:
+ lines2 = fp.readlines()
+ self.assertEqual(lines1, lines2)
+
+ @unittest.skipIf(not os.path.exists(GRAMMAR_FILE),
+ 'test only works from source build directory')
+ def test_real_grammar_and_symbol_file(self):
+ output = support.TESTFN
+ self.addCleanup(support.unlink, output)
+
+ self._copy_file_without_generated_symbols(SYMBOL_FILE, output)
+
+ exitcode, stderr = self._generate_symbols(GRAMMAR_FILE, output)
+ self.assertEqual(b'', stderr)
+ self.assertEqual(0, exitcode)
+
+ self.compare_files(SYMBOL_FILE, output)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py
index 057441c83c..38fc417524 100644
--- a/Lib/test/test_syntax.py
+++ b/Lib/test/test_syntax.py
@@ -35,14 +35,6 @@ SyntaxError: invalid syntax
Traceback (most recent call last):
SyntaxError: can't assign to keyword
-It's a syntax error to assign to the empty tuple. Why isn't it an
-error to assign to the empty list? It will always raise some error at
-runtime.
-
->>> () = 1
-Traceback (most recent call last):
-SyntaxError: can't assign to ()
-
>>> f() = 1
Traceback (most recent call last):
SyntaxError: can't assign to function call
@@ -491,10 +483,6 @@ Traceback (most recent call last):
...
SyntaxError: keyword argument repeated
->>> del ()
-Traceback (most recent call last):
-SyntaxError: can't delete ()
-
>>> {1, 2, 3} = 42
Traceback (most recent call last):
SyntaxError: can't assign to literal
diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py
index ae8f845ee1..bb836233e1 100644
--- a/Lib/test/test_sys_settrace.py
+++ b/Lib/test/test_sys_settrace.py
@@ -338,8 +338,8 @@ class TraceTestCase(unittest.TestCase):
def test_14_onliner_if(self):
def onliners():
- if True: False
- else: True
+ if True: x=False
+ else: x=True
return 0
self.run_and_compare(
onliners,
diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py
index abfb34dfb8..d7785ceada 100644
--- a/Lib/test/test_tarfile.py
+++ b/Lib/test/test_tarfile.py
@@ -2074,6 +2074,24 @@ class MiscTest(unittest.TestCase):
with self.assertRaises(ValueError):
tarfile.itn(0x10000000000, 6, tarfile.GNU_FORMAT)
+ def test__all__(self):
+ blacklist = {'version', 'grp', 'pwd', 'symlink_exception',
+ 'NUL', 'BLOCKSIZE', 'RECORDSIZE', 'GNU_MAGIC',
+ 'POSIX_MAGIC', 'LENGTH_NAME', 'LENGTH_LINK',
+ 'LENGTH_PREFIX', 'REGTYPE', 'AREGTYPE', 'LNKTYPE',
+ 'SYMTYPE', 'CHRTYPE', 'BLKTYPE', 'DIRTYPE', 'FIFOTYPE',
+ 'CONTTYPE', 'GNUTYPE_LONGNAME', 'GNUTYPE_LONGLINK',
+ 'GNUTYPE_SPARSE', 'XHDTYPE', 'XGLTYPE', 'SOLARIS_XHDTYPE',
+ 'SUPPORTED_TYPES', 'REGULAR_TYPES', 'GNU_TYPES',
+ 'PAX_FIELDS', 'PAX_NAME_FIELDS', 'PAX_NUMBER_FIELDS',
+ 'stn', 'nts', 'nti', 'itn', 'calc_chksums', 'copyfileobj',
+ 'filemode',
+ 'EmptyHeaderError', 'TruncatedHeaderError',
+ 'EOFHeaderError', 'InvalidHeaderError',
+ 'SubsequentHeaderError', 'ExFileObject',
+ 'main'}
+ support.check__all__(self, tarfile, blacklist=blacklist)
+
class CommandLineTest(unittest.TestCase):
diff --git a/Lib/test/test_telnetlib.py b/Lib/test/test_telnetlib.py
index 8e219f4217..51d82e1158 100644
--- a/Lib/test/test_telnetlib.py
+++ b/Lib/test/test_telnetlib.py
@@ -1,7 +1,6 @@
import socket
import selectors
import telnetlib
-import time
import contextlib
from test import support
@@ -42,6 +41,11 @@ class GeneralTests(unittest.TestCase):
telnet = telnetlib.Telnet(HOST, self.port)
telnet.sock.close()
+ def testContextManager(self):
+ with telnetlib.Telnet(HOST, self.port) as tn:
+ self.assertIsNotNone(tn.get_socket())
+ self.assertIsNone(tn.get_socket())
+
def testTimeoutDefault(self):
self.assertTrue(socket.getdefaulttimeout() is None)
socket.setdefaulttimeout(30)
diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py
index b49a9615f0..d6317c71bf 100644
--- a/Lib/test/test_threading.py
+++ b/Lib/test/test_threading.py
@@ -3,11 +3,10 @@ Tests for the threading module.
"""
import test.support
-from test.support import verbose, strip_python_stderr, import_module, cpython_only
+from test.support import verbose, import_module, cpython_only
from test.support.script_helper import assert_python_ok, assert_python_failure
import random
-import re
import sys
_thread = import_module('_thread')
threading = import_module('threading')
@@ -18,6 +17,7 @@ import os
import subprocess
from test import lock_tests
+from test import support
# Between fork() and exec(), only async-safe functions are allowed (issues
@@ -1097,5 +1097,12 @@ class BoundedSemaphoreTests(lock_tests.BoundedSemaphoreTests):
class BarrierTests(lock_tests.BarrierTests):
barriertype = staticmethod(threading.Barrier)
+class MiscTestCase(unittest.TestCase):
+ def test__all__(self):
+ extra = {"ThreadError"}
+ blacklist = {'currentThread', 'activeCount'}
+ support.check__all__(self, threading, ('threading', '_thread'),
+ extra=extra, blacklist=blacklist)
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py
index 76b894eece..f883c45d04 100644
--- a/Lib/test/test_time.py
+++ b/Lib/test/test_time.py
@@ -1,6 +1,8 @@
from test import support
+import decimal
import enum
import locale
+import math
import platform
import sys
import sysconfig
@@ -21,17 +23,27 @@ SIZEOF_INT = sysconfig.get_config_var('SIZEOF_INT') or 4
TIME_MAXYEAR = (1 << 8 * SIZEOF_INT - 1) - 1
TIME_MINYEAR = -TIME_MAXYEAR - 1
+SEC_TO_US = 10 ** 6
US_TO_NS = 10 ** 3
MS_TO_NS = 10 ** 6
SEC_TO_NS = 10 ** 9
+NS_TO_SEC = 10 ** 9
class _PyTime(enum.IntEnum):
# Round towards minus infinity (-inf)
ROUND_FLOOR = 0
# Round towards infinity (+inf)
ROUND_CEILING = 1
+ # Round to nearest with ties going to nearest even integer
+ ROUND_HALF_EVEN = 2
-ALL_ROUNDING_METHODS = (_PyTime.ROUND_FLOOR, _PyTime.ROUND_CEILING)
+# Rounding modes supported by PyTime
+ROUNDING_MODES = (
+ # (PyTime rounding method, decimal rounding method)
+ (_PyTime.ROUND_FLOOR, decimal.ROUND_FLOOR),
+ (_PyTime.ROUND_CEILING, decimal.ROUND_CEILING),
+ (_PyTime.ROUND_HALF_EVEN, decimal.ROUND_HALF_EVEN),
+)
class TimeTestCase(unittest.TestCase):
@@ -607,79 +619,6 @@ class TestStrftime4dyear(_TestStrftimeYear, _Test4dYear, unittest.TestCase):
class TestPytime(unittest.TestCase):
- def setUp(self):
- self.invalid_values = (
- -(2 ** 100), 2 ** 100,
- -(2.0 ** 100.0), 2.0 ** 100.0,
- )
-
- @support.cpython_only
- def test_time_t(self):
- from _testcapi import pytime_object_to_time_t
- for obj, time_t, rnd in (
- # Round towards minus infinity (-inf)
- (0, 0, _PyTime.ROUND_FLOOR),
- (-1, -1, _PyTime.ROUND_FLOOR),
- (-1.0, -1, _PyTime.ROUND_FLOOR),
- (-1.9, -2, _PyTime.ROUND_FLOOR),
- (1.0, 1, _PyTime.ROUND_FLOOR),
- (1.9, 1, _PyTime.ROUND_FLOOR),
- # Round towards infinity (+inf)
- (0, 0, _PyTime.ROUND_CEILING),
- (-1, -1, _PyTime.ROUND_CEILING),
- (-1.0, -1, _PyTime.ROUND_CEILING),
- (-1.9, -1, _PyTime.ROUND_CEILING),
- (1.0, 1, _PyTime.ROUND_CEILING),
- (1.9, 2, _PyTime.ROUND_CEILING),
- ):
- self.assertEqual(pytime_object_to_time_t(obj, rnd), time_t)
-
- rnd = _PyTime.ROUND_FLOOR
- for invalid in self.invalid_values:
- self.assertRaises(OverflowError,
- pytime_object_to_time_t, invalid, rnd)
-
- @support.cpython_only
- def test_timespec(self):
- from _testcapi import pytime_object_to_timespec
- for obj, timespec, rnd in (
- # Round towards minus infinity (-inf)
- (0, (0, 0), _PyTime.ROUND_FLOOR),
- (-1, (-1, 0), _PyTime.ROUND_FLOOR),
- (-1.0, (-1, 0), _PyTime.ROUND_FLOOR),
- (1e-9, (0, 1), _PyTime.ROUND_FLOOR),
- (1e-10, (0, 0), _PyTime.ROUND_FLOOR),
- (-1e-9, (-1, 999999999), _PyTime.ROUND_FLOOR),
- (-1e-10, (-1, 999999999), _PyTime.ROUND_FLOOR),
- (-1.2, (-2, 800000000), _PyTime.ROUND_FLOOR),
- (0.9999999999, (0, 999999999), _PyTime.ROUND_FLOOR),
- (1.1234567890, (1, 123456789), _PyTime.ROUND_FLOOR),
- (1.1234567899, (1, 123456789), _PyTime.ROUND_FLOOR),
- (-1.1234567890, (-2, 876543211), _PyTime.ROUND_FLOOR),
- (-1.1234567891, (-2, 876543210), _PyTime.ROUND_FLOOR),
- # Round towards infinity (+inf)
- (0, (0, 0), _PyTime.ROUND_CEILING),
- (-1, (-1, 0), _PyTime.ROUND_CEILING),
- (-1.0, (-1, 0), _PyTime.ROUND_CEILING),
- (1e-9, (0, 1), _PyTime.ROUND_CEILING),
- (1e-10, (0, 1), _PyTime.ROUND_CEILING),
- (-1e-9, (-1, 999999999), _PyTime.ROUND_CEILING),
- (-1e-10, (0, 0), _PyTime.ROUND_CEILING),
- (-1.2, (-2, 800000000), _PyTime.ROUND_CEILING),
- (0.9999999999, (1, 0), _PyTime.ROUND_CEILING),
- (1.1234567890, (1, 123456790), _PyTime.ROUND_CEILING),
- (1.1234567899, (1, 123456790), _PyTime.ROUND_CEILING),
- (-1.1234567890, (-2, 876543211), _PyTime.ROUND_CEILING),
- (-1.1234567891, (-2, 876543211), _PyTime.ROUND_CEILING),
- ):
- with self.subTest(obj=obj, round=rnd, timespec=timespec):
- self.assertEqual(pytime_object_to_timespec(obj, rnd), timespec)
-
- rnd = _PyTime.ROUND_FLOOR
- for invalid in self.invalid_values:
- self.assertRaises(OverflowError,
- pytime_object_to_timespec, invalid, rnd)
-
@unittest.skipUnless(time._STRUCT_TM_ITEMS == 11, "needs tm_zone support")
def test_localtime_timezone(self):
@@ -734,266 +673,291 @@ class TestPytime(unittest.TestCase):
self.assertIs(lt.tm_zone, None)
-@unittest.skipUnless(_testcapi is not None,
- 'need the _testcapi module')
-class TestPyTime_t(unittest.TestCase):
+@unittest.skipIf(_testcapi is None, 'need the _testcapi module')
+class CPyTimeTestCase:
+ """
+ Base class to test the C _PyTime_t API.
+ """
+ OVERFLOW_SECONDS = None
+
+ def setUp(self):
+ from _testcapi import SIZEOF_TIME_T
+ bits = SIZEOF_TIME_T * 8 - 1
+ self.time_t_min = -2 ** bits
+ self.time_t_max = 2 ** bits - 1
+
+ def time_t_filter(self, seconds):
+ return (self.time_t_min <= seconds <= self.time_t_max)
+
+ def _rounding_values(self, use_float):
+ "Build timestamps used to test rounding."
+
+ units = [1, US_TO_NS, MS_TO_NS, SEC_TO_NS]
+ if use_float:
+ # picoseconds are only tested to pytime_converter accepting floats
+ units.append(1e-3)
+
+ values = (
+ # small values
+ 1, 2, 5, 7, 123, 456, 1234,
+ # 10^k - 1
+ 9,
+ 99,
+ 999,
+ 9999,
+ 99999,
+ 999999,
+ # test half even rounding near 0.5, 1.5, 2.5, 3.5, 4.5
+ 499, 500, 501,
+ 1499, 1500, 1501,
+ 2500,
+ 3500,
+ 4500,
+ )
+
+ ns_timestamps = [0]
+ for unit in units:
+ for value in values:
+ ns = value * unit
+ ns_timestamps.extend((-ns, ns))
+ for pow2 in (0, 5, 10, 15, 22, 23, 24, 30, 33):
+ ns = (2 ** pow2) * SEC_TO_NS
+ ns_timestamps.extend((
+ -ns-1, -ns, -ns+1,
+ ns-1, ns, ns+1
+ ))
+ for seconds in (_testcapi.INT_MIN, _testcapi.INT_MAX):
+ ns_timestamps.append(seconds * SEC_TO_NS)
+ if use_float:
+ # numbers with an extract representation in IEEE 754 (base 2)
+ for pow2 in (3, 7, 10, 15):
+ ns = 2.0 ** (-pow2)
+ ns_timestamps.extend((-ns, ns))
+
+ # seconds close to _PyTime_t type limit
+ ns = (2 ** 63 // SEC_TO_NS) * SEC_TO_NS
+ ns_timestamps.extend((-ns, ns))
+
+ return ns_timestamps
+
+ def _check_rounding(self, pytime_converter, expected_func,
+ use_float, unit_to_sec, value_filter=None):
+
+ def convert_values(ns_timestamps):
+ if use_float:
+ unit_to_ns = SEC_TO_NS / float(unit_to_sec)
+ values = [ns / unit_to_ns for ns in ns_timestamps]
+ else:
+ unit_to_ns = SEC_TO_NS // unit_to_sec
+ values = [ns // unit_to_ns for ns in ns_timestamps]
+
+ if value_filter:
+ values = filter(value_filter, values)
+
+ # remove duplicates and sort
+ return sorted(set(values))
+
+ # test rounding
+ ns_timestamps = self._rounding_values(use_float)
+ valid_values = convert_values(ns_timestamps)
+ for time_rnd, decimal_rnd in ROUNDING_MODES :
+ context = decimal.getcontext()
+ context.rounding = decimal_rnd
+
+ for value in valid_values:
+ debug_info = {'value': value, 'rounding': decimal_rnd}
+ try:
+ result = pytime_converter(value, time_rnd)
+ expected = expected_func(value)
+ except Exception as exc:
+ self.fail("Error on timestamp conversion: %s" % debug_info)
+ self.assertEqual(result,
+ expected,
+ debug_info)
+
+ # test overflow
+ ns = self.OVERFLOW_SECONDS * SEC_TO_NS
+ ns_timestamps = (-ns, ns)
+ overflow_values = convert_values(ns_timestamps)
+ for time_rnd, _ in ROUNDING_MODES :
+ for value in overflow_values:
+ debug_info = {'value': value, 'rounding': time_rnd}
+ with self.assertRaises(OverflowError, msg=debug_info):
+ pytime_converter(value, time_rnd)
+
+ def check_int_rounding(self, pytime_converter, expected_func,
+ unit_to_sec=1, value_filter=None):
+ self._check_rounding(pytime_converter, expected_func,
+ False, unit_to_sec, value_filter)
+
+ def check_float_rounding(self, pytime_converter, expected_func,
+ unit_to_sec=1, value_filter=None):
+ self._check_rounding(pytime_converter, expected_func,
+ True, unit_to_sec, value_filter)
+
+ def decimal_round(self, x):
+ d = decimal.Decimal(x)
+ d = d.quantize(1)
+ return int(d)
+
+
+class TestCPyTime(CPyTimeTestCase, unittest.TestCase):
+ """
+ Test the C _PyTime_t API.
+ """
+ # _PyTime_t is a 64-bit signed integer
+ OVERFLOW_SECONDS = math.ceil((2**63 + 1) / SEC_TO_NS)
+
def test_FromSeconds(self):
from _testcapi import PyTime_FromSeconds
- for seconds in (0, 3, -456, _testcapi.INT_MAX, _testcapi.INT_MIN):
- with self.subTest(seconds=seconds):
- self.assertEqual(PyTime_FromSeconds(seconds),
- seconds * SEC_TO_NS)
+
+ # PyTime_FromSeconds() expects a C int, reject values out of range
+ def c_int_filter(secs):
+ return (_testcapi.INT_MIN <= secs <= _testcapi.INT_MAX)
+
+ self.check_int_rounding(lambda secs, rnd: PyTime_FromSeconds(secs),
+ lambda secs: secs * SEC_TO_NS,
+ value_filter=c_int_filter)
def test_FromSecondsObject(self):
from _testcapi import PyTime_FromSecondsObject
- # Conversion giving the same result for all rounding methods
- for rnd in ALL_ROUNDING_METHODS:
- for obj, ts in (
- # integers
- (0, 0),
- (1, SEC_TO_NS),
- (-3, -3 * SEC_TO_NS),
-
- # float: subseconds
- (0.0, 0),
- (1e-9, 1),
- (1e-6, 10 ** 3),
- (1e-3, 10 ** 6),
-
- # float: seconds
- (2.0, 2 * SEC_TO_NS),
- (123.0, 123 * SEC_TO_NS),
- (-7.0, -7 * SEC_TO_NS),
-
- # nanosecond are kept for value <= 2^23 seconds
- (2**22 - 1e-9, 4194303999999999),
- (2**22, 4194304000000000),
- (2**22 + 1e-9, 4194304000000001),
- (2**23 - 1e-9, 8388607999999999),
- (2**23, 8388608000000000),
-
- # start losing precision for value > 2^23 seconds
- (2**23 + 1e-9, 8388608000000002),
-
- # nanoseconds are lost for value > 2^23 seconds
- (2**24 - 1e-9, 16777215999999998),
- (2**24, 16777216000000000),
- (2**24 + 1e-9, 16777216000000000),
- (2**25 - 1e-9, 33554432000000000),
- (2**25 , 33554432000000000),
- (2**25 + 1e-9, 33554432000000000),
-
- # close to 2^63 nanoseconds (_PyTime_t limit)
- (9223372036, 9223372036 * SEC_TO_NS),
- (9223372036.0, 9223372036 * SEC_TO_NS),
- (-9223372036, -9223372036 * SEC_TO_NS),
- (-9223372036.0, -9223372036 * SEC_TO_NS),
- ):
- with self.subTest(obj=obj, round=rnd, timestamp=ts):
- self.assertEqual(PyTime_FromSecondsObject(obj, rnd), ts)
-
- with self.subTest(round=rnd):
- with self.assertRaises(OverflowError):
- PyTime_FromSecondsObject(9223372037, rnd)
- PyTime_FromSecondsObject(9223372037.0, rnd)
- PyTime_FromSecondsObject(-9223372037, rnd)
- PyTime_FromSecondsObject(-9223372037.0, rnd)
-
- # Conversion giving different results depending on the rounding method
- FLOOR = _PyTime.ROUND_FLOOR
- CEILING = _PyTime.ROUND_CEILING
- for obj, ts, rnd in (
- # close to zero
- ( 1e-10, 0, FLOOR),
- ( 1e-10, 1, CEILING),
- (-1e-10, -1, FLOOR),
- (-1e-10, 0, CEILING),
-
- # test rounding of the last nanosecond
- ( 1.1234567899, 1123456789, FLOOR),
- ( 1.1234567899, 1123456790, CEILING),
- (-1.1234567899, -1123456790, FLOOR),
- (-1.1234567899, -1123456789, CEILING),
-
- # close to 1 second
- ( 0.9999999999, 999999999, FLOOR),
- ( 0.9999999999, 1000000000, CEILING),
- (-0.9999999999, -1000000000, FLOOR),
- (-0.9999999999, -999999999, CEILING),
- ):
- with self.subTest(obj=obj, round=rnd, timestamp=ts):
- self.assertEqual(PyTime_FromSecondsObject(obj, rnd), ts)
+ self.check_int_rounding(
+ PyTime_FromSecondsObject,
+ lambda secs: secs * SEC_TO_NS)
+
+ self.check_float_rounding(
+ PyTime_FromSecondsObject,
+ lambda ns: self.decimal_round(ns * SEC_TO_NS))
def test_AsSecondsDouble(self):
from _testcapi import PyTime_AsSecondsDouble
- for nanoseconds, seconds in (
- # near 1 nanosecond
- ( 0, 0.0),
- ( 1, 1e-9),
- (-1, -1e-9),
-
- # near 1 second
- (SEC_TO_NS + 1, 1.0 + 1e-9),
- (SEC_TO_NS, 1.0),
- (SEC_TO_NS - 1, 1.0 - 1e-9),
-
- # a few seconds
- (123 * SEC_TO_NS, 123.0),
- (-567 * SEC_TO_NS, -567.0),
-
- # nanosecond are kept for value <= 2^23 seconds
- (4194303999999999, 2**22 - 1e-9),
- (4194304000000000, 2**22),
- (4194304000000001, 2**22 + 1e-9),
-
- # start losing precision for value > 2^23 seconds
- (8388608000000002, 2**23 + 1e-9),
-
- # nanoseconds are lost for value > 2^23 seconds
- (16777215999999998, 2**24 - 1e-9),
- (16777215999999999, 2**24 - 1e-9),
- (16777216000000000, 2**24 ),
- (16777216000000001, 2**24 ),
- (16777216000000002, 2**24 + 2e-9),
-
- (33554432000000000, 2**25 ),
- (33554432000000002, 2**25 ),
- (33554432000000004, 2**25 + 4e-9),
-
- # close to 2^63 nanoseconds (_PyTime_t limit)
- (9223372036 * SEC_TO_NS, 9223372036.0),
- (-9223372036 * SEC_TO_NS, -9223372036.0),
- ):
- with self.subTest(nanoseconds=nanoseconds, seconds=seconds):
- self.assertEqual(PyTime_AsSecondsDouble(nanoseconds),
- seconds)
-
- def test_timeval(self):
+ def float_converter(ns):
+ if abs(ns) % SEC_TO_NS == 0:
+ return float(ns // SEC_TO_NS)
+ else:
+ return float(ns) / SEC_TO_NS
+
+ self.check_int_rounding(lambda ns, rnd: PyTime_AsSecondsDouble(ns),
+ float_converter,
+ NS_TO_SEC)
+
+ def create_decimal_converter(self, denominator):
+ denom = decimal.Decimal(denominator)
+
+ def converter(value):
+ d = decimal.Decimal(value) / denom
+ return self.decimal_round(d)
+
+ return converter
+
+ def test_AsTimeval(self):
from _testcapi import PyTime_AsTimeval
- for rnd in ALL_ROUNDING_METHODS:
- for ns, tv in (
- # microseconds
- (0, (0, 0)),
- (1000, (0, 1)),
- (-1000, (-1, 999999)),
-
- # seconds
- (2 * SEC_TO_NS, (2, 0)),
- (-3 * SEC_TO_NS, (-3, 0)),
- ):
- with self.subTest(nanoseconds=ns, timeval=tv, round=rnd):
- self.assertEqual(PyTime_AsTimeval(ns, rnd), tv)
-
- FLOOR = _PyTime.ROUND_FLOOR
- CEILING = _PyTime.ROUND_CEILING
- for ns, tv, rnd in (
- # nanoseconds
- (1, (0, 0), FLOOR),
- (1, (0, 1), CEILING),
- (-1, (-1, 999999), FLOOR),
- (-1, (0, 0), CEILING),
-
- # seconds + nanoseconds
- (1234567001, (1, 234567), FLOOR),
- (1234567001, (1, 234568), CEILING),
- (-1234567001, (-2, 765432), FLOOR),
- (-1234567001, (-2, 765433), CEILING),
- ):
- with self.subTest(nanoseconds=ns, timeval=tv, round=rnd):
- self.assertEqual(PyTime_AsTimeval(ns, rnd), tv)
+
+ us_converter = self.create_decimal_converter(US_TO_NS)
+
+ def timeval_converter(ns):
+ us = us_converter(ns)
+ return divmod(us, SEC_TO_US)
+
+ if sys.platform == 'win32':
+ from _testcapi import LONG_MIN, LONG_MAX
+
+ # On Windows, timeval.tv_sec type is a C long
+ def seconds_filter(secs):
+ return LONG_MIN <= secs <= LONG_MAX
+ else:
+ seconds_filter = self.time_t_filter
+
+ self.check_int_rounding(PyTime_AsTimeval,
+ timeval_converter,
+ NS_TO_SEC,
+ value_filter=seconds_filter)
@unittest.skipUnless(hasattr(_testcapi, 'PyTime_AsTimespec'),
'need _testcapi.PyTime_AsTimespec')
- def test_timespec(self):
+ def test_AsTimespec(self):
from _testcapi import PyTime_AsTimespec
- for ns, ts in (
- # nanoseconds
- (0, (0, 0)),
- (1, (0, 1)),
- (-1, (-1, 999999999)),
-
- # seconds
- (2 * SEC_TO_NS, (2, 0)),
- (-3 * SEC_TO_NS, (-3, 0)),
-
- # seconds + nanoseconds
- (1234567890, (1, 234567890)),
- (-1234567890, (-2, 765432110)),
- ):
- with self.subTest(nanoseconds=ns, timespec=ts):
- self.assertEqual(PyTime_AsTimespec(ns), ts)
-
- def test_milliseconds(self):
+
+ def timespec_converter(ns):
+ return divmod(ns, SEC_TO_NS)
+
+ self.check_int_rounding(lambda ns, rnd: PyTime_AsTimespec(ns),
+ timespec_converter,
+ NS_TO_SEC,
+ value_filter=self.time_t_filter)
+
+ def test_AsMilliseconds(self):
from _testcapi import PyTime_AsMilliseconds
- for rnd in ALL_ROUNDING_METHODS:
- for ns, tv in (
- # milliseconds
- (1 * MS_TO_NS, 1),
- (-2 * MS_TO_NS, -2),
-
- # seconds
- (2 * SEC_TO_NS, 2000),
- (-3 * SEC_TO_NS, -3000),
- ):
- with self.subTest(nanoseconds=ns, timeval=tv, round=rnd):
- self.assertEqual(PyTime_AsMilliseconds(ns, rnd), tv)
-
- FLOOR = _PyTime.ROUND_FLOOR
- CEILING = _PyTime.ROUND_CEILING
- for ns, ms, rnd in (
- # nanoseconds
- (1, 0, FLOOR),
- (1, 1, CEILING),
- (-1, -1, FLOOR),
- (-1, 0, CEILING),
-
- # seconds + nanoseconds
- (1234 * MS_TO_NS + 1, 1234, FLOOR),
- (1234 * MS_TO_NS + 1, 1235, CEILING),
- (-1234 * MS_TO_NS - 1, -1235, FLOOR),
- (-1234 * MS_TO_NS - 1, -1234, CEILING),
- ):
- with self.subTest(nanoseconds=ns, milliseconds=ms, round=rnd):
- self.assertEqual(PyTime_AsMilliseconds(ns, rnd), ms)
-
- def test_microseconds(self):
+
+ self.check_int_rounding(PyTime_AsMilliseconds,
+ self.create_decimal_converter(MS_TO_NS),
+ NS_TO_SEC)
+
+ def test_AsMicroseconds(self):
from _testcapi import PyTime_AsMicroseconds
- for rnd in ALL_ROUNDING_METHODS:
- for ns, tv in (
- # microseconds
- (1 * US_TO_NS, 1),
- (-2 * US_TO_NS, -2),
-
- # milliseconds
- (1 * MS_TO_NS, 1000),
- (-2 * MS_TO_NS, -2000),
-
- # seconds
- (2 * SEC_TO_NS, 2000000),
- (-3 * SEC_TO_NS, -3000000),
- ):
- with self.subTest(nanoseconds=ns, timeval=tv, round=rnd):
- self.assertEqual(PyTime_AsMicroseconds(ns, rnd), tv)
-
- FLOOR = _PyTime.ROUND_FLOOR
- CEILING = _PyTime.ROUND_CEILING
- for ns, ms, rnd in (
- # nanoseconds
- (1, 0, FLOOR),
- (1, 1, CEILING),
- (-1, -1, FLOOR),
- (-1, 0, CEILING),
-
- # seconds + nanoseconds
- (1234 * US_TO_NS + 1, 1234, FLOOR),
- (1234 * US_TO_NS + 1, 1235, CEILING),
- (-1234 * US_TO_NS - 1, -1235, FLOOR),
- (-1234 * US_TO_NS - 1, -1234, CEILING),
- ):
- with self.subTest(nanoseconds=ns, milliseconds=ms, round=rnd):
- self.assertEqual(PyTime_AsMicroseconds(ns, rnd), ms)
+
+ self.check_int_rounding(PyTime_AsMicroseconds,
+ self.create_decimal_converter(US_TO_NS),
+ NS_TO_SEC)
+
+
+class TestOldPyTime(CPyTimeTestCase, unittest.TestCase):
+ """
+ Test the old C _PyTime_t API: _PyTime_ObjectToXXX() functions.
+ """
+
+ # time_t is a 32-bit or 64-bit signed integer
+ OVERFLOW_SECONDS = 2 ** 64
+
+ def test_object_to_time_t(self):
+ from _testcapi import pytime_object_to_time_t
+
+ self.check_int_rounding(pytime_object_to_time_t,
+ lambda secs: secs,
+ value_filter=self.time_t_filter)
+
+ self.check_float_rounding(pytime_object_to_time_t,
+ self.decimal_round,
+ value_filter=self.time_t_filter)
+
+ def create_converter(self, sec_to_unit):
+ def converter(secs):
+ floatpart, intpart = math.modf(secs)
+ intpart = int(intpart)
+ floatpart *= sec_to_unit
+ floatpart = self.decimal_round(floatpart)
+ if floatpart < 0:
+ floatpart += sec_to_unit
+ intpart -= 1
+ elif floatpart >= sec_to_unit:
+ floatpart -= sec_to_unit
+ intpart += 1
+ return (intpart, floatpart)
+ return converter
+
+ def test_object_to_timeval(self):
+ from _testcapi import pytime_object_to_timeval
+
+ self.check_int_rounding(pytime_object_to_timeval,
+ lambda secs: (secs, 0),
+ value_filter=self.time_t_filter)
+
+ self.check_float_rounding(pytime_object_to_timeval,
+ self.create_converter(SEC_TO_US),
+ value_filter=self.time_t_filter)
+
+ def test_object_to_timespec(self):
+ from _testcapi import pytime_object_to_timespec
+
+ self.check_int_rounding(pytime_object_to_timespec,
+ lambda secs: (secs, 0),
+ value_filter=self.time_t_filter)
+
+ self.check_float_rounding(pytime_object_to_timespec,
+ self.create_converter(SEC_TO_NS),
+ value_filter=self.time_t_filter)
if __name__ == "__main__":
diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py
index 3b17ca6329..90438e7d30 100644
--- a/Lib/test/test_tokenize.py
+++ b/Lib/test/test_tokenize.py
@@ -24,8 +24,7 @@ class TokenizeTest(TestCase):
if type == ENDMARKER:
break
type = tok_name[type]
- result.append(" %(type)-10.10s %(token)-13.13r %(start)s %(end)s" %
- locals())
+ result.append(f" {type:10} {token!r:13} {start} {end}")
self.assertEqual(result,
[" ENCODING 'utf-8' (0, 0) (0, 0)"] +
expected.rstrip().splitlines())
@@ -132,18 +131,18 @@ def k(x):
self.check_tokenize("x = 0xfffffffffff", """\
NAME 'x' (1, 0) (1, 1)
OP '=' (1, 2) (1, 3)
- NUMBER '0xffffffffff (1, 4) (1, 17)
+ NUMBER '0xfffffffffff' (1, 4) (1, 17)
""")
self.check_tokenize("x = 123141242151251616110", """\
NAME 'x' (1, 0) (1, 1)
OP '=' (1, 2) (1, 3)
- NUMBER '123141242151 (1, 4) (1, 25)
+ NUMBER '123141242151251616110' (1, 4) (1, 25)
""")
self.check_tokenize("x = -15921590215012591", """\
NAME 'x' (1, 0) (1, 1)
OP '=' (1, 2) (1, 3)
OP '-' (1, 4) (1, 5)
- NUMBER '159215902150 (1, 5) (1, 22)
+ NUMBER '15921590215012591' (1, 5) (1, 22)
""")
def test_float(self):
@@ -307,6 +306,50 @@ def k(x):
OP '+' (1, 28) (1, 29)
STRING 'RB"abc"' (1, 30) (1, 37)
""")
+ # Check 0, 1, and 2 character string prefixes.
+ self.check_tokenize(r'"a\
+de\
+fg"', """\
+ STRING '"a\\\\\\nde\\\\\\nfg"\' (1, 0) (3, 3)
+ """)
+ self.check_tokenize(r'u"a\
+de"', """\
+ STRING 'u"a\\\\\\nde"\' (1, 0) (2, 3)
+ """)
+ self.check_tokenize(r'rb"a\
+d"', """\
+ STRING 'rb"a\\\\\\nd"\' (1, 0) (2, 2)
+ """)
+ self.check_tokenize(r'"""a\
+b"""', """\
+ STRING '\"\""a\\\\\\nb\"\""' (1, 0) (2, 4)
+ """)
+ self.check_tokenize(r'u"""a\
+b"""', """\
+ STRING 'u\"\""a\\\\\\nb\"\""' (1, 0) (2, 4)
+ """)
+ self.check_tokenize(r'rb"""a\
+b\
+c"""', """\
+ STRING 'rb"\""a\\\\\\nb\\\\\\nc"\""' (1, 0) (3, 4)
+ """)
+ self.check_tokenize('f"abc"', """\
+ STRING 'f"abc"' (1, 0) (1, 6)
+ """)
+ self.check_tokenize('fR"a{b}c"', """\
+ STRING 'fR"a{b}c"' (1, 0) (1, 9)
+ """)
+ self.check_tokenize('f"""abc"""', """\
+ STRING 'f\"\"\"abc\"\"\"' (1, 0) (1, 10)
+ """)
+ self.check_tokenize(r'f"abc\
+def"', """\
+ STRING 'f"abc\\\\\\ndef"' (1, 0) (2, 4)
+ """)
+ self.check_tokenize(r'Rf"abc\
+def"', """\
+ STRING 'Rf"abc\\\\\\ndef"' (1, 0) (2, 4)
+ """)
def test_function(self):
self.check_tokenize("def d22(a, b, c=2, d=2, *k): pass", """\
@@ -505,7 +548,7 @@ def k(x):
# Methods
self.check_tokenize("@staticmethod\ndef foo(x,y): pass", """\
OP '@' (1, 0) (1, 1)
- NAME 'staticmethod (1, 1) (1, 13)
+ NAME 'staticmethod' (1, 1) (1, 13)
NEWLINE '\\n' (1, 13) (1, 14)
NAME 'def' (2, 0) (2, 3)
NAME 'foo' (2, 4) (2, 7)
diff --git a/Lib/test/test_tools/__init__.py b/Lib/test/test_tools/__init__.py
index 04c8726e11..4d0fca330a 100644
--- a/Lib/test/test_tools/__init__.py
+++ b/Lib/test/test_tools/__init__.py
@@ -3,7 +3,6 @@ import os
import unittest
import importlib
from test import support
-from fnmatch import fnmatch
basepath = os.path.dirname( # <src/install dir>
os.path.dirname( # Lib
diff --git a/Lib/test/test_tools/test_gprof2html.py b/Lib/test/test_tools/test_gprof2html.py
index 0c294ec0c4..9489ed91f9 100644
--- a/Lib/test/test_tools/test_gprof2html.py
+++ b/Lib/test/test_tools/test_gprof2html.py
@@ -2,12 +2,11 @@
import os
import sys
-import importlib
import unittest
from unittest import mock
import tempfile
-from test.test_tools import scriptsdir, skip_if_missing, import_tool
+from test.test_tools import skip_if_missing, import_tool
skip_if_missing()
diff --git a/Lib/test/test_tools/test_md5sum.py b/Lib/test/test_tools/test_md5sum.py
index 1305295ef1..fb565b7377 100644
--- a/Lib/test/test_tools/test_md5sum.py
+++ b/Lib/test/test_tools/test_md5sum.py
@@ -1,12 +1,11 @@
"""Tests for the md5sum script in the Tools directory."""
import os
-import sys
import unittest
from test import support
from test.support.script_helper import assert_python_ok, assert_python_failure
-from test.test_tools import scriptsdir, import_tool, skip_if_missing
+from test.test_tools import scriptsdir, skip_if_missing
skip_if_missing()
diff --git a/Lib/test/test_tools/test_pdeps.py b/Lib/test/test_tools/test_pdeps.py
index 091fa6a06d..27cbfe215d 100644
--- a/Lib/test/test_tools/test_pdeps.py
+++ b/Lib/test/test_tools/test_pdeps.py
@@ -1,12 +1,10 @@
"""Tests for the pdeps script in the Tools directory."""
import os
-import sys
import unittest
import tempfile
-from test import support
-from test.test_tools import scriptsdir, skip_if_missing, import_tool
+from test.test_tools import skip_if_missing, import_tool
skip_if_missing()
diff --git a/Lib/test/test_tools/test_unparse.py b/Lib/test/test_tools/test_unparse.py
index 734bbc215a..d91ade9228 100644
--- a/Lib/test/test_tools/test_unparse.py
+++ b/Lib/test/test_tools/test_unparse.py
@@ -134,6 +134,15 @@ class ASTTestCase(unittest.TestCase):
class UnparseTestCase(ASTTestCase):
# Tests for specific bugs found in earlier versions of unparse
+ def test_fstrings(self):
+ # See issue 25180
+ self.check_roundtrip(r"""f'{f"{0}"*3}'""")
+ self.check_roundtrip(r"""f'{f"{y}"*3}'""")
+ self.check_roundtrip(r"""f'{f"{\'x\'}"*3}'""")
+
+ self.check_roundtrip(r'''f"{r'x' f'{\"s\"}'}"''')
+ self.check_roundtrip(r'''f"{r'x'rf'{\"s\"}'}"''')
+
def test_del_statement(self):
self.check_roundtrip("del x, y, z")
diff --git a/Lib/test/test_trace.py b/Lib/test/test_trace.py
index 03dff8432d..1d894aaf84 100644
--- a/Lib/test/test_trace.py
+++ b/Lib/test/test_trace.py
@@ -1,11 +1,11 @@
import os
-import io
import sys
from test.support import TESTFN, rmtree, unlink, captured_stdout
+from test.support.script_helper import assert_python_ok, assert_python_failure
import unittest
import trace
-from trace import CoverageResults, Trace
+from trace import Trace
from test.tracedmodules import testmod
@@ -365,51 +365,27 @@ class Test_Ignore(unittest.TestCase):
# Matched before.
self.assertTrue(ignore.names(jn('bar', 'baz.py'), 'baz'))
-
-class TestDeprecatedMethods(unittest.TestCase):
-
- def test_deprecated_usage(self):
- sio = io.StringIO()
- with self.assertWarns(DeprecationWarning):
- trace.usage(sio)
- self.assertIn('Usage:', sio.getvalue())
-
- def test_deprecated_Ignore(self):
- with self.assertWarns(DeprecationWarning):
- trace.Ignore()
-
- def test_deprecated_modname(self):
- with self.assertWarns(DeprecationWarning):
- self.assertEqual("spam", trace.modname("spam"))
-
- def test_deprecated_fullmodname(self):
- with self.assertWarns(DeprecationWarning):
- self.assertEqual("spam", trace.fullmodname("spam"))
-
- def test_deprecated_find_lines_from_code(self):
- with self.assertWarns(DeprecationWarning):
- def foo():
- pass
- trace.find_lines_from_code(foo.__code__, ["eggs"])
-
- def test_deprecated_find_lines(self):
- with self.assertWarns(DeprecationWarning):
- def foo():
- pass
- trace.find_lines(foo.__code__, ["eggs"])
-
- def test_deprecated_find_strings(self):
- with open(TESTFN, 'w') as fd:
- self.addCleanup(unlink, TESTFN)
- with self.assertWarns(DeprecationWarning):
- trace.find_strings(fd.name)
-
- def test_deprecated_find_executable_linenos(self):
+class TestCommandLine(unittest.TestCase):
+
+ def test_failures(self):
+ _errors = (
+ (b'filename is missing: required with the main options', '-l', '-T'),
+ (b'cannot specify both --listfuncs and (--trace or --count)', '-lc'),
+ (b'argument -R/--no-report: not allowed with argument -r/--report', '-rR'),
+ (b'must specify one of --trace, --count, --report, --listfuncs, or --trackcalls', '-g'),
+ (b'-r/--report requires -f/--file', '-r'),
+ (b'--summary can only be used with --count or --report', '-sT'),
+ (b'unrecognized arguments: -y', '-y'))
+ for message, *args in _errors:
+ *_, stderr = assert_python_failure('-m', 'trace', *args)
+ self.assertIn(message, stderr)
+
+ def test_listfuncs_flag_success(self):
with open(TESTFN, 'w') as fd:
self.addCleanup(unlink, TESTFN)
- with self.assertWarns(DeprecationWarning):
- trace.find_executable_linenos(fd.name)
-
+ fd.write("a = 1\n")
+ status, stdout, stderr = assert_python_ok('-m', 'trace', '-l', TESTFN)
+ self.assertIn(b'functions called:', stdout)
if __name__ == '__main__':
unittest.main()
diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py
index b7695d6eb4..5e4b6a27e5 100644
--- a/Lib/test/test_traceback.py
+++ b/Lib/test/test_traceback.py
@@ -129,12 +129,12 @@ class SyntaxTracebackCases(unittest.TestCase):
def do_test(firstlines, message, charset, lineno):
# Raise the message in a subprocess, and catch the output
try:
- output = open(TESTFN, "w", encoding=charset)
- output.write("""{0}if 1:
- import traceback;
- raise RuntimeError('{1}')
- """.format(firstlines, message))
- output.close()
+ with open(TESTFN, "w", encoding=charset) as output:
+ output.write("""{0}if 1:
+ import traceback;
+ raise RuntimeError('{1}')
+ """.format(firstlines, message))
+
process = subprocess.Popen([sys.executable, TESTFN],
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout, stderr = process.communicate()
@@ -175,8 +175,8 @@ class SyntaxTracebackCases(unittest.TestCase):
text, charset, 5)
do_test(" \t\f\n# coding: {0}\n".format(charset),
text, charset, 5)
- # Issue #18960: coding spec should has no effect
- do_test("0\n# coding: GBK\n", "h\xe9 ho", 'utf-8', 5)
+ # Issue #18960: coding spec should have no effect
+ do_test("x=0\n# coding: GBK\n", "h\xe9 ho", 'utf-8', 5)
def test_print_traceback_at_exit(self):
# Issue #22599: Ensure that it is possible to use the traceback module
diff --git a/Lib/test/test_tracemalloc.py b/Lib/test/test_tracemalloc.py
index da89a9a871..790ab7ee60 100644
--- a/Lib/test/test_tracemalloc.py
+++ b/Lib/test/test_tracemalloc.py
@@ -11,9 +11,15 @@ try:
import threading
except ImportError:
threading = None
+try:
+ import _testcapi
+except ImportError:
+ _testcapi = None
+
EMPTY_STRING_SIZE = sys.getsizeof(b'')
+
def get_frames(nframe, lineno_delta):
frames = []
frame = sys._getframe(1)
@@ -37,28 +43,31 @@ def allocate_bytes(size):
def create_snapshots():
traceback_limit = 2
+ # _tracemalloc._get_traces() returns a list of (domain, size,
+ # traceback_frames) tuples. traceback_frames is a tuple of (filename,
+ # line_number) tuples.
raw_traces = [
- (10, (('a.py', 2), ('b.py', 4))),
- (10, (('a.py', 2), ('b.py', 4))),
- (10, (('a.py', 2), ('b.py', 4))),
+ (0, 10, (('a.py', 2), ('b.py', 4))),
+ (0, 10, (('a.py', 2), ('b.py', 4))),
+ (0, 10, (('a.py', 2), ('b.py', 4))),
- (2, (('a.py', 5), ('b.py', 4))),
+ (1, 2, (('a.py', 5), ('b.py', 4))),
- (66, (('b.py', 1),)),
+ (2, 66, (('b.py', 1),)),
- (7, (('<unknown>', 0),)),
+ (3, 7, (('<unknown>', 0),)),
]
snapshot = tracemalloc.Snapshot(raw_traces, traceback_limit)
raw_traces2 = [
- (10, (('a.py', 2), ('b.py', 4))),
- (10, (('a.py', 2), ('b.py', 4))),
- (10, (('a.py', 2), ('b.py', 4))),
+ (0, 10, (('a.py', 2), ('b.py', 4))),
+ (0, 10, (('a.py', 2), ('b.py', 4))),
+ (0, 10, (('a.py', 2), ('b.py', 4))),
- (2, (('a.py', 5), ('b.py', 4))),
- (5000, (('a.py', 5), ('b.py', 4))),
+ (2, 2, (('a.py', 5), ('b.py', 4))),
+ (2, 5000, (('a.py', 5), ('b.py', 4))),
- (400, (('c.py', 578),)),
+ (4, 400, (('c.py', 578),)),
]
snapshot2 = tracemalloc.Snapshot(raw_traces2, traceback_limit)
@@ -126,7 +135,7 @@ class TestTracemallocEnabled(unittest.TestCase):
def find_trace(self, traces, traceback):
for trace in traces:
- if trace[1] == traceback._frames:
+ if trace[2] == traceback._frames:
return trace
self.fail("trace not found")
@@ -140,7 +149,7 @@ class TestTracemallocEnabled(unittest.TestCase):
trace = self.find_trace(traces, obj_traceback)
self.assertIsInstance(trace, tuple)
- size, traceback = trace
+ domain, size, traceback = trace
self.assertEqual(size, obj_size)
self.assertEqual(traceback, obj_traceback._frames)
@@ -167,9 +176,8 @@ class TestTracemallocEnabled(unittest.TestCase):
trace1 = self.find_trace(traces, obj1_traceback)
trace2 = self.find_trace(traces, obj2_traceback)
- size1, traceback1 = trace1
- size2, traceback2 = trace2
- self.assertEqual(traceback2, traceback1)
+ domain1, size1, traceback1 = trace1
+ domain2, size2, traceback2 = trace2
self.assertIs(traceback2, traceback1)
def test_get_traced_memory(self):
@@ -292,7 +300,7 @@ class TestSnapshot(unittest.TestCase):
maxDiff = 4000
def test_create_snapshot(self):
- raw_traces = [(5, (('a.py', 2),))]
+ raw_traces = [(0, 5, (('a.py', 2),))]
with contextlib.ExitStack() as stack:
stack.enter_context(patch.object(tracemalloc, 'is_tracing',
@@ -322,11 +330,11 @@ class TestSnapshot(unittest.TestCase):
# exclude b.py
snapshot3 = snapshot.filter_traces((filter1,))
self.assertEqual(snapshot3.traces._traces, [
- (10, (('a.py', 2), ('b.py', 4))),
- (10, (('a.py', 2), ('b.py', 4))),
- (10, (('a.py', 2), ('b.py', 4))),
- (2, (('a.py', 5), ('b.py', 4))),
- (7, (('<unknown>', 0),)),
+ (0, 10, (('a.py', 2), ('b.py', 4))),
+ (0, 10, (('a.py', 2), ('b.py', 4))),
+ (0, 10, (('a.py', 2), ('b.py', 4))),
+ (1, 2, (('a.py', 5), ('b.py', 4))),
+ (3, 7, (('<unknown>', 0),)),
])
# filter_traces() must not touch the original snapshot
@@ -335,10 +343,10 @@ class TestSnapshot(unittest.TestCase):
# only include two lines of a.py
snapshot4 = snapshot3.filter_traces((filter2, filter3))
self.assertEqual(snapshot4.traces._traces, [
- (10, (('a.py', 2), ('b.py', 4))),
- (10, (('a.py', 2), ('b.py', 4))),
- (10, (('a.py', 2), ('b.py', 4))),
- (2, (('a.py', 5), ('b.py', 4))),
+ (0, 10, (('a.py', 2), ('b.py', 4))),
+ (0, 10, (('a.py', 2), ('b.py', 4))),
+ (0, 10, (('a.py', 2), ('b.py', 4))),
+ (1, 2, (('a.py', 5), ('b.py', 4))),
])
# No filter: just duplicate the snapshot
@@ -349,6 +357,54 @@ class TestSnapshot(unittest.TestCase):
self.assertRaises(TypeError, snapshot.filter_traces, filter1)
+ def test_filter_traces_domain(self):
+ snapshot, snapshot2 = create_snapshots()
+ filter1 = tracemalloc.Filter(False, "a.py", domain=1)
+ filter2 = tracemalloc.Filter(True, "a.py", domain=1)
+
+ original_traces = list(snapshot.traces._traces)
+
+ # exclude a.py of domain 1
+ snapshot3 = snapshot.filter_traces((filter1,))
+ self.assertEqual(snapshot3.traces._traces, [
+ (0, 10, (('a.py', 2), ('b.py', 4))),
+ (0, 10, (('a.py', 2), ('b.py', 4))),
+ (0, 10, (('a.py', 2), ('b.py', 4))),
+ (2, 66, (('b.py', 1),)),
+ (3, 7, (('<unknown>', 0),)),
+ ])
+
+ # include domain 1
+ snapshot3 = snapshot.filter_traces((filter1,))
+ self.assertEqual(snapshot3.traces._traces, [
+ (0, 10, (('a.py', 2), ('b.py', 4))),
+ (0, 10, (('a.py', 2), ('b.py', 4))),
+ (0, 10, (('a.py', 2), ('b.py', 4))),
+ (2, 66, (('b.py', 1),)),
+ (3, 7, (('<unknown>', 0),)),
+ ])
+
+ def test_filter_traces_domain_filter(self):
+ snapshot, snapshot2 = create_snapshots()
+ filter1 = tracemalloc.DomainFilter(False, domain=3)
+ filter2 = tracemalloc.DomainFilter(True, domain=3)
+
+ # exclude domain 2
+ snapshot3 = snapshot.filter_traces((filter1,))
+ self.assertEqual(snapshot3.traces._traces, [
+ (0, 10, (('a.py', 2), ('b.py', 4))),
+ (0, 10, (('a.py', 2), ('b.py', 4))),
+ (0, 10, (('a.py', 2), ('b.py', 4))),
+ (1, 2, (('a.py', 5), ('b.py', 4))),
+ (2, 66, (('b.py', 1),)),
+ ])
+
+ # include domain 2
+ snapshot3 = snapshot.filter_traces((filter2,))
+ self.assertEqual(snapshot3.traces._traces, [
+ (3, 7, (('<unknown>', 0),)),
+ ])
+
def test_snapshot_group_by_line(self):
snapshot, snapshot2 = create_snapshots()
tb_0 = traceback_lineno('<unknown>', 0)
@@ -816,12 +872,121 @@ class TestCommandLine(unittest.TestCase):
assert_python_ok('-X', 'tracemalloc', '-c', code)
+@unittest.skipIf(_testcapi is None, 'need _testcapi')
+class TestCAPI(unittest.TestCase):
+ maxDiff = 80 * 20
+
+ def setUp(self):
+ if tracemalloc.is_tracing():
+ self.skipTest("tracemalloc must be stopped before the test")
+
+ self.domain = 5
+ self.size = 123
+ self.obj = allocate_bytes(self.size)[0]
+
+ # for the type "object", id(obj) is the address of its memory block.
+ # This type is not tracked by the garbage collector
+ self.ptr = id(self.obj)
+
+ def tearDown(self):
+ tracemalloc.stop()
+
+ def get_traceback(self):
+ frames = _testcapi.tracemalloc_get_traceback(self.domain, self.ptr)
+ if frames is not None:
+ return tracemalloc.Traceback(frames)
+ else:
+ return None
+
+ def track(self, release_gil=False, nframe=1):
+ frames = get_frames(nframe, 2)
+ _testcapi.tracemalloc_track(self.domain, self.ptr, self.size,
+ release_gil)
+ return frames
+
+ def untrack(self):
+ _testcapi.tracemalloc_untrack(self.domain, self.ptr)
+
+ def get_traced_memory(self):
+ # Get the traced size in the domain
+ snapshot = tracemalloc.take_snapshot()
+ domain_filter = tracemalloc.DomainFilter(True, self.domain)
+ snapshot = snapshot.filter_traces([domain_filter])
+ return sum(trace.size for trace in snapshot.traces)
+
+ def check_track(self, release_gil):
+ nframe = 5
+ tracemalloc.start(nframe)
+
+ size = tracemalloc.get_traced_memory()[0]
+
+ frames = self.track(release_gil, nframe)
+ self.assertEqual(self.get_traceback(),
+ tracemalloc.Traceback(frames))
+
+ self.assertEqual(self.get_traced_memory(), self.size)
+
+ def test_track(self):
+ self.check_track(False)
+
+ def test_track_without_gil(self):
+ # check that calling _PyTraceMalloc_Track() without holding the GIL
+ # works too
+ self.check_track(True)
+
+ def test_track_already_tracked(self):
+ nframe = 5
+ tracemalloc.start(nframe)
+
+ # track a first time
+ self.track()
+
+ # calling _PyTraceMalloc_Track() must remove the old trace and add
+ # a new trace with the new traceback
+ frames = self.track(nframe=nframe)
+ self.assertEqual(self.get_traceback(),
+ tracemalloc.Traceback(frames))
+
+ def test_untrack(self):
+ tracemalloc.start()
+
+ self.track()
+ self.assertIsNotNone(self.get_traceback())
+ self.assertEqual(self.get_traced_memory(), self.size)
+
+ # untrack must remove the trace
+ self.untrack()
+ self.assertIsNone(self.get_traceback())
+ self.assertEqual(self.get_traced_memory(), 0)
+
+ # calling _PyTraceMalloc_Untrack() multiple times must not crash
+ self.untrack()
+ self.untrack()
+
+ def test_stop_track(self):
+ tracemalloc.start()
+ tracemalloc.stop()
+
+ with self.assertRaises(RuntimeError):
+ self.track()
+ self.assertIsNone(self.get_traceback())
+
+ def test_stop_untrack(self):
+ tracemalloc.start()
+ self.track()
+
+ tracemalloc.stop()
+ with self.assertRaises(RuntimeError):
+ self.untrack()
+
+
def test_main():
support.run_unittest(
TestTracemallocEnabled,
TestSnapshot,
TestFilters,
TestCommandLine,
+ TestCAPI,
)
if __name__ == "__main__":
diff --git a/Lib/test/test_ttk_guionly.py b/Lib/test/test_ttk_guionly.py
index 490e72337f..462665db5f 100644
--- a/Lib/test/test_ttk_guionly.py
+++ b/Lib/test/test_ttk_guionly.py
@@ -1,4 +1,3 @@
-import os
import unittest
from test import support
diff --git a/Lib/test/test_ttk_textonly.py b/Lib/test/test_ttk_textonly.py
index 566fc9d09a..7540a43103 100644
--- a/Lib/test/test_ttk_textonly.py
+++ b/Lib/test/test_ttk_textonly.py
@@ -1,4 +1,3 @@
-import os
from test import support
# Skip this test if _tkinter does not exist.
diff --git a/Lib/test/test_unpack.py b/Lib/test/test_unpack.py
index d1ccb38937..3fcb18fb43 100644
--- a/Lib/test/test_unpack.py
+++ b/Lib/test/test_unpack.py
@@ -117,6 +117,27 @@ error)
...
test.test_unpack.BozoError
+Allow unpacking empty iterables
+
+ >>> () = []
+ >>> [] = ()
+ >>> [] = []
+ >>> () = ()
+
+Unpacking non-iterables should raise TypeError
+
+ >>> () = 42
+ Traceback (most recent call last):
+ ...
+ TypeError: 'int' object is not iterable
+
+Unpacking to an empty iterable should raise ValueError
+
+ >>> () = [42]
+ Traceback (most recent call last):
+ ...
+ ValueError: too many values to unpack (expected 0)
+
"""
__test__ = {'doctests' : doctests}
diff --git a/Lib/test/test_unpack_ex.py b/Lib/test/test_unpack_ex.py
index d27eef0397..f426e5afd7 100644
--- a/Lib/test/test_unpack_ex.py
+++ b/Lib/test/test_unpack_ex.py
@@ -352,7 +352,6 @@ Some size constraints (all fail.)
__test__ = {'doctests' : doctests}
def test_main(verbose=False):
- import sys
from test import support
from test import test_unpack_ex
support.run_doctest(test_unpack_ex, verbose)
diff --git a/Lib/test/test_urllib2_localnet.py b/Lib/test/test_urllib2_localnet.py
index c8b37eecea..e9564fde62 100644
--- a/Lib/test/test_urllib2_localnet.py
+++ b/Lib/test/test_urllib2_localnet.py
@@ -289,12 +289,12 @@ class BasicAuthTests(unittest.TestCase):
def http_server_with_basic_auth_handler(*args, **kwargs):
return BasicAuthHandler(*args, **kwargs)
self.server = LoopbackHttpServerThread(http_server_with_basic_auth_handler)
+ self.addCleanup(self.server.stop)
self.server_url = 'http://127.0.0.1:%s' % self.server.port
self.server.start()
self.server.ready.wait()
def tearDown(self):
- self.server.stop()
super(BasicAuthTests, self).tearDown()
def test_basic_auth_success(self):
@@ -438,17 +438,13 @@ class TestUrlopen(unittest.TestCase):
def setUp(self):
super(TestUrlopen, self).setUp()
+
# Ignore proxies for localhost tests.
- self.old_environ = os.environ.copy()
+ def restore_environ(old_environ):
+ os.environ.clear()
+ os.environ.update(old_environ)
+ self.addCleanup(restore_environ, os.environ.copy())
os.environ['NO_PROXY'] = '*'
- self.server = None
-
- def tearDown(self):
- if self.server is not None:
- self.server.stop()
- os.environ.clear()
- os.environ.update(self.old_environ)
- super(TestUrlopen, self).tearDown()
def urlopen(self, url, data=None, **kwargs):
l = []
@@ -469,6 +465,7 @@ class TestUrlopen(unittest.TestCase):
handler = GetRequestHandler(responses)
self.server = LoopbackHttpServerThread(handler)
+ self.addCleanup(self.server.stop)
self.server.start()
self.server.ready.wait()
port = self.server.port
@@ -592,7 +589,8 @@ class TestUrlopen(unittest.TestCase):
handler = self.start_server()
req = urllib.request.Request("http://localhost:%s/" % handler.port,
headers={"Range": "bytes=20-39"})
- urllib.request.urlopen(req)
+ with urllib.request.urlopen(req):
+ pass
self.assertEqual(handler.headers_received["Range"], "bytes=20-39")
def test_basic(self):
@@ -608,22 +606,21 @@ class TestUrlopen(unittest.TestCase):
def test_info(self):
handler = self.start_server()
- try:
- open_url = urllib.request.urlopen(
- "http://localhost:%s" % handler.port)
+ open_url = urllib.request.urlopen(
+ "http://localhost:%s" % handler.port)
+ with open_url:
info_obj = open_url.info()
- self.assertIsInstance(info_obj, email.message.Message,
- "object returned by 'info' is not an "
- "instance of email.message.Message")
- self.assertEqual(info_obj.get_content_subtype(), "plain")
- finally:
- self.server.stop()
+ self.assertIsInstance(info_obj, email.message.Message,
+ "object returned by 'info' is not an "
+ "instance of email.message.Message")
+ self.assertEqual(info_obj.get_content_subtype(), "plain")
def test_geturl(self):
# Make sure same URL as opened is returned by geturl.
handler = self.start_server()
open_url = urllib.request.urlopen("http://localhost:%s" % handler.port)
- url = open_url.geturl()
+ with open_url:
+ url = open_url.geturl()
self.assertEqual(url, "http://localhost:%s" % handler.port)
def test_iteration(self):
diff --git a/Lib/test/test_urllibnet.py b/Lib/test/test_urllibnet.py
index b811930bbc..949716c2b5 100644
--- a/Lib/test/test_urllibnet.py
+++ b/Lib/test/test_urllibnet.py
@@ -4,7 +4,6 @@ from test import support
import contextlib
import socket
import urllib.request
-import sys
import os
import email.message
import time
diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py
index 829997fd6a..9165d73e82 100644
--- a/Lib/test/test_urlparse.py
+++ b/Lib/test/test_urlparse.py
@@ -605,29 +605,27 @@ class UrlParseTestCase(unittest.TestCase):
self.assertEqual(p.port, 80)
self.assertEqual(p.geturl(), url)
- # Verify an illegal port is returned as None
+ # Verify an illegal port raises ValueError
url = b"HTTP://WWW.PYTHON.ORG:65536/doc/#frag"
p = urllib.parse.urlsplit(url)
- self.assertEqual(p.port, None)
+ with self.assertRaisesRegex(ValueError, "out of range"):
+ p.port
def test_attributes_bad_port(self):
- """Check handling of non-integer ports."""
- p = urllib.parse.urlsplit("http://www.example.net:foo")
- self.assertEqual(p.netloc, "www.example.net:foo")
- self.assertRaises(ValueError, lambda: p.port)
-
- p = urllib.parse.urlparse("http://www.example.net:foo")
- self.assertEqual(p.netloc, "www.example.net:foo")
- self.assertRaises(ValueError, lambda: p.port)
-
- # Once again, repeat ourselves to test bytes
- p = urllib.parse.urlsplit(b"http://www.example.net:foo")
- self.assertEqual(p.netloc, b"www.example.net:foo")
- self.assertRaises(ValueError, lambda: p.port)
-
- p = urllib.parse.urlparse(b"http://www.example.net:foo")
- self.assertEqual(p.netloc, b"www.example.net:foo")
- self.assertRaises(ValueError, lambda: p.port)
+ """Check handling of invalid ports."""
+ for bytes in (False, True):
+ for parse in (urllib.parse.urlsplit, urllib.parse.urlparse):
+ for port in ("foo", "1.5", "-1", "0x10"):
+ with self.subTest(bytes=bytes, parse=parse, port=port):
+ netloc = "www.example.net:" + port
+ url = "http://" + netloc
+ if bytes:
+ netloc = netloc.encode("ascii")
+ url = url.encode("ascii")
+ p = parse(url)
+ self.assertEqual(p.netloc, netloc)
+ with self.assertRaises(ValueError):
+ p.port
def test_attributes_without_netloc(self):
# This example is straight from RFC 3261. It looks like it
diff --git a/Lib/test/test_userdict.py b/Lib/test/test_userdict.py
index 8357f8bcd1..662c7f641a 100644
--- a/Lib/test/test_userdict.py
+++ b/Lib/test/test_userdict.py
@@ -1,6 +1,6 @@
# Check every path through every method of UserDict
-from test import support, mapping_tests
+from test import mapping_tests
import unittest
import collections
@@ -30,7 +30,7 @@ class UserDictTest(mapping_tests.TestHashMappingProtocol):
self.assertEqual(collections.UserDict(one=1, two=2), d2)
# item sequence constructor
self.assertEqual(collections.UserDict([('one',1), ('two',2)]), d2)
- with self.assertWarnsRegex(PendingDeprecationWarning, "'dict'"):
+ with self.assertWarnsRegex(DeprecationWarning, "'dict'"):
self.assertEqual(collections.UserDict(dict=[('one',1), ('two',2)]), d2)
# both together
self.assertEqual(collections.UserDict([('one',1), ('two',2)], two=3, three=5), d3)
@@ -149,7 +149,7 @@ class UserDictTest(mapping_tests.TestHashMappingProtocol):
[('dict', 42)])
self.assertEqual(list(collections.UserDict({}, dict=None).items()),
[('dict', None)])
- with self.assertWarnsRegex(PendingDeprecationWarning, "'dict'"):
+ with self.assertWarnsRegex(DeprecationWarning, "'dict'"):
self.assertEqual(list(collections.UserDict(dict={'a': 42}).items()),
[('a', 42)])
self.assertRaises(TypeError, collections.UserDict, 42)
diff --git a/Lib/test/test_userlist.py b/Lib/test/test_userlist.py
index f92e4d385e..8de6c14e39 100644
--- a/Lib/test/test_userlist.py
+++ b/Lib/test/test_userlist.py
@@ -1,7 +1,7 @@
# Check every path through every method of UserList
from collections import UserList
-from test import support, list_tests
+from test import list_tests
import unittest
class UserListTest(list_tests.CommonTest):
diff --git a/Lib/test/test_userstring.py b/Lib/test/test_userstring.py
index 9bc8edd99d..71528223d3 100644
--- a/Lib/test/test_userstring.py
+++ b/Lib/test/test_userstring.py
@@ -1,9 +1,8 @@
# UserString is a wrapper around the native builtin string type.
# UserString instances should behave similar to builtin string objects.
-import string
import unittest
-from test import support, string_tests
+from test import string_tests
from collections import UserString
diff --git a/Lib/test/test_uu.py b/Lib/test/test_uu.py
index 25fffbf993..ad2f2c59c1 100644
--- a/Lib/test/test_uu.py
+++ b/Lib/test/test_uu.py
@@ -8,7 +8,6 @@ from test import support
import sys, os
import uu
-from io import BytesIO
import io
plaintext = b"The smooth-scaled python crept over the sleeping dog\n"
diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py
index d2c986e71e..a2842b0217 100644
--- a/Lib/test/test_venv.py
+++ b/Lib/test/test_venv.py
@@ -15,7 +15,6 @@ import sys
import tempfile
from test.support import (captured_stdout, captured_stderr,
can_symlink, EnvironmentVarGuard, rmtree)
-import textwrap
import unittest
import venv
@@ -31,18 +30,17 @@ try:
except ImportError:
threading = None
+try:
+ import ctypes
+except ImportError:
+ ctypes = None
+
skipInVenv = unittest.skipIf(sys.prefix != sys.base_prefix,
'Test not appropriate in a venv')
-# os.path.exists('nul') is False: http://bugs.python.org/issue20541
-if os.devnull.lower() == 'nul':
- failsOnWindows = unittest.expectedFailure
-else:
- def failsOnWindows(f):
- return f
-
class BaseTest(unittest.TestCase):
"""Base class for venv tests."""
+ maxDiff = 80 * 50
def setUp(self):
self.env_dir = os.path.realpath(tempfile.mkdtemp())
@@ -52,7 +50,7 @@ class BaseTest(unittest.TestCase):
self.include = 'Include'
else:
self.bindir = 'bin'
- self.lib = ('lib', 'python%s' % sys.version[:3])
+ self.lib = ('lib', 'python%d.%d' % sys.version_info[:2])
self.include = 'include'
if sys.platform == 'darwin' and '__PYVENV_LAUNCHER__' in os.environ:
executable = os.environ['__PYVENV_LAUNCHER__']
@@ -313,20 +311,27 @@ class EnsurePipTest(BaseTest):
self.run_with_capture(venv.create, self.env_dir, with_pip=False)
self.assert_pip_not_installed()
- @failsOnWindows
- def test_devnull_exists_and_is_empty(self):
+ def test_devnull(self):
# Fix for issue #20053 uses os.devnull to force a config file to
# appear empty. However http://bugs.python.org/issue20541 means
# that doesn't currently work properly on Windows. Once that is
# fixed, the "win_location" part of test_with_pip should be restored
- self.assertTrue(os.path.exists(os.devnull))
with open(os.devnull, "rb") as f:
self.assertEqual(f.read(), b"")
+ # Issue #20541: os.path.exists('nul') is False on Windows
+ if os.devnull.lower() == 'nul':
+ self.assertFalse(os.path.exists(os.devnull))
+ else:
+ self.assertTrue(os.path.exists(os.devnull))
+
+
# Requesting pip fails without SSL (http://bugs.python.org/issue19744)
@unittest.skipIf(ssl is None, ensurepip._MISSING_SSL_MESSAGE)
@unittest.skipUnless(threading, 'some dependencies of pip import threading'
' module unconditionally')
+ # Issue #26610: pip/pep425tags.py requires ctypes
+ @unittest.skipUnless(ctypes, 'pip requires ctypes')
def test_with_pip(self):
rmtree(self.env_dir)
with EnvironmentVarGuard() as envvars:
diff --git a/Lib/test/test_warnings/__init__.py b/Lib/test/test_warnings/__init__.py
index 72fcc73661..497c5cc94b 100644
--- a/Lib/test/test_warnings/__init__.py
+++ b/Lib/test/test_warnings/__init__.py
@@ -2,7 +2,9 @@ from contextlib import contextmanager
import linecache
import os
from io import StringIO
+import re
import sys
+import textwrap
import unittest
from test import support
from test.support.script_helper import assert_python_ok, assert_python_failure
@@ -708,6 +710,17 @@ class _WarningsTests(BaseTest, unittest.TestCase):
result = stream.getvalue()
self.assertIn(text, result)
+ def test_showwarnmsg_missing(self):
+ # Test that _showwarnmsg() missing is okay.
+ text = 'del _showwarnmsg test'
+ with original_warnings.catch_warnings(module=self.module):
+ self.module.filterwarnings("always", category=UserWarning)
+ del self.module._showwarnmsg
+ with support.captured_output('stderr') as stream:
+ self.module.warn(text)
+ result = stream.getvalue()
+ self.assertIn(text, result)
+
def test_showwarning_not_callable(self):
with original_warnings.catch_warnings(module=self.module):
self.module.filterwarnings("always", category=UserWarning)
@@ -809,12 +822,44 @@ class WarningsDisplayTests(BaseTest):
file_object, expected_file_line)
self.assertEqual(expect, file_object.getvalue())
+
class CWarningsDisplayTests(WarningsDisplayTests, unittest.TestCase):
module = c_warnings
class PyWarningsDisplayTests(WarningsDisplayTests, unittest.TestCase):
module = py_warnings
+ def test_tracemalloc(self):
+ self.addCleanup(support.unlink, support.TESTFN)
+
+ with open(support.TESTFN, 'w') as fp:
+ fp.write(textwrap.dedent("""
+ def func():
+ f = open(__file__)
+ # Emit ResourceWarning
+ f = None
+
+ func()
+ """))
+
+ res = assert_python_ok('-Wd', '-X', 'tracemalloc=2', support.TESTFN)
+
+ stderr = res.err.decode('ascii', 'replace')
+ # normalize newlines
+ stderr = '\n'.join(stderr.splitlines())
+ stderr = re.sub('<.*>', '<...>', stderr)
+ expected = textwrap.dedent('''
+ {fname}:5: ResourceWarning: unclosed file <...>
+ f = None
+ Object allocated at (most recent call first):
+ File "{fname}", lineno 3
+ f = open(__file__)
+ File "{fname}", lineno 7
+ func()
+ ''')
+ expected = expected.format(fname=support.TESTFN).strip()
+ self.assertEqual(stderr, expected)
+
class CatchWarningTests(BaseTest):
diff --git a/Lib/test/test_warnings/data/import_warning.py b/Lib/test/test_warnings/data/import_warning.py
index d6ea2ce104..32daec1140 100644
--- a/Lib/test/test_warnings/data/import_warning.py
+++ b/Lib/test/test_warnings/data/import_warning.py
@@ -1,3 +1,3 @@
import warnings
-warnings.warn('module-level warning', DeprecationWarning, stacklevel=2) \ No newline at end of file
+warnings.warn('module-level warning', DeprecationWarning, stacklevel=2)
diff --git a/Lib/test/test_wave.py b/Lib/test/test_wave.py
index 3eff773bca..8666f7269c 100644
--- a/Lib/test/test_wave.py
+++ b/Lib/test/test_wave.py
@@ -1,6 +1,6 @@
-from test.support import TESTFN
import unittest
from test import audiotests
+from test import support
from audioop import byteswap
import sys
import wave
@@ -103,5 +103,11 @@ class WavePCM32Test(WaveTest, unittest.TestCase):
frames = byteswap(frames, 4)
+class MiscTestCase(unittest.TestCase):
+ def test__all__(self):
+ blacklist = {'WAVE_FORMAT_PCM'}
+ support.check__all__(self, wave, blacklist=blacklist)
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/Lib/test/test_weakset.py b/Lib/test/test_weakset.py
index 9ce672b815..691b95e77c 100644
--- a/Lib/test/test_weakset.py
+++ b/Lib/test/test_weakset.py
@@ -1,13 +1,6 @@
import unittest
-from weakref import proxy, ref, WeakSet
-import operator
-import copy
+from weakref import WeakSet
import string
-import os
-from random import randrange, shuffle
-import sys
-import warnings
-import collections
from collections import UserString as ustr
import gc
import contextlib
diff --git a/Lib/test/test_winreg.py b/Lib/test/test_winreg.py
index 2c4ac08f39..ef40e8bc37 100644
--- a/Lib/test/test_winreg.py
+++ b/Lib/test/test_winreg.py
@@ -37,6 +37,7 @@ test_reflect_key_name = "SOFTWARE\\Classes\\" + test_key_base
test_data = [
("Int Value", 45, REG_DWORD),
+ ("Qword Value", 0x1122334455667788, REG_QWORD),
("String Val", "A string value", REG_SZ),
("StringExpand", "The path is %path%", REG_EXPAND_SZ),
("Multi-string", ["Lots", "of", "string", "values"], REG_MULTI_SZ),
diff --git a/Lib/test/test_with.py b/Lib/test/test_with.py
index e8d789bc2c..e247ff6a61 100644
--- a/Lib/test/test_with.py
+++ b/Lib/test/test_with.py
@@ -140,11 +140,6 @@ class FailureTestCase(unittest.TestCase):
'with mock as (None):\n'
' pass')
- def testAssignmentToEmptyTupleError(self):
- self.assertRaisesSyntaxError(
- 'with mock as ():\n'
- ' pass')
-
def testAssignmentToTupleOnlyContainingNoneError(self):
self.assertRaisesSyntaxError('with mock as None,:\n pass')
self.assertRaisesSyntaxError(
@@ -454,7 +449,7 @@ class ExceptionalTestCase(ContextmanagerAssertionMixin, unittest.TestCase):
with cm():
raise StopIteration("from with")
- with self.assertWarnsRegex(PendingDeprecationWarning, "StopIteration"):
+ with self.assertWarnsRegex(DeprecationWarning, "StopIteration"):
self.assertRaises(StopIteration, shouldThrow)
def testRaisedStopIteration2(self):
@@ -482,7 +477,7 @@ class ExceptionalTestCase(ContextmanagerAssertionMixin, unittest.TestCase):
with cm():
raise next(iter([]))
- with self.assertWarnsRegex(PendingDeprecationWarning, "StopIteration"):
+ with self.assertWarnsRegex(DeprecationWarning, "StopIteration"):
self.assertRaises(StopIteration, shouldThrow)
def testRaisedGeneratorExit1(self):
diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py
index 44e3142dc9..a56f1582b6 100644
--- a/Lib/test/test_xml_etree.py
+++ b/Lib/test/test_xml_etree.py
@@ -91,8 +91,6 @@ ENTITY_XML = """\
class ModuleTest(unittest.TestCase):
- # TODO: this should be removed once we get rid of the global module vars
-
def test_sanity(self):
# Import sanity.
@@ -100,6 +98,10 @@ class ModuleTest(unittest.TestCase):
from xml.etree import ElementInclude
from xml.etree import ElementPath
+ def test_all(self):
+ names = ("xml.etree.ElementTree", "_elementtree")
+ support.check__all__(self, ET, names, blacklist=("HTML_EMPTY",))
+
def serialize(elem, to_string=True, encoding='unicode', **options):
if encoding != 'unicode':
@@ -182,10 +184,12 @@ class ElementTreeTest(unittest.TestCase):
def check_element(element):
self.assertTrue(ET.iselement(element), msg="not an element")
- self.assertTrue(hasattr(element, "tag"), msg="no tag member")
- self.assertTrue(hasattr(element, "attrib"), msg="no attrib member")
- self.assertTrue(hasattr(element, "text"), msg="no text member")
- self.assertTrue(hasattr(element, "tail"), msg="no tail member")
+ direlem = dir(element)
+ for attr in 'tag', 'attrib', 'text', 'tail':
+ self.assertTrue(hasattr(element, attr),
+ msg='no %s member' % attr)
+ self.assertIn(attr, direlem,
+ msg='no %s visible by dir' % attr)
check_string(element.tag)
check_mapping(element.attrib)
diff --git a/Lib/test/test_xml_etree_c.py b/Lib/test/test_xml_etree_c.py
index 96b446e32e..87f3f27abc 100644
--- a/Lib/test/test_xml_etree_c.py
+++ b/Lib/test/test_xml_etree_c.py
@@ -1,5 +1,5 @@
# xml.etree test for cElementTree
-import sys, struct
+import struct
from test import support
from test.support import import_fresh_module
import types
@@ -108,7 +108,7 @@ class SizeofTest(unittest.TestCase):
struct.calcsize('8P'))
def test_main():
- from test import test_xml_etree, test_xml_etree_c
+ from test import test_xml_etree
# Run the tests specific to the C implementation
support.run_unittest(
diff --git a/Lib/test/test_xmlrpc.py b/Lib/test/test_xmlrpc.py
index 02d9f5c650..0773a86984 100644
--- a/Lib/test/test_xmlrpc.py
+++ b/Lib/test/test_xmlrpc.py
@@ -9,7 +9,6 @@ import xmlrpc.server
import http.client
import http, http.server
import socket
-import os
import re
import io
import contextlib
@@ -1147,7 +1146,6 @@ def captured_stdout(encoding='utf-8'):
"""A variation on support.captured_stdout() which gives a text stream
having a `buffer` attribute.
"""
- import io
orig_stdout = sys.stdout
sys.stdout = io.TextIOWrapper(io.BytesIO(), encoding=encoding)
try:
diff --git a/Lib/test/test_xmlrpc_net.py b/Lib/test/test_xmlrpc_net.py
index b60b82f3e2..ae0a28e721 100644
--- a/Lib/test/test_xmlrpc_net.py
+++ b/Lib/test/test_xmlrpc_net.py
@@ -1,7 +1,4 @@
import collections.abc
-import errno
-import socket
-import sys
import unittest
from test import support
diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py
index d278e06a45..6a77d6c91f 100644
--- a/Lib/test/test_zipfile.py
+++ b/Lib/test/test_zipfile.py
@@ -1,8 +1,8 @@
import contextlib
import io
import os
-import sys
import importlib.util
+import posixpath
import time
import struct
import zipfile
@@ -61,6 +61,9 @@ class AbstractTestsWithSourceFile:
zipfp.write(TESTFN, "another.name")
zipfp.write(TESTFN, TESTFN)
zipfp.writestr("strfile", self.data)
+ with zipfp.open('written-open-w', mode='w') as f:
+ for line in self.line_gen:
+ f.write(line)
def zip_test(self, f, compression):
self.make_test_archive(f, compression)
@@ -76,7 +79,7 @@ class AbstractTestsWithSourceFile:
zipfp.printdir(file=fp)
directory = fp.getvalue()
lines = directory.splitlines()
- self.assertEqual(len(lines), 4) # Number of files + header
+ self.assertEqual(len(lines), 5) # Number of files + header
self.assertIn('File Name', lines[0])
self.assertIn('Modified', lines[0])
@@ -90,23 +93,25 @@ class AbstractTestsWithSourceFile:
# Check the namelist
names = zipfp.namelist()
- self.assertEqual(len(names), 3)
+ self.assertEqual(len(names), 4)
self.assertIn(TESTFN, names)
self.assertIn("another.name", names)
self.assertIn("strfile", names)
+ self.assertIn("written-open-w", names)
# Check infolist
infos = zipfp.infolist()
names = [i.filename for i in infos]
- self.assertEqual(len(names), 3)
+ self.assertEqual(len(names), 4)
self.assertIn(TESTFN, names)
self.assertIn("another.name", names)
self.assertIn("strfile", names)
+ self.assertIn("written-open-w", names)
for i in infos:
self.assertEqual(i.file_size, len(self.data))
# check getinfo
- for nm in (TESTFN, "another.name", "strfile"):
+ for nm in (TESTFN, "another.name", "strfile", "written-open-w"):
info = zipfp.getinfo(nm)
self.assertEqual(info.filename, nm)
self.assertEqual(info.file_size, len(self.data))
@@ -372,14 +377,18 @@ class StoredTestsWithSourceFile(AbstractTestsWithSourceFile,
test_low_compression = None
def zip_test_writestr_permissions(self, f, compression):
- # Make sure that writestr creates files with mode 0600,
- # when it is passed a name rather than a ZipInfo instance.
+ # Make sure that writestr and open(... mode='w') create files with
+ # mode 0600, when they are passed a name rather than a ZipInfo
+ # instance.
self.make_test_archive(f, compression)
with zipfile.ZipFile(f, "r") as zipfp:
zinfo = zipfp.getinfo('strfile')
self.assertEqual(zinfo.external_attr, 0o600 << 16)
+ zinfo2 = zipfp.getinfo('written-open-w')
+ self.assertEqual(zinfo2.external_attr, 0o600 << 16)
+
def test_writestr_permissions(self):
for f in get_files(self):
self.zip_test_writestr_permissions(f, zipfile.ZIP_STORED)
@@ -451,6 +460,10 @@ class StoredTestsWithSourceFile(AbstractTestsWithSourceFile,
with zipfile.ZipFile(TESTFN2, mode="r") as zipfp:
self.assertRaises(RuntimeError, zipfp.write, TESTFN)
+ with zipfile.ZipFile(TESTFN2, mode="r") as zipfp:
+ with self.assertRaises(RuntimeError):
+ zipfp.open(TESTFN, mode='w')
+
def test_add_file_before_1980(self):
# Set atime and mtime to 1970-01-01
os.utime(TESTFN, (0, 0))
@@ -1428,6 +1441,35 @@ class OtherTests(unittest.TestCase):
# testzip returns the name of the first corrupt file, or None
self.assertIsNone(zipf.testzip())
+ def test_open_conflicting_handles(self):
+ # It's only possible to open one writable file handle at a time
+ msg1 = b"It's fun to charter an accountant!"
+ msg2 = b"And sail the wide accountant sea"
+ msg3 = b"To find, explore the funds offshore"
+ with zipfile.ZipFile(TESTFN2, 'w', zipfile.ZIP_STORED) as zipf:
+ with zipf.open('foo', mode='w') as w2:
+ w2.write(msg1)
+ with zipf.open('bar', mode='w') as w1:
+ with self.assertRaises(RuntimeError):
+ zipf.open('handle', mode='w')
+ with self.assertRaises(RuntimeError):
+ zipf.open('foo', mode='r')
+ with self.assertRaises(RuntimeError):
+ zipf.writestr('str', 'abcde')
+ with self.assertRaises(RuntimeError):
+ zipf.write(__file__, 'file')
+ with self.assertRaises(RuntimeError):
+ zipf.close()
+ w1.write(msg2)
+ with zipf.open('baz', mode='w') as w2:
+ w2.write(msg3)
+
+ with zipfile.ZipFile(TESTFN2, 'r') as zipf:
+ self.assertEqual(zipf.read('foo'), msg1)
+ self.assertEqual(zipf.read('bar'), msg2)
+ self.assertEqual(zipf.read('baz'), msg3)
+ self.assertEqual(zipf.namelist(), ['foo', 'bar', 'baz'])
+
def tearDown(self):
unlink(TESTFN)
unlink(TESTFN2)
@@ -1761,6 +1803,22 @@ class UnseekableTests(unittest.TestCase):
with zipf.open('twos') as zopen:
self.assertEqual(zopen.read(), b'222')
+ def test_open_write(self):
+ for wrapper in (lambda f: f), Tellable, Unseekable:
+ with self.subTest(wrapper=wrapper):
+ f = io.BytesIO()
+ f.write(b'abc')
+ bf = io.BufferedWriter(f)
+ with zipfile.ZipFile(wrapper(bf), 'w', zipfile.ZIP_STORED) as zipf:
+ with zipf.open('ones', 'w') as zopen:
+ zopen.write(b'111')
+ with zipf.open('twos', 'w') as zopen:
+ zopen.write(b'222')
+ self.assertEqual(f.getvalue()[:5], b'abcPK')
+ with zipfile.ZipFile(f) as zipf:
+ self.assertEqual(zipf.read('ones'), b'111')
+ self.assertEqual(zipf.read('twos'), b'222')
+
@requires_zlib
class TestsWithMultipleOpens(unittest.TestCase):
@@ -1871,6 +1929,19 @@ class TestsWithMultipleOpens(unittest.TestCase):
with open(os.devnull) as f:
self.assertLess(f.fileno(), 100)
+ def test_write_while_reading(self):
+ with zipfile.ZipFile(TESTFN2, 'w', zipfile.ZIP_DEFLATED) as zipf:
+ zipf.writestr('ones', self.data1)
+ with zipfile.ZipFile(TESTFN2, 'a', zipfile.ZIP_DEFLATED) as zipf:
+ with zipf.open('ones', 'r') as r1:
+ data1 = r1.read(500)
+ with zipf.open('twos', 'w') as w1:
+ w1.write(self.data2)
+ data1 += r1.read()
+ self.assertEqual(data1, self.data1)
+ with zipfile.ZipFile(TESTFN2) as zipf:
+ self.assertEqual(zipf.read('twos'), self.data2)
+
def tearDown(self):
unlink(TESTFN2)
@@ -2072,5 +2143,19 @@ class LzmaUniversalNewlineTests(AbstractUniversalNewlineTests,
unittest.TestCase):
compression = zipfile.ZIP_LZMA
+class ZipInfoTests(unittest.TestCase):
+ def test_from_file(self):
+ zi = zipfile.ZipInfo.from_file(__file__)
+ self.assertEqual(posixpath.basename(zi.filename), 'test_zipfile.py')
+ self.assertFalse(zi.is_dir())
+
+ def test_from_dir(self):
+ dirpath = os.path.dirname(os.path.abspath(__file__))
+ zi = zipfile.ZipInfo.from_file(dirpath, 'stdlib_tests')
+ self.assertEqual(zi.filename, 'stdlib_tests/')
+ self.assertTrue(zi.is_dir())
+ self.assertEqual(zi.compress_type, zipfile.ZIP_STORED)
+ self.assertEqual(zi.file_size, 0)
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/test/test_zipimport.py b/Lib/test/test_zipimport.py
index 0da5906f28..1f10095f43 100644
--- a/Lib/test/test_zipimport.py
+++ b/Lib/test/test_zipimport.py
@@ -398,7 +398,8 @@ class UncompressedZipImportTestCase(ImportHooksBaseTestCase):
packdir2 = packdir + TESTPACK2 + os.sep
files = {packdir + "__init__" + pyc_ext: (NOW, test_pyc),
packdir2 + "__init__" + pyc_ext: (NOW, test_pyc),
- packdir2 + TESTMOD + pyc_ext: (NOW, test_pyc)}
+ packdir2 + TESTMOD + pyc_ext: (NOW, test_pyc),
+ "spam" + pyc_ext: (NOW, test_pyc)}
z = ZipFile(TEMP_ZIP, "w")
try:
@@ -412,6 +413,14 @@ class UncompressedZipImportTestCase(ImportHooksBaseTestCase):
zi = zipimport.zipimporter(TEMP_ZIP)
self.assertEqual(zi.archive, TEMP_ZIP)
self.assertEqual(zi.is_package(TESTPACK), True)
+
+ find_mod = zi.find_module('spam')
+ self.assertIsNotNone(find_mod)
+ self.assertIsInstance(find_mod, zipimport.zipimporter)
+ self.assertFalse(find_mod.is_package('spam'))
+ load_mod = find_mod.load_module('spam')
+ self.assertEqual(find_mod.get_filename('spam'), load_mod.__file__)
+
mod = zi.load_module(TESTPACK)
self.assertEqual(zi.get_filename(TESTPACK), mod.__file__)
@@ -471,6 +480,16 @@ class UncompressedZipImportTestCase(ImportHooksBaseTestCase):
self.assertEqual(
zi.is_package(TESTPACK2 + os.sep + TESTMOD), False)
+ pkg_path = TEMP_ZIP + os.sep + packdir + TESTPACK2
+ zi2 = zipimport.zipimporter(pkg_path)
+ find_mod_dotted = zi2.find_module(TESTMOD)
+ self.assertIsNotNone(find_mod_dotted)
+ self.assertIsInstance(find_mod_dotted, zipimport.zipimporter)
+ self.assertFalse(zi2.is_package(TESTMOD))
+ load_mod = find_mod_dotted.load_module(TESTMOD)
+ self.assertEqual(
+ find_mod_dotted.get_filename(TESTMOD), load_mod.__file__)
+
mod_path = TESTPACK2 + os.sep + TESTMOD
mod_name = module_path_to_dotted_name(mod_path)
mod = importlib.import_module(mod_name)
diff --git a/Lib/test/test_zipimport_support.py b/Lib/test/test_zipimport_support.py
index 5913622f56..84d526c3db 100644
--- a/Lib/test/test_zipimport_support.py
+++ b/Lib/test/test_zipimport_support.py
@@ -12,7 +12,6 @@ import zipimport
import doctest
import inspect
import linecache
-import pdb
import unittest
from test.support.script_helper import (spawn_python, kill_python, assert_python_ok,
make_script, make_zip_script)
diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py
index b6bebbced1..b3e10c05e4 100644
--- a/Lib/test/test_zlib.py
+++ b/Lib/test/test_zlib.py
@@ -162,6 +162,10 @@ class CompressTestCase(BaseCompressTestCase, unittest.TestCase):
x = zlib.compress(HAMLET_SCENE)
self.assertEqual(zlib.decompress(x), HAMLET_SCENE)
+ def test_keywords(self):
+ x = zlib.compress(data=HAMLET_SCENE, level=3)
+ self.assertEqual(zlib.decompress(x), HAMLET_SCENE)
+
def test_speech128(self):
# compress more data
data = HAMLET_SCENE * 128