Python-checkins
Threads by month
- ----- 2026 -----
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
September 2023
- 1 participants
- 800 discussions
Sept. 29, 2023
https://github.com/python/cpython/commit/743e3572ee940a6cf88fd518e5f4a44790…
commit: 743e3572ee940a6cf88fd518e5f4a447905ba5eb
branch: main
author: Victor Stinner <vstinner(a)python.org>
committer: vstinner <vstinner(a)python.org>
date: 2023-09-29T12:21:18Z
summary:
gh-109974: Fix more threading lock_tests race conditions (#110089)
* Add context manager on Bunch class.
* Bunch now catchs exceptions on executed functions and re-raise them
at __exit__() as an ExceptionGroup.
* Rewrite BarrierProxy.test_default_timeout(). Use a single thread.
Only check that barrier.wait() blocks for at least default timeout
seconds.
* test_with(): inline _with() function.
files:
M Lib/test/lock_tests.py
M Lib/test/test_importlib/test_locks.py
diff --git a/Lib/test/lock_tests.py b/Lib/test/lock_tests.py
index cbaae3afd6dde..024c6debcd4a5 100644
--- a/Lib/test/lock_tests.py
+++ b/Lib/test/lock_tests.py
@@ -39,40 +39,54 @@ def __init__(self, func, nthread, wait_before_exit=False):
self.nthread = nthread
self.started = []
self.finished = []
+ self.exceptions = []
self._can_exit = not wait_before_exit
- self.wait_thread = threading_helper.wait_threads_exit()
- self.wait_thread.__enter__()
+ self._wait_thread = None
- def task():
- tid = threading.get_ident()
- self.started.append(tid)
- try:
- func()
- finally:
- self.finished.append(tid)
- for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
- if self._can_exit:
- break
+ def task(self):
+ tid = threading.get_ident()
+ self.started.append(tid)
+ try:
+ self.func()
+ except BaseException as exc:
+ self.exceptions.append(exc)
+ finally:
+ self.finished.append(tid)
+ for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
+ if self._can_exit:
+ break
+
+ def __enter__(self):
+ self._wait_thread = threading_helper.wait_threads_exit(support.SHORT_TIMEOUT)
+ self._wait_thread.__enter__()
try:
- for i in range(nthread):
- start_new_thread(task, ())
+ for _ in range(self.nthread):
+ start_new_thread(self.task, ())
except:
self._can_exit = True
raise
- def wait_for_started(self):
for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
if len(self.started) >= self.nthread:
break
- def wait_for_finished(self):
+ return self
+
+ def __exit__(self, exc_type, exc_value, traceback):
for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
if len(self.finished) >= self.nthread:
break
- # Wait for threads exit
- self.wait_thread.__exit__(None, None, None)
+ # Wait until threads completely exit according to _thread._count()
+ self._wait_thread.__exit__(None, None, None)
+
+ # Break reference cycle
+ exceptions = self.exceptions
+ self.exceptions = None
+ if exceptions:
+ raise ExceptionGroup(f"{self.func} threads raised exceptions",
+ exceptions)
def do_finish(self):
self._can_exit = True
@@ -143,7 +157,8 @@ def test_try_acquire_contended(self):
result = []
def f():
result.append(lock.acquire(False))
- Bunch(f, 1).wait_for_finished()
+ with Bunch(f, 1):
+ pass
self.assertFalse(result[0])
lock.release()
@@ -154,33 +169,45 @@ def f():
lock.acquire()
lock.release()
- # Threads block on lock.acquire()
N = 5
- b = Bunch(f, N)
- b.wait_for_started()
- wait_threads_blocked(N)
- self.assertEqual(len(b.finished), 0)
+ with Bunch(f, N) as bunch:
+ # Threads block on lock.acquire()
+ wait_threads_blocked(N)
+ self.assertEqual(len(bunch.finished), 0)
- # Threads unblocked
- lock.release()
- b.wait_for_finished()
- self.assertEqual(len(b.finished), N)
+ # Threads unblocked
+ lock.release()
+
+ self.assertEqual(len(bunch.finished), N)
def test_with(self):
lock = self.locktype()
def f():
lock.acquire()
lock.release()
- def _with(err=None):
+
+ def with_lock(err=None):
with lock:
if err is not None:
raise err
- _with()
- # Check the lock is unacquired
- Bunch(f, 1).wait_for_finished()
- self.assertRaises(TypeError, _with, TypeError)
- # Check the lock is unacquired
- Bunch(f, 1).wait_for_finished()
+
+ # Acquire the lock, do nothing, with releases the lock
+ with lock:
+ pass
+
+ # Check that the lock is unacquired
+ with Bunch(f, 1):
+ pass
+
+ # Acquire the lock, raise an exception, with releases the lock
+ with self.assertRaises(TypeError):
+ with lock:
+ raise TypeError
+
+ # Check that the lock is unacquired even if after an exception
+ # was raised in the previous "with lock:" block
+ with Bunch(f, 1):
+ pass
def test_thread_leak(self):
# The lock shouldn't leak a Thread instance when used from a foreign
@@ -192,7 +219,8 @@ def f():
# We run many threads in the hope that existing threads ids won't
# be recycled.
- Bunch(f, 15).wait_for_finished()
+ with Bunch(f, 15):
+ pass
def test_timeout(self):
lock = self.locktype()
@@ -216,7 +244,8 @@ def f():
results.append(lock.acquire(timeout=0.5))
t2 = time.monotonic()
results.append(t2 - t1)
- Bunch(f, 1).wait_for_finished()
+ with Bunch(f, 1):
+ pass
self.assertFalse(results[0])
self.assertTimeout(results[1], 0.5)
@@ -264,8 +293,8 @@ def test_different_thread(self):
lock.acquire()
def f():
lock.release()
- b = Bunch(f, 1)
- b.wait_for_finished()
+ with Bunch(f, 1):
+ pass
lock.acquire()
lock.release()
@@ -376,12 +405,12 @@ def test_different_thread(self):
lock = self.locktype()
def f():
lock.acquire()
- b = Bunch(f, 1, True)
- try:
- self.assertRaises(RuntimeError, lock.release)
- finally:
- b.do_finish()
- b.wait_for_finished()
+
+ with Bunch(f, 1, True) as bunch:
+ try:
+ self.assertRaises(RuntimeError, lock.release)
+ finally:
+ bunch.do_finish()
def test__is_owned(self):
lock = self.locktype()
@@ -393,7 +422,8 @@ def test__is_owned(self):
result = []
def f():
result.append(lock._is_owned())
- Bunch(f, 1).wait_for_finished()
+ with Bunch(f, 1):
+ pass
self.assertFalse(result[0])
lock.release()
self.assertTrue(lock._is_owned())
@@ -427,15 +457,14 @@ def f():
results1.append(evt.wait())
results2.append(evt.wait())
- # Threads blocked on first evt.wait()
- b = Bunch(f, N)
- b.wait_for_started()
- wait_threads_blocked(N)
- self.assertEqual(len(results1), 0)
+ with Bunch(f, N):
+ # Threads blocked on first evt.wait()
+ wait_threads_blocked(N)
+ self.assertEqual(len(results1), 0)
+
+ # Threads unblocked
+ evt.set()
- # Threads unblocked
- evt.set()
- b.wait_for_finished()
self.assertEqual(results1, [True] * N)
self.assertEqual(results2, [True] * N)
@@ -458,16 +487,22 @@ def f():
r = evt.wait(0.5)
t2 = time.monotonic()
results2.append((r, t2 - t1))
- Bunch(f, N).wait_for_finished()
+
+ with Bunch(f, N):
+ pass
+
self.assertEqual(results1, [False] * N)
for r, dt in results2:
self.assertFalse(r)
self.assertTimeout(dt, 0.5)
+
# The event is set
results1 = []
results2 = []
evt.set()
- Bunch(f, N).wait_for_finished()
+ with Bunch(f, N):
+ pass
+
self.assertEqual(results1, [True] * N)
for r, dt in results2:
self.assertTrue(r)
@@ -480,16 +515,15 @@ def test_set_and_clear(self):
def f():
results.append(event.wait(support.LONG_TIMEOUT))
- # Threads blocked on event.wait()
N = 5
- b = Bunch(f, N)
- b.wait_for_started()
- wait_threads_blocked(N)
-
- # Threads unblocked
- event.set()
- event.clear()
- b.wait_for_finished()
+ with Bunch(f, N):
+ # Threads blocked on event.wait()
+ wait_threads_blocked(N)
+
+ # Threads unblocked
+ event.set()
+ event.clear()
+
self.assertEqual(results, [True] * N)
@requires_fork
@@ -573,73 +607,71 @@ def f():
results2.append((result, phase_num))
N = 5
- b = Bunch(f, N)
- b.wait_for_started()
- # first wait, to ensure all workers settle into cond.wait() before
- # we continue. See issues #8799 and #30727.
- for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
- if len(ready) >= N:
- break
+ with Bunch(f, N):
+ # first wait, to ensure all workers settle into cond.wait() before
+ # we continue. See issues #8799 and #30727.
+ for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
+ if len(ready) >= N:
+ break
- ready.clear()
- self.assertEqual(results1, [])
+ ready.clear()
+ self.assertEqual(results1, [])
- # Notify 3 threads at first
- count1 = 3
- cond.acquire()
- cond.notify(count1)
- wait_threads_blocked(count1)
+ # Notify 3 threads at first
+ count1 = 3
+ cond.acquire()
+ cond.notify(count1)
+ wait_threads_blocked(count1)
- # Phase 1
- phase_num = 1
- cond.release()
- for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
- if len(results1) >= count1:
- break
+ # Phase 1
+ phase_num = 1
+ cond.release()
+ for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
+ if len(results1) >= count1:
+ break
- self.assertEqual(results1, [(True, 1)] * count1)
- self.assertEqual(results2, [])
+ self.assertEqual(results1, [(True, 1)] * count1)
+ self.assertEqual(results2, [])
- # Wait until awaken workers are blocked on cond.wait()
- for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
- if len(ready) >= count1 :
- break
+ # Wait until awaken workers are blocked on cond.wait()
+ for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
+ if len(ready) >= count1 :
+ break
- # Notify 5 threads: they might be in their first or second wait
- cond.acquire()
- cond.notify(5)
- wait_threads_blocked(N)
+ # Notify 5 threads: they might be in their first or second wait
+ cond.acquire()
+ cond.notify(5)
+ wait_threads_blocked(N)
- # Phase 2
- phase_num = 2
- cond.release()
- for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
- if len(results1) + len(results2) >= (N + count1):
- break
+ # Phase 2
+ phase_num = 2
+ cond.release()
+ for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
+ if len(results1) + len(results2) >= (N + count1):
+ break
- count2 = N - count1
- self.assertEqual(results1, [(True, 1)] * count1 + [(True, 2)] * count2)
- self.assertEqual(results2, [(True, 2)] * count1)
+ count2 = N - count1
+ self.assertEqual(results1, [(True, 1)] * count1 + [(True, 2)] * count2)
+ self.assertEqual(results2, [(True, 2)] * count1)
- # Make sure all workers settle into cond.wait()
- for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
- if len(ready) >= N:
- break
+ # Make sure all workers settle into cond.wait()
+ for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
+ if len(ready) >= N:
+ break
- # Notify all threads: they are all in their second wait
- cond.acquire()
- cond.notify_all()
- wait_threads_blocked(N)
+ # Notify all threads: they are all in their second wait
+ cond.acquire()
+ cond.notify_all()
+ wait_threads_blocked(N)
- # Phase 3
- phase_num = 3
- cond.release()
- for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
- if len(results2) >= N:
- break
- self.assertEqual(results1, [(True, 1)] * count1 + [(True, 2)] * count2)
- self.assertEqual(results2, [(True, 2)] * count1 + [(True, 3)] * count2)
- b.wait_for_finished()
+ # Phase 3
+ phase_num = 3
+ cond.release()
+ for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
+ if len(results2) >= N:
+ break
+ self.assertEqual(results1, [(True, 1)] * count1 + [(True, 2)] * count2)
+ self.assertEqual(results2, [(True, 2)] * count1 + [(True, 3)] * count2)
def test_notify(self):
cond = self.condtype()
@@ -660,7 +692,8 @@ def f():
results.append((t2 - t1, result))
N = 5
- Bunch(f, N).wait_for_finished()
+ with Bunch(f, N):
+ pass
self.assertEqual(len(results), N)
for dt, result in results:
@@ -680,14 +713,13 @@ def f():
result = cond.wait_for(lambda: state == 4)
self.assertTrue(result)
self.assertEqual(state, 4)
- b = Bunch(f, 1)
- b.wait_for_started()
- for i in range(4):
- time.sleep(0.010)
- with cond:
- state += 1
- cond.notify()
- b.wait_for_finished()
+
+ with Bunch(f, 1):
+ for i in range(4):
+ time.sleep(0.010)
+ with cond:
+ state += 1
+ cond.notify()
def test_waitfor_timeout(self):
cond = self.condtype()
@@ -702,16 +734,14 @@ def f():
self.assertTimeout(dt, 0.1)
success.append(None)
- b = Bunch(f, 1)
- b.wait_for_started()
- # Only increment 3 times, so state == 4 is never reached.
- for i in range(3):
- time.sleep(0.010)
- with cond:
- state += 1
- cond.notify()
+ with Bunch(f, 1):
+ # Only increment 3 times, so state == 4 is never reached.
+ for i in range(3):
+ time.sleep(0.010)
+ with cond:
+ state += 1
+ cond.notify()
- b.wait_for_finished()
self.assertEqual(len(success), 1)
@@ -761,38 +791,37 @@ def wait_count(count):
if len(results1) + len(results2) >= count:
break
- # Phase 0
N = 10
- b = Bunch(func, N)
- b.wait_for_started()
- count1 = sem_value - 1
- wait_count(count1)
- self.assertEqual(results1 + results2, [0] * count1)
-
- # Phase 1
- phase_num = 1
- for i in range(sem_value):
- sem.release()
- count2 = sem_value
- wait_count(count1 + count2)
- self.assertEqual(sorted(results1 + results2),
- [0] * count1 + [1] * count2)
-
- # Phase 2
- phase_num = 2
- count3 = (sem_value - 1)
- for i in range(count3):
+ with Bunch(func, N):
+ # Phase 0
+ count1 = sem_value - 1
+ wait_count(count1)
+ self.assertEqual(results1 + results2, [0] * count1)
+
+ # Phase 1
+ phase_num = 1
+ for i in range(sem_value):
+ sem.release()
+ count2 = sem_value
+ wait_count(count1 + count2)
+ self.assertEqual(sorted(results1 + results2),
+ [0] * count1 + [1] * count2)
+
+ # Phase 2
+ phase_num = 2
+ count3 = (sem_value - 1)
+ for i in range(count3):
+ sem.release()
+ wait_count(count1 + count2 + count3)
+ self.assertEqual(sorted(results1 + results2),
+ [0] * count1 + [1] * count2 + [2] * count3)
+ # The semaphore is still locked
+ self.assertFalse(sem.acquire(False))
+
+ # Final release, to let the last thread finish
+ count4 = 1
sem.release()
- wait_count(count1 + count2 + count3)
- self.assertEqual(sorted(results1 + results2),
- [0] * count1 + [1] * count2 + [2] * count3)
- # The semaphore is still locked
- self.assertFalse(sem.acquire(False))
- # Final release, to let the last thread finish
- count4 = 1
- sem.release()
- b.wait_for_finished()
self.assertEqual(sem_results,
[True] * (count1 + count2 + count3 + count4))
@@ -816,34 +845,32 @@ def wait_count(count):
if len(results1) + len(results2) >= count:
break
- # Phase 0
- b = Bunch(func, 10)
- b.wait_for_started()
- count1 = sem_value - 1
- wait_count(count1)
- self.assertEqual(results1 + results2, [0] * count1)
-
- # Phase 1
- phase_num = 1
- count2 = sem_value
- sem.release(count2)
- wait_count(count1 + count2)
- self.assertEqual(sorted(results1 + results2),
- [0] * count1 + [1] * count2)
-
- # Phase 2
- phase_num = 2
- count3 = sem_value - 1
- sem.release(count3)
- wait_count(count1 + count2 + count3)
- self.assertEqual(sorted(results1 + results2),
- [0] * count1 + [1] * count2 + [2] * count3)
- # The semaphore is still locked
- self.assertFalse(sem.acquire(False))
-
- # Final release, to let the last thread finish
- sem.release()
- b.wait_for_finished()
+ with Bunch(func, 10):
+ # Phase 0
+ count1 = sem_value - 1
+ wait_count(count1)
+ self.assertEqual(results1 + results2, [0] * count1)
+
+ # Phase 1
+ phase_num = 1
+ count2 = sem_value
+ sem.release(count2)
+ wait_count(count1 + count2)
+ self.assertEqual(sorted(results1 + results2),
+ [0] * count1 + [1] * count2)
+
+ # Phase 2
+ phase_num = 2
+ count3 = sem_value - 1
+ sem.release(count3)
+ wait_count(count1 + count2 + count3)
+ self.assertEqual(sorted(results1 + results2),
+ [0] * count1 + [1] * count2 + [2] * count3)
+ # The semaphore is still locked
+ self.assertFalse(sem.acquire(False))
+
+ # Final release, to let the last thread finish
+ sem.release()
def test_try_acquire(self):
sem = self.semtype(2)
@@ -860,7 +887,8 @@ def test_try_acquire_contended(self):
def f():
results.append(sem.acquire(False))
results.append(sem.acquire(False))
- Bunch(f, 5).wait_for_finished()
+ with Bunch(f, 5):
+ pass
# There can be a thread switch between acquiring the semaphore and
# appending the result, therefore results will not necessarily be
# ordered.
@@ -887,15 +915,13 @@ def f():
sem.acquire()
sem.release()
- # Thread blocked on sem.acquire()
- b = Bunch(f, 1)
- b.wait_for_started()
- wait_threads_blocked(1)
- self.assertFalse(b.finished)
+ with Bunch(f, 1) as bunch:
+ # Thread blocked on sem.acquire()
+ wait_threads_blocked(1)
+ self.assertFalse(bunch.finished)
- # Thread unblocked
- sem.release()
- b.wait_for_finished()
+ # Thread unblocked
+ sem.release()
def test_with(self):
sem = self.semtype(2)
@@ -971,9 +997,8 @@ def tearDown(self):
self.barrier.abort()
def run_threads(self, f):
- b = Bunch(f, self.N-1)
- f()
- b.wait_for_finished()
+ with Bunch(f, self.N):
+ pass
def multipass(self, results, n):
m = self.barrier.parties
@@ -1126,27 +1151,27 @@ def f():
i = self.barrier.wait()
if i == self.N // 2:
# One thread is late!
- time.sleep(1.0)
+ time.sleep(self.defaultTimeout / 2)
# Default timeout is 2.0, so this is shorter.
self.assertRaises(threading.BrokenBarrierError,
- self.barrier.wait, 0.5)
+ self.barrier.wait, self.defaultTimeout / 4)
self.run_threads(f)
def test_default_timeout(self):
"""
Test the barrier's default timeout
"""
- # gh-109401: Barrier timeout should be long enough
- # to create 4 threads on a slow CI.
- timeout = 1.0
- barrier = self.barriertype(self.N, timeout=timeout)
+ timeout = 0.100
+ barrier = self.barriertype(2, timeout=timeout)
def f():
- i = barrier.wait()
- if i == self.N // 2:
- # One thread is later than the default timeout.
- time.sleep(timeout * 2)
- self.assertRaises(threading.BrokenBarrierError, barrier.wait)
- self.run_threads(f)
+ self.assertRaises(threading.BrokenBarrierError,
+ barrier.wait)
+
+ start_time = time.monotonic()
+ with Bunch(f, 1):
+ pass
+ dt = time.monotonic() - start_time
+ self.assertGreaterEqual(dt, timeout)
def test_single_thread(self):
b = self.barriertype(1)
@@ -1160,19 +1185,18 @@ def test_repr(self):
def f():
barrier.wait(timeout)
- # Threads blocked on barrier.wait()
N = 2
- bunch = Bunch(f, N)
- bunch.wait_for_started()
- for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
- if barrier.n_waiting >= N:
- break
- self.assertRegex(repr(barrier),
- r"<\w+\.Barrier at .*: waiters=2/3>")
+ with Bunch(f, N):
+ # Threads blocked on barrier.wait()
+ for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
+ if barrier.n_waiting >= N:
+ break
+ self.assertRegex(repr(barrier),
+ r"<\w+\.Barrier at .*: waiters=2/3>")
+
+ # Threads unblocked
+ barrier.wait(timeout)
- # Threads unblocked
- barrier.wait(timeout)
- bunch.wait_for_finished()
self.assertRegex(repr(barrier),
r"<\w+\.Barrier at .*: waiters=0/3>")
diff --git a/Lib/test/test_importlib/test_locks.py b/Lib/test/test_importlib/test_locks.py
index 7091c36aaaf76..befac5d62b0ab 100644
--- a/Lib/test/test_importlib/test_locks.py
+++ b/Lib/test/test_importlib/test_locks.py
@@ -93,7 +93,8 @@ def f():
b.release()
if ra:
a.release()
- lock_tests.Bunch(f, NTHREADS).wait_for_finished()
+ with lock_tests.Bunch(f, NTHREADS):
+ pass
self.assertEqual(len(results), NTHREADS)
return results
1
0
gh-105323: Update readline module to detect apple editline variant (gh-108665)
by corona10 Sept. 29, 2023
by corona10 Sept. 29, 2023
Sept. 29, 2023
https://github.com/python/cpython/commit/501939c9c1433c5b95ca19ae752e588114…
commit: 501939c9c1433c5b95ca19ae752e5881149f61b9
branch: main
author: Donghee Na <donghee.na(a)python.org>
committer: corona10 <donghee.na92(a)gmail.com>
date: 2023-09-29T21:18:18+09:00
summary:
gh-105323: Update readline module to detect apple editline variant (gh-108665)
files:
M Doc/using/configure.rst
M Modules/readline.c
M configure
M configure.ac
M pyconfig.h.in
diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst
index 9403c19a69577..83b4c7aa0481e 100644
--- a/Doc/using/configure.rst
+++ b/Doc/using/configure.rst
@@ -758,11 +758,12 @@ Libraries options
.. versionadded:: 3.3
-.. cmdoption:: --with-readline=editline
+.. cmdoption:: --with-readline=readline|editline
- Use ``editline`` library for backend of the :mod:`readline` module.
+ Designate a backend library for the :mod:`readline` module.
- Define the ``WITH_EDITLINE`` macro.
+ * readline: Use readline as the backend.
+ * editline: Use editline as the backend.
.. versionadded:: 3.10
diff --git a/Modules/readline.c b/Modules/readline.c
index aeae654162f13..4b473023c6e52 100644
--- a/Modules/readline.c
+++ b/Modules/readline.c
@@ -1018,6 +1018,8 @@ on_hook(PyObject *func)
static int
#if defined(_RL_FUNCTION_TYPEDEF)
on_startup_hook(void)
+#elif defined(WITH_APPLE_EDITLINE)
+on_startup_hook(const char *Py_UNUSED(text), int Py_UNUSED(state))
#else
on_startup_hook(void)
#endif
@@ -1033,6 +1035,8 @@ on_startup_hook(void)
static int
#if defined(_RL_FUNCTION_TYPEDEF)
on_pre_input_hook(void)
+#elif defined(WITH_APPLE_EDITLINE)
+on_pre_input_hook(const char *Py_UNUSED(text), int Py_UNUSED(state))
#else
on_pre_input_hook(void)
#endif
diff --git a/configure b/configure
index 098def9aab08b..0e5f3f64c680b 100755
--- a/configure
+++ b/configure
@@ -23781,6 +23781,7 @@ fi
+
# Check whether --with-readline was given.
if test ${with_readline+y}
then :
@@ -23803,6 +23804,22 @@ else $as_nop
fi
+# gh-105323: Need to handle the macOS editline as an alias of readline.
+case $ac_sys_system/$ac_sys_release in #(
+ Darwin/*) :
+ ac_fn_c_check_type "$LINENO" "Function" "ac_cv_type_Function" "#include <readline/readline.h>
+"
+if test "x$ac_cv_type_Function" = xyes
+then :
+ printf "%s\n" "#define WITH_APPLE_EDITLINE 1" >>confdefs.h
+
+fi
+ ;; #(
+ *) :
+
+ ;;
+esac
+
if test "x$with_readline" = xreadline
then :
diff --git a/configure.ac b/configure.ac
index 3e6cbc69c2100..493868130414e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -5832,6 +5832,7 @@ dnl library (tinfo ncursesw ncurses termcap). We now assume that libreadline
dnl or readline.pc provide correct linker information.
AH_TEMPLATE([WITH_EDITLINE], [Define to build the readline module against libedit.])
+AH_TEMPLATE([WITH_APPLE_EDITLINE], [Define to build the readline module against Apple BSD editline.])
AC_ARG_WITH(
[readline],
@@ -5848,6 +5849,15 @@ AC_ARG_WITH(
[with_readline=readline]
)
+# gh-105323: Need to handle the macOS editline as an alias of readline.
+AS_CASE([$ac_sys_system/$ac_sys_release],
+ [Darwin/*], [AC_CHECK_TYPE([Function],
+ [AC_DEFINE([WITH_APPLE_EDITLINE])],
+ [],
+ [@%:@include <readline/readline.h>])],
+ []
+)
+
AS_VAR_IF([with_readline], [readline], [
PKG_CHECK_MODULES([LIBREADLINE], [readline], [
LIBREADLINE=readline
diff --git a/pyconfig.h.in b/pyconfig.h.in
index 86c72cc6b4e62..c2c75c96dcaad 100644
--- a/pyconfig.h.in
+++ b/pyconfig.h.in
@@ -1788,6 +1788,9 @@
/* Define if WINDOW in curses.h offers a field _flags. */
#undef WINDOW_HAS_FLAGS
+/* Define to build the readline module against Apple BSD editline. */
+#undef WITH_APPLE_EDITLINE
+
/* Define if you want build the _decimal module using a coroutine-local rather
than a thread-local context */
#undef WITH_DECIMAL_CONTEXTVAR
1
0
[3.11] gh-110088, gh-109878: Fix test_asyncio timeouts (#110092) (#110099)
by vstinner Sept. 29, 2023
by vstinner Sept. 29, 2023
Sept. 29, 2023
https://github.com/python/cpython/commit/184ce1414baa7ceb6450d54783ff8e63c9…
commit: 184ce1414baa7ceb6450d54783ff8e63c907a6b0
branch: 3.11
author: Victor Stinner <vstinner(a)python.org>
committer: vstinner <vstinner(a)python.org>
date: 2023-09-29T14:16:15+02:00
summary:
[3.11] gh-110088, gh-109878: Fix test_asyncio timeouts (#110092) (#110099)
gh-110088, gh-109878: Fix test_asyncio timeouts (#110092)
Fix test_asyncio timeouts: don't measure the maximum duration, a test
should not measure a CI performance. Only measure the minimum
duration when a task has a timeout or delay. Add CLOCK_RES to
test_asyncio.utils.
(cherry picked from commit db0a258e796703e12befea9d6dec04e349ca2f5b)
files:
A Misc/NEWS.d/next/Tests/2023-09-29-12-48-42.gh-issue-110088.qUhRga.rst
M Lib/test/test_asyncio/test_base_events.py
M Lib/test/test_asyncio/test_events.py
M Lib/test/test_asyncio/test_timeouts.py
M Lib/test/test_asyncio/test_waitfor.py
M Lib/test/test_asyncio/test_windows_events.py
M Lib/test/test_asyncio/utils.py
diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py
index 6ba602dd619fb..f3f83ad318c95 100644
--- a/Lib/test/test_asyncio/test_base_events.py
+++ b/Lib/test/test_asyncio/test_base_events.py
@@ -273,7 +273,7 @@ def cb():
self.loop.stop()
self.loop._process_events = mock.Mock()
- delay = 0.1
+ delay = 0.100
when = self.loop.time() + delay
self.loop.call_at(when, cb)
@@ -282,10 +282,7 @@ def cb():
dt = self.loop.time() - t0
# 50 ms: maximum granularity of the event loop
- self.assertGreaterEqual(dt, delay - 0.050, dt)
- # tolerate a difference of +800 ms because some Python buildbots
- # are really slow
- self.assertLessEqual(dt, 0.9, dt)
+ self.assertGreaterEqual(dt, delay - test_utils.CLOCK_RES)
with self.assertRaises(TypeError, msg="when cannot be None"):
self.loop.call_at(None, cb)
diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py
index 4e0321a87daec..daf2fb87994a8 100644
--- a/Lib/test/test_asyncio/test_events.py
+++ b/Lib/test/test_asyncio/test_events.py
@@ -294,10 +294,11 @@ async def coro2():
# 15.6 msec, we use fairly long sleep times here (~100 msec).
def test_run_until_complete(self):
+ delay = 0.100
t0 = self.loop.time()
- self.loop.run_until_complete(asyncio.sleep(0.1))
- t1 = self.loop.time()
- self.assertTrue(0.08 <= t1-t0 <= 0.8, t1-t0)
+ self.loop.run_until_complete(asyncio.sleep(delay))
+ dt = self.loop.time() - t0
+ self.assertGreaterEqual(dt, delay - test_utils.CLOCK_RES)
def test_run_until_complete_stopped(self):
@@ -1695,7 +1696,6 @@ def _run_once():
self.loop._run_once = _run_once
async def wait():
- loop = self.loop
await asyncio.sleep(1e-2)
await asyncio.sleep(1e-4)
await asyncio.sleep(1e-6)
diff --git a/Lib/test/test_asyncio/test_timeouts.py b/Lib/test/test_asyncio/test_timeouts.py
index cc8feb8d0c1af..5a4093e94707b 100644
--- a/Lib/test/test_asyncio/test_timeouts.py
+++ b/Lib/test/test_asyncio/test_timeouts.py
@@ -47,7 +47,6 @@ async def test_nested_timeouts(self):
self.assertTrue(cm2.expired())
async def test_waiter_cancelled(self):
- loop = asyncio.get_running_loop()
cancelled = False
with self.assertRaises(TimeoutError):
async with asyncio.timeout(0.01):
@@ -60,39 +59,26 @@ async def test_waiter_cancelled(self):
async def test_timeout_not_called(self):
loop = asyncio.get_running_loop()
- t0 = loop.time()
async with asyncio.timeout(10) as cm:
await asyncio.sleep(0.01)
t1 = loop.time()
self.assertFalse(cm.expired())
- # 2 sec for slow CI boxes
- self.assertLess(t1-t0, 2)
self.assertGreater(cm.when(), t1)
async def test_timeout_disabled(self):
- loop = asyncio.get_running_loop()
- t0 = loop.time()
async with asyncio.timeout(None) as cm:
await asyncio.sleep(0.01)
- t1 = loop.time()
self.assertFalse(cm.expired())
self.assertIsNone(cm.when())
- # 2 sec for slow CI boxes
- self.assertLess(t1-t0, 2)
async def test_timeout_at_disabled(self):
- loop = asyncio.get_running_loop()
- t0 = loop.time()
async with asyncio.timeout_at(None) as cm:
await asyncio.sleep(0.01)
- t1 = loop.time()
self.assertFalse(cm.expired())
self.assertIsNone(cm.when())
- # 2 sec for slow CI boxes
- self.assertLess(t1-t0, 2)
async def test_timeout_zero(self):
loop = asyncio.get_running_loop()
@@ -102,8 +88,6 @@ async def test_timeout_zero(self):
await asyncio.sleep(10)
t1 = loop.time()
self.assertTrue(cm.expired())
- # 2 sec for slow CI boxes
- self.assertLess(t1-t0, 2)
self.assertTrue(t0 <= cm.when() <= t1)
async def test_timeout_zero_sleep_zero(self):
@@ -114,8 +98,6 @@ async def test_timeout_zero_sleep_zero(self):
await asyncio.sleep(0)
t1 = loop.time()
self.assertTrue(cm.expired())
- # 2 sec for slow CI boxes
- self.assertLess(t1-t0, 2)
self.assertTrue(t0 <= cm.when() <= t1)
async def test_timeout_in_the_past_sleep_zero(self):
@@ -126,8 +108,6 @@ async def test_timeout_in_the_past_sleep_zero(self):
await asyncio.sleep(0)
t1 = loop.time()
self.assertTrue(cm.expired())
- # 2 sec for slow CI boxes
- self.assertLess(t1-t0, 2)
self.assertTrue(t0 >= cm.when() <= t1)
async def test_foreign_exception_passed(self):
diff --git a/Lib/test/test_asyncio/test_waitfor.py b/Lib/test/test_asyncio/test_waitfor.py
index 07dbab3b39ca2..c0cc606825b5e 100644
--- a/Lib/test/test_asyncio/test_waitfor.py
+++ b/Lib/test/test_asyncio/test_waitfor.py
@@ -66,17 +66,12 @@ async def test_wait_for_timeout_less_then_0_or_0_future_done(self):
fut = loop.create_future()
fut.set_result('done')
- t0 = loop.time()
ret = await asyncio.wait_for(fut, 0)
- t1 = loop.time()
self.assertEqual(ret, 'done')
self.assertTrue(fut.done())
- self.assertLess(t1 - t0, 0.1)
async def test_wait_for_timeout_less_then_0_or_0_coroutine_do_not_started(self):
- loop = asyncio.get_running_loop()
-
foo_started = False
async def foo():
@@ -84,12 +79,9 @@ async def foo():
foo_started = True
with self.assertRaises(asyncio.TimeoutError):
- t0 = loop.time()
await asyncio.wait_for(foo(), 0)
- t1 = loop.time()
self.assertEqual(foo_started, False)
- self.assertLess(t1 - t0, 0.1)
async def test_wait_for_timeout_less_then_0_or_0(self):
loop = asyncio.get_running_loop()
@@ -113,18 +105,14 @@ async def foo():
await started
with self.assertRaises(asyncio.TimeoutError):
- t0 = loop.time()
await asyncio.wait_for(fut, timeout)
- t1 = loop.time()
self.assertTrue(fut.done())
# it should have been cancelled due to the timeout
self.assertTrue(fut.cancelled())
self.assertEqual(foo_running, False)
- self.assertLess(t1 - t0, 0.1)
async def test_wait_for(self):
- loop = asyncio.get_running_loop()
foo_running = None
async def foo():
@@ -139,13 +127,10 @@ async def foo():
fut = asyncio.create_task(foo())
with self.assertRaises(asyncio.TimeoutError):
- t0 = loop.time()
await asyncio.wait_for(fut, 0.1)
- t1 = loop.time()
self.assertTrue(fut.done())
# it should have been cancelled due to the timeout
self.assertTrue(fut.cancelled())
- self.assertLess(t1 - t0, support.SHORT_TIMEOUT)
self.assertEqual(foo_running, False)
async def test_wait_for_blocking(self):
diff --git a/Lib/test/test_asyncio/test_windows_events.py b/Lib/test/test_asyncio/test_windows_events.py
index a36119a8004f9..6e6c90a247b29 100644
--- a/Lib/test/test_asyncio/test_windows_events.py
+++ b/Lib/test/test_asyncio/test_windows_events.py
@@ -163,29 +163,25 @@ def test_wait_for_handle(self):
# Wait for unset event with 0.5s timeout;
# result should be False at timeout
- fut = self.loop._proactor.wait_for_handle(event, 0.5)
+ timeout = 0.5
+ fut = self.loop._proactor.wait_for_handle(event, timeout)
start = self.loop.time()
done = self.loop.run_until_complete(fut)
elapsed = self.loop.time() - start
self.assertEqual(done, False)
self.assertFalse(fut.result())
- # bpo-31008: Tolerate only 450 ms (at least 500 ms expected),
- # because of bad clock resolution on Windows
- self.assertTrue(0.45 <= elapsed <= 0.9, elapsed)
+ self.assertGreaterEqual(elapsed, timeout - test_utils.CLOCK_RES)
_overlapped.SetEvent(event)
# Wait for set event;
# result should be True immediately
fut = self.loop._proactor.wait_for_handle(event, 10)
- start = self.loop.time()
done = self.loop.run_until_complete(fut)
- elapsed = self.loop.time() - start
self.assertEqual(done, True)
self.assertTrue(fut.result())
- self.assertTrue(0 <= elapsed < 0.3, elapsed)
# asyncio issue #195: cancelling a done _WaitHandleFuture
# must not crash
@@ -199,11 +195,8 @@ def test_wait_for_handle_cancel(self):
# CancelledError should be raised immediately
fut = self.loop._proactor.wait_for_handle(event, 10)
fut.cancel()
- start = self.loop.time()
with self.assertRaises(asyncio.CancelledError):
self.loop.run_until_complete(fut)
- elapsed = self.loop.time() - start
- self.assertTrue(0 <= elapsed < 0.1, elapsed)
# asyncio issue #195: cancelling a _WaitHandleFuture twice
# must not crash
diff --git a/Lib/test/test_asyncio/utils.py b/Lib/test/test_asyncio/utils.py
index c32494d40ccea..19de8540fdb54 100644
--- a/Lib/test/test_asyncio/utils.py
+++ b/Lib/test/test_asyncio/utils.py
@@ -37,6 +37,12 @@
from test.support import threading_helper
+# Use the maximum known clock resolution (gh-75191, gh-110088): Windows
+# GetTickCount64() has a resolution of 15.6 ms. Use 20 ms to tolerate rounding
+# issues.
+CLOCK_RES = 0.020
+
+
def data_file(filename):
if hasattr(support, 'TEST_HOME_DIR'):
fullname = os.path.join(support.TEST_HOME_DIR, filename)
diff --git a/Misc/NEWS.d/next/Tests/2023-09-29-12-48-42.gh-issue-110088.qUhRga.rst b/Misc/NEWS.d/next/Tests/2023-09-29-12-48-42.gh-issue-110088.qUhRga.rst
new file mode 100644
index 0000000000000..cf44a123c2c92
--- /dev/null
+++ b/Misc/NEWS.d/next/Tests/2023-09-29-12-48-42.gh-issue-110088.qUhRga.rst
@@ -0,0 +1,4 @@
+Fix test_asyncio timeouts: don't measure the maximum duration, a test should
+not measure a CI performance. Only measure the minimum duration when a task has
+a timeout or delay. Add ``CLOCK_RES`` to ``test_asyncio.utils``. Patch by
+Victor Stinner.
1
0
https://github.com/python/cpython/commit/db0a258e796703e12befea9d6dec04e349…
commit: db0a258e796703e12befea9d6dec04e349ca2f5b
branch: main
author: Victor Stinner <vstinner(a)python.org>
committer: vstinner <vstinner(a)python.org>
date: 2023-09-29T11:49:30Z
summary:
gh-110088, gh-109878: Fix test_asyncio timeouts (#110092)
Fix test_asyncio timeouts: don't measure the maximum duration, a test
should not measure a CI performance. Only measure the minimum
duration when a task has a timeout or delay. Add CLOCK_RES to
test_asyncio.utils.
files:
A Misc/NEWS.d/next/Tests/2023-09-29-12-48-42.gh-issue-110088.qUhRga.rst
M Lib/test/test_asyncio/test_base_events.py
M Lib/test/test_asyncio/test_events.py
M Lib/test/test_asyncio/test_timeouts.py
M Lib/test/test_asyncio/test_waitfor.py
M Lib/test/test_asyncio/test_windows_events.py
M Lib/test/test_asyncio/utils.py
diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py
index 3b4026cb73869..abcb6f55c4b04 100644
--- a/Lib/test/test_asyncio/test_base_events.py
+++ b/Lib/test/test_asyncio/test_base_events.py
@@ -273,7 +273,7 @@ def cb():
self.loop.stop()
self.loop._process_events = mock.Mock()
- delay = 0.1
+ delay = 0.100
when = self.loop.time() + delay
self.loop.call_at(when, cb)
@@ -282,10 +282,7 @@ def cb():
dt = self.loop.time() - t0
# 50 ms: maximum granularity of the event loop
- self.assertGreaterEqual(dt, delay - 0.050, dt)
- # tolerate a difference of +800 ms because some Python buildbots
- # are really slow
- self.assertLessEqual(dt, 0.9, dt)
+ self.assertGreaterEqual(dt, delay - test_utils.CLOCK_RES)
with self.assertRaises(TypeError, msg="when cannot be None"):
self.loop.call_at(None, cb)
diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py
index f22cb5e58bba6..3ee6565b2b65a 100644
--- a/Lib/test/test_asyncio/test_events.py
+++ b/Lib/test/test_asyncio/test_events.py
@@ -293,10 +293,11 @@ async def coro2():
# 15.6 msec, we use fairly long sleep times here (~100 msec).
def test_run_until_complete(self):
+ delay = 0.100
t0 = self.loop.time()
- self.loop.run_until_complete(asyncio.sleep(0.1))
- t1 = self.loop.time()
- self.assertTrue(0.08 <= t1-t0 <= 0.8, t1-t0)
+ self.loop.run_until_complete(asyncio.sleep(delay))
+ dt = self.loop.time() - t0
+ self.assertGreaterEqual(dt, delay - test_utils.CLOCK_RES)
def test_run_until_complete_stopped(self):
@@ -1717,7 +1718,6 @@ def _run_once():
self.loop._run_once = _run_once
async def wait():
- loop = self.loop
await asyncio.sleep(1e-2)
await asyncio.sleep(1e-4)
await asyncio.sleep(1e-6)
diff --git a/Lib/test/test_asyncio/test_timeouts.py b/Lib/test/test_asyncio/test_timeouts.py
index 8b6b9a1fea0be..e9b59b953518b 100644
--- a/Lib/test/test_asyncio/test_timeouts.py
+++ b/Lib/test/test_asyncio/test_timeouts.py
@@ -46,7 +46,6 @@ async def test_nested_timeouts(self):
self.assertTrue(cm2.expired())
async def test_waiter_cancelled(self):
- loop = asyncio.get_running_loop()
cancelled = False
with self.assertRaises(TimeoutError):
async with asyncio.timeout(0.01):
@@ -59,39 +58,26 @@ async def test_waiter_cancelled(self):
async def test_timeout_not_called(self):
loop = asyncio.get_running_loop()
- t0 = loop.time()
async with asyncio.timeout(10) as cm:
await asyncio.sleep(0.01)
t1 = loop.time()
self.assertFalse(cm.expired())
- # 2 sec for slow CI boxes
- self.assertLess(t1-t0, 2)
self.assertGreater(cm.when(), t1)
async def test_timeout_disabled(self):
- loop = asyncio.get_running_loop()
- t0 = loop.time()
async with asyncio.timeout(None) as cm:
await asyncio.sleep(0.01)
- t1 = loop.time()
self.assertFalse(cm.expired())
self.assertIsNone(cm.when())
- # 2 sec for slow CI boxes
- self.assertLess(t1-t0, 2)
async def test_timeout_at_disabled(self):
- loop = asyncio.get_running_loop()
- t0 = loop.time()
async with asyncio.timeout_at(None) as cm:
await asyncio.sleep(0.01)
- t1 = loop.time()
self.assertFalse(cm.expired())
self.assertIsNone(cm.when())
- # 2 sec for slow CI boxes
- self.assertLess(t1-t0, 2)
async def test_timeout_zero(self):
loop = asyncio.get_running_loop()
@@ -101,8 +87,6 @@ async def test_timeout_zero(self):
await asyncio.sleep(10)
t1 = loop.time()
self.assertTrue(cm.expired())
- # 2 sec for slow CI boxes
- self.assertLess(t1-t0, 2)
self.assertTrue(t0 <= cm.when() <= t1)
async def test_timeout_zero_sleep_zero(self):
@@ -113,8 +97,6 @@ async def test_timeout_zero_sleep_zero(self):
await asyncio.sleep(0)
t1 = loop.time()
self.assertTrue(cm.expired())
- # 2 sec for slow CI boxes
- self.assertLess(t1-t0, 2)
self.assertTrue(t0 <= cm.when() <= t1)
async def test_timeout_in_the_past_sleep_zero(self):
@@ -125,8 +107,6 @@ async def test_timeout_in_the_past_sleep_zero(self):
await asyncio.sleep(0)
t1 = loop.time()
self.assertTrue(cm.expired())
- # 2 sec for slow CI boxes
- self.assertLess(t1-t0, 2)
self.assertTrue(t0 >= cm.when() <= t1)
async def test_foreign_exception_passed(self):
diff --git a/Lib/test/test_asyncio/test_waitfor.py b/Lib/test/test_asyncio/test_waitfor.py
index e714b154c5cad..d52f32534a0cf 100644
--- a/Lib/test/test_asyncio/test_waitfor.py
+++ b/Lib/test/test_asyncio/test_waitfor.py
@@ -66,17 +66,12 @@ async def test_wait_for_timeout_less_then_0_or_0_future_done(self):
fut = loop.create_future()
fut.set_result('done')
- t0 = loop.time()
ret = await asyncio.wait_for(fut, 0)
- t1 = loop.time()
self.assertEqual(ret, 'done')
self.assertTrue(fut.done())
- self.assertLess(t1 - t0, 0.1)
async def test_wait_for_timeout_less_then_0_or_0_coroutine_do_not_started(self):
- loop = asyncio.get_running_loop()
-
foo_started = False
async def foo():
@@ -84,12 +79,9 @@ async def foo():
foo_started = True
with self.assertRaises(asyncio.TimeoutError):
- t0 = loop.time()
await asyncio.wait_for(foo(), 0)
- t1 = loop.time()
self.assertEqual(foo_started, False)
- self.assertLess(t1 - t0, 0.1)
async def test_wait_for_timeout_less_then_0_or_0(self):
loop = asyncio.get_running_loop()
@@ -113,18 +105,14 @@ async def foo():
await started
with self.assertRaises(asyncio.TimeoutError):
- t0 = loop.time()
await asyncio.wait_for(fut, timeout)
- t1 = loop.time()
self.assertTrue(fut.done())
# it should have been cancelled due to the timeout
self.assertTrue(fut.cancelled())
self.assertEqual(foo_running, False)
- self.assertLess(t1 - t0, 0.1)
async def test_wait_for(self):
- loop = asyncio.get_running_loop()
foo_running = None
async def foo():
@@ -139,13 +127,10 @@ async def foo():
fut = asyncio.create_task(foo())
with self.assertRaises(asyncio.TimeoutError):
- t0 = loop.time()
await asyncio.wait_for(fut, 0.1)
- t1 = loop.time()
self.assertTrue(fut.done())
# it should have been cancelled due to the timeout
self.assertTrue(fut.cancelled())
- self.assertLess(t1 - t0, support.SHORT_TIMEOUT)
self.assertEqual(foo_running, False)
async def test_wait_for_blocking(self):
diff --git a/Lib/test/test_asyncio/test_windows_events.py b/Lib/test/test_asyncio/test_windows_events.py
index a36119a8004f9..6e6c90a247b29 100644
--- a/Lib/test/test_asyncio/test_windows_events.py
+++ b/Lib/test/test_asyncio/test_windows_events.py
@@ -163,29 +163,25 @@ def test_wait_for_handle(self):
# Wait for unset event with 0.5s timeout;
# result should be False at timeout
- fut = self.loop._proactor.wait_for_handle(event, 0.5)
+ timeout = 0.5
+ fut = self.loop._proactor.wait_for_handle(event, timeout)
start = self.loop.time()
done = self.loop.run_until_complete(fut)
elapsed = self.loop.time() - start
self.assertEqual(done, False)
self.assertFalse(fut.result())
- # bpo-31008: Tolerate only 450 ms (at least 500 ms expected),
- # because of bad clock resolution on Windows
- self.assertTrue(0.45 <= elapsed <= 0.9, elapsed)
+ self.assertGreaterEqual(elapsed, timeout - test_utils.CLOCK_RES)
_overlapped.SetEvent(event)
# Wait for set event;
# result should be True immediately
fut = self.loop._proactor.wait_for_handle(event, 10)
- start = self.loop.time()
done = self.loop.run_until_complete(fut)
- elapsed = self.loop.time() - start
self.assertEqual(done, True)
self.assertTrue(fut.result())
- self.assertTrue(0 <= elapsed < 0.3, elapsed)
# asyncio issue #195: cancelling a done _WaitHandleFuture
# must not crash
@@ -199,11 +195,8 @@ def test_wait_for_handle_cancel(self):
# CancelledError should be raised immediately
fut = self.loop._proactor.wait_for_handle(event, 10)
fut.cancel()
- start = self.loop.time()
with self.assertRaises(asyncio.CancelledError):
self.loop.run_until_complete(fut)
- elapsed = self.loop.time() - start
- self.assertTrue(0 <= elapsed < 0.1, elapsed)
# asyncio issue #195: cancelling a _WaitHandleFuture twice
# must not crash
diff --git a/Lib/test/test_asyncio/utils.py b/Lib/test/test_asyncio/utils.py
index 1e5ab6eb935ef..e1101bf42eb24 100644
--- a/Lib/test/test_asyncio/utils.py
+++ b/Lib/test/test_asyncio/utils.py
@@ -36,6 +36,12 @@
from test.support import threading_helper
+# Use the maximum known clock resolution (gh-75191, gh-110088): Windows
+# GetTickCount64() has a resolution of 15.6 ms. Use 20 ms to tolerate rounding
+# issues.
+CLOCK_RES = 0.020
+
+
def data_file(*filename):
fullname = os.path.join(support.TEST_HOME_DIR, *filename)
if os.path.isfile(fullname):
diff --git a/Misc/NEWS.d/next/Tests/2023-09-29-12-48-42.gh-issue-110088.qUhRga.rst b/Misc/NEWS.d/next/Tests/2023-09-29-12-48-42.gh-issue-110088.qUhRga.rst
new file mode 100644
index 0000000000000..cf44a123c2c92
--- /dev/null
+++ b/Misc/NEWS.d/next/Tests/2023-09-29-12-48-42.gh-issue-110088.qUhRga.rst
@@ -0,0 +1,4 @@
+Fix test_asyncio timeouts: don't measure the maximum duration, a test should
+not measure a CI performance. Only measure the minimum duration when a task has
+a timeout or delay. Add ``CLOCK_RES`` to ``test_asyncio.utils``. Patch by
+Victor Stinner.
1
0
https://github.com/python/cpython/commit/e27adc68ccee8345e05b7516e6b46f6c7f…
commit: e27adc68ccee8345e05b7516e6b46f6c7ff53371
branch: main
author: Jacob Coffee <jacob(a)z7x.org>
committer: serhiy-storchaka <storchaka(a)gmail.com>
date: 2023-09-29T14:21:34+03:00
summary:
gh-109634: Fix `:samp:` syntax (GH-110073)
files:
M Doc/library/codecs.rst
M Doc/reference/lexical_analysis.rst
M Misc/NEWS.d/3.8.0a1.rst
diff --git a/Doc/library/codecs.rst b/Doc/library/codecs.rst
index 053bf64addb82..2db4a67d1973d 100644
--- a/Doc/library/codecs.rst
+++ b/Doc/library/codecs.rst
@@ -1350,7 +1350,7 @@ encodings.
+--------------------+---------+---------------------------+
| raw_unicode_escape | | Latin-1 encoding with |
| | | :samp:`\\u{XXXX}` and |
-| | | :samp:`\\U{XXXXXXXX}`` |
+| | | :samp:`\\U{XXXXXXXX}` |
| | | for other code points. |
| | | Existing |
| | | backslashes are not |
diff --git a/Doc/reference/lexical_analysis.rst b/Doc/reference/lexical_analysis.rst
index 9fd80b1cb7f84..e54e0ebb7fae9 100644
--- a/Doc/reference/lexical_analysis.rst
+++ b/Doc/reference/lexical_analysis.rst
@@ -582,7 +582,7 @@ Standard C. The recognized escape sequences are:
+-------------------------+---------------------------------+-------+
| ``\v`` | ASCII Vertical Tab (VT) | |
+-------------------------+---------------------------------+-------+
-| :samp:`\\{ooo}` | Character with octal value | (2,4) |
+| :samp:`\\\\{ooo}` | Character with octal value | (2,4) |
| | *ooo* | |
+-------------------------+---------------------------------+-------+
| :samp:`\\x{hh}` | Character with hex value *hh* | (3,4) |
diff --git a/Misc/NEWS.d/3.8.0a1.rst b/Misc/NEWS.d/3.8.0a1.rst
index 57f72e95b029f..3cbbbf7465032 100644
--- a/Misc/NEWS.d/3.8.0a1.rst
+++ b/Misc/NEWS.d/3.8.0a1.rst
@@ -8253,7 +8253,7 @@ Explain how IDLE's Shell displays output.
Improve the doc about IDLE running user code. The section is renamed from
"IDLE -- console differences" is renamed "Running user code". It mostly
-covers the implications of using custom :samp:sys.std{xxx}` objects.
+covers the implications of using custom :samp:`sys.std{xxx}` objects.
..
1
0
gh-108716: make regen-global-objects no longer builds deepfreeze.c (#110078)
by vstinner Sept. 29, 2023
by vstinner Sept. 29, 2023
Sept. 29, 2023
https://github.com/python/cpython/commit/e260087a8e7f1a564f9b797af6291f99e2…
commit: e260087a8e7f1a564f9b797af6291f99e225a73c
branch: main
author: Victor Stinner <vstinner(a)python.org>
committer: vstinner <vstinner(a)python.org>
date: 2023-09-29T10:17:49Z
summary:
gh-108716: make regen-global-objects no longer builds deepfreeze.c (#110078)
Remove more references to now unused Python/deepfreeze/deepfreeze.c.
files:
M .github/workflows/build.yml
M Makefile.pre.in
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index a60632dc56523..ffcfbac290b72 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -140,9 +140,6 @@ jobs:
run: make regen-configure
- name: Build CPython
run: |
- # Deepfreeze will usually cause global objects to be added or removed,
- # so we run it before regen-global-objects gets rum (in regen-all).
- make regen-deepfreeze
make -j4 regen-all
make regen-stdlib-module-names
- name: Check for changes
diff --git a/Makefile.pre.in b/Makefile.pre.in
index f7b52bdab316f..d62b4d24b3e18 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -492,9 +492,6 @@ OBJECT_OBJS= \
Objects/weakrefobject.o \
@PERF_TRAMPOLINE_OBJ@
-DEEPFREEZE_C = Python/deepfreeze/deepfreeze.c
-DEEPFREEZE_OBJS = Python/deepfreeze/deepfreeze.o
-
##########################################################################
# objects that get linked into the Python library
LIBRARY_OBJS_OMIT_FROZEN= \
@@ -1252,9 +1249,7 @@ regen-frozen: Tools/build/freeze_modules.py $(FROZEN_FILES_IN)
############################################################################
# Deepfreeze targets
-.PHONY: regen-deepfreeze
-regen-deepfreeze: $(DEEPFREEZE_C)
-
+DEEPFREEZE_C = Python/deepfreeze/deepfreeze.c
DEEPFREEZE_DEPS=$(srcdir)/Tools/build/deepfreeze.py Include/internal/pycore_global_strings.h $(FREEZE_MODULE_DEPS) $(FROZEN_FILES_OUT)
# BEGIN: deepfreeze modules
@@ -1294,10 +1289,9 @@ regen-importlib: regen-frozen
# Global objects
# Dependencies which can add and/or remove _Py_ID() identifiers:
-# - deepfreeze.c
# - "make clinic"
.PHONY: regen-global-objects
-regen-global-objects: $(srcdir)/Tools/build/generate_global_objects.py $(DEEPFREEZE_C) clinic
+regen-global-objects: $(srcdir)/Tools/build/generate_global_objects.py clinic
$(PYTHON_FOR_REGEN) $(srcdir)/Tools/build/generate_global_objects.py
############################################################################
1
0
[3.11] gh-102304: Add links to the Stable ABI and Limited C API docs (#105345) (#105371) (#109901)
by erlend-aasland Sept. 29, 2023
by erlend-aasland Sept. 29, 2023
Sept. 29, 2023
https://github.com/python/cpython/commit/d81bcc232765613b2e48a2b29d238bff87…
commit: d81bcc232765613b2e48a2b29d238bff8723a794
branch: 3.11
author: Adam Turner <9087854+AA-Turner(a)users.noreply.github.com>
committer: erlend-aasland <erlend.aasland(a)protonmail.com>
date: 2023-09-29T11:17:44+02:00
summary:
[3.11] gh-102304: Add links to the Stable ABI and Limited C API docs (#105345) (#105371) (#109901)
* Add "limited-c-api" and "stable-api" targets
* Rename the "stable-abi-list" target to "limited-api-list"
files:
M Doc/c-api/exceptions.rst
M Doc/c-api/stable.rst
M Doc/c-api/structures.rst
M Doc/c-api/type.rst
M Doc/c-api/typeobj.rst
M Doc/c-api/unicode.rst
M Doc/howto/isolating-extensions.rst
M Doc/whatsnew/3.11.rst
M Misc/NEWS.d/3.11.0a1.rst
M Misc/NEWS.d/3.11.0a2.rst
diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst
index 82050845237bb..320f1e6dbcc4e 100644
--- a/Doc/c-api/exceptions.rst
+++ b/Doc/c-api/exceptions.rst
@@ -806,7 +806,7 @@ because the :ref:`call protocol <call>` takes care of recursion handling.
depth limit.
.. versionchanged:: 3.9
- This function is now also available in the limited API.
+ This function is now also available in the :ref:`limited API <limited-c-api>`.
.. c:function:: void Py_LeaveRecursiveCall(void)
@@ -814,7 +814,7 @@ because the :ref:`call protocol <call>` takes care of recursion handling.
*successful* invocation of :c:func:`Py_EnterRecursiveCall`.
.. versionchanged:: 3.9
- This function is now also available in the limited API.
+ This function is now also available in the :ref:`limited API <limited-c-api>`.
Properly implementing :c:member:`~PyTypeObject.tp_repr` for container types requires
special recursion handling. In addition to protecting the stack,
diff --git a/Doc/c-api/stable.rst b/Doc/c-api/stable.rst
index a697f6cd3edd9..4817da41e3e21 100644
--- a/Doc/c-api/stable.rst
+++ b/Doc/c-api/stable.rst
@@ -25,19 +25,19 @@ are private API that can change without notice even in patch releases.
Stable Application Binary Interface
===================================
+For simplicity, this document talks about *extensions*, but the Limited API
+and Stable ABI work the same way for all uses of the API – for example,
+embedding Python.
+
+.. _limited-c-api:
+
+Limited C API
+-------------
+
Python 3.2 introduced the *Limited API*, a subset of Python's C API.
Extensions that only use the Limited API can be
compiled once and work with multiple versions of Python.
-Contents of the Limited API are :ref:`listed below <stable-abi-list>`.
-
-To enable this, Python provides a *Stable ABI*: a set of symbols that will
-remain compatible across Python 3.x versions. The Stable ABI contains symbols
-exposed in the Limited API, but also other ones – for example, functions
-necessary to support older versions of the Limited API.
-
-(For simplicity, this document talks about *extensions*, but the Limited API
-and Stable ABI work the same way for all uses of the API – for example,
-embedding Python.)
+Contents of the Limited API are :ref:`listed below <limited-api-list>`.
.. c:macro:: Py_LIMITED_API
@@ -57,6 +57,19 @@ embedding Python.)
You can also define ``Py_LIMITED_API`` to ``3``. This works the same as
``0x03020000`` (Python 3.2, the version that introduced Limited API).
+
+.. _stable-abi:
+
+Stable ABI
+----------
+
+To enable this, Python provides a *Stable ABI*: a set of symbols that will
+remain compatible across Python 3.x versions.
+
+The Stable ABI contains symbols exposed in the :ref:`Limited API
+<limited-c-api>`, but also other ones – for example, functions necessary to
+support older versions of the Limited API.
+
On Windows, extensions that use the Stable ABI should be linked against
``python3.dll`` rather than a version-specific library such as
``python39.dll``.
@@ -101,9 +114,9 @@ Limited API Caveats
-------------------
Note that compiling with ``Py_LIMITED_API`` is *not* a complete guarantee that
-code conforms to the Limited API or the Stable ABI. ``Py_LIMITED_API`` only
-covers definitions, but an API also includes other issues, such as expected
-semantics.
+code conforms to the :ref:`Limited API <limited-c-api>` or the :ref:`Stable ABI
+<stable-abi>`. ``Py_LIMITED_API`` only covers definitions, but an API also
+includes other issues, such as expected semantics.
One issue that ``Py_LIMITED_API`` does not guard against is calling a function
with arguments that are invalid in a lower Python version.
@@ -136,9 +149,9 @@ Platform Considerations
=======================
ABI stability depends not only on Python, but also on the compiler used,
-lower-level libraries and compiler options. For the purposes of the Stable ABI,
-these details define a “platform”. They usually depend on the OS
-type and processor architecture
+lower-level libraries and compiler options. For the purposes of
+the :ref:`Stable ABI <stable-abi>`, these details define a “platform”. They
+usually depend on the OS type and processor architecture
It is the responsibility of each particular distributor of Python
to ensure that all Python versions on a particular platform are built
@@ -147,12 +160,12 @@ This is the case with Windows and macOS releases from ``python.org`` and many
third-party distributors.
-.. _stable-abi-list:
+.. _limited-api-list:
Contents of Limited API
=======================
-Currently, the Limited API includes the following items:
+Currently, the :ref:`Limited API <limited-c-api>` includes the following items:
.. limited-api-list::
diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst
index c2903b9ec3285..304cc31575b1d 100644
--- a/Doc/c-api/structures.rst
+++ b/Doc/c-api/structures.rst
@@ -318,7 +318,7 @@ There are these calling conventions:
.. versionchanged:: 3.10
- ``METH_FASTCALL`` is now part of the stable ABI.
+ ``METH_FASTCALL`` is now part of the :ref:`stable ABI <stable-abi>`.
.. _METH_FASTCALL-METH_KEYWORDS:
diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst
index 01d7fc4dc1ecf..a7ca19677134d 100644
--- a/Doc/c-api/type.rst
+++ b/Doc/c-api/type.rst
@@ -42,7 +42,7 @@ Type Objects
Return the :c:member:`~PyTypeObject.tp_flags` member of *type*. This function is primarily
meant for use with ``Py_LIMITED_API``; the individual flag bits are
guaranteed to be stable across Python releases, but access to
- :c:member:`~PyTypeObject.tp_flags` itself is not part of the limited API.
+ :c:member:`~PyTypeObject.tp_flags` itself is not part of the :ref:`limited API <limited-c-api>`.
.. versionadded:: 3.2
@@ -301,7 +301,7 @@ The following functions and structs are used to create
.. versionchanged:: 3.11
:c:member:`~PyBufferProcs.bf_getbuffer` and
:c:member:`~PyBufferProcs.bf_releasebuffer` are now available
- under the limited API.
+ under the :ref:`limited API <limited-c-api>`.
.. c:member:: void *PyType_Slot.pfunc
diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst
index 62711802a783a..8b662ceac84e7 100644
--- a/Doc/c-api/typeobj.rst
+++ b/Doc/c-api/typeobj.rst
@@ -2082,7 +2082,7 @@ This results in types that are limited relative to types defined in Python:
include any subinterpreter-specific state.
Also, since :c:type:`PyTypeObject` is only part of the :ref:`Limited API
-<stable>` as an opaque struct, any extension modules using static types must be
+<limited-c-api>` as an opaque struct, any extension modules using static types must be
compiled for a specific Python minor version.
diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst
index 146511b9e3658..686252d808653 100644
--- a/Doc/c-api/unicode.rst
+++ b/Doc/c-api/unicode.rst
@@ -1084,7 +1084,7 @@ These are the UTF-8 codec APIs:
The return type is now ``const char *`` rather of ``char *``.
.. versionchanged:: 3.10
- This function is a part of the :ref:`limited API <stable>`.
+ This function is a part of the :ref:`limited API <limited-c-api>`.
.. c:function:: const char* PyUnicode_AsUTF8(PyObject *unicode)
diff --git a/Doc/howto/isolating-extensions.rst b/Doc/howto/isolating-extensions.rst
index 0362fa6c68544..732fd6f993b72 100644
--- a/Doc/howto/isolating-extensions.rst
+++ b/Doc/howto/isolating-extensions.rst
@@ -461,7 +461,7 @@ Module State Access from Slot Methods, Getters and Setters
.. After adding to limited API:
- If you use the :ref:`limited API <stable>,
+ If you use the :ref:`limited API <limited-c-api>`,
you must update ``Py_LIMITED_API`` to ``0x030b0000``, losing ABI
compatibility with earlier versions.
diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst
index c93541d18582d..fda4fbcb122dc 100644
--- a/Doc/whatsnew/3.11.rst
+++ b/Doc/whatsnew/3.11.rst
@@ -2654,7 +2654,7 @@ Removed
* :c:func:`PyMarshal_WriteObjectToString`
* the ``Py_MARSHAL_VERSION`` macro
- These are not part of the :ref:`limited API <stable-abi-list>`.
+ These are not part of the :ref:`limited API <limited-api-list>`.
(Contributed by Victor Stinner in :issue:`45474`.)
diff --git a/Misc/NEWS.d/3.11.0a1.rst b/Misc/NEWS.d/3.11.0a1.rst
index fe21d9b5e6609..46c65300abf2c 100644
--- a/Misc/NEWS.d/3.11.0a1.rst
+++ b/Misc/NEWS.d/3.11.0a1.rst
@@ -4980,7 +4980,7 @@ Removed documentation for the removed ``PyParser_*`` C API.
.. nonce: fy0AXK
.. section: C API
-The list in :ref:`stable-abi-list` now shows the public name
+The list in :ref:`limited-api-list` now shows the public name
:c:struct:`PyFrameObject` rather than ``_frame``. The non-existing entry
``_node`` no longer appears in the list.
diff --git a/Misc/NEWS.d/3.11.0a2.rst b/Misc/NEWS.d/3.11.0a2.rst
index d4ae7dc30b04b..3f9a66298faa1 100644
--- a/Misc/NEWS.d/3.11.0a2.rst
+++ b/Misc/NEWS.d/3.11.0a2.rst
@@ -1234,7 +1234,7 @@ defined:
* :c:func:`PyMarshal_WriteObjectToString`
* the ``Py_MARSHAL_VERSION`` macro
-These are not part of the :ref:`limited API <stable-abi-list>`.
+These are not part of the :ref:`limited API <limited-api-list>`.
Patch by Victor Stinner.
1
0
https://github.com/python/cpython/commit/8b626a47bafdb2d1ebb1321e50ffa5d6c7…
commit: 8b626a47bafdb2d1ebb1321e50ffa5d6c721bf3a
branch: main
author: Victor Stinner <vstinner(a)python.org>
committer: vstinner <vstinner(a)python.org>
date: 2023-09-29T10:56:49+02:00
summary:
gh-110079: Remove extern "C" { ...} in C code (#110080)
files:
M Modules/_scproxy.c
M Modules/_stat.c
M Modules/main.c
M Modules/posixmodule.c
M Objects/fileobject.c
M Objects/object.c
M Objects/unicodeobject.c
M Python/dtoa.c
M Python/errors.c
M Python/getargs.c
M Python/getopt.c
M Python/import.c
M Python/pathconfig.c
M Python/pyhash.c
M Python/pylifecycle.c
M Python/pystate.c
M Python/pythonrun.c
M Python/sysmodule.c
diff --git a/Modules/_scproxy.c b/Modules/_scproxy.c
index 0df0324df55f7..6cc09088bdc86 100644
--- a/Modules/_scproxy.c
+++ b/Modules/_scproxy.c
@@ -249,16 +249,8 @@ static struct PyModuleDef _scproxy_module = {
.m_slots = _scproxy_slots,
};
-#ifdef __cplusplus
-extern "C" {
-#endif
-
PyMODINIT_FUNC
PyInit__scproxy(void)
{
return PyModuleDef_Init(&_scproxy_module);
}
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/Modules/_stat.c b/Modules/_stat.c
index 6cea26175dee5..3fd951b6fc102 100644
--- a/Modules/_stat.c
+++ b/Modules/_stat.c
@@ -13,10 +13,6 @@
#include "Python.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif /* HAVE_SYS_TYPES_H */
@@ -631,7 +627,3 @@ PyInit__stat(void)
{
return PyModuleDef_Init(&statmodule);
}
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/Modules/main.c b/Modules/main.c
index 7f88c97207475..05bedff050699 100644
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -26,10 +26,6 @@
"Type \"help\", \"copyright\", \"credits\" or \"license\" " \
"for more information."
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/* --- pymain_init() ---------------------------------------------- */
static PyStatus
@@ -742,7 +738,3 @@ Py_BytesMain(int argc, char **argv)
.wchar_argv = NULL};
return pymain_main(&args);
}
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index abf449e25493f..d7d3e365d2c55 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -222,10 +222,6 @@
#endif
-#ifdef __cplusplus
-extern "C" {
-#endif
-
PyDoc_STRVAR(posix__doc__,
"This module provides access to operating system functionality that is\n\
standardized by the C Standard and the POSIX standard (a thinly\n\
@@ -17002,7 +16998,3 @@ INITFUNC(void)
{
return PyModuleDef_Init(&posixmodule);
}
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/Objects/fileobject.c b/Objects/fileobject.c
index 0cf2b47c3b3ae..066172baf9f02 100644
--- a/Objects/fileobject.c
+++ b/Objects/fileobject.c
@@ -21,10 +21,6 @@
#define NEWLINE_LF 2 /* \n newline seen */
#define NEWLINE_CRLF 4 /* \r\n newline seen */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/* External C interface */
PyObject *
@@ -539,8 +535,3 @@ _PyFile_Flush(PyObject *file)
Py_DECREF(tmp);
return 0;
}
-
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/Objects/object.c b/Objects/object.c
index 15c2bf65de6ac..3ed272afdced7 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -28,10 +28,6 @@
# error "Py_LIMITED_API macro must not be defined"
#endif
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/* Defined in tracemalloc.c */
extern void _PyMem_DumpTraceback(int fd, const void *ptr);
@@ -2808,7 +2804,3 @@ int Py_IsFalse(PyObject *x)
{
return Py_Is(x, Py_False);
}
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index aca28e4842d64..49981a1f881c2 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -100,11 +100,6 @@ NOTE: In the interpreter's initialization phase, some globals are currently
*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
// Maximum code point of Unicode 6.0: 0x10ffff (1,114,111).
// The value must be the same in fileutils.c.
#define MAX_UNICODE 0x10ffff
@@ -15397,8 +15392,3 @@ PyInit__string(void)
{
return PyModuleDef_Init(&_string_module);
}
-
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/Python/dtoa.c b/Python/dtoa.c
index c5e343b82f74c..5dfc0e179cbc3 100644
--- a/Python/dtoa.c
+++ b/Python/dtoa.c
@@ -172,10 +172,6 @@ typedef uint64_t ULLong;
#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);}
#endif
-#ifdef __cplusplus
-extern "C" {
-#endif
-
typedef union { double d; ULong L[2]; } U;
#ifdef IEEE_8087
@@ -2813,8 +2809,5 @@ _Py_dg_dtoa(double dd, int mode, int ndigits,
_Py_dg_freedtoa(s0);
return NULL;
}
-#ifdef __cplusplus
-}
-#endif
#endif // _PY_SHORT_FLOAT_REPR == 1
diff --git a/Python/errors.c b/Python/errors.c
index b05b3ef1dda8f..15af39b10dc07 100644
--- a/Python/errors.c
+++ b/Python/errors.c
@@ -16,11 +16,6 @@
# include <stdlib.h> // _sys_nerr
#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/* Forward declarations */
static PyObject *
_PyErr_FormatV(PyThreadState *tstate, PyObject *exception,
@@ -1918,7 +1913,3 @@ PyErr_ProgramTextObject(PyObject *filename, int lineno)
{
return _PyErr_ProgramDecodedTextObject(filename, lineno, NULL);
}
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/Python/getargs.c b/Python/getargs.c
index cbfe561111176..d590e2e153389 100644
--- a/Python/getargs.c
+++ b/Python/getargs.c
@@ -7,10 +7,6 @@
#include "pycore_pylifecycle.h" // _PyArg_Fini
#include "pycore_tuple.h" // _PyTuple_ITEMS()
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/* Export Stable ABIs (abi only) */
PyAPI_FUNC(int) _PyArg_Parse_SizeT(PyObject *, const char *, ...);
PyAPI_FUNC(int) _PyArg_ParseTuple_SizeT(PyObject *, const char *, ...);
@@ -2867,7 +2863,3 @@ _PyArg_Fini(void)
}
_PyRuntime.getargs.static_parsers = NULL;
}
-
-#ifdef __cplusplus
-};
-#endif
diff --git a/Python/getopt.c b/Python/getopt.c
index 4135bf1446ecf..f64c89fa22734 100644
--- a/Python/getopt.c
+++ b/Python/getopt.c
@@ -29,10 +29,6 @@
#include <wchar.h>
#include "pycore_getopt.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
int _PyOS_opterr = 1; /* generate error messages */
Py_ssize_t _PyOS_optind = 1; /* index into argv array */
const wchar_t *_PyOS_optarg = NULL; /* optional argument */
@@ -172,8 +168,3 @@ int _PyOS_GetOpt(Py_ssize_t argc, wchar_t * const *argv, int *longindex)
return option;
}
-
-#ifdef __cplusplus
-}
-#endif
-
diff --git a/Python/import.c b/Python/import.c
index 5a06cb367e828..5636968ed9e63 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -24,9 +24,6 @@
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
-#ifdef __cplusplus
-extern "C" {
-#endif
/*[clinic input]
@@ -3887,8 +3884,3 @@ PyInit__imp(void)
{
return PyModuleDef_Init(&imp_module);
}
-
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/Python/pathconfig.c b/Python/pathconfig.c
index 0ac64ec811025..50c60093cd4e3 100644
--- a/Python/pathconfig.c
+++ b/Python/pathconfig.c
@@ -16,10 +16,6 @@
# include <shlwapi.h>
#endif
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/* External interface */
@@ -500,8 +496,3 @@ _PyPathConfig_ComputeSysPath0(const PyWideStringList *argv, PyObject **path0_p)
*path0_p = path0_obj;
return 1;
}
-
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/Python/pyhash.c b/Python/pyhash.c
index b2bdab5099d86..f9060b8003a0a 100644
--- a/Python/pyhash.c
+++ b/Python/pyhash.c
@@ -14,10 +14,6 @@
# include <sys/endian.h>
#endif
-#ifdef __cplusplus
-extern "C" {
-#endif
-
_Py_HashSecret_t _Py_HashSecret = {{0}};
#if Py_HASH_ALGORITHM == Py_HASH_EXTERNAL
@@ -503,7 +499,3 @@ pysiphash(const void *src, Py_ssize_t src_sz) {
static PyHash_FuncDef PyHash_Func = {pysiphash, "siphash24", 64, 128};
#endif
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index aec8da10249d2..23f66ec3601df 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -61,11 +61,6 @@
#define PUTS(fd, str) (void)_Py_write_noraise(fd, str, (int)strlen(str))
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
/* Forward declarations */
static PyStatus add_main_module(PyInterpreterState *interp);
static PyStatus init_import_site(void);
@@ -3139,7 +3134,3 @@ PyOS_setsig(int sig, PyOS_sighandler_t handler)
return oldhandler;
#endif
}
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/Python/pystate.c b/Python/pystate.c
index 570b5242600c0..01aa2552e56f0 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -29,16 +29,12 @@ to avoid the expense of doing their own locking).
-------------------------------------------------------------------------- */
#ifdef HAVE_DLOPEN
-#ifdef HAVE_DLFCN_H
-#include <dlfcn.h>
-#endif
-#if !HAVE_DECL_RTLD_LAZY
-#define RTLD_LAZY 1
-#endif
-#endif
-
-#ifdef __cplusplus
-extern "C" {
+# ifdef HAVE_DLFCN_H
+# include <dlfcn.h>
+# endif
+# if !HAVE_DECL_RTLD_LAZY
+# define RTLD_LAZY 1
+# endif
#endif
@@ -2985,8 +2981,3 @@ _PyThreadState_MustExit(PyThreadState *tstate)
}
return 1;
}
-
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index 81ab78e95ab68..1b282aa870bfd 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -37,11 +37,6 @@
# include "windows.h"
#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/* Forward */
static void flush_io(void);
static PyObject *run_mod(mod_ty, PyObject *, PyObject *, PyObject *,
@@ -2017,7 +2012,3 @@ PyRun_InteractiveLoop(FILE *f, const char *p)
{
return PyRun_InteractiveLoopFlags(f, p, NULL);
}
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
index 9c1ee0215d7cf..7ba7be10aacb9 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -2039,11 +2039,6 @@ sys_call_tracing_impl(PyObject *module, PyObject *func, PyObject *funcargs)
return _PyEval_CallTracing(func, funcargs);
}
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/*[clinic input]
sys._debugmallocstats
@@ -2072,10 +2067,6 @@ sys__debugmallocstats_impl(PyObject *module)
extern PyObject *_Py_GetObjects(PyObject *, PyObject *);
#endif
-#ifdef __cplusplus
-}
-#endif
-
/*[clinic input]
sys._clear_type_cache
@@ -2297,11 +2288,6 @@ sys__getframemodulename_impl(PyObject *module, int depth)
return Py_NewRef(r);
}
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
static PerfMapState perf_map_state;
PyAPI_FUNC(int) PyUnstable_PerfMapState_Init(void) {
@@ -2370,10 +2356,6 @@ PyAPI_FUNC(void) PyUnstable_PerfMapState_Fini(void) {
#endif
}
-#ifdef __cplusplus
-}
-#endif
-
static PyMethodDef sys_methods[] = {
/* Might as well keep this in alphabetic order */
1
0
[3.11] gh-101100: Fix references to ``URLError`` and ``HTTPError`` in ``howto/urllib2.rst`` (GH-107966) (#110087)
by hugovk Sept. 29, 2023
by hugovk Sept. 29, 2023
Sept. 29, 2023
https://github.com/python/cpython/commit/6024a75b10679bacca9b5a8bb7736c106f…
commit: 6024a75b10679bacca9b5a8bb7736c106f82d508
branch: 3.11
author: Miss Islington (bot) <31488909+miss-islington(a)users.noreply.github.com>
committer: hugovk <hugovk(a)users.noreply.github.com>
date: 2023-09-29T08:44:28Z
summary:
[3.11] gh-101100: Fix references to ``URLError`` and ``HTTPError`` in ``howto/urllib2.rst`` (GH-107966) (#110087)
Co-authored-by: Yuki K <drsuaimqjgar(a)gmail.com>
Co-authored-by: Hugo van Kemenade <hugovk(a)users.noreply.github.com>
files:
M Doc/howto/urllib2.rst
diff --git a/Doc/howto/urllib2.rst b/Doc/howto/urllib2.rst
index 86137fb38c9b9..570435d48866d 100644
--- a/Doc/howto/urllib2.rst
+++ b/Doc/howto/urllib2.rst
@@ -194,11 +194,11 @@ which comes after we have a look at what happens when things go wrong.
Handling Exceptions
===================
-*urlopen* raises :exc:`URLError` when it cannot handle a response (though as
+*urlopen* raises :exc:`~urllib.error.URLError` when it cannot handle a response (though as
usual with Python APIs, built-in exceptions such as :exc:`ValueError`,
:exc:`TypeError` etc. may also be raised).
-:exc:`HTTPError` is the subclass of :exc:`URLError` raised in the specific case of
+:exc:`~urllib.error.HTTPError` is the subclass of :exc:`~urllib.error.URLError` raised in the specific case of
HTTP URLs.
The exception classes are exported from the :mod:`urllib.error` module.
@@ -229,12 +229,12 @@ the status code indicates that the server is unable to fulfil the request. The
default handlers will handle some of these responses for you (for example, if
the response is a "redirection" that requests the client fetch the document from
a different URL, urllib will handle that for you). For those it can't handle,
-urlopen will raise an :exc:`HTTPError`. Typical errors include '404' (page not
+urlopen will raise an :exc:`~urllib.error.HTTPError`. Typical errors include '404' (page not
found), '403' (request forbidden), and '401' (authentication required).
See section 10 of :rfc:`2616` for a reference on all the HTTP error codes.
-The :exc:`HTTPError` instance raised will have an integer 'code' attribute, which
+The :exc:`~urllib.error.HTTPError` instance raised will have an integer 'code' attribute, which
corresponds to the error sent by the server.
Error Codes
@@ -317,7 +317,7 @@ dictionary is reproduced here for convenience ::
}
When an error is raised the server responds by returning an HTTP error code
-*and* an error page. You can use the :exc:`HTTPError` instance as a response on the
+*and* an error page. You can use the :exc:`~urllib.error.HTTPError` instance as a response on the
page returned. This means that as well as the code attribute, it also has read,
geturl, and info, methods as returned by the ``urllib.response`` module::
@@ -338,7 +338,7 @@ geturl, and info, methods as returned by the ``urllib.response`` module::
Wrapping it Up
--------------
-So if you want to be prepared for :exc:`HTTPError` *or* :exc:`URLError` there are two
+So if you want to be prepared for :exc:`~urllib.error.HTTPError` *or* :exc:`~urllib.error.URLError` there are two
basic approaches. I prefer the second approach.
Number 1
@@ -365,7 +365,7 @@ Number 1
.. note::
The ``except HTTPError`` *must* come first, otherwise ``except URLError``
- will *also* catch an :exc:`HTTPError`.
+ will *also* catch an :exc:`~urllib.error.HTTPError`.
Number 2
~~~~~~~~
@@ -391,7 +391,7 @@ Number 2
info and geturl
===============
-The response returned by urlopen (or the :exc:`HTTPError` instance) has two
+The response returned by urlopen (or the :exc:`~urllib.error.HTTPError` instance) has two
useful methods :meth:`info` and :meth:`geturl` and is defined in the module
:mod:`urllib.response`..
1
0
[3.11] gh-101100: Fix Sphinx warnings in `tutorial/controlflow.rst` (GH-109424) (#110085)
by hugovk Sept. 29, 2023
by hugovk Sept. 29, 2023
Sept. 29, 2023
https://github.com/python/cpython/commit/58ac0ed093754c34884b152e05cbf5a009…
commit: 58ac0ed093754c34884b152e05cbf5a009b49576
branch: 3.11
author: Miss Islington (bot) <31488909+miss-islington(a)users.noreply.github.com>
committer: hugovk <hugovk(a)users.noreply.github.com>
date: 2023-09-29T08:36:24Z
summary:
[3.11] gh-101100: Fix Sphinx warnings in `tutorial/controlflow.rst` (GH-109424) (#110085)
Co-authored-by: Maciej Olko <maciej.olko(a)affirm.com>
Co-authored-by: Adam Turner <9087854+AA-Turner(a)users.noreply.github.com>
files:
M Doc/tools/.nitignore
M Doc/tutorial/controlflow.rst
diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore
index 36ea3a95314ff..dace135cb560f 100644
--- a/Doc/tools/.nitignore
+++ b/Doc/tools/.nitignore
@@ -150,7 +150,6 @@ Doc/reference/datamodel.rst
Doc/reference/expressions.rst
Doc/reference/import.rst
Doc/reference/simple_stmts.rst
-Doc/tutorial/controlflow.rst
Doc/tutorial/datastructures.rst
Doc/tutorial/introduction.rst
Doc/using/cmdline.rst
diff --git a/Doc/tutorial/controlflow.rst b/Doc/tutorial/controlflow.rst
index 4bcc3768111cc..aa9caa101da40 100644
--- a/Doc/tutorial/controlflow.rst
+++ b/Doc/tutorial/controlflow.rst
@@ -534,7 +534,7 @@ This example, as usual, demonstrates some new Python features:
Different types define different methods. Methods of different types may have
the same name without causing ambiguity. (It is possible to define your own
object types and methods, using *classes*, see :ref:`tut-classes`)
- The method :meth:`~list.append` shown in the example is defined for list objects; it
+ The method :meth:`!append` shown in the example is defined for list objects; it
adds a new element at the end of the list. In this example it is equivalent to
``result = result + [a]``, but more efficient.
@@ -1046,7 +1046,7 @@ Function Annotations
information about the types used by user-defined functions (see :pep:`3107` and
:pep:`484` for more information).
-:term:`Annotations <function annotation>` are stored in the :attr:`__annotations__`
+:term:`Annotations <function annotation>` are stored in the :attr:`!__annotations__`
attribute of the function as a dictionary and have no effect on any other part of the
function. Parameter annotations are defined by a colon after the parameter name, followed
by an expression evaluating to the value of the annotation. Return annotations are
1
0