zoukankan      html  css  js  c++  java
  • sys:1: RuntimeWarning: coroutine 'Launcher.killChrome' was never awaited


    def
    ret_loop(): loop = events.new_event_loop() try: events.set_event_loop(loop) # loop.set_debug(debug) return loop.run_until_complete(get_browser()) # except Exception as e: finally: try: _cancel_all_tasks(loop) loop.run_until_complete(loop.shutdown_asyncgens()) finally: events.set_event_loop(None) loop.close() # print(e) # print('adfafdadsf') if __name__=='__main__': # asyncio.run(get_browser()) # asyncio.get_event_loop().run_until_complete(get_browser()) ret_loop()

    我自己写的这个ret_loop方法其实是照抄的

    asyncio.run
    __all__ = 'run',
    
    from . import coroutines
    from . import events
    from . import tasks
    
    
    def run(main, *, debug=False):
        """Execute the coroutine and return the result.
    
        This function runs the passed coroutine, taking care of
        managing the asyncio event loop and finalizing asynchronous
        generators.
    
        This function cannot be called when another asyncio event loop is
        running in the same thread.
    
        If debug is True, the event loop will be run in debug mode.
    
        This function always creates a new event loop and closes it at the end.
        It should be used as a main entry point for asyncio programs, and should
        ideally only be called once.
    
        Example:
    
            async def main():
                await asyncio.sleep(1)
                print('hello')
    
            asyncio.run(main())
        """
        if events._get_running_loop() is not None:
            raise RuntimeError(
                "asyncio.run() cannot be called from a running event loop")
    
        if not coroutines.iscoroutine(main):
            raise ValueError("a coroutine was expected, got {!r}".format(main))
    
        loop = events.new_event_loop()
        try:
            events.set_event_loop(loop)
            loop.set_debug(debug)
            return loop.run_until_complete(main)
        finally:
            try:
                _cancel_all_tasks(loop)
                loop.run_until_complete(loop.shutdown_asyncgens())
            finally:
                events.set_event_loop(None)
                loop.close()

    发现报错的是最后一句话,完整的错误信息如下:

    Error in atexit._run_exitfuncs:
    Traceback (most recent call last):
      File "C:UsersAdministratorAppDataLocalProgramsPythonPython38libsite-packagespyppeteerlauncher.py", line 174, in _close_process
        self._loop.run_until_complete(self.killChrome())
      File "C:UsersAdministratorAppDataLocalProgramsPythonPython38libasyncioase_events.py", line 591, in run_until_complete
        self._check_closed()
      File "C:UsersAdministratorAppDataLocalProgramsPythonPython38libasyncioase_events.py", line 508, in _check_closed
        raise RuntimeError('Event loop is closed')
    RuntimeError: Event loop is closed
    sys:1: RuntimeWarning: coroutine 'Launcher.killChrome' was never awaited
    RuntimeWarning: Enable tracemalloc to get the object allocation traceback

    那这个

    'Launcher.killChrome'为什么失败呢?
    找到这个方法:
    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    """Chromium process launcher module."""
    
    import asyncio
    import atexit
    import json
    from urllib.request import urlopen
    from urllib.error import URLError
    import logging
    import os
    import os.path
    from pathlib import Path
    import shutil
    import signal
    import subprocess
    import sys
    import tempfile
    import time
    from typing import Any, Dict, List, TYPE_CHECKING
    
    from pyppeteer import __pyppeteer_home__
    from pyppeteer.browser import Browser
    from pyppeteer.connection import Connection
    from pyppeteer.errors import BrowserError
    from pyppeteer.helper import addEventListener, debugError, removeEventListeners
    from pyppeteer.target import Target
    from pyppeteer.util import check_chromium, chromium_executable
    from pyppeteer.util import download_chromium, merge_dict, get_free_port
    
    if TYPE_CHECKING:
        from typing import Optional  # noqa: F401
    
    logger = logging.getLogger(__name__)
    
    pyppeteer_home = Path(__pyppeteer_home__)
    CHROME_PROFILE_PATH = pyppeteer_home / '.dev_profile'
    
    DEFAULT_ARGS = [
        '--disable-background-networking',
        '--disable-background-timer-throttling',
        '--disable-breakpad',
        '--disable-browser-side-navigation',
        '--disable-client-side-phishing-detection',
        '--disable-default-apps',
        '--disable-dev-shm-usage',
        '--disable-extensions',
        '--disable-features=site-per-process',
        '--disable-hang-monitor',
        '--disable-popup-blocking',
        '--disable-prompt-on-repost',
        '--disable-sync',
        '--disable-translate',
        '--metrics-recording-only',
        '--no-first-run',
        '--safebrowsing-disable-auto-update',
    ]
    
    AUTOMATION_ARGS = [
        '--enable-automation',
        '--password-store=basic',
        '--use-mock-keychain',
    ]
    
    
    class Launcher(object):
        """Chrome process launcher class."""
    
        def __init__(self, options: Dict[str, Any] = None,  # noqa: C901
                     **kwargs: Any) -> None:
            """Make new launcher."""
            self.options = merge_dict(options, kwargs)
            self.port = get_free_port()
            self.url = f'http://127.0.0.1:{self.port}'
            self.chrome_args: List[str] = []
            self._loop = self.options.get('loop', asyncio.get_event_loop())
    
            logLevel = self.options.get('logLevel')
            if logLevel:
                logging.getLogger('pyppeteer').setLevel(logLevel)
    
            if not self.options.get('ignoreDefaultArgs', False):
                self.chrome_args.extend(DEFAULT_ARGS)
                self.chrome_args.append(
                    f'--remote-debugging-port={self.port}',
                )
    
            self.chromeClosed = True
            if self.options.get('appMode', False):
                self.options['headless'] = False
            elif not self.options.get('ignoreDefaultArgs', False):
                self.chrome_args.extend(AUTOMATION_ARGS)
    
            self._tmp_user_data_dir: Optional[str] = None
            self._parse_args()
    
            if self.options.get('devtools'):
                self.chrome_args.append('--auto-open-devtools-for-tabs')
                self.options['headless'] = False
    
            if 'headless' not in self.options or self.options.get('headless'):
                self.chrome_args.extend([
                    '--headless',
                    '--disable-gpu',
                    '--hide-scrollbars',
                    '--mute-audio',
                ])
    
            def _is_default_url() -> bool:
                for arg in self.options['args']:
                    if not arg.startswith('-'):
                        return False
                return True
    
            if (not self.options.get('ignoreDefaultArgs') and
                    isinstance(self.options.get('args'), list) and
                    _is_default_url()):
                self.chrome_args.append('about:blank')
    
            if 'executablePath' in self.options:
                self.exec = self.options['executablePath']
            else:
                if not check_chromium():
                    download_chromium()
                self.exec = str(chromium_executable())
    
            self.cmd = [self.exec] + self.chrome_args
    
        def _parse_args(self) -> None:
            if (not isinstance(self.options.get('args'), list) or
                    not any(opt for opt in self.options['args']
                            if opt.startswith('--user-data-dir'))):
                if 'userDataDir' not in self.options:
                    if not CHROME_PROFILE_PATH.exists():
                        CHROME_PROFILE_PATH.mkdir(parents=True)
                    self._tmp_user_data_dir = tempfile.mkdtemp(
                        dir=str(CHROME_PROFILE_PATH))
                self.chrome_args.append('--user-data-dir={}'.format(
                    self.options.get('userDataDir', self._tmp_user_data_dir)))
            if isinstance(self.options.get('args'), list):
                self.chrome_args.extend(self.options['args'])
    
        def _cleanup_tmp_user_data_dir(self) -> None:
            for retry in range(100):
                if self._tmp_user_data_dir and os.path.exists(
                        self._tmp_user_data_dir):
                    shutil.rmtree(self._tmp_user_data_dir, ignore_errors=True)
                    if os.path.exists(self._tmp_user_data_dir):
                        time.sleep(0.01)
                else:
                    break
            else:
                raise IOError('Unable to remove Temporary User Data')
    
        async def launch(self) -> Browser:  # noqa: C901
            """Start chrome process and return `Browser` object."""
            self.chromeClosed = False
            self.connection: Optional[Connection] = None
    
            options = dict()
            options['env'] = self.options.get('env')
            if not self.options.get('dumpio'):
                options['stdout'] = subprocess.PIPE
                options['stderr'] = subprocess.STDOUT
    
            self.proc = subprocess.Popen(  # type: ignore
                self.cmd,
                **options,
            )
    
            def _close_process(*args: Any, **kwargs: Any) -> None:
                if not self.chromeClosed:
                    self._loop.run_until_complete(self.killChrome())
    
            # don't forget to close browser process
            if self.options.get('autoClose', True):
                atexit.register(_close_process)
            if self.options.get('handleSIGINT', True):
                signal.signal(signal.SIGINT, _close_process)
            if self.options.get('handleSIGTERM', True):
                signal.signal(signal.SIGTERM, _close_process)
            if not sys.platform.startswith('win'):
                # SIGHUP is not defined on windows
                if self.options.get('handleSIGHUP', True):
                    signal.signal(signal.SIGHUP, _close_process)
    
            connectionDelay = self.options.get('slowMo', 0)
            self.browserWSEndpoint = self._get_ws_endpoint()
            logger.info(f'Browser listening on: {self.browserWSEndpoint}')
            self.connection = Connection(
                self.browserWSEndpoint, self._loop, connectionDelay)
            ignoreHTTPSErrors = bool(self.options.get('ignoreHTTPSErrors', False))
            setDefaultViewport = not self.options.get('appMode', False)
            browser = await Browser.create(
                self.connection, [], ignoreHTTPSErrors, setDefaultViewport,
                self.proc, self.killChrome)
            await self.ensureInitialPage(browser)
            return browser
    
    

    注意看下这个方法:

        async def launch(self) -> Browser:  # noqa: C901
            """Start chrome process and return `Browser` object."""
            self.chromeClosed = False
            self.connection: Optional[Connection] = None
    
            options = dict()
            options['env'] = self.options.get('env')
            if not self.options.get('dumpio'):
                options['stdout'] = subprocess.PIPE
                options['stderr'] = subprocess.STDOUT
    
            self.proc = subprocess.Popen(  # type: ignore
                self.cmd,
                **options,
            )
    
            def _close_process(*args: Any, **kwargs: Any) -> None:
                if not self.chromeClosed:
                    self._loop.run_until_complete(self.killChrome())
    
            # don't forget to close browser process
            if self.options.get('autoClose', True):
                atexit.register(_close_process)
            if self.options.get('handleSIGINT', True):
                signal.signal(signal.SIGINT, _close_process)
            if self.options.get('handleSIGTERM', True):
                signal.signal(signal.SIGTERM, _close_process)
            if not sys.platform.startswith('win'):
                # SIGHUP is not defined on windows
                if self.options.get('handleSIGHUP', True):
                    signal.signal(signal.SIGHUP, _close_process)
    
            connectionDelay = self.options.get('slowMo', 0)
            self.browserWSEndpoint = self._get_ws_endpoint()
            logger.info(f'Browser listening on: {self.browserWSEndpoint}')
            self.connection = Connection(
                self.browserWSEndpoint, self._loop, connectionDelay)
            ignoreHTTPSErrors = bool(self.options.get('ignoreHTTPSErrors', False))
            setDefaultViewport = not self.options.get('appMode', False)
            browser = await Browser.create(
                self.connection, [], ignoreHTTPSErrors, setDefaultViewport,
                self.proc, self.killChrome)
            await self.ensureInitialPage(browser)
            return browser

    于是乎,找到了bug之源!!!!!~

    就是他们

            def _close_process(*args: Any, **kwargs: Any) -> None:
                if not self.chromeClosed:
                    self._loop.run_until_complete(self.killChrome())
    
            # don't forget to close browser process
            if self.options.get('autoClose', True):
                atexit.register(_close_process)
            if self.options.get('handleSIGINT', True):
                signal.signal(signal.SIGINT, _close_process)
            if self.options.get('handleSIGTERM', True):
                signal.signal(signal.SIGTERM, _close_process)
            if not sys.platform.startswith('win'):
                # SIGHUP is not defined on windows
                if self.options.get('handleSIGHUP', True):
                    signal.signal(signal.SIGHUP, _close_process)

    程序结束时候注册一个事件,就是上面那个函数,会使用当前的loop来close掉浏览器

    可是这个run方法,已经在程序退出之前就finally里面close掉了loop

    于是乎,GG思密达,我也是强迫症,看不得红色!!!!虽然并没有什么影响!!!!

    就!是!不!能!报!红!!!!

    解决方法当然很简单:

    直接

     asyncio.get_event_loop().run_until_complete(get_browser())

    不用你run就行了

    当然还有一种,关闭那个程序退出时候自动杀掉进程的方法,然而,我并不想这么做,为什么?,我!就!不!

    def ret_loop():
    loop = events.new_event_loop()
    try:
    events.set_event_loop(loop)
    # loop.set_debug(debug)
    return loop.run_until_complete(get_browser())
    # except Exception as e:
    finally:
    try:
    _cancel_all_tasks(loop)
    loop.run_until_complete(loop.shutdown_asyncgens())
    finally:
    events.set_event_loop(None)
    loop.close()
    # print(e)
    # print('adfafdadsf')

    if __name__=='__main__':
    # asyncio.run(get_browser())
    # asyncio.get_event_loop().run_until_complete(get_browser())
    ret_loop()
  • 相关阅读:
    编写高质量代码改善C#程序的157个建议——建议55:利用定制特性减少可序列化的字段
    编写高质量代码改善C#程序的157个建议——建议54:为无用字段标注不可序列化
    编写高质量代码改善C#程序的157个建议——建议53:必要时应将不再使用的对象引用赋值为null
    编写高质量代码改善C#程序的157个建议——建议52:及时释放资源
    编写高质量代码改善C#程序的157个建议——建议51:具有可释放字段的类型或拥有本机资源的类型应该是可释放的
    编写高质量代码改善C#程序的157个建议——建议50:在Dispose模式中应区别对待托管资源和非托管资源
    编写高质量代码改善C#程序的157个建议——建议49:在Dispose模式中应提取一个受保护的虚方法
    编写高质量代码改善C#程序的157个建议——建议48:Dispose方法应允许被多次调用
    编写高质量代码改善C#程序的157个建议——建议47:即使提供了显式释放方法,也应该在终结器中提供隐式清理
    编写高质量代码改善C#程序的157个建议——建议46:显式释放资源需继承接口IDisposable
  • 原文地址:https://www.cnblogs.com/DDBD/p/12942920.html
Copyright © 2011-2022 走看看