Skip to content

Commit 9b31456

Browse files
committed
Pin Python dependencies in requirements.txt
- Pinned the following dependencies for consistency and stability: - pytest==7.3.0 - trio==0.22.0 - pytest-trio==0.8.0 - pytest-rerunfailures==10.2 - flake8==6.1.0 - requests==2.32.3 This ensures consistent behavior across environments and avoids issues from unexpected updates or breaking changes. Verified with ============================= test session starts ============================== platform darwin -- Python 3.12.4, pytest-7.3.0, pluggy-1.0.0 rootdir: /Users/Vinay/Documents/SeleniumRepo/seleniumhq.github.io plugins: rerunfailures-10.2, trio-0.8.0, anyio-4.2.0 collected 153 items examples/python/tests/actions_api/test_actions.py .. [ 1%] examples/python/tests/actions_api/test_keys.py ..... [ 4%] examples/python/tests/actions_api/test_mouse.py ............ [ 12%] examples/python/tests/actions_api/test_pen.py .. [ 13%] examples/python/tests/actions_api/test_wheel.py ..... [ 16%] examples/python/tests/bidi/test_bidi_logging.py .... [ 19%] examples/python/tests/bidi/cdp/test_cdp.py . [ 20%] examples/python/tests/bidi/cdp/test_logs.py .. [ 21%] examples/python/tests/bidi/cdp/test_network.py ... [ 23%] examples/python/tests/bidi/cdp/test_script.py F [ 24%] examples/python/tests/browsers/test_chrome.py ...F.........s. [ 33%] examples/python/tests/browsers/test_edge.py ...F.........s. [ 43%] examples/python/tests/browsers/test_firefox.py ........FFFF... [ 53%] examples/python/tests/browsers/test_internet_explorer.py sssssssssssss [ 62%] examples/python/tests/browsers/test_safari.py ..s [ 64%] examples/python/tests/drivers/test_http_client.py F. [ 65%] examples/python/tests/drivers/test_options.py .............. [ 74%] examples/python/tests/drivers/test_remote_webdriver.py ... [ 76%] examples/python/tests/drivers/test_service.py ... [ 78%] examples/python/tests/elements/test_file_upload.py . [ 79%] examples/python/tests/elements/test_information.py . [ 79%] examples/python/tests/elements/test_interaction.py . [ 80%] examples/python/tests/interactions/test_alerts.py ... [ 82%] examples/python/tests/interactions/test_print_options.py ....... [ 86%] examples/python/tests/interactions/test_prints_page.py . [ 87%] examples/python/tests/interactions/test_virtual_authenticator.py ....... [ 92%] ... [ 94%] examples/python/tests/support/test_select_list.py ... [ 96%] examples/python/tests/troubleshooting/test_logging.py . [ 96%] examples/python/tests/waits/test_waits.py ..... [100%] =================================== FAILURES =================================== ________________________________ test_mutation _________________________________ driver = <selenium.webdriver.chrome.webdriver.WebDriver (session="515c6a21ab4301c18bbe46871e7bf148")> @pytest.mark.trio async def test_mutation(driver): async with driver.bidi_connection() as session: > async with Log(driver, session).mutation_events() as event: examples/python/tests/bidi/cdp/test_script.py:11: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /opt/anaconda3/lib/python3.12/contextlib.py:217: in __aexit__ await anext(self.gen) /opt/anaconda3/lib/python3.12/site-packages/selenium/webdriver/common/log.py:93: in mutation_events elements: list = self.driver.find_elements(By.CSS_SELECTOR, f"*[data-__webdriver_id={payload['target']}]") /opt/anaconda3/lib/python3.12/site-packages/selenium/webdriver/remote/webdriver.py:792: in find_elements return self.execute(Command.FIND_ELEMENTS, {"using": by, "value": value})["value"] or [] /opt/anaconda3/lib/python3.12/site-packages/selenium/webdriver/remote/webdriver.py:384: in execute self.error_handler.check_response(response) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <selenium.webdriver.remote.errorhandler.ErrorHandler object at 0x111e254c0> response = {'status': 400, 'value': '{"value":{"error":"invalid selector","message":"invalid selector\\nfrom javascript error: {\...00019107f2e4 _pthread_start + 136\\n19 libsystem_pthread.dylib 0x000000019107a0fc thread_start + 8\\n"}}'} def check_response(self, response: Dict[str, Any]) -> None: """Checks that a JSON response from the WebDriver does not have an error. :Args: - response - The JSON response from the WebDriver server as a dictionary object. :Raises: If the response contains an error message. """ status = response.get("status", None) if not status or status == ErrorCode.SUCCESS: return value = None message = response.get("message", "") screen: str = response.get("screen", "") stacktrace = None if isinstance(status, int): value_json = response.get("value", None) if value_json and isinstance(value_json, str): import json try: value = json.loads(value_json) if len(value) == 1: value = value["value"] status = value.get("error", None) if not status: status = value.get("status", ErrorCode.UNKNOWN_ERROR) message = value.get("value") or value.get("message") if not isinstance(message, str): value = message message = message.get("message") else: message = value.get("message", None) except ValueError: pass exception_class: Type[WebDriverException] e = ErrorCode() error_codes = [item for item in dir(e) if not item.startswith("__")] for error_code in error_codes: error_info = getattr(ErrorCode, error_code) if isinstance(error_info, list) and status in error_info: exception_class = getattr(ExceptionMapping, error_code, WebDriverException) break else: exception_class = WebDriverException if not value: value = response["value"] if isinstance(value, str): raise exception_class(value) if message == "" and "message" in value: message = value["message"] screen = None # type: ignore[assignment] if "screen" in value: screen = value["screen"] stacktrace = None st_value = value.get("stackTrace") or value.get("stacktrace") if st_value: if isinstance(st_value, str): stacktrace = st_value.split("\n") else: stacktrace = [] try: for frame in st_value: line = frame.get("lineNumber", "") file = frame.get("fileName", "<anonymous>") if line: file = f"{file}:{line}" meth = frame.get("methodName", "<anonymous>") if "className" in frame: meth = f"{frame['className']}.{meth}" msg = " at %s (%s)" msg = msg % (meth, file) stacktrace.append(msg) except TypeError: pass if exception_class == UnexpectedAlertPresentException: alert_text = None if "data" in value: alert_text = value["data"].get("text") elif "alert" in value: alert_text = value["alert"].get("text") raise exception_class(message, screen, stacktrace, alert_text) # type: ignore[call-arg] # mypy is not smart enough here > raise exception_class(message, screen, stacktrace) E selenium.common.exceptions.InvalidSelectorException: Message: invalid selector E from javascript error: {"status":32,"value":"An invalid or illegal selector was specified"} E (Session info: chrome=131.0.6778.205); For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors#invalid-selector-exception E Stacktrace: E 0 chromedriver 0x0000000102d9f184 cxxbridge1$str$ptr + 3626716 E 1 chromedriver 0x0000000102d979d4 cxxbridge1$str$ptr + 3596076 E 2 chromedriver 0x0000000102804968 cxxbridge1$string$len + 89228 E 3 chromedriver 0x000000010280984c cxxbridge1$string$len + 109424 E 4 chromedriver 0x000000010280b89c cxxbridge1$string$len + 117696 E 5 chromedriver 0x000000010280b944 cxxbridge1$string$len + 117864 E 6 chromedriver 0x0000000102848a94 cxxbridge1$string$len + 368056 E 7 chromedriver 0x00000001028825b4 cxxbridge1$string$len + 604376 E 8 chromedriver 0x000000010283d568 cxxbridge1$string$len + 321676 E 9 chromedriver 0x000000010283e1b8 cxxbridge1$string$len + 324828 E 10 chromedriver 0x0000000102d6a9ac cxxbridge1$str$ptr + 3411716 E 11 chromedriver 0x0000000102d6dccc cxxbridge1$str$ptr + 3424804 E 12 chromedriver 0x0000000102d5186c cxxbridge1$str$ptr + 3308996 E 13 chromedriver 0x0000000102d6e58c cxxbridge1$str$ptr + 3427044 E 14 chromedriver 0x0000000102d4309c cxxbridge1$str$ptr + 3249652 E 15 chromedriver 0x0000000102d884b8 cxxbridge1$str$ptr + 3533328 E 16 chromedriver 0x0000000102d88634 cxxbridge1$str$ptr + 3533708 E 17 chromedriver 0x0000000102d97648 cxxbridge1$str$ptr + 3595168 E 18 libsystem_pthread.dylib 0x000000019107f2e4 _pthread_start + 136 E 19 libsystem_pthread.dylib 0x000000019107a0fc thread_start + 8 /opt/anaconda3/lib/python3.12/site-packages/selenium/webdriver/remote/errorhandler.py:232: InvalidSelectorException ______________________________ test_add_extension ______________________________ def test_add_extension(): options = webdriver.ChromeOptions() extension_file_path = os.path.abspath("tests/extensions/webextensions-selenium-example.crx") > options.add_extension(extension_file_path) examples/python/tests/browsers/test_chrome.py:40: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <selenium.webdriver.chrome.options.Options object at 0x111e09d30> extension = '/Users/Vinay/Documents/SeleniumRepo/seleniumhq.github.io/tests/extensions/webextensions-selenium-example.crx' def add_extension(self, extension: str) -> None: """Adds the path to the extension to a list that will be used to extract it to the ChromeDriver. :Args: - extension: path to the \\*.crx file """ if extension: extension_to_add = os.path.abspath(os.path.expanduser(extension)) if os.path.exists(extension_to_add): self._extension_files.append(extension_to_add) else: > raise OSError("Path to the extension doesn't exist") E OSError: Path to the extension doesn't exist /opt/anaconda3/lib/python3.12/site-packages/selenium/webdriver/chromium/options.py:103: OSError ______________________________ test_add_extension ______________________________ def test_add_extension(): options = webdriver.EdgeOptions() extension_file_path = os.path.abspath("tests/extensions/webextensions-selenium-example.crx") > options.add_extension(extension_file_path) examples/python/tests/browsers/test_edge.py:40: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <selenium.webdriver.edge.options.Options object at 0x111e0a2d0> extension = '/Users/Vinay/Documents/SeleniumRepo/seleniumhq.github.io/tests/extensions/webextensions-selenium-example.crx' def add_extension(self, extension: str) -> None: """Adds the path to the extension to a list that will be used to extract it to the ChromeDriver. :Args: - extension: path to the \\*.crx file """ if extension: extension_to_add = os.path.abspath(os.path.expanduser(extension)) if os.path.exists(extension_to_add): self._extension_files.append(extension_to_add) else: > raise OSError("Path to the extension doesn't exist") E OSError: Path to the extension doesn't exist /opt/anaconda3/lib/python3.12/site-packages/selenium/webdriver/chromium/options.py:103: OSError ______________________________ test_install_addon ______________________________ firefox_driver = <selenium.webdriver.firefox.webdriver.WebDriver (session="9c05f940-a875-49b3-8de1-d4d892150f37")> addon_path_xpi = '/Users/Vinay/Documents/SeleniumRepo/seleniumhq.github.io/tests/extensions/webextensions-selenium-example.xpi' def test_install_addon(firefox_driver, addon_path_xpi): driver = firefox_driver > driver.install_addon(addon_path_xpi) examples/python/tests/browsers/test_firefox.py:94: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <selenium.webdriver.firefox.webdriver.WebDriver (session="9c05f940-a875-49b3-8de1-d4d892150f37")> path = '/Users/Vinay/Documents/SeleniumRepo/seleniumhq.github.io/tests/extensions/webextensions-selenium-example.xpi' temporary = False def install_addon(self, path, temporary=False) -> str: """Installs Firefox addon. Returns identifier of installed addon. This identifier can later be used to uninstall addon. :param temporary: allows you to load browser extensions temporarily during a session :param path: Absolute path to the addon that will be installed. :Usage: :: driver.install_addon('/path/to/firebug.xpi') """ if os.path.isdir(path): fp = BytesIO() # filter all trailing slash found in path path = os.path.normpath(path) # account for trailing slash that will be added by os.walk() path_root = len(path) + 1 with zipfile.ZipFile(fp, "w", zipfile.ZIP_DEFLATED) as zipped: for base, _, files in os.walk(path): for fyle in files: filename = os.path.join(base, fyle) zipped.write(filename, filename[path_root:]) addon = base64.b64encode(fp.getvalue()).decode("UTF-8") else: > with open(path, "rb") as file: E FileNotFoundError: [Errno 2] No such file or directory: '/Users/Vinay/Documents/SeleniumRepo/seleniumhq.github.io/tests/extensions/webextensions-selenium-example.xpi' /opt/anaconda3/lib/python3.12/site-packages/selenium/webdriver/firefox/webdriver.py:141: FileNotFoundError _____________________________ test_uninstall_addon _____________________________ firefox_driver = <selenium.webdriver.firefox.webdriver.WebDriver (session="acfdd1d4-bdbe-4904-b9ea-5d8273f8ae00")> addon_path_xpi = '/Users/Vinay/Documents/SeleniumRepo/seleniumhq.github.io/tests/extensions/webextensions-selenium-example.xpi' def test_uninstall_addon(firefox_driver, addon_path_xpi): driver = firefox_driver > id = driver.install_addon(addon_path_xpi) examples/python/tests/browsers/test_firefox.py:105: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <selenium.webdriver.firefox.webdriver.WebDriver (session="acfdd1d4-bdbe-4904-b9ea-5d8273f8ae00")> path = '/Users/Vinay/Documents/SeleniumRepo/seleniumhq.github.io/tests/extensions/webextensions-selenium-example.xpi' temporary = False def install_addon(self, path, temporary=False) -> str: """Installs Firefox addon. Returns identifier of installed addon. This identifier can later be used to uninstall addon. :param temporary: allows you to load browser extensions temporarily during a session :param path: Absolute path to the addon that will be installed. :Usage: :: driver.install_addon('/path/to/firebug.xpi') """ if os.path.isdir(path): fp = BytesIO() # filter all trailing slash found in path path = os.path.normpath(path) # account for trailing slash that will be added by os.walk() path_root = len(path) + 1 with zipfile.ZipFile(fp, "w", zipfile.ZIP_DEFLATED) as zipped: for base, _, files in os.walk(path): for fyle in files: filename = os.path.join(base, fyle) zipped.write(filename, filename[path_root:]) addon = base64.b64encode(fp.getvalue()).decode("UTF-8") else: > with open(path, "rb") as file: E FileNotFoundError: [Errno 2] No such file or directory: '/Users/Vinay/Documents/SeleniumRepo/seleniumhq.github.io/tests/extensions/webextensions-selenium-example.xpi' /opt/anaconda3/lib/python3.12/site-packages/selenium/webdriver/firefox/webdriver.py:141: FileNotFoundError ____________________ test_install_unsigned_addon_directory _____________________ firefox_driver = <selenium.webdriver.firefox.webdriver.WebDriver (session="6210c6b0-47e2-4ea4-83ba-ccb5513b4a96")> addon_path_dir = '/Users/Vinay/Documents/SeleniumRepo/seleniumhq.github.io/tests/extensions/webextensions-selenium-example' def test_install_unsigned_addon_directory(firefox_driver, addon_path_dir): driver = firefox_driver > driver.install_addon(addon_path_dir, temporary=True) examples/python/tests/browsers/test_firefox.py:115: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <selenium.webdriver.firefox.webdriver.WebDriver (session="6210c6b0-47e2-4ea4-83ba-ccb5513b4a96")> path = '/Users/Vinay/Documents/SeleniumRepo/seleniumhq.github.io/tests/extensions/webextensions-selenium-example' temporary = True def install_addon(self, path, temporary=False) -> str: """Installs Firefox addon. Returns identifier of installed addon. This identifier can later be used to uninstall addon. :param temporary: allows you to load browser extensions temporarily during a session :param path: Absolute path to the addon that will be installed. :Usage: :: driver.install_addon('/path/to/firebug.xpi') """ if os.path.isdir(path): fp = BytesIO() # filter all trailing slash found in path path = os.path.normpath(path) # account for trailing slash that will be added by os.walk() path_root = len(path) + 1 with zipfile.ZipFile(fp, "w", zipfile.ZIP_DEFLATED) as zipped: for base, _, files in os.walk(path): for fyle in files: filename = os.path.join(base, fyle) zipped.write(filename, filename[path_root:]) addon = base64.b64encode(fp.getvalue()).decode("UTF-8") else: > with open(path, "rb") as file: E FileNotFoundError: [Errno 2] No such file or directory: '/Users/Vinay/Documents/SeleniumRepo/seleniumhq.github.io/tests/extensions/webextensions-selenium-example' /opt/anaconda3/lib/python3.12/site-packages/selenium/webdriver/firefox/webdriver.py:141: FileNotFoundError _________________ test_install_unsigned_addon_directory_slash __________________ firefox_driver = <selenium.webdriver.firefox.webdriver.WebDriver (session="676fa6a5-8e2f-4776-b853-3a933f218d25")> addon_path_dir_slash = '/Users/Vinay/Documents/SeleniumRepo/seleniumhq.github.io/tests/extensions/webextensions-selenium-example' def test_install_unsigned_addon_directory_slash(firefox_driver, addon_path_dir_slash): driver = firefox_driver > driver.install_addon(addon_path_dir_slash, temporary=True) examples/python/tests/browsers/test_firefox.py:126: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <selenium.webdriver.firefox.webdriver.WebDriver (session="676fa6a5-8e2f-4776-b853-3a933f218d25")> path = '/Users/Vinay/Documents/SeleniumRepo/seleniumhq.github.io/tests/extensions/webextensions-selenium-example' temporary = True def install_addon(self, path, temporary=False) -> str: """Installs Firefox addon. Returns identifier of installed addon. This identifier can later be used to uninstall addon. :param temporary: allows you to load browser extensions temporarily during a session :param path: Absolute path to the addon that will be installed. :Usage: :: driver.install_addon('/path/to/firebug.xpi') """ if os.path.isdir(path): fp = BytesIO() # filter all trailing slash found in path path = os.path.normpath(path) # account for trailing slash that will be added by os.walk() path_root = len(path) + 1 with zipfile.ZipFile(fp, "w", zipfile.ZIP_DEFLATED) as zipped: for base, _, files in os.walk(path): for fyle in files: filename = os.path.join(base, fyle) zipped.write(filename, filename[path_root:]) addon = base64.b64encode(fp.getvalue()).decode("UTF-8") else: > with open(path, "rb") as file: E FileNotFoundError: [Errno 2] No such file or directory: '/Users/Vinay/Documents/SeleniumRepo/seleniumhq.github.io/tests/extensions/webextensions-selenium-example' /opt/anaconda3/lib/python3.12/site-packages/selenium/webdriver/firefox/webdriver.py:141: FileNotFoundError _____________________ test_start_remote_with_client_config _____________________ sock = <socket.socket [closed] fd=-1, family=30, type=1, proto=6> keyfile = None, certfile = None, cert_reqs = None ca_certs = '/Users/Vinay/Documents/SeleniumRepo/seleniumhq.github.io/tests/resources/tls.crt' server_hostname = 'localhost', ssl_version = None, ciphers = None ssl_context = <ssl.SSLContext object at 0x111ee5250>, ca_cert_dir = None key_password = None, ca_cert_data = None, tls_in_tls = False def ssl_wrap_socket( sock: socket.socket, keyfile: str | None = None, certfile: str | None = None, cert_reqs: int | None = None, ca_certs: str | None = None, server_hostname: str | None = None, ssl_version: int | None = None, ciphers: str | None = None, ssl_context: ssl.SSLContext | None = None, ca_cert_dir: str | None = None, key_password: str | None = None, ca_cert_data: None | str | bytes = None, tls_in_tls: bool = False, ) -> ssl.SSLSocket | SSLTransportType: """ All arguments except for server_hostname, ssl_context, tls_in_tls, ca_cert_data and ca_cert_dir have the same meaning as they do when using :func:`ssl.create_default_context`, :meth:`ssl.SSLContext.load_cert_chain`, :meth:`ssl.SSLContext.set_ciphers` and :meth:`ssl.SSLContext.wrap_socket`. :param server_hostname: When SNI is supported, the expected hostname of the certificate :param ssl_context: A pre-made :class:`SSLContext` object. If none is provided, one will be created using :func:`create_urllib3_context`. :param ciphers: A string of ciphers we wish the client to support. :param ca_cert_dir: A directory containing CA certificates in multiple separate files, as supported by OpenSSL's -CApath flag or the capath argument to SSLContext.load_verify_locations(). :param key_password: Optional password if the keyfile is encrypted. :param ca_cert_data: Optional string containing CA certificates in PEM format suitable for passing as the cadata parameter to SSLContext.load_verify_locations() :param tls_in_tls: Use SSLTransport to wrap the existing socket. """ context = ssl_context if context is None: # Note: This branch of code and all the variables in it are only used in tests. # We should consider deprecating and removing this code. context = create_urllib3_context(ssl_version, cert_reqs, ciphers=ciphers) if ca_certs or ca_cert_dir or ca_cert_data: try: > context.load_verify_locations(ca_certs, ca_cert_dir, ca_cert_data) E FileNotFoundError: [Errno 2] No such file or directory /opt/anaconda3/lib/python3.12/site-packages/urllib3/util/ssl_.py:447: FileNotFoundError The above exception was the direct cause of the following exception: self = <urllib3.connectionpool.HTTPSConnectionPool object at 0x111ee3aa0> method = 'POST', url = '/session' body = '{"capabilities": {"firstMatch": [{}], "alwaysMatch": {"browserName": "chrome", "pageLoadStrategy": "normal", "goog:chromeOptions": {"extensions": [], "args": []}}}}' headers = HTTPHeaderDict({'Accept': 'application/json', 'Content-Type': 'application/json;charset=UTF-8', 'User-Agent': 'selenium/4.27.1 (python mac)', 'Connection': 'keep-alive', 'Authorization': 'Basic YWRtaW46bXlTdHJvbmdQYXNzd29yZA=='}) retries = Retry(total=0, connect=2, read=2, redirect=2, status=None) redirect = False, assert_same_host = False, timeout = None, pool_timeout = None release_conn = True, chunked = False, body_pos = None, preload_content = True decode_content = True, response_kw = {} parsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/session', query=None, fragment=None) destination_scheme = None, conn = None, release_this_conn = True http_tunnel_required = False, err = None, clean_exit = False def urlopen( # type: ignore[override] self, method: str, url: str, body: _TYPE_BODY | None = None, headers: typing.Mapping[str, str] | None = None, retries: Retry | bool | int | None = None, redirect: bool = True, assert_same_host: bool = True, timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT, pool_timeout: int | None = None, release_conn: bool | None = None, chunked: bool = False, body_pos: _TYPE_BODY_POSITION | None = None, preload_content: bool = True, decode_content: bool = True, **response_kw: typing.Any, ) -> BaseHTTPResponse: """ Get a connection from the pool and perform an HTTP request. This is the lowest level call for making a request, so you'll need to specify all the raw details. .. note:: More commonly, it's appropriate to use a convenience method such as :meth:`request`. .. note:: `release_conn` will only behave as expected if `preload_content=False` because we want to make `preload_content=False` the default behaviour someday soon without breaking backwards compatibility. :param method: HTTP request method (such as GET, POST, PUT, etc.) :param url: The URL to perform the request on. :param body: Data to send in the request body, either :class:`str`, :class:`bytes`, an iterable of :class:`str`/:class:`bytes`, or a file-like object. :param headers: Dictionary of custom headers to send, such as User-Agent, If-None-Match, etc. If None, pool headers are used. If provided, these headers completely replace any pool-specific headers. :param retries: Configure the number of retries to allow before raising a :class:`~urllib3.exceptions.MaxRetryError` exception. If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a :class:`~urllib3.util.retry.Retry` object for fine-grained control over different types of retries. Pass an integer number to retry connection errors that many times, but no other types of errors. Pass zero to never retry. If ``False``, then retries are disabled and any exception is raised immediately. Also, instead of raising a MaxRetryError on redirects, the redirect response will be returned. :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int. :param redirect: If True, automatically handle redirects (status codes 301, 302, 303, 307, 308). Each redirect counts as a retry. Disabling retries will disable redirect, too. :param assert_same_host: If ``True``, will make sure that the host of the pool requests is consistent else will raise HostChangedError. When ``False``, you can use the pool on an HTTP proxy and request foreign hosts. :param timeout: If specified, overrides the default timeout for this one request. It may be a float (in seconds) or an instance of :class:`urllib3.util.Timeout`. :param pool_timeout: If set and the pool is set to block=True, then this method will block for ``pool_timeout`` seconds and raise EmptyPoolError if no connection is available within the time period. :param bool preload_content: If True, the response's body will be preloaded into memory. :param bool decode_content: If True, will attempt to decode the body based on the 'content-encoding' header. :param release_conn: If False, then the urlopen call will not release the connection back into the pool once a response is received (but will release if you read the entire contents of the response such as when `preload_content=True`). This is useful if you're not preloading the response's content immediately. You will need to call ``r.release_conn()`` on the response ``r`` to return the connection back into the pool. If None, it takes the value of ``preload_content`` which defaults to ``True``. :param bool chunked: If True, urllib3 will send the body using chunked transfer encoding. Otherwise, urllib3 will send the body using the standard content-length form. Defaults to False. :param int body_pos: Position to seek to in file-like body in the event of a retry or redirect. Typically this won't need to be set because urllib3 will auto-populate the value when needed. """ parsed_url = parse_url(url) destination_scheme = parsed_url.scheme if headers is None: headers = self.headers if not isinstance(retries, Retry): retries = Retry.from_int(retries, redirect=redirect, default=self.retries) if release_conn is None: release_conn = preload_content # Check host if assert_same_host and not self.is_same_host(url): raise HostChangedError(self, url, retries) # Ensure that the URL we're connecting to is properly encoded if url.startswith("/"): url = to_str(_encode_target(url)) else: url = to_str(parsed_url.url) conn = None # Track whether `conn` needs to be released before # returning/raising/recursing. Update this variable if necessary, and # leave `release_conn` constant throughout the function. That way, if # the function recurses, the original value of `release_conn` will be # passed down into the recursive call, and its value will be respected. # # See issue #651 [1] for details. # # [1] <https://github.com/urllib3/urllib3/issues/651> release_this_conn = release_conn http_tunnel_required = connection_requires_http_tunnel( self.proxy, self.proxy_config, destination_scheme ) # Merge the proxy headers. Only done when not using HTTP CONNECT. We # have to copy the headers dict so we can safely change it without those # changes being reflected in anyone else's copy. if not http_tunnel_required: headers = headers.copy() # type: ignore[attr-defined] headers.update(self.proxy_headers) # type: ignore[union-attr] # Must keep the exception bound to a separate variable or else Python 3 # complains about UnboundLocalError. err = None # Keep track of whether we cleanly exited the except block. This # ensures we do proper cleanup in finally. clean_exit = False # Rewind body position, if needed. Record current position # for future rewinds in the event of a redirect/retry. body_pos = set_file_position(body, body_pos) try: # Request a connection from the queue. timeout_obj = self._get_timeout(timeout) conn = self._get_conn(timeout=pool_timeout) conn.timeout = timeout_obj.connect_timeout # type: ignore[assignment] # Is this a closed/new connection that requires CONNECT tunnelling? if self.proxy is not None and http_tunnel_required and conn.is_closed: try: self._prepare_proxy(conn) except (BaseSSLError, OSError, SocketTimeout) as e: self._raise_timeout( err=e, url=self.proxy.url, timeout_value=conn.timeout ) raise # If we're going to release the connection in ``finally:``, then # the response doesn't need to know about the connection. Otherwise # it will also try to release it and we'll have a double-release # mess. response_conn = conn if not release_conn else None # Make the request on the HTTPConnection object > response = self._make_request( conn, method, url, timeout=timeout_obj, body=body, headers=headers, chunked=chunked, retries=retries, response_conn=response_conn, preload_content=preload_content, decode_content=decode_content, **response_kw, ) /opt/anaconda3/lib/python3.12/site-packages/urllib3/connectionpool.py:789: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <urllib3.connectionpool.HTTPSConnectionPool object at 0x111ee3aa0> conn = <urllib3.connection.HTTPSConnection object at 0x111ee2630> method = 'POST', url = '/session' body = '{"capabilities": {"firstMatch": [{}], "alwaysMatch": {"browserName": "chrome", "pageLoadStrategy": "normal", "goog:chromeOptions": {"extensions": [], "args": []}}}}' headers = HTTPHeaderDict({'Accept': 'application/json', 'Content-Type': 'application/json;charset=UTF-8', 'User-Agent': 'selenium/4.27.1 (python mac)', 'Connection': 'keep-alive', 'Authorization': 'Basic YWRtaW46bXlTdHJvbmdQYXNzd29yZA=='}) retries = Retry(total=0, connect=2, read=2, redirect=2, status=None) timeout = Timeout(connect=None, read=None, total=None), chunked = False response_conn = None, preload_content = True, decode_content = True enforce_content_length = True def _make_request( self, conn: BaseHTTPConnection, method: str, url: str, body: _TYPE_BODY | None = None, headers: typing.Mapping[str, str] | None = None, retries: Retry | None = None, timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT, chunked: bool = False, response_conn: BaseHTTPConnection | None = None, preload_content: bool = True, decode_content: bool = True, enforce_content_length: bool = True, ) -> BaseHTTPResponse: """ Perform a request on a given urllib connection object taken from our pool. :param conn: a connection from one of our connection pools :param method: HTTP request method (such as GET, POST, PUT, etc.) :param url: The URL to perform the request on. :param body: Data to send in the request body, either :class:`str`, :class:`bytes`, an iterable of :class:`str`/:class:`bytes`, or a file-like object. :param headers: Dictionary of custom headers to send, such as User-Agent, If-None-Match, etc. If None, pool headers are used. If provided, these headers completely replace any pool-specific headers. :param retries: Configure the number of retries to allow before raising a :class:`~urllib3.exceptions.MaxRetryError` exception. Pass ``None`` to retry until you receive a response. Pass a :class:`~urllib3.util.retry.Retry` object for fine-grained control over different types of retries. Pass an integer number to retry connection errors that many times, but no other types of errors. Pass zero to never retry. If ``False``, then retries are disabled and any exception is raised immediately. Also, instead of raising a MaxRetryError on redirects, the redirect response will be returned. :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int. :param timeout: If specified, overrides the default timeout for this one request. It may be a float (in seconds) or an instance of :class:`urllib3.util.Timeout`. :param chunked: If True, urllib3 will send the body using chunked transfer encoding. Otherwise, urllib3 will send the body using the standard content-length form. Defaults to False. :param response_conn: Set this to ``None`` if you will handle releasing the connection or set the connection to have the response release it. :param preload_content: If True, the response's body will be preloaded during construction. :param decode_content: If True, will attempt to decode the body based on the 'content-encoding' header. :param enforce_content_length: Enforce content length checking. Body returned by server must match value of Content-Length header, if present. Otherwise, raise error. """ self.num_requests += 1 timeout_obj = self._get_timeout(timeout) timeout_obj.start_connect() conn.timeout = Timeout.resolve_default_timeout(timeout_obj.connect_timeout) try: # Trigger any extra validation we need to do. try: self._validate_conn(conn) except (SocketTimeout, BaseSSLError) as e: self._raise_timeout(err=e, url=url, timeout_value=conn.timeout) raise # _validate_conn() starts the connection to an HTTPS proxy # so we need to wrap errors with 'ProxyError' here too. except ( OSError, NewConnectionError, TimeoutError, BaseSSLError, CertificateError, SSLError, ) as e: new_e: Exception = e if isinstance(e, (BaseSSLError, CertificateError)): new_e = SSLError(e) # If the connection didn't successfully connect to it's proxy # then there if isinstance( new_e, (OSError, NewConnectionError, TimeoutError, SSLError) ) and (conn and conn.proxy and not conn.has_connected_to_proxy): new_e = _wrap_proxy_error(new_e, conn.proxy.scheme) > raise new_e /opt/anaconda3/lib/python3.12/site-packages/urllib3/connectionpool.py:490: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <urllib3.connectionpool.HTTPSConnectionPool object at 0x111ee3aa0> conn = <urllib3.connection.HTTPSConnection object at 0x111ee2630> method = 'POST', url = '/session' body = '{"capabilities": {"firstMatch": [{}], "alwaysMatch": {"browserName": "chrome", "pageLoadStrategy": "normal", "goog:chromeOptions": {"extensions": [], "args": []}}}}' headers = HTTPHeaderDict({'Accept': 'application/json', 'Content-Type': 'application/json;charset=UTF-8', 'User-Agent': 'selenium/4.27.1 (python mac)', 'Connection': 'keep-alive', 'Authorization': 'Basic YWRtaW46bXlTdHJvbmdQYXNzd29yZA=='}) retries = Retry(total=0, connect=2, read=2, redirect=2, status=None) timeout = Timeout(connect=None, read=None, total=None), chunked = False response_conn = None, preload_content = True, decode_content = True enforce_content_length = True def _make_request( self, conn: BaseHTTPConnection, method: str, url: str, body: _TYPE_BODY | None = None, headers: typing.Mapping[str, str] | None = None, retries: Retry | None = None, timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT, chunked: bool = False, response_conn: BaseHTTPConnection | None = None, preload_content: bool = True, decode_content: bool = True, enforce_content_length: bool = True, ) -> BaseHTTPResponse: """ Perform a request on a given urllib connection object taken from our pool. :param conn: a connection from one of our connection pools :param method: HTTP request method (such as GET, POST, PUT, etc.) :param url: The URL to perform the request on. :param body: Data to send in the request body, either :class:`str`, :class:`bytes`, an iterable of :class:`str`/:class:`bytes`, or a file-like object. :param headers: Dictionary of custom headers to send, such as User-Agent, If-None-Match, etc. If None, pool headers are used. If provided, these headers completely replace any pool-specific headers. :param retries: Configure the number of retries to allow before raising a :class:`~urllib3.exceptions.MaxRetryError` exception. Pass ``None`` to retry until you receive a response. Pass a :class:`~urllib3.util.retry.Retry` object for fine-grained control over different types of retries. Pass an integer number to retry connection errors that many times, but no other types of errors. Pass zero to never retry. If ``False``, then retries are disabled and any exception is raised immediately. Also, instead of raising a MaxRetryError on redirects, the redirect response will be returned. :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int. :param timeout: If specified, overrides the default timeout for this one request. It may be a float (in seconds) or an instance of :class:`urllib3.util.Timeout`. :param chunked: If True, urllib3 will send the body using chunked transfer encoding. Otherwise, urllib3 will send the body using the standard content-length form. Defaults to False. :param response_conn: Set this to ``None`` if you will handle releasing the connection or set the connection to have the response release it. :param preload_content: If True, the response's body will be preloaded during construction. :param decode_content: If True, will attempt to decode the body based on the 'content-encoding' header. :param enforce_content_length: Enforce content length checking. Body returned by server must match value of Content-Length header, if present. Otherwise, raise error. """ self.num_requests += 1 timeout_obj = self._get_timeout(timeout) timeout_obj.start_connect() conn.timeout = Timeout.resolve_default_timeout(timeout_obj.connect_timeout) try: # Trigger any extra validation we need to do. try: > self._validate_conn(conn) /opt/anaconda3/lib/python3.12/site-packages/urllib3/connectionpool.py:466: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <urllib3.connectionpool.HTTPSConnectionPool object at 0x111ee3aa0> conn = <urllib3.connection.HTTPSConnection object at 0x111ee2630> def _validate_conn(self, conn: BaseHTTPConnection) -> None: """ Called right before a request is made, after the socket is created. """ super()._validate_conn(conn) # Force connect early to allow us to validate the connection. if conn.is_closed: > conn.connect() /opt/anaconda3/lib/python3.12/site-packages/urllib3/connectionpool.py:1095: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <urllib3.connection.HTTPSConnection object at 0x111ee2630> def connect(self) -> None: # Today we don't need to be doing this step before the /actual/ socket # connection, however in the future we'll need to decide whether to # create a new socket or re-use an existing "shared" socket as a part # of the HTTP/2 handshake dance. if self._tunnel_host is not None and self._tunnel_port is not None: probe_http2_host = self._tunnel_host probe_http2_port = self._tunnel_port else: probe_http2_host = self.host probe_http2_port = self.port # Check if the target origin supports HTTP/2. # If the value comes back as 'None' it means that the current thread # is probing for HTTP/2 support. Otherwise, we're waiting for another # probe to complete, or we get a value right away. target_supports_http2: bool | None if "h2" in ssl_.ALPN_PROTOCOLS: target_supports_http2 = http2_probe.acquire_and_get( host=probe_http2_host, port=probe_http2_port ) else: # If HTTP/2 isn't going to be offered it doesn't matter if # the target supports HTTP/2. Don't want to make a probe. target_supports_http2 = False if self._connect_callback is not None: self._connect_callback( "before connect", thread_id=threading.get_ident(), target_supports_http2=target_supports_http2, ) try: sock: socket.socket | ssl.SSLSocket self.sock = sock = self._new_conn() server_hostname: str = self.host tls_in_tls = False # Do we need to establish a tunnel? if self._tunnel_host is not None: # We're tunneling to an HTTPS origin so need to do TLS-in-TLS. if self._tunnel_scheme == "https": # _connect_tls_proxy will verify and assign proxy_is_verified self.sock = sock = self._connect_tls_proxy(self.host, sock) tls_in_tls = True elif self._tunnel_scheme == "http": self.proxy_is_verified = False # If we're tunneling it means we're connected to our proxy. self._has_connected_to_proxy = True self._tunnel() # Override the host with the one we're requesting data from. server_hostname = self._tunnel_host if self.server_hostname is not None: server_hostname = self.server_hostname is_time_off = datetime.date.today() < RECENT_DATE if is_time_off: warnings.warn( ( f"System time is way off (before {RECENT_DATE}). This will probably " "lead to SSL verification errors" ), SystemTimeWarning, ) # Remove trailing '.' from fqdn hostnames to allow certificate validation server_hostname_rm_dot = server_hostname.rstrip(".") > sock_and_verified = _ssl_wrap_socket_and_match_hostname( sock=sock, cert_reqs=self.cert_reqs, ssl_version=self.ssl_version, ssl_minimum_version=self.ssl_minimum_version, ssl_maximum_version=self.ssl_maximum_version, ca_certs=self.ca_certs, ca_cert_dir=self.ca_cert_dir, ca_cert_data=self.ca_cert_data, cert_file=self.cert_file, key_file=self.key_file, key_password=self.key_password, server_hostname=server_hostname_rm_dot, ssl_context=self.ssl_context, tls_in_tls=tls_in_tls, assert_hostname=self.assert_hostname, assert_fingerprint=self.assert_fingerprint, ) /opt/anaconda3/lib/python3.12/site-packages/urllib3/connection.py:730: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ sock = <socket.socket [closed] fd=-1, family=30, type=1, proto=6> def _ssl_wrap_socket_and_match_hostname( sock: socket.socket, *, cert_reqs: None | str | int, ssl_version: None | str | int, ssl_minimum_version: int | None, ssl_maximum_version: int | None, cert_file: str | None, key_file: str | None, key_password: str | None, ca_certs: str | None, ca_cert_dir: str | None, ca_cert_data: None | str | bytes, assert_hostname: None | str | typing.Literal[False], assert_fingerprint: str | None, server_hostname: str | None, ssl_context: ssl.SSLContext | None, tls_in_tls: bool = False, ) -> _WrappedAndVerifiedSocket: """Logic for constructing an SSLContext from all TLS parameters, passing that down into ssl_wrap_socket, and then doing certificate verification either via hostname or fingerprint. This function exists to guarantee that both proxies and targets have the same behavior when connecting via TLS. """ default_ssl_context = False if ssl_context is None: default_ssl_context = True context = create_urllib3_context( ssl_version=resolve_ssl_version(ssl_version), ssl_minimum_version=ssl_minimum_version, ssl_maximum_version=ssl_maximum_version, cert_reqs=resolve_cert_reqs(cert_reqs), ) else: context = ssl_context context.verify_mode = resolve_cert_reqs(cert_reqs) # In some cases, we want to verify hostnames ourselves if ( # `ssl` can't verify fingerprints or alternate hostnames assert_fingerprint or assert_hostname # assert_hostname can be set to False to disable hostname checking or assert_hostname is False # We still support OpenSSL 1.0.2, which prevents us from verifying # hostnames easily: https://github.com/pyca/pyopenssl/pull/933 or ssl_.IS_PYOPENSSL or not ssl_.HAS_NEVER_CHECK_COMMON_NAME ): context.check_hostname = False # Try to load OS default certs if none are given. We need to do the hasattr() check # for custom pyOpenSSL SSLContext objects because they don't support # load_default_certs(). if ( not ca_certs and not ca_cert_dir and not ca_cert_data and default_ssl_context and hasattr(context, "load_default_certs") ): context.load_default_certs() # Ensure that IPv6 addresses are in the proper format and don't have a # scope ID. Python's SSL module fails to recognize scoped IPv6 addresses # and interprets them as DNS hostnames. if server_hostname is not None: normalized = server_hostname.strip("[]") if "%" in normalized: normalized = normalized[: normalized.rfind("%")] if is_ipaddress(normalized): server_hostname = normalized > ssl_sock = ssl_wrap_socket( sock=sock, keyfile=key_file, certfile=cert_file, key_password=key_password, ca_certs=ca_certs, ca_cert_dir=ca_cert_dir, ca_cert_data=ca_cert_data, server_hostname=server_hostname, ssl_context=context, tls_in_tls=tls_in_tls, ) /opt/anaconda3/lib/python3.12/site-packages/urllib3/connection.py:909: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ sock = <socket.socket [closed] fd=-1, family=30, type=1, proto=6> keyfile = None, certfile = None, cert_reqs = None ca_certs = '/Users/Vinay/Documents/SeleniumRepo/seleniumhq.github.io/tests/resources/tls.crt' server_hostname = 'localhost', ssl_version = None, ciphers = None ssl_context = <ssl.SSLContext object at 0x111ee5250>, ca_cert_dir = None key_password = None, ca_cert_data = None, tls_in_tls = False def ssl_wrap_socket( sock: socket.socket, keyfile: str | None = None, certfile: str | None = None, cert_reqs: int | None = None, ca_certs: str | None = None, server_hostname: str | None = None, ssl_version: int | None = None, ciphers: str | None = None, ssl_context: ssl.SSLContext | None = None, ca_cert_dir: str | None = None, key_password: str | None = None, ca_cert_data: None | str | bytes = None, tls_in_tls: bool = False, ) -> ssl.SSLSocket | SSLTransportType: """ All arguments except for server_hostname, ssl_context, tls_in_tls, ca_cert_data and ca_cert_dir have the same meaning as they do when using :func:`ssl.create_default_context`, :meth:`ssl.SSLContext.load_cert_chain`, :meth:`ssl.SSLContext.set_ciphers` and :meth:`ssl.SSLContext.wrap_socket`. :param server_hostname: When SNI is supported, the expected hostname of the certificate :param ssl_context: A pre-made :class:`SSLContext` object. If none is provided, one will be created using :func:`create_urllib3_context`. :param ciphers: A string of ciphers we wish the client to support. :param ca_cert_dir: A directory containing CA certificates in multiple separate files, as supported by OpenSSL's -CApath flag or the capath argument to SSLContext.load_verify_locations(). :param key_password: Optional password if the keyfile is encrypted. :param ca_cert_data: Optional string containing CA certificates in PEM format suitable for passing as the cadata parameter to SSLContext.load_verify_locations() :param tls_in_tls: Use SSLTransport to wrap the existing socket. """ context = ssl_context if context is None: # Note: This branch of code and all the variables in it are only used in tests. # We should consider deprecating and removing this code. context = create_urllib3_context(ssl_version, cert_reqs, ciphers=ciphers) if ca_certs or ca_cert_dir or ca_cert_data: try: context.load_verify_locations(ca_certs, ca_cert_dir, ca_cert_data) except OSError as e: > raise SSLError(e) from e E urllib3.exceptions.SSLError: [Errno 2] No such file or directory /opt/anaconda3/lib/python3.12/site-packages/urllib3/util/ssl_.py:449: SSLError The above exception was the direct cause of the following exception: grid_server = 'https://localhost:55939' @pytest.mark.skipif(sys.platform == "win32", reason="Gets stuck on Windows, passes locally") def test_start_remote_with_client_config(grid_server): proxy = Proxy({"proxyType": ProxyType.AUTODETECT}) retries = Retry(connect=2, read=2, redirect=2) timeout = Timeout(connect=300, read=3600) client_config = ClientConfig(remote_server_addr=grid_server, proxy=proxy, init_args_for_pool_manager={ "init_args_for_pool_manager": {"retries": retries, "timeout": timeout}}, ca_certs=_get_resource_path("tls.crt"), username="admin", password="myStrongPassword") options = webdriver.ChromeOptions() > driver = webdriver.Remote(command_executor=grid_server, options=options, client_config=client_config) examples/python/tests/drivers/test_http_client.py:23: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /opt/anaconda3/lib/python3.12/site-packages/selenium/webdriver/remote/webdriver.py:241: in __init__ self.start_session(capabilities) /opt/anaconda3/lib/python3.12/site-packages/selenium/webdriver/remote/webdriver.py:329: in start_session response = self.execute(Command.NEW_SESSION, caps)["value"] /opt/anaconda3/lib/python3.12/site-packages/selenium/webdriver/remote/webdriver.py:382: in execute response = self.command_executor.execute(driver_command, params) /opt/anaconda3/lib/python3.12/site-packages/selenium/webdriver/remote/remote_connection.py:404: in execute return self._request(command_info[0], url, body=data) /opt/anaconda3/lib/python3.12/site-packages/selenium/webdriver/remote/remote_connection.py:428: in _request response = self._conn.request(method, url, body=body, headers=headers, timeout=self._client_config.timeout) /opt/anaconda3/lib/python3.12/site-packages/urllib3/_request_methods.py:143: in request return self.request_encode_body( /opt/anaconda3/lib/python3.12/site-packages/urllib3/_request_methods.py:278: in request_encode_body return self.urlopen(method, url, **extra_kw) /opt/anaconda3/lib/python3.12/site-packages/urllib3/poolmanager.py:443: in urlopen response = conn.urlopen(method, u.request_uri, **kw) /opt/anaconda3/lib/python3.12/site-packages/urllib3/connectionpool.py:873: in urlopen return self.urlopen( /opt/anaconda3/lib/python3.12/site-packages/urllib3/connectionpool.py:873: in urlopen return self.urlopen( /opt/anaconda3/lib/python3.12/site-packages/urllib3/connectionpool.py:873: in urlopen return self.urlopen( /opt/anaconda3/lib/python3.12/site-packages/urllib3/connectionpool.py:873: in urlopen return self.urlopen( /opt/anaconda3/lib/python3.12/site-packages/urllib3/connectionpool.py:873: in urlopen return self.urlopen( /opt/anaconda3/lib/python3.12/site-packages/urllib3/connectionpool.py:873: in urlopen return self.urlopen( /opt/anaconda3/lib/python3.12/site-packages/urllib3/connectionpool.py:873: in urlopen return self.urlopen( /opt/anaconda3/lib/python3.12/site-packages/urllib3/connectionpool.py:873: in urlopen return self.urlopen( /opt/anaconda3/lib/python3.12/site-packages/urllib3/connectionpool.py:873: in urlopen return self.urlopen( /opt/anaconda3/lib/python3.12/site-packages/urllib3/connectionpool.py:873: in urlopen return self.urlopen( /opt/anaconda3/lib/python3.12/site-packages/urllib3/connectionpool.py:843: in urlopen retries = retries.increment( _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = Retry(total=0, connect=2, read=2, redirect=2, status=None) method = 'POST', url = '/session', response = None error = SSLError(FileNotFoundError(2, 'No such file or directory')) _pool = <urllib3.connectionpool.HTTPSConnectionPool object at 0x111ee3aa0> _stacktrace = <traceback object at 0x111ed9a00> def increment( self, method: str | None = None, url: str | None = None, response: BaseHTTPResponse | None = None, error: Exception | None = None, _pool: ConnectionPool | None = None, _stacktrace: TracebackType | None = None, ) -> Self: """Return a new Retry object with incremented retry counters. :param response: A response object, or None, if the server did not return a response. :type response: :class:`~urllib3.response.BaseHTTPResponse` :param Exception error: An error encountered during the request, or None if the response was received successfully. :return: A new ``Retry`` object. """ if self.total is False and error: # Disabled, indicate to re-raise the error. raise reraise(type(error), error, _stacktrace) total = self.total if total is not None: total -= 1 connect = self.connect read = self.read redirect = self.redirect status_count = self.status other = self.other cause = "unknown" status = None redirect_location = None if error and self._is_connection_error(error): # Connect retry? if connect is False: raise reraise(type(error), error, _stacktrace) elif connect is not None: connect -= 1 elif error and self._is_read_error(error): # Read retry? if read is False or method is None or not self._is_method_retryable(method): raise reraise(type(error), error, _stacktrace) elif read is not None: read -= 1 elif error: # Other retry? if other is not None: other -= 1 elif response and response.get_redirect_location(): # Redirect retry? if redirect is not None: redirect -= 1 cause = "too many redirects" response_redirect_location = response.get_redirect_location() if response_redirect_location: redirect_location = response_redirect_location status = response.status else: # Incrementing because of a server error like a 500 in # status_forcelist and the given method is in the allowed_methods cause = ResponseError.GENERIC_ERROR if response and response.status: if status_count is not None: status_count -= 1 cause = ResponseError.SPECIFIC_ERROR.format(status_code=response.status) status = response.status history = self.history + ( RequestHistory(method, url, error, status, redirect_location), ) new_retry = self.new( total=total, connect=connect, read=read, redirect=redirect, status=status_count, other=other, history=history, ) if new_retry.is_exhausted(): reason = error or ResponseError(cause) > raise MaxRetryError(_pool, url, reason) from reason # type: ignore[arg-type] E urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='localhost', port=55939): Max retries exceeded with url: /session (Caused by SSLError(FileNotFoundError(2, 'No such file or directory'))) /opt/anaconda3/lib/python3.12/site-packages/urllib3/util/retry.py:519: MaxRetryError ---------------------------- Captured stdout setup ----------------------------- HTTPSConnectionPool(host='localhost', port=55939): Max retries exceeded with url: /status (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x111ee1580>: Failed to establish a new connection: [Errno 61] Connection refused')) HTTPSConnectionPool(host='localhost', port=55939): Max retries exceeded with url: /status (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x111f20260>: Failed to establish a new connection: [Errno 61] Connection refused')) HTTPSConnectionPool(host='localhost', port=55939): Max retries exceeded with url: /sta…
1 parent df6fabb commit 9b31456

File tree

1 file changed

+6
-6
lines changed

1 file changed

+6
-6
lines changed

examples/python/requirements.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
selenium==4.27.1
2-
pytest
3-
trio
4-
pytest-trio
5-
pytest-rerunfailures
6-
flake8
7-
requests
2+
pytest==7.3.0
3+
trio==0.22.0
4+
pytest-trio==0.8.0
5+
pytest-rerunfailures==10.2
6+
flake8==6.1.0
7+
requests==2.32.3

0 commit comments

Comments
 (0)