1313# limitations under the License.
1414
1515import asyncio
16- from typing import Any
16+ import sys
17+ from typing import Any , Optional
1718
1819from greenlet import greenlet
1920
@@ -31,6 +32,7 @@ def __init__(self) -> None:
3132 self ._playwright : SyncPlaywright
3233 self ._loop : asyncio .AbstractEventLoop
3334 self ._own_loop = False
35+ self ._watcher : Optional [asyncio .AbstractChildWatcher ] = None
3436
3537 def __enter__ (self ) -> SyncPlaywright :
3638 try :
@@ -44,6 +46,20 @@ def __enter__(self) -> SyncPlaywright:
4446Please use the Async API instead."""
4547 )
4648
49+ # In Python 3.7, asyncio.Process.wait() hangs because it does not use ThreadedChildWatcher
50+ # which is used in Python 3.8+. This is unix specific and also takes care about
51+ # cleaning up zombie processes. See https://bugs.python.org/issue35621
52+ if (
53+ sys .version_info [0 ] == 3
54+ and sys .version_info [1 ] == 7
55+ and sys .platform != "win32"
56+ and isinstance (asyncio .get_child_watcher (), asyncio .SafeChildWatcher )
57+ ):
58+ from ._py37ThreadedChildWatcher import ThreadedChildWatcher # type: ignore
59+
60+ self ._watcher = ThreadedChildWatcher ()
61+ asyncio .set_child_watcher (self ._watcher ) # type: ignore
62+
4763 def greenlet_main () -> None :
4864 self ._loop .run_until_complete (self ._connection .run_as_sync ())
4965
@@ -73,6 +89,8 @@ def start(self) -> SyncPlaywright:
7389
7490 def __exit__ (self , * args : Any ) -> None :
7591 self ._connection .stop_sync ()
92+ if self ._watcher :
93+ self ._watcher .close ()
7694 if self ._own_loop :
7795 self ._loop .run_until_complete (self ._loop .shutdown_asyncgens ())
7896 self ._loop .close ()
0 commit comments