alttester / EXAMPLES-Python-Android-with-Appium-AltTrashCat

1 stars 1 forks source link

[Android-Appium-Python] - Tests fails #8

Open YhondriPM opened 1 year ago

YhondriPM commented 1 year ago

Description

Hi :D, the tests fails when running the script ./run-tests_android.sh I've had also tried running Appium adding the path as follow: appium --use-plugins=altunity --base-path /wd/hub

I'm having the same problem with a new project I've created following the documentation and the examples on this project.

Here is the log.

` /opt/homebrew/lib/python3.11/site-packages/urllib3/connection.py:200:


/opt/homebrew/lib/python3.11/site-packages/urllib3/util/connection.py:85: in create_connection raise err


address = ('localhost', 4723), timeout = None, source_address = None, socket_options = [(6, 1, 1)]

def create_connection(
    address: tuple[str, int],
    timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,
    source_address: tuple[str, int] | None = None,
    socket_options: _TYPE_SOCKET_OPTIONS | None = None,
) -> socket.socket:
    """Connect to *address* and return the socket object.

    Convenience function.  Connect to *address* (a 2-tuple ``(host,
    port)``) and return the socket object.  Passing the optional
    *timeout* parameter will set the timeout on the socket instance
    before attempting to connect.  If no *timeout* is supplied, the
    global default timeout setting returned by :func:`socket.getdefaulttimeout`
    is used.  If *source_address* is set it must be a tuple of (host, port)
    for the socket to bind as a source address before making the connection.
    An host of '' or port 0 tells the OS to use the default.
    """

    host, port = address
    if host.startswith("["):
        host = host.strip("[]")
    err = None

    # Using the value from allowed_gai_family() in the context of getaddrinfo lets
    # us select whether to work with IPv4 DNS records, IPv6 records, or both.
    # The original create_connection function always returns all records.
    family = allowed_gai_family()

    try:
        host.encode("idna")
    except UnicodeError:
        raise LocationParseError(f"'{host}', label empty or too long") from None

    for res in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM):
        af, socktype, proto, canonname, sa = res
        sock = None
        try:
            sock = socket.socket(af, socktype, proto)

            # If provided, set socket level options before connecting.
            _set_socket_options(sock, socket_options)

            if timeout is not _DEFAULT_TIMEOUT:
                sock.settimeout(timeout)
            if source_address:
                sock.bind(source_address)
          sock.connect(sa)

E ConnectionRefusedError: [Errno 61] Connection refused

/opt/homebrew/lib/python3.11/site-packages/urllib3/util/connection.py:73: ConnectionRefusedError

The above exception was the direct cause of the following exception:

self = <urllib3.connectionpool.HTTPConnectionPool object at 0x1036cc1d0>, method = 'POST', url = '/wd/hub/session' body = '{"capabilities": {"firstMatch": [{}], "alwaysMatch": {"platformName": "android", "appium:deviceName": "Local Device",...s_apk/EXAMPLES-Python-Android-with-Appium-AltTrashCat-master/TrashCat.apk", "appium:automationName": "uiautomator2"}}}' headers = HTTPHeaderDict({'Accept': 'application/json', 'Content-Type': 'application/json;charset=UTF-8', 'User-Agent': 'appium/...lenium/4.10.0 (python mac))', 'Connection': 'keep-alive', 'X-Idempotency-Key': '60cf3bb5-d106-478d-96be-c8f5e8b5d05e'}) retries = Retry(total=0, connect=None, read=None, redirect=None, status=None), redirect = False, assert_same_host = False, timeout = <_TYPE_DEFAULT.token: -1> 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='/wd/hub/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.

        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 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/homebrew/lib/python3.11/site-packages/urllib3/connectionpool.py:790:


/opt/homebrew/lib/python3.11/site-packages/urllib3/connectionpool.py:496: in _make_request conn.request( /opt/homebrew/lib/python3.11/site-packages/urllib3/connection.py:388: in request self.endheaders() /opt/homebrew/Cellar/python@3.11/3.11.4_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/http/client.py:1281: in endheaders self._send_output(message_body, encode_chunked=encode_chunked) /opt/homebrew/Cellar/python@3.11/3.11.4_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/http/client.py:1041: in _send_output self.send(msg) /opt/homebrew/Cellar/python@3.11/3.11.4_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/http/client.py:979: in send self.connect() /opt/homebrew/lib/python3.11/site-packages/urllib3/connection.py:236: in connect self.sock = self._new_conn()


self = <urllib3.connection.HTTPConnection object at 0x1036cead0>

def _new_conn(self) -> socket.socket:
    """Establish a socket connection and set nodelay settings on it.

    :return: New socket connection.
    """
    try:
        sock = connection.create_connection(
            (self._dns_host, self.port),
            self.timeout,
            source_address=self.source_address,
            socket_options=self.socket_options,
        )
    except socket.gaierror as e:
        raise NameResolutionError(self.host, self, e) from e
    except SocketTimeout as e:
        raise ConnectTimeoutError(
            self,
            f"Connection to {self.host} timed out. (connect timeout={self.timeout})",
        ) from e

    except OSError as e:
      raise NewConnectionError(

self, f"Failed to establish a new connection: {e}" ) from e E urllib3.exceptions.NewConnectionError: <urllib3.connection.HTTPConnection object at 0x1036cead0>: Failed to establish a new connection: [Errno 61] Connection refused

/opt/homebrew/lib/python3.11/site-packages/urllib3/connection.py:215: NewConnectionError

The above exception was the direct cause of the following exception:

cls = <class 'tests.start_page_test.TestStartPage'>

@classmethod
def setUpClass(cls):
    if os.getenv("APPIUM_PLATFORM", "android") == 'android':
        cls.platform = 'android'
    else:
        cls.platform = 'ios'
    print("Running on " + cls.platform)
    cls.desired_caps = {}
    cls.desired_caps['platformName'] = os.getenv('APPIUM_PLATFORM', 'Android')
    cls.desired_caps['deviceName'] = os.getenv('APPIUM_DEVICE', 'device')
    cls.desired_caps['app'] = os.getenv("APPIUM_APPFILE", "application.apk")
    cls.desired_caps['automationName'] = os.getenv('APPIUM_AUTOMATION', 'UIAutomator2')
  cls.appium_driver = webdriver.Remote('http://localhost:4723/wd/hub', cls.desired_caps)

tests/base_test.py:27:


/opt/homebrew/lib/python3.11/site-packages/appium/webdriver/webdriver.py:257: in init super().init( /opt/homebrew/lib/python3.11/site-packages/selenium/webdriver/remote/webdriver.py:206: in init self.start_session(capabilities) /opt/homebrew/lib/python3.11/site-packages/appium/webdriver/webdriver.py:346: in start_session response = self.execute(RemoteCommand.NEW_SESSION, w3c_caps) /opt/homebrew/lib/python3.11/site-packages/selenium/webdriver/remote/webdriver.py:344: in execute response = self.command_executor.execute(driver_command, params) /opt/homebrew/lib/python3.11/site-packages/selenium/webdriver/remote/remote_connection.py:290: in execute return self._request(command_info[0], url, body=data) /opt/homebrew/lib/python3.11/site-packages/selenium/webdriver/remote/remote_connection.py:311: in _request response = self._conn.request(method, url, body=body, headers=headers) /opt/homebrew/lib/python3.11/site-packages/urllib3/_request_methods.py:118: in request return self.request_encode_body( /opt/homebrew/lib/python3.11/site-packages/urllib3/_request_methods.py:217: in request_encode_body return self.urlopen(method, url, extra_kw) /opt/homebrew/lib/python3.11/site-packages/urllib3/poolmanager.py:443: in urlopen response = conn.urlopen(method, u.request_uri, kw) /opt/homebrew/lib/python3.11/site-packages/urllib3/connectionpool.py:874: in urlopen return self.urlopen( /opt/homebrew/lib/python3.11/site-packages/urllib3/connectionpool.py:874: in urlopen return self.urlopen( /opt/homebrew/lib/python3.11/site-packages/urllib3/connectionpool.py:874: in urlopen return self.urlopen( /opt/homebrew/lib/python3.11/site-packages/urllib3/connectionpool.py:844: in urlopen retries = retries.increment(


self = Retry(total=0, connect=None, read=None, redirect=None, status=None), method = 'POST', url = '/wd/hub/session', response = None error = NewConnectionError('<urllib3.connection.HTTPConnection object at 0x1036cead0>: Failed to establish a new connection: [Errno 61] Connection refused') _pool = <urllib3.connectionpool.HTTPConnectionPool object at 0x1036cc1d0>, _stacktrace = <traceback object at 0x1036cea80>

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,
) -> Retry:
    """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: HTTPConnectionPool(host='localhost', port=4723): Max retries exceeded with url: /wd/hub/session (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x1036cead0>: Failed to establish a new connection: [Errno 61] Connection refused'))

/opt/homebrew/lib/python3.11/site-packages/urllib3/util/retry.py:515: MaxRetryError --------------------------------------------------------------------- Captured log setup --------------------------------------------------------------------- WARNING urllib3.connectionpool:connectionpool.py:871 Retrying (Retry(total=2, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NewConnectionError('<urllib3.connection.HTTPConnection object at 0x1036cc790>: Failed to establish a new connection: [Errno 61] Connection refused')': /wd/hub/session WARNING urllib3.connectionpool:connectionpool.py:871 Retrying (Retry(total=1, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NewConnectionError('<urllib3.connection.HTTPConnection object at 0x1036cd3d0>: Failed to establish a new connection: [Errno 61] Connection refused')': /wd/hub/session WARNING urllib3.connectionpool:connectionpool.py:871 Retrying (Retry(total=0, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NewConnectionError('<urllib3.connection.HTTPConnection object at 0x1036cdc50>: Failed to establish a new connection: [Errno 61] Connection refused')': /wd/hub/session __ ERROR at setup of TestStartPage.test_start_page_loaded_correctly __

self = <urllib3.connection.HTTPConnection object at 0x1036cead0>

def _new_conn(self) -> socket.socket:
    """Establish a socket connection and set nodelay settings on it.

    :return: New socket connection.
    """
    try:
      sock = connection.create_connection(

(self._dns_host, self.port), self.timeout, source_address=self.source_address, socket_options=self.socket_options, )

/opt/homebrew/lib/python3.11/site-packages/urllib3/connection.py:200:


/opt/homebrew/lib/python3.11/site-packages/urllib3/util/connection.py:85: in create_connection raise err


address = ('localhost', 4723), timeout = None, source_address = None, socket_options = [(6, 1, 1)]

def create_connection(
    address: tuple[str, int],
    timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,
    source_address: tuple[str, int] | None = None,
    socket_options: _TYPE_SOCKET_OPTIONS | None = None,
) -> socket.socket:
    """Connect to *address* and return the socket object.

    Convenience function.  Connect to *address* (a 2-tuple ``(host,
    port)``) and return the socket object.  Passing the optional
    *timeout* parameter will set the timeout on the socket instance
    before attempting to connect.  If no *timeout* is supplied, the
    global default timeout setting returned by :func:`socket.getdefaulttimeout`
    is used.  If *source_address* is set it must be a tuple of (host, port)
    for the socket to bind as a source address before making the connection.
    An host of '' or port 0 tells the OS to use the default.
    """

    host, port = address
    if host.startswith("["):
        host = host.strip("[]")
    err = None

    # Using the value from allowed_gai_family() in the context of getaddrinfo lets
    # us select whether to work with IPv4 DNS records, IPv6 records, or both.
    # The original create_connection function always returns all records.
    family = allowed_gai_family()

    try:
        host.encode("idna")
    except UnicodeError:
        raise LocationParseError(f"'{host}', label empty or too long") from None

    for res in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM):
        af, socktype, proto, canonname, sa = res
        sock = None
        try:
            sock = socket.socket(af, socktype, proto)

            # If provided, set socket level options before connecting.
            _set_socket_options(sock, socket_options)

            if timeout is not _DEFAULT_TIMEOUT:
                sock.settimeout(timeout)
            if source_address:
                sock.bind(source_address)
          sock.connect(sa)

E ConnectionRefusedError: [Errno 61] Connection refused

/opt/homebrew/lib/python3.11/site-packages/urllib3/util/connection.py:73: ConnectionRefusedError

The above exception was the direct cause of the following exception:

self = <urllib3.connectionpool.HTTPConnectionPool object at 0x1036cc1d0>, method = 'POST', url = '/wd/hub/session' body = '{"capabilities": {"firstMatch": [{}], "alwaysMatch": {"platformName": "android", "appium:deviceName": "Local Device",...s_apk/EXAMPLES-Python-Android-with-Appium-AltTrashCat-master/TrashCat.apk", "appium:automationName": "uiautomator2"}}}' headers = HTTPHeaderDict({'Accept': 'application/json', 'Content-Type': 'application/json;charset=UTF-8', 'User-Agent': 'appium/...lenium/4.10.0 (python mac))', 'Connection': 'keep-alive', 'X-Idempotency-Key': '60cf3bb5-d106-478d-96be-c8f5e8b5d05e'}) retries = Retry(total=0, connect=None, read=None, redirect=None, status=None), redirect = False, assert_same_host = False, timeout = <_TYPE_DEFAULT.token: -1> 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='/wd/hub/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.

        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 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/homebrew/lib/python3.11/site-packages/urllib3/connectionpool.py:790:


/opt/homebrew/lib/python3.11/site-packages/urllib3/connectionpool.py:496: in _make_request conn.request( /opt/homebrew/lib/python3.11/site-packages/urllib3/connection.py:388: in request self.endheaders() /opt/homebrew/Cellar/python@3.11/3.11.4_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/http/client.py:1281: in endheaders self._send_output(message_body, encode_chunked=encode_chunked) /opt/homebrew/Cellar/python@3.11/3.11.4_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/http/client.py:1041: in _send_output self.send(msg) /opt/homebrew/Cellar/python@3.11/3.11.4_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/http/client.py:979: in send self.connect() /opt/homebrew/lib/python3.11/site-packages/urllib3/connection.py:236: in connect self.sock = self._new_conn()


self = <urllib3.connection.HTTPConnection object at 0x1036cead0>

def _new_conn(self) -> socket.socket:
    """Establish a socket connection and set nodelay settings on it.

    :return: New socket connection.
    """
    try:
        sock = connection.create_connection(
            (self._dns_host, self.port),
            self.timeout,
            source_address=self.source_address,
            socket_options=self.socket_options,
        )
    except socket.gaierror as e:
        raise NameResolutionError(self.host, self, e) from e
    except SocketTimeout as e:
        raise ConnectTimeoutError(
            self,
            f"Connection to {self.host} timed out. (connect timeout={self.timeout})",
        ) from e

    except OSError as e:
      raise NewConnectionError(

self, f"Failed to establish a new connection: {e}" ) from e E urllib3.exceptions.NewConnectionError: <urllib3.connection.HTTPConnection object at 0x1036cead0>: Failed to establish a new connection: [Errno 61] Connection refused

/opt/homebrew/lib/python3.11/site-packages/urllib3/connection.py:215: NewConnectionError

The above exception was the direct cause of the following exception:

cls = <class 'tests.start_page_test.TestStartPage'>

@classmethod
def setUpClass(cls):
    if os.getenv("APPIUM_PLATFORM", "android") == 'android':
        cls.platform = 'android'
    else:
        cls.platform = 'ios'
    print("Running on " + cls.platform)
    cls.desired_caps = {}
    cls.desired_caps['platformName'] = os.getenv('APPIUM_PLATFORM', 'Android')
    cls.desired_caps['deviceName'] = os.getenv('APPIUM_DEVICE', 'device')
    cls.desired_caps['app'] = os.getenv("APPIUM_APPFILE", "application.apk")
    cls.desired_caps['automationName'] = os.getenv('APPIUM_AUTOMATION', 'UIAutomator2')
  cls.appium_driver = webdriver.Remote('http://localhost:4723/wd/hub', cls.desired_caps)

tests/base_test.py:27:


/opt/homebrew/lib/python3.11/site-packages/appium/webdriver/webdriver.py:257: in init super().init( /opt/homebrew/lib/python3.11/site-packages/selenium/webdriver/remote/webdriver.py:206: in init self.start_session(capabilities) /opt/homebrew/lib/python3.11/site-packages/appium/webdriver/webdriver.py:346: in start_session response = self.execute(RemoteCommand.NEW_SESSION, w3c_caps) /opt/homebrew/lib/python3.11/site-packages/selenium/webdriver/remote/webdriver.py:344: in execute response = self.command_executor.execute(driver_command, params) /opt/homebrew/lib/python3.11/site-packages/selenium/webdriver/remote/remote_connection.py:290: in execute return self._request(command_info[0], url, body=data) /opt/homebrew/lib/python3.11/site-packages/selenium/webdriver/remote/remote_connection.py:311: in _request response = self._conn.request(method, url, body=body, headers=headers) /opt/homebrew/lib/python3.11/site-packages/urllib3/_request_methods.py:118: in request return self.request_encode_body( /opt/homebrew/lib/python3.11/site-packages/urllib3/_request_methods.py:217: in request_encode_body return self.urlopen(method, url, extra_kw) /opt/homebrew/lib/python3.11/site-packages/urllib3/poolmanager.py:443: in urlopen response = conn.urlopen(method, u.request_uri, kw) /opt/homebrew/lib/python3.11/site-packages/urllib3/connectionpool.py:874: in urlopen return self.urlopen( /opt/homebrew/lib/python3.11/site-packages/urllib3/connectionpool.py:874: in urlopen return self.urlopen( /opt/homebrew/lib/python3.11/site-packages/urllib3/connectionpool.py:874: in urlopen return self.urlopen( /opt/homebrew/lib/python3.11/site-packages/urllib3/connectionpool.py:844: in urlopen retries = retries.increment(


self = Retry(total=0, connect=None, read=None, redirect=None, status=None), method = 'POST', url = '/wd/hub/session', response = None error = NewConnectionError('<urllib3.connection.HTTPConnection object at 0x1036cead0>: Failed to establish a new connection: [Errno 61] Connection refused') _pool = <urllib3.connectionpool.HTTPConnectionPool object at 0x1036cc1d0>, _stacktrace = <traceback object at 0x1036cea80>

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,
) -> Retry:
    """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: HTTPConnectionPool(host='localhost', port=4723): Max retries exceeded with url: /wd/hub/session (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x1036cead0>: Failed to establish a new connection: [Errno 61] Connection refused'))

/opt/homebrew/lib/python3.11/site-packages/urllib3/util/retry.py:515: MaxRetryError ====================================================================== warnings summary ====================================================================== tests/game_play_test.py::TestGamePlay::test_avoiding_obstacles tests/main_page_test.py::TestMainPage::test_main_menu_page_loaded_correctly tests/start_page_test.py::TestStartPage::test_start_button_loads_main_menu /opt/homebrew/lib/python3.11/site-packages/appium/webdriver/webdriver.py:245: DeprecationWarning: desired_capabilities argument is deprecated and will be removed in future versions. Use options instead. warnings.warn(

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html ================================================================== short test summary info =================================================================== ERROR tests/game_play_test.py::TestGamePlay::test_avoiding_obstacles - urllib3.exceptions.MaxRetryError: HTTPConnectionPool(host='localhost', port=4723): Max retries exceeded with url: /wd/hub/session (Caused by NewConnectio... ERROR tests/game_play_test.py::TestGamePlay::test_game_can_be_paused_and_resumed - urllib3.exceptions.MaxRetryError: HTTPConnectionPool(host='localhost', port=4723): Max retries exceeded with url: /wd/hub/session (Caused by NewConnectio... ERROR tests/game_play_test.py::TestGamePlay::test_game_can_be_paused_and_stopped - urllib3.exceptions.MaxRetryError: HTTPConnectionPool(host='localhost', port=4723): Max retries exceeded with url: /wd/hub/session (Caused by NewConnectio... ERROR tests/game_play_test.py::TestGamePlay::test_game_play_page_displayed_correctly - urllib3.exceptions.MaxRetryError: HTTPConnectionPool(host='localhost', port=4723): Max retries exceeded with url: /wd/hub/session (Caused by NewConnectio... ERROR tests/game_play_test.py::TestGamePlay::test_player_dies_when_obstacles_not_avoided - urllib3.exceptions.MaxRetryError: HTTPConnectionPool(host='localhost', port=4723): Max retries exceeded with url: /wd/hub/session (Caused by NewConnectio... ERROR tests/main_page_test.py::TestMainPage::test_main_menu_page_loaded_correctly - urllib3.exceptions.MaxRetryError: HTTPConnectionPool(host='localhost', port=4723): Max retries exceeded with url: /wd/hub/session (Caused by NewConnectio... ERROR tests/start_page_test.py::TestStartPage::test_start_button_loads_main_menu - urllib3.exceptions.MaxRetryError: HTTPConnectionPool(host='localhost', port=4723): Max retries exceeded with url: /wd/hub/session (Caused by NewConnectio... ERROR tests/start_page_test.py::TestStartPage::test_start_page_loaded_correctly - urllib3.exceptions.MaxRetryError: HTTPConnectionPool(host='localhost', port=4723): Max retries exceeded with url: /wd/hub/session (Caused by NewConnectio... =============================================================== 3 warnings, 8 errors in 0.70s ================================================================ Tests done `

ata-matthewm commented 1 year ago

Having the exact same issue.

It looks like /wd/hub is no longer a thing since Appium 2.0

The solution is to change the references to http://localhost:4723/wd/hub to simply http://localhost:4723/

It seems like there is a lot in this example that is out of date. For example, the --command-timeout parameter passed into appium is obsolete now and causes an error as well.