aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Lib
diff options
context:
space:
mode:
Diffstat (limited to 'Lib')
-rw-r--r--Lib/logging/__init__.py28
-rw-r--r--Lib/pprint.py68
-rw-r--r--Lib/reprlib.py17
-rw-r--r--Lib/test/libregrtest/main.py16
-rw-r--r--Lib/test/test__interpreters.py15
-rw-r--r--Lib/test/test_hashlib.py10
-rw-r--r--Lib/test/test_logging.py83
-rw-r--r--Lib/test/test_regrtest.py11
-rw-r--r--Lib/test/test_reprlib.py40
9 files changed, 136 insertions, 152 deletions
diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py
index 5c3c4424934..c5860d53b1b 100644
--- a/Lib/logging/__init__.py
+++ b/Lib/logging/__init__.py
@@ -1475,8 +1475,6 @@ class Logger(Filterer):
level, and "input.csv", "input.xls" and "input.gnu" for the sub-levels.
There is no arbitrary limit to the depth of nesting.
"""
- _tls = threading.local()
-
def __init__(self, name, level=NOTSET):
"""
Initialize the logger with a name and an optional level.
@@ -1673,19 +1671,14 @@ class Logger(Filterer):
This method is used for unpickled records received from a socket, as
well as those created locally. Logger-level filtering is applied.
"""
- if self._is_disabled():
+ if self.disabled:
return
-
- self._tls.in_progress = True
- try:
- maybe_record = self.filter(record)
- if not maybe_record:
- return
- if isinstance(maybe_record, LogRecord):
- record = maybe_record
- self.callHandlers(record)
- finally:
- self._tls.in_progress = False
+ maybe_record = self.filter(record)
+ if not maybe_record:
+ return
+ if isinstance(maybe_record, LogRecord):
+ record = maybe_record
+ self.callHandlers(record)
def addHandler(self, hdlr):
"""
@@ -1773,7 +1766,7 @@ class Logger(Filterer):
"""
Is this logger enabled for level 'level'?
"""
- if self._is_disabled():
+ if self.disabled:
return False
try:
@@ -1823,11 +1816,6 @@ class Logger(Filterer):
if isinstance(item, Logger) and item.parent is self and
_hierlevel(item) == 1 + _hierlevel(item.parent))
- def _is_disabled(self):
- # We need to use getattr as it will only be set the first time a log
- # message is recorded on any given thread
- return self.disabled or getattr(self._tls, 'in_progress', False)
-
def __repr__(self):
level = getLevelName(self.getEffectiveLevel())
return '<%s %s (%s)>' % (self.__class__.__name__, self.name, level)
diff --git a/Lib/pprint.py b/Lib/pprint.py
index 1e611481b51..92a2c543ac2 100644
--- a/Lib/pprint.py
+++ b/Lib/pprint.py
@@ -653,6 +653,40 @@ class PrettyPrinter:
del context[objid]
return "{%s}" % ", ".join(components), readable, recursive
+ if (issubclass(typ, list) and r is list.__repr__) or \
+ (issubclass(typ, tuple) and r is tuple.__repr__):
+ if issubclass(typ, list):
+ if not object:
+ return "[]", True, False
+ format = "[%s]"
+ elif len(object) == 1:
+ format = "(%s,)"
+ else:
+ if not object:
+ return "()", True, False
+ format = "(%s)"
+ objid = id(object)
+ if maxlevels and level >= maxlevels:
+ return format % "...", False, objid in context
+ if objid in context:
+ return _recursion(object), False, True
+ context[objid] = 1
+ readable = True
+ recursive = False
+ components = []
+ append = components.append
+ level += 1
+ for o in object:
+ orepr, oreadable, orecur = self.format(
+ o, context, maxlevels, level)
+ append(orepr)
+ if not oreadable:
+ readable = False
+ if orecur:
+ recursive = True
+ del context[objid]
+ return format % ", ".join(components), readable, recursive
+
if issubclass(typ, _collections.abc.MappingView) and r in self._view_reprs:
objid = id(object)
if maxlevels and level >= maxlevels:
@@ -689,40 +723,6 @@ class PrettyPrinter:
del context[objid]
return typ.__name__ + '([%s])' % ", ".join(components), readable, recursive
- if (issubclass(typ, list) and r is list.__repr__) or \
- (issubclass(typ, tuple) and r is tuple.__repr__):
- if issubclass(typ, list):
- if not object:
- return "[]", True, False
- format = "[%s]"
- elif len(object) == 1:
- format = "(%s,)"
- else:
- if not object:
- return "()", True, False
- format = "(%s)"
- objid = id(object)
- if maxlevels and level >= maxlevels:
- return format % "...", False, objid in context
- if objid in context:
- return _recursion(object), False, True
- context[objid] = 1
- readable = True
- recursive = False
- components = []
- append = components.append
- level += 1
- for o in object:
- orepr, oreadable, orecur = self.format(
- o, context, maxlevels, level)
- append(orepr)
- if not oreadable:
- readable = False
- if orecur:
- recursive = True
- del context[objid]
- return format % ", ".join(components), readable, recursive
-
rep = repr(object)
return rep, (rep and not rep.startswith('<')), False
diff --git a/Lib/reprlib.py b/Lib/reprlib.py
index 441d1be4bde..ab18247682b 100644
--- a/Lib/reprlib.py
+++ b/Lib/reprlib.py
@@ -181,7 +181,22 @@ class Repr:
return s
def repr_int(self, x, level):
- s = builtins.repr(x) # XXX Hope this isn't too slow...
+ try:
+ s = builtins.repr(x)
+ except ValueError as exc:
+ assert 'sys.set_int_max_str_digits()' in str(exc)
+ # Those imports must be deferred due to Python's build system
+ # where the reprlib module is imported before the math module.
+ import math, sys
+ # Integers with more than sys.get_int_max_str_digits() digits
+ # are rendered differently as their repr() raises a ValueError.
+ # See https://github.com/python/cpython/issues/135487.
+ k = 1 + int(math.log10(abs(x)))
+ # Note: math.log10(abs(x)) may be overestimated or underestimated,
+ # but for simplicity, we do not compute the exact number of digits.
+ max_digits = sys.get_int_max_str_digits()
+ return (f'<{x.__class__.__name__} instance with roughly {k} '
+ f'digits (limit at {max_digits}) at 0x{id(x):x}>')
if len(s) > self.maxlong:
i = max(0, (self.maxlong-3)//2)
j = max(0, self.maxlong-3-i)
diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py
index 0d9c059a938..a2d01b157ac 100644
--- a/Lib/test/libregrtest/main.py
+++ b/Lib/test/libregrtest/main.py
@@ -190,6 +190,12 @@ class Regrtest:
strip_py_suffix(tests)
+ exclude_tests = set()
+ if self.exclude:
+ for arg in self.cmdline_args:
+ exclude_tests.add(arg)
+ self.cmdline_args = []
+
if self.pgo:
# add default PGO tests if no tests are specified
setup_pgo_tests(self.cmdline_args, self.pgo_extended)
@@ -200,17 +206,15 @@ class Regrtest:
if self.tsan_parallel:
setup_tsan_parallel_tests(self.cmdline_args)
- exclude_tests = set()
- if self.exclude:
- for arg in self.cmdline_args:
- exclude_tests.add(arg)
- self.cmdline_args = []
-
alltests = findtests(testdir=self.test_dir,
exclude=exclude_tests)
if not self.fromfile:
selected = tests or self.cmdline_args
+ if exclude_tests:
+ # Support "--pgo/--tsan -x test_xxx" command
+ selected = [name for name in selected
+ if name not in exclude_tests]
if selected:
selected = split_test_packages(selected)
else:
diff --git a/Lib/test/test__interpreters.py b/Lib/test/test__interpreters.py
index ad3ebbfdff6..a32d5d81d2b 100644
--- a/Lib/test/test__interpreters.py
+++ b/Lib/test/test__interpreters.py
@@ -485,6 +485,21 @@ class CommonTests(TestBase):
msg = r'_interpreters.run_func\(\) argument 3 must be dict, not int'
with self.assertRaisesRegex(TypeError, msg):
_interpreters.run_func(self.id, lambda: None, shared=1)
+ # See https://github.com/python/cpython/issues/135855
+ msg = r'_interpreters.set___main___attrs\(\) argument 2 must be dict, not int'
+ with self.assertRaisesRegex(TypeError, msg):
+ _interpreters.set___main___attrs(self.id, 1)
+
+ def test_invalid_shared_none(self):
+ msg = r'must be dict, not None'
+ with self.assertRaisesRegex(TypeError, msg):
+ _interpreters.exec(self.id, 'a', shared=None)
+ with self.assertRaisesRegex(TypeError, msg):
+ _interpreters.run_string(self.id, 'a', shared=None)
+ with self.assertRaisesRegex(TypeError, msg):
+ _interpreters.run_func(self.id, lambda: None, shared=None)
+ with self.assertRaisesRegex(TypeError, msg):
+ _interpreters.set___main___attrs(self.id, None)
def test_invalid_shared_encoding(self):
# See https://github.com/python/cpython/issues/127196
diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py
index 6e4e41e4fbb..7b378c45e71 100644
--- a/Lib/test/test_hashlib.py
+++ b/Lib/test/test_hashlib.py
@@ -371,6 +371,16 @@ class HashLibTestCase(unittest.TestCase):
self.assertIs(constructor, _md5.md5)
self.assertEqual(sorted(builtin_constructor_cache), ['MD5', 'md5'])
+ def test_copy(self):
+ for cons in self.hash_constructors:
+ h1 = cons(os.urandom(16), usedforsecurity=False)
+ h2 = h1.copy()
+ self.assertIs(type(h1), type(h2))
+ self.assertEqual(h1.name, h2.name)
+ size = (16,) if h1.name in self.shakes else ()
+ self.assertEqual(h1.digest(*size), h2.digest(*size))
+ self.assertEqual(h1.hexdigest(*size), h2.hexdigest(*size))
+
def test_hexdigest(self):
for cons in self.hash_constructors:
h = cons(usedforsecurity=False)
diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py
index e672dfcbb46..3819965ed2c 100644
--- a/Lib/test/test_logging.py
+++ b/Lib/test/test_logging.py
@@ -4214,89 +4214,6 @@ class ConfigDictTest(BaseTest):
handler = logging.getHandlerByName('custom')
self.assertEqual(handler.custom_kwargs, custom_kwargs)
- # See gh-91555 and gh-90321
- @support.requires_subprocess()
- def test_deadlock_in_queue(self):
- queue = multiprocessing.Queue()
- handler = logging.handlers.QueueHandler(queue)
- logger = multiprocessing.get_logger()
- level = logger.level
- try:
- logger.setLevel(logging.DEBUG)
- logger.addHandler(handler)
- logger.debug("deadlock")
- finally:
- logger.setLevel(level)
- logger.removeHandler(handler)
-
- def test_recursion_in_custom_handler(self):
- class BadHandler(logging.Handler):
- def __init__(self):
- super().__init__()
- def emit(self, record):
- logger.debug("recurse")
- logger = logging.getLogger("test_recursion_in_custom_handler")
- logger.addHandler(BadHandler())
- logger.setLevel(logging.DEBUG)
- logger.debug("boom")
-
- @threading_helper.requires_working_threading()
- def test_thread_supression_noninterference(self):
- lock = threading.Lock()
- logger = logging.getLogger("test_thread_supression_noninterference")
-
- # Block on the first call, allow others through
- #
- # NOTE: We need to bypass the base class's lock, otherwise that will
- # block multiple calls to the same handler itself.
- class BlockOnceHandler(TestHandler):
- def __init__(self, barrier):
- super().__init__(support.Matcher())
- self.barrier = barrier
-
- def createLock(self):
- self.lock = None
-
- def handle(self, record):
- self.emit(record)
-
- def emit(self, record):
- if self.barrier:
- barrier = self.barrier
- self.barrier = None
- barrier.wait()
- with lock:
- pass
- super().emit(record)
- logger.info("blow up if not supressed")
-
- barrier = threading.Barrier(2)
- handler = BlockOnceHandler(barrier)
- logger.addHandler(handler)
- logger.setLevel(logging.DEBUG)
-
- t1 = threading.Thread(target=logger.debug, args=("1",))
- with lock:
-
- # Ensure first thread is blocked in the handler, hence supressing logging...
- t1.start()
- barrier.wait()
-
- # ...but the second thread should still be able to log...
- t2 = threading.Thread(target=logger.debug, args=("2",))
- t2.start()
- t2.join(timeout=3)
-
- self.assertEqual(len(handler.buffer), 1)
- self.assertTrue(handler.matches(levelno=logging.DEBUG, message='2'))
-
- # The first thread should still be blocked here
- self.assertTrue(t1.is_alive())
-
- # Now the lock has been released the first thread should complete
- t1.join()
- self.assertEqual(len(handler.buffer), 2)
- self.assertTrue(handler.matches(levelno=logging.DEBUG, message='1'))
class ManagerTest(BaseTest):
def test_manager_loggerclass(self):
diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py
index a43d2678ebd..5bc3c5924b0 100644
--- a/Lib/test/test_regrtest.py
+++ b/Lib/test/test_regrtest.py
@@ -2346,6 +2346,17 @@ class ArgsTestCase(BaseTestCase):
output = self.run_tests('-j1', '-v', testname, env=env, isolated=False)
check(output)
+ def test_pgo_exclude(self):
+ # Get PGO tests
+ output = self.run_tests('--pgo', '--list-tests')
+ pgo_tests = output.strip().split()
+
+ # Exclude test_re
+ output = self.run_tests('--pgo', '--list-tests', '-x', 'test_re')
+ tests = output.strip().split()
+ self.assertNotIn('test_re', tests)
+ self.assertEqual(len(tests), len(pgo_tests) - 1)
+
class TestUtils(unittest.TestCase):
def test_format_duration(self):
diff --git a/Lib/test/test_reprlib.py b/Lib/test/test_reprlib.py
index 16623654c29..d5631efcdb7 100644
--- a/Lib/test/test_reprlib.py
+++ b/Lib/test/test_reprlib.py
@@ -151,14 +151,38 @@ class ReprTests(unittest.TestCase):
eq(r(frozenset({1, 2, 3, 4, 5, 6, 7})), "frozenset({1, 2, 3, 4, 5, 6, ...})")
def test_numbers(self):
- eq = self.assertEqual
- eq(r(123), repr(123))
- eq(r(123), repr(123))
- eq(r(1.0/3), repr(1.0/3))
-
- n = 10**100
- expected = repr(n)[:18] + "..." + repr(n)[-19:]
- eq(r(n), expected)
+ for x in [123, 1.0 / 3]:
+ self.assertEqual(r(x), repr(x))
+
+ max_digits = sys.get_int_max_str_digits()
+ for k in [100, max_digits - 1]:
+ with self.subTest(f'10 ** {k}', k=k):
+ n = 10 ** k
+ expected = repr(n)[:18] + "..." + repr(n)[-19:]
+ self.assertEqual(r(n), expected)
+
+ def re_msg(n, d):
+ return (rf'<{n.__class__.__name__} instance with roughly {d} '
+ rf'digits \(limit at {max_digits}\) at 0x[a-f0-9]+>')
+
+ k = max_digits
+ with self.subTest(f'10 ** {k}', k=k):
+ n = 10 ** k
+ self.assertRaises(ValueError, repr, n)
+ self.assertRegex(r(n), re_msg(n, k + 1))
+
+ for k in [max_digits + 1, 2 * max_digits]:
+ self.assertGreater(k, 100)
+ with self.subTest(f'10 ** {k}', k=k):
+ n = 10 ** k
+ self.assertRaises(ValueError, repr, n)
+ self.assertRegex(r(n), re_msg(n, k + 1))
+ with self.subTest(f'10 ** {k} - 1', k=k):
+ n = 10 ** k - 1
+ # Here, since math.log10(n) == math.log10(n-1),
+ # the number of digits of n - 1 is overestimated.
+ self.assertRaises(ValueError, repr, n)
+ self.assertRegex(r(n), re_msg(n, k + 1))
def test_instance(self):
eq = self.assertEqual