https://github.com/python/cpython/commit/96ead91f0f0db59a942b8b34da9cc980c05588a2
commit: 96ead91f0f0db59a942b8b34da9cc980c05588a2
branch: main
author: Kumar Aditya <[email protected]>
committer: kumaraditya303 <[email protected]>
date: 2024-06-23T09:53:23+05:30
summary:
GH-120804: Remove `get_child_watcher` and `set_child_watcher` from asyncio
(#120818)
files:
M Lib/asyncio/events.py
M Lib/asyncio/unix_events.py
M Lib/test/test_asyncio/test_events.py
M Lib/test/test_asyncio/test_subprocess.py
M Lib/test/test_asyncio/test_unix_events.py
M Lib/test/test_asyncio/utils.py
diff --git a/Lib/asyncio/events.py b/Lib/asyncio/events.py
index be495469a0558b..b63fe6aa79604b 100644
--- a/Lib/asyncio/events.py
+++ b/Lib/asyncio/events.py
@@ -10,7 +10,6 @@
'Handle', 'TimerHandle',
'get_event_loop_policy', 'set_event_loop_policy',
'get_event_loop', 'set_event_loop', 'new_event_loop',
- 'get_child_watcher', 'set_child_watcher',
'_set_running_loop', 'get_running_loop',
'_get_running_loop',
)
@@ -652,17 +651,6 @@ def new_event_loop(self):
the current context, set_event_loop must be called explicitly."""
raise NotImplementedError
- # Child processes handling (Unix only).
-
- def get_child_watcher(self):
- "Get the watcher for child processes."
- raise NotImplementedError
-
- def set_child_watcher(self, watcher):
- """Set the watcher for child processes."""
- raise NotImplementedError
-
-
class BaseDefaultEventLoopPolicy(AbstractEventLoopPolicy):
"""Default policy implementation for accessing the event loop.
@@ -837,17 +825,6 @@ def new_event_loop():
return get_event_loop_policy().new_event_loop()
-def get_child_watcher():
- """Equivalent to calling get_event_loop_policy().get_child_watcher()."""
- return get_event_loop_policy().get_child_watcher()
-
-
-def set_child_watcher(watcher):
- """Equivalent to calling
- get_event_loop_policy().set_child_watcher(watcher)."""
- return get_event_loop_policy().set_child_watcher(watcher)
-
-
# Alias pure-Python implementations for testing purposes.
_py__get_running_loop = _get_running_loop
_py__set_running_loop = _set_running_loop
diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py
index 9a2e300259ee8c..ff2df653e41b89 100644
--- a/Lib/asyncio/unix_events.py
+++ b/Lib/asyncio/unix_events.py
@@ -199,7 +199,7 @@ async def _make_subprocess_transport(self, protocol, args,
shell,
extra=None, **kwargs):
with warnings.catch_warnings():
warnings.simplefilter('ignore', DeprecationWarning)
- watcher = events.get_child_watcher()
+ watcher = events.get_event_loop_policy()._watcher
with watcher:
if not watcher.is_active():
@@ -1009,59 +1009,6 @@ def remove_child_handler(self, pid):
return True
-class BaseChildWatcher(AbstractChildWatcher):
-
- def __init__(self):
- self._loop = None
- self._callbacks = {}
-
- def close(self):
- self.attach_loop(None)
-
- def is_active(self):
- return self._loop is not None and self._loop.is_running()
-
- def _do_waitpid(self, expected_pid):
- raise NotImplementedError()
-
- def _do_waitpid_all(self):
- raise NotImplementedError()
-
- def attach_loop(self, loop):
- assert loop is None or isinstance(loop, events.AbstractEventLoop)
-
- if self._loop is not None and loop is None and self._callbacks:
- warnings.warn(
- 'A loop is being detached '
- 'from a child watcher with pending handlers',
- RuntimeWarning)
-
- if self._loop is not None:
- self._loop.remove_signal_handler(signal.SIGCHLD)
-
- self._loop = loop
- if loop is not None:
- loop.add_signal_handler(signal.SIGCHLD, self._sig_chld)
-
- # Prevent a race condition in case a child terminated
- # during the switch.
- self._do_waitpid_all()
-
- def _sig_chld(self):
- try:
- self._do_waitpid_all()
- except (SystemExit, KeyboardInterrupt):
- raise
- except BaseException as exc:
- # self._loop should always be available here
- # as '_sig_chld' is added as a signal handler
- # in 'attach_loop'
- self._loop.call_exception_handler({
- 'message': 'Unknown exception in SIGCHLD handler',
- 'exception': exc,
- })
-
-
class ThreadedChildWatcher(AbstractChildWatcher):
"""Threaded child watcher implementation.
@@ -1161,15 +1108,10 @@ class
_UnixDefaultEventLoopPolicy(events.BaseDefaultEventLoopPolicy):
def __init__(self):
super().__init__()
- self._watcher = None
-
- def _init_watcher(self):
- with events._lock:
- if self._watcher is None: # pragma: no branch
- if can_use_pidfd():
- self._watcher = PidfdChildWatcher()
- else:
- self._watcher = ThreadedChildWatcher()
+ if can_use_pidfd():
+ self._watcher = PidfdChildWatcher()
+ else:
+ self._watcher = ThreadedChildWatcher()
def set_event_loop(self, loop):
"""Set the event loop.
@@ -1185,33 +1127,6 @@ def set_event_loop(self, loop):
threading.current_thread() is threading.main_thread()):
self._watcher.attach_loop(loop)
- def get_child_watcher(self):
- """Get the watcher for child processes.
-
- If not yet set, a ThreadedChildWatcher object is automatically created.
- """
- if self._watcher is None:
- self._init_watcher()
-
- warnings._deprecated("get_child_watcher",
- "{name!r} is deprecated as of Python 3.12 and will
be "
- "removed in Python {remove}.", remove=(3, 14))
- return self._watcher
-
- def set_child_watcher(self, watcher):
- """Set the watcher for child processes."""
-
- assert watcher is None or isinstance(watcher, AbstractChildWatcher)
-
- if self._watcher is not None:
- self._watcher.close()
-
- self._watcher = watcher
- warnings._deprecated("set_child_watcher",
- "{name!r} is deprecated as of Python 3.12 and will
be "
- "removed in Python {remove}.", remove=(3, 14))
-
-
SelectorEventLoop = _UnixSelectorEventLoop
DefaultEventLoopPolicy = _UnixDefaultEventLoopPolicy
EventLoop = SelectorEventLoop
diff --git a/Lib/test/test_asyncio/test_events.py
b/Lib/test/test_asyncio/test_events.py
index 06eb4d3841a0d2..5b660de28d6fa0 100644
--- a/Lib/test/test_asyncio/test_events.py
+++ b/Lib/test/test_asyncio/test_events.py
@@ -2212,16 +2212,14 @@ def test_remove_fds_after_closing(self):
class UnixEventLoopTestsMixin(EventLoopTestsMixin):
def setUp(self):
super().setUp()
- with warnings.catch_warnings():
- warnings.simplefilter('ignore', DeprecationWarning)
- watcher = asyncio.ThreadedChildWatcher()
- watcher.attach_loop(self.loop)
- asyncio.set_child_watcher(watcher)
+ watcher = asyncio.ThreadedChildWatcher()
+ watcher.attach_loop(self.loop)
+ policy = asyncio.get_event_loop_policy()
+ policy._watcher = watcher
def tearDown(self):
- with warnings.catch_warnings():
- warnings.simplefilter('ignore', DeprecationWarning)
- asyncio.set_child_watcher(None)
+ policy = asyncio.get_event_loop_policy()
+ policy._watcher = None
super().tearDown()
@@ -2716,9 +2714,6 @@ def test_event_loop_policy(self):
self.assertRaises(NotImplementedError, policy.get_event_loop)
self.assertRaises(NotImplementedError, policy.set_event_loop, object())
self.assertRaises(NotImplementedError, policy.new_event_loop)
- self.assertRaises(NotImplementedError, policy.get_child_watcher)
- self.assertRaises(NotImplementedError, policy.set_child_watcher,
- object())
def test_get_event_loop(self):
policy = asyncio.DefaultEventLoopPolicy()
@@ -2836,9 +2831,8 @@ def setUp(self):
def tearDown(self):
try:
if sys.platform != 'win32':
- with warnings.catch_warnings():
- warnings.simplefilter('ignore', DeprecationWarning)
- asyncio.set_child_watcher(None)
+ policy = asyncio.get_event_loop_policy()
+ policy._watcher = None
super().tearDown()
finally:
diff --git a/Lib/test/test_asyncio/test_subprocess.py
b/Lib/test/test_asyncio/test_subprocess.py
index 27ae766a19413b..d7f03e6dd0f4a9 100644
--- a/Lib/test/test_asyncio/test_subprocess.py
+++ b/Lib/test/test_asyncio/test_subprocess.py
@@ -879,17 +879,13 @@ def setUp(self):
watcher = self._get_watcher()
watcher.attach_loop(self.loop)
- with warnings.catch_warnings():
- warnings.simplefilter('ignore', DeprecationWarning)
- policy.set_child_watcher(watcher)
+ policy._watcher = watcher
def tearDown(self):
super().tearDown()
policy = asyncio.get_event_loop_policy()
- with warnings.catch_warnings():
- warnings.simplefilter('ignore', DeprecationWarning)
- watcher = policy.get_child_watcher()
- policy.set_child_watcher(None)
+ watcher = policy._watcher
+ policy._watcher = None
watcher.attach_loop(None)
watcher.close()
@@ -910,66 +906,6 @@ def _get_watcher(self):
return unix_events.PidfdChildWatcher()
- class GenericWatcherTests(test_utils.TestCase):
-
- def test_create_subprocess_fails_with_inactive_watcher(self):
- watcher = mock.create_autospec(asyncio.AbstractChildWatcher)
- watcher.is_active.return_value = False
-
- async def execute():
- asyncio.set_child_watcher(watcher)
-
- with self.assertRaises(RuntimeError):
- await subprocess.create_subprocess_exec(
- os_helper.FakePath(sys.executable), '-c', 'pass')
-
- watcher.add_child_handler.assert_not_called()
-
- with asyncio.Runner(loop_factory=asyncio.new_event_loop) as runner:
- with warnings.catch_warnings():
- warnings.simplefilter('ignore', DeprecationWarning)
- self.assertIsNone(runner.run(execute()))
- self.assertListEqual(watcher.mock_calls, [
- mock.call.__enter__(),
- mock.call.is_active(),
- mock.call.__exit__(RuntimeError, mock.ANY, mock.ANY),
- ], watcher.mock_calls)
-
-
- @unittest.skipUnless(
- unix_events.can_use_pidfd(),
- "operating system does not support pidfds",
- )
- def test_create_subprocess_with_pidfd(self):
- async def in_thread():
- proc = await asyncio.create_subprocess_exec(
- *PROGRAM_CAT,
- stdin=subprocess.PIPE,
- stdout=subprocess.PIPE,
- )
- stdout, stderr = await proc.communicate(b"some data")
- return proc.returncode, stdout
-
- async def main():
- # asyncio.Runner did not call asyncio.set_event_loop()
- with warnings.catch_warnings():
- warnings.simplefilter('error', DeprecationWarning)
- # get_event_loop() raises DeprecationWarning if
- # set_event_loop() was never called and RuntimeError if
- # it was called at least once.
- with self.assertRaises((RuntimeError, DeprecationWarning)):
- asyncio.get_event_loop_policy().get_event_loop()
- return await asyncio.to_thread(asyncio.run, in_thread())
- with self.assertWarns(DeprecationWarning):
- asyncio.set_child_watcher(asyncio.PidfdChildWatcher())
- try:
- with asyncio.Runner(loop_factory=asyncio.new_event_loop) as
runner:
- returncode, stdout = runner.run(main())
- self.assertEqual(returncode, 0)
- self.assertEqual(stdout, b'some data')
- finally:
- with self.assertWarns(DeprecationWarning):
- asyncio.set_child_watcher(None)
else:
# Windows
class SubprocessProactorTests(SubprocessMixin, test_utils.TestCase):
diff --git a/Lib/test/test_asyncio/test_unix_events.py
b/Lib/test/test_asyncio/test_unix_events.py
index 42fb54a4c3a7a5..2ea698f4d74cf7 100644
--- a/Lib/test/test_asyncio/test_unix_events.py
+++ b/Lib/test/test_asyncio/test_unix_events.py
@@ -1138,35 +1138,6 @@ def test_not_implemented(self):
NotImplementedError, watcher.__exit__, f, f, f)
-class PolicyTests(unittest.TestCase):
-
- def create_policy(self):
- return asyncio.DefaultEventLoopPolicy()
-
- @mock.patch('asyncio.unix_events.can_use_pidfd')
- def test_get_default_child_watcher(self, m_can_use_pidfd):
- m_can_use_pidfd.return_value = False
- policy = self.create_policy()
- self.assertIsNone(policy._watcher)
- with self.assertWarns(DeprecationWarning):
- watcher = policy.get_child_watcher()
- self.assertIsInstance(watcher, asyncio.ThreadedChildWatcher)
-
- self.assertIs(policy._watcher, watcher)
- with self.assertWarns(DeprecationWarning):
- self.assertIs(watcher, policy.get_child_watcher())
-
- m_can_use_pidfd.return_value = True
- policy = self.create_policy()
- self.assertIsNone(policy._watcher)
- with self.assertWarns(DeprecationWarning):
- watcher = policy.get_child_watcher()
- self.assertIsInstance(watcher, asyncio.PidfdChildWatcher)
-
- self.assertIs(policy._watcher, watcher)
- with self.assertWarns(DeprecationWarning):
- self.assertIs(watcher, policy.get_child_watcher())
-
class TestFunctional(unittest.TestCase):
def setUp(self):
diff --git a/Lib/test/test_asyncio/utils.py b/Lib/test/test_asyncio/utils.py
index 44943e1fa7bc4e..3fe2ecd2be6d0c 100644
--- a/Lib/test/test_asyncio/utils.py
+++ b/Lib/test/test_asyncio/utils.py
@@ -550,10 +550,8 @@ def close_loop(loop):
policy = support.maybe_get_event_loop_policy()
if policy is not None:
try:
- with warnings.catch_warnings():
- warnings.simplefilter('ignore', DeprecationWarning)
- watcher = policy.get_child_watcher()
- except NotImplementedError:
+ watcher = policy._watcher
+ except AttributeError:
# watcher is not implemented by EventLoopPolicy, e.g. Windows
pass
else:
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]