Clone
1
run 2704 TEST commit c8b8f24
ci-bot edited this page 2025-08-28 10:16:37 +00:00

Test Report

View CI Run 2704 | Commit c8b8f24 Pytest completed successfully

All tests were collected and executed properly. See the details below.

📋 Short test summary info
=========================== short test summary info ============================
FAILED tests/test_utils_debug.py::test_short_repr[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-10-'aaaaaaaaaa...] - assert "'aaaaaaaaa..." == "'aaaaaaaaaa..."
  
  - 'aaaaaaaaaa...
  ?  -
  + 'aaaaaaaaa...
FAILED tests/test_utils_debug.py::test_short_repr[value5-20-Obj(xxxxxxxxxxxxxxxxx...] - AssertionError: assert 'Obj(xxxxxxxxxxxxxxxx...' == 'Obj(xxxxxxxxxxxxxxxxx...'
  
  - Obj(xxxxxxxxxxxxxxxxx...
  ?                     -
  + Obj(xxxxxxxxxxxxxxxx...
FAILED tests/test_utils_elog.py::test_get_default_elog_instance_with_direct_password_and_real_check - Failed: elog.post() raised an unexpected exception: No response from the logbook server.
Details: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09b7e4f0>: Failed to establish a new connection: [Errno 111] Connection refused'))
FAILED tests/test_utils_elog.py::test_get_default_elog_instance_asks_password_and_opens - Failed: elog.post() raised an unexpected exception: No response from the logbook server.
Details: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb098025b0>: Failed to establish a new connection: [Errno 111] Connection refused'))
FAILED tests/test_utils_elog.py::test_get_default_elog_with_path_home - Failed: elog.post() raised an unexpected exception: No response from the logbook server.
Details: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb098b2bb0>: Failed to establish a new connection: [Errno 111] Connection refused'))
FAILED tests/test_utils_elog.py::test_screenshot - elog.logbook_exceptions.LogbookServerProblem: No response from the logbook server.
Details: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09b7ea60>: Failed to establish a new connection: [Errno 111] Connection refused'))
FAILED tests/test_utils_get_adj.py::test_get_adjs_filter - AssertionError: assert {'contrast', ...mid_contrast'} == {'brightness'...mid_contrast'}
  
  Extra items in the right set:
  'brightness'
  
  Full diff:
    {
  -     'brightness',
        'contrast',
        'mid_brightness',
        'mid_contrast',
    }
FAILED tests/test_utils_logcfg.py::test_import_logging_once_per_module - AssertionError: Expected 1 import log for 'math', found 0
assert 0 == 1
FAILED tests/test_utils_shortcut.py::TestShortcutsSingleton::test_registration - assert 3 == 2
 +  where 3 = len({'<lambda>': Shortcut "<lambda>", 'FuncA': Shortcut "FuncA", 'FuncB': Shortcut "FuncB"})
 +    where {'<lambda>': Shortcut "<lambda>", 'FuncA': Shortcut "FuncA", 'FuncB': Shortcut "FuncB"} = _get()
 +      where _get = <lambda>: Shortcut "<lambda>"\nFuncA:    Shortcut "FuncA"\nFuncB:    Shortcut "FuncB"\n._get
FAILED tests/test_utils_shortcut.py::TestFullIntegration::test_multiple_shortcuts - assert 5 == 2
 +  where 5 = len({'<lambda>': Shortcut "<lambda>", 'First': Shortcut "First", 'FuncA': Shortcut "FuncA", 'FuncB': Shortcut "FuncB", ...})
 +    where {'<lambda>': Shortcut "<lambda>", 'First': Shortcut "First", 'FuncA': Shortcut "FuncA", 'FuncB': Shortcut "FuncB", ...} = _get()
 +      where _get = <lambda>: Shortcut "<lambda>"\nFirst:    Shortcut "First"\nFuncA:    Shortcut "FuncA"\nFuncB:    Shortcut "FuncB"\nSecond:   Shortcut "Second"\n._get
FAILED tests/test_utils_tqdm_mod.py::test_float_alignment_in_bar - assert 3 == 1
 +  where 3 = len({50, 64, 65})
 +    where {50, 64, 65} = set([50, 64, 64, 65, 65])
============ 11 failed, 518 passed, 2 warnings in 161.11s (0:02:41) ============
]0;TerminalERROR conda.cli.main_run:execute(125): `conda run pytest . --continue-on-collection-errors --cov=slic --json-report --json-report-file=markdown/pytest-report.json` failed. (See above for error)

🪵 Full raw pytest log
============================= test session starts ==============================
platform linux -- Python 3.8.20, pytest-8.3.5, pluggy-1.5.0
rootdir: /workspace/tligui_y/slic
plugins: time-machine-2.15.0, metadata-3.1.1, cov-5.0.0, json-report-1.5.0
collected 529 items

morbidissimo/morbidissimo/morioc/test_infer_type.py .................... [  3%]
............                                                             [  6%]
tests/test_utils_argfwd.py ............................                  [ 11%]
tests/test_utils_ask_yes_no.py ........................................  [ 18%]
tests/test_utils_channels.py .                                           [ 19%]
tests/test_utils_config.py ..                                            [ 19%]
tests/test_utils_cpint.py ........................                       [ 24%]
tests/test_utils_dbusnotify.py .......                                   [ 25%]
tests/test_utils_debug.py ......F...F                                    [ 27%]
tests/test_utils_dictext.py .................                            [ 30%]
tests/test_utils_dotdir.py ...                                           [ 31%]
tests/test_utils_duo.py ...........                                      [ 33%]
tests/test_utils_elog.py F.FFF                                           [ 34%]
tests/test_utils_eval.py ......................................          [ 41%]
tests/test_utils_exceptions.py ..........                                [ 43%]
tests/test_utils_get_adj.py ...F                                         [ 44%]
tests/test_utils_ipy.py .                                                [ 44%]
tests/test_utils_jsonext.py ........                                     [ 45%]
tests/test_utils_lazypv.py .                                             [ 45%]
tests/test_utils_logcfg.py ..F                                           [ 46%]
tests/test_utils_logign.py .....                                         [ 47%]
tests/test_utils_marker.py .............                                 [ 49%]
tests/test_utils_metaclasses.py ..                                       [ 50%]
tests/test_utils_namespace.py .                                          [ 50%]
tests/test_utils_npy.py ................................................ [ 59%]
......                                                                   [ 60%]
tests/test_utils_path.py .....                                           [ 61%]
tests/test_utils_picklio.py .......                                      [ 62%]
tests/test_utils_printing.py .......................................     [ 70%]
tests/test_utils_rangebar.py .................                           [ 73%]
tests/test_utils_readable.py ........................                    [ 78%]
tests/test_utils_registry.py ........                                    [ 79%]
tests/test_utils_richcfg.py ╭─ user = <test_utils_richcfg.User object at 0x7feb09898850> ─╮
 Represents a user in the system.                            
                                                             
 ╭─────────────────────────────────────────────────────────╮ 
  <test_utils_richcfg.User object at 0x7feb09898850>       
 ╰─────────────────────────────────────────────────────────╯ 
                                                             
   age = 30                                                  
  name = 'Alice'                                             
  role = 'admin'                                             
 greet = def greet(): Returns a welcome message.             
╰─────────────────────────────────────────────────────────────╯





Type:        User
String form: <test_utils_richcfg.User object at 0x7feb09512e80>
File:        /workspace/tligui_y/slic/tests/test_utils_richcfg.py
Source:     
class User:
    """Represents a user in the system."""

    role = "admin"

    def __init__(self, name: str, age: int):
        self.name = name
        self.age = age

    def greet(self):
        """Returns a welcome message."""
        return f"Welcome, {self.name}!"

.                                            [ 79%]
tests/test_utils_run_later.py ..................                         [ 83%]
tests/test_utils_sendmail.py ..                                          [ 83%]
tests/test_utils_sendsms.py .                                            [ 83%]
tests/test_utils_shortcut.py ..........F....F.                           [ 86%]
tests/test_utils_snapshot.py ........                                    [ 88%]
tests/test_utils_termtitle.py .                                          [ 88%]
tests/test_utils_tqdm_mod.py ...F...                                     [ 89%]
tests/test_utils_trinary.py ...                                          [ 90%]
tests/test_utils_typecast.py .........                                   [ 92%]
tests/test_utils_utils.py ..................................             [ 98%]
tests/test_utils_xrange.py .......                                       [100%]

=================================== FAILURES ===================================
_ test_short_repr[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-10-'aaaaaaaaaa...] _

value = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
cutoff = 10, expected = "'aaaaaaaaaa..."

    @pytest.mark.parametrize(
        "value, cutoff, expected",
        [
            ("abc", 10, "'abc'"),
            ("a" * 100, 10, "'aaaaaaaaaa..."),
            (12345, 10, "12345"),
            ([0]*100, 15, str(repr([0]*100))[:15] + "..."),
            (None, 10, "None"),
            (type("Obj", (), {"__repr__": lambda self: "Obj(" + "x"*50 + ")"})(), 20, "Obj(xxxxxxxxxxxxxxxxx..."),
        ]
    )
    
    def test_short_repr(value, cutoff, expected):
>       assert short_repr(value, cutoff) == expected
E       assert "'aaaaaaaaa..." == "'aaaaaaaaaa..."
E         
E         - 'aaaaaaaaaa...
E         ?  -
E         + 'aaaaaaaaa...

tests/test_utils_debug.py:66: AssertionError
_____________ test_short_repr[value5-20-Obj(xxxxxxxxxxxxxxxxx...] ______________

value = Obj(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx), cutoff = 20
expected = 'Obj(xxxxxxxxxxxxxxxxx...'

    @pytest.mark.parametrize(
        "value, cutoff, expected",
        [
            ("abc", 10, "'abc'"),
            ("a" * 100, 10, "'aaaaaaaaaa..."),
            (12345, 10, "12345"),
            ([0]*100, 15, str(repr([0]*100))[:15] + "..."),
            (None, 10, "None"),
            (type("Obj", (), {"__repr__": lambda self: "Obj(" + "x"*50 + ")"})(), 20, "Obj(xxxxxxxxxxxxxxxxx..."),
        ]
    )
    
    def test_short_repr(value, cutoff, expected):
>       assert short_repr(value, cutoff) == expected
E       AssertionError: assert 'Obj(xxxxxxxxxxxxxxxx...' == 'Obj(xxxxxxxxxxxxxxxxx...'
E         
E         - Obj(xxxxxxxxxxxxxxxxx...
E         ?                     -
E         + Obj(xxxxxxxxxxxxxxxx...

tests/test_utils_debug.py:66: AssertionError
______ test_get_default_elog_instance_with_direct_password_and_real_check ______

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

    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,
            )

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:199: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/connection.py:85: in create_connection
    raise err
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

address = ('localhost', 8080), 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 111] Connection refused

/root/mambaforge/envs/ci-env/lib/python3.8/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 0x7feb09b79910>
method = 'POST', url = '/demo/'
body = b'--06a2aba8224344deb19cc358b997508b\r\nContent-Disposition: form-data; name="Author"\r\n\r\nrobot\r\n--06a2aba8224344...Disposition: form-data; name="Text"; filename=""\r\n\r\nThis is a message1\r\n--06a2aba8224344deb19cc358b997508b--\r\n'
headers = {'User-Agent': 'python-requests/2.32.4', 'Accept-Encoding': 'gzip, deflate, br, zstd', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '736', 'Content-Type': 'multipart/form-data; boundary=06a2aba8224344deb19cc358b997508b'}
retries = Retry(total=0, connect=None, read=False, redirect=None, status=None)
redirect = False, assert_same_host = False
timeout = Timeout(connect=None, read=None, total=None), pool_timeout = None
release_conn = False, chunked = False, body_pos = None, preload_content = False
decode_content = False, response_kw = {}
parsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/demo/', 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,
            )

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:789: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:495: in _make_request
    conn.request(
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:441: in request
    self.endheaders()
/root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1251: in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
/root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1011: in _send_output
    self.send(msg)
/root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:951: in send
    self.connect()
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:279: in connect
    self.sock = self._new_conn()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

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

    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 0x7feb09b79310>: Failed to establish a new connection: [Errno 111] Connection refused

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:214: NewConnectionError

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

self = <requests.adapters.HTTPAdapter object at 0x7feb09b79730>
request = <PreparedRequest [POST]>, stream = False
timeout = Timeout(connect=None, read=None, total=None), verify = False
cert = None, proxies = OrderedDict()

    def send(
        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
    ):
        """Sends PreparedRequest object. Returns Response object.
    
        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
        :param stream: (optional) Whether to stream the request content.
        :param timeout: (optional) How long to wait for the server to send
            data before giving up, as a float, or a :ref:`(connect timeout,
            read timeout) <timeouts>` tuple.
        :type timeout: float or tuple or urllib3 Timeout object
        :param verify: (optional) Either a boolean, in which case it controls whether
            we verify the server's TLS certificate, or a string, in which case it
            must be a path to a CA bundle to use
        :param cert: (optional) Any user-provided SSL certificate to be trusted.
        :param proxies: (optional) The proxies dictionary to apply to the request.
        :rtype: requests.Response
        """
    
        try:
            conn = self.get_connection_with_tls_context(
                request, verify, proxies=proxies, cert=cert
            )
        except LocationValueError as e:
            raise InvalidURL(e, request=request)
    
        self.cert_verify(conn, request.url, verify, cert)
        url = self.request_url(request, proxies)
        self.add_headers(
            request,
            stream=stream,
            timeout=timeout,
            verify=verify,
            cert=cert,
            proxies=proxies,
        )
    
        chunked = not (request.body is None or "Content-Length" in request.headers)
    
        if isinstance(timeout, tuple):
            try:
                connect, read = timeout
                timeout = TimeoutSauce(connect=connect, read=read)
            except ValueError:
                raise ValueError(
                    f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                    f"or a single float to set both timeouts to the same value."
                )
        elif isinstance(timeout, TimeoutSauce):
            pass
        else:
            timeout = TimeoutSauce(connect=timeout, read=timeout)
    
        try:
>           resp = conn.urlopen(
                method=request.method,
                url=url,
                body=request.body,
                headers=request.headers,
                redirect=False,
                assert_same_host=False,
                preload_content=False,
                decode_content=False,
                retries=self.max_retries,
                timeout=timeout,
                chunked=chunked,
            )

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:667: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:843: in urlopen
    retries = retries.increment(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = Retry(total=0, connect=None, read=False, redirect=None, status=None)
method = 'POST', url = '/demo/', response = None
error = NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09b79310>: Failed to establish a new connection: [Errno 111] Connection refused')
_pool = <urllib3.connectionpool.HTTPConnectionPool object at 0x7feb09b79910>
_stacktrace = <traceback object at 0x7feb09b744c0>

    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: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/ (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09b79310>: Failed to establish a new connection: [Errno 111] Connection refused'))

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/retry.py:519: MaxRetryError

During handling of the above exception, another exception occurred:

self = <elog.logbook.Logbook object at 0x7feb09b79e80>
message = 'This is a message1', msg_id = None, reply = False
attributes = {'Author': 'robot', 'When': 1756376001, 'cmd': 'Submit', 'exp': 'demo', ...}
attachments = [], suppress_email_notification = False, encoding = None
timeout = None, kwargs = {'Author': 'robot'}
new_attachment_list = [('Text', ('', b'This is a message1'))]
objects_to_close = []
attributes_to_edit = {'Author': b'robot', 'When': 1756376001, 'cmd': b'Submit', 'exp': b'demo', ...}

    def post(self, message, msg_id=None, reply=False, attributes=None, attachments=None,
             suppress_email_notification=False, encoding=None, timeout=None, **kwargs):
        """
        Posts message to the logbook. If msg_id is not specified new message will be created, otherwise existing
        message will be edited, or a reply (if reply=True) to it will be created. This method returns the msg_id
        of the newly created message.
    
        :param message: string with message text
        :param msg_id: ID number of message to edit or reply. If not specified new message is created.
        :param reply: If 'True' reply to existing message is created instead of editing it
        :param attributes: Dictionary of attributes. Following attributes are used internally by the elog and will be
                           ignored: Text, Date, Encoding, Reply to, In reply to, Locked by, Attachment
        :param attachments: list of:
                                  - file like objects which read() will return bytes (if file_like_object.name is not
                                    defined, default name "attachment<i>" will be used.
                                  - paths to the files
                            All items will be appended as attachment to the elog entry. In case of unknown
                            attachment an exception LogbookInvalidAttachment will be raised.
        :param suppress_email_notification: If set to True or 1, E-Mail notification will be suppressed, defaults to False.
        :param encoding: Defines encoding of the message. Can be: 'plain' -> plain text, 'html'->html-text,
                         'ELCode' --> elog formatting syntax
        :param timeout: Define the timeout to be used by the post request. Its value is directly passed to the requests
                        post. Use None to disable the request timeout.
        :param kwargs: Anything in the kwargs will be interpreted as attribute. e.g.: logbook.post('Test text',
                       Author='Rok Vintar), "Author" will be sent as an attribute. If named same as one of the
                       attributes defined in "attributes", kwargs will have priority.
    
        :return: msg_id
        """
    
        attributes = attributes or {}
        attributes = {**attributes, **kwargs}  # kwargs as attributes with higher priority
    
        attachments = attachments or []
    
        if encoding is not None:
            if encoding not in ['plain', 'HTML', 'ELCode']:
                raise LogbookMessageRejected('Invalid message encoding. Valid options: plain, HTML, ELCode.')
            attributes['Encoding'] = encoding
    
        if suppress_email_notification:
            attributes["suppress"] = 1
    
        # THE ATTACHMENT STRATEGY WHEN DEALING WITH POST MODIFICATION
        #
        # 1. Does the message on the server have already attachments?
        #    1.1 - We read the message getting the existing attachment list.
        #    1.2 - Add to the attributes dictionary one line for each attachment like this:
        #       attributes['attachmentN'] = timestamped_filename_name
        #
        # 2. Do we have new attachments?
        #    2.1 - Those are in the new_attachment_list. This is a list of this type:
        #       [ ('attfileN', ('filename', fileobject)) ]
        #    2.2 - We need to loop over all the new attachments:
        #       2.2.1 - Does a file already on the server with the same name exist?
        #         2.2.1.1 - No: OK. Then we go ahead with the next attachment.
        #         2.2.1.2 - Yes:
        #           2.2.1.2.1 - Are the two files identical?
        #               2.2.1.2.1.1 - Yes: then we remove this current entry from the new_attachment_list and we leave the one
        #                      already on server.
        #               2.2.1.2.1.2 - No:
        #                  2.2.1.2.1.2.1 - Then the file has been update.
        #                  2.2.1.2.1.2.2 - We need to remove the file on server first (using special post)
        #                  2.2.1.2.1.2.3 - We have to remove the old attachment from the attributes dictionary.
        #
    
        if attachments:
            # here we accomplish point 2.1.
            # new_attachment_list is something like [ ('attfileN', ('filename', fileobject)) ]
            new_attachment_list, objects_to_close = self._prepare_attachments(attachments)
        else:
            objects_to_close = list()
            new_attachment_list = list()
    
        attributes_to_edit = dict()
        if msg_id:
            # Message exists, we can continue
            if reply:
                # Verify that there is a message on the server, otherwise do not reply to it!
                self._check_if_message_on_server(msg_id)  # raises exception in case of none existing message
                attributes['reply_to'] = str(msg_id)
            else:  # Edit existing
                attributes['edit_id'] = str(msg_id)
                attributes['skiplock'] = '1'
    
                # here we accomplish point 1.1.
                # existing_attachments_list is something like:
                # [ 'https://elog.url.com/logbook/timestamped_filename' ]
                msg_to_edit, attributes_to_edit, existing_attachments_list = self.read(msg_id)
    
                for attribute, data in attributes.items():
                    new_data = attributes.get(attribute)
                    if new_data is not None:
                        attributes_to_edit[attribute] = new_data
    
                i = 0
                existing_attachments_filename_list = list()
                for attachment in existing_attachments_list:
                    # here we accomplish point 1.2. We strip the timestamped_filename from the whole URL.
                    attributes_to_edit[f'attachment{i}'] = os.path.basename(attachment)
                    existing_attachments_filename_list.append(os.path.basename(attachment)[14:])
                    i += 1
    
                # let's accomplish 2.2. Loop over all new attachment
                duplicate_attachment_list = list()
                for new_attachment in new_attachment_list:
                    # the new_attachment_list is something like:
                    # [ ('attfileN', ('filename', fileobject)) ]
                    new_attachment_filename = new_attachment[1][0]
                    if new_attachment_filename in existing_attachments_filename_list:
                        # a file with the same name existing already on the server.
                        # we need to check if the two files are the same.
                        # read the content of the new file
                        new_attachment_content = new_attachment[1][1].read()
                        # don't forget to reset the fileobj to the beginning of the file
                        new_attachment[1][1].seek(0)
                        # get the existing attachment content
                        attachment_index = existing_attachments_filename_list.index(new_attachment_filename)
                        existing_attachment_content = self.download_attachment(
                            url=existing_attachments_list[attachment_index],
                            timeout=timeout
                        )
                        # check if the two contents are the same
                        if new_attachment_content == existing_attachment_content:
                            # yes. then we don't upload a second copy. we remove the current entry from the list
                            duplicate_attachment_list.append(new_attachment)
                        else:
                            # no. they are not the same file. we will replace the existing file with the new one
                            # first: we need to remove the attachment from the server using the dedicated method
                            self.delete_attachment(msg_id, attributes=attributes_to_edit,
                                                   attachment_id=attachment_index,
                                                   timeout=timeout, text=msg_to_edit)
                            # now we can remove this attachment from the auxiliary lists.
                            existing_attachments_filename_list.pop(attachment_index)
                            existing_attachments_list.pop(attachment_index)
                            # now we need to rebuild the attributes dictionary for the part concerning the attachments.
                            # we remove all of them first
                            keys_to_be_removed = list()
                            for key in attributes_to_edit.keys():
                                if key.startswith('attachment'):
                                    keys_to_be_removed.append(key)
                                if key.startswith('delatt'):
                                    keys_to_be_removed.append(key)
                            for key in keys_to_be_removed:
                                del attributes_to_edit[key]
    
                            # now we rebuild it
                            for i, attachment in enumerate(existing_attachments_list):
                                attributes_to_edit[f'attachment{i}'] = os.path.basename(attachment)
    
                # remove all duplicate attachments from the new_attachment_list
                for attach in duplicate_attachment_list:
                    new_attachment_list.remove(attach)
    
        else:
            # As we create a new message, specify creation time if not already specified in attributes
            if 'When' not in attributes:
                attributes['When'] = int(datetime.now().timestamp())
    
        if not attributes_to_edit:
            attributes_to_edit = attributes
    
        # Remove any attributes that should not be sent
        _remove_reserved_attributes(attributes_to_edit)
    
        # Make requests module think that Text is a "file". This is the only way to force requests to send data as
        # multipart/form-data even if there are no attachments. Elog understands only multipart/form-data
        new_attachment_list.append(('Text', ('', message.encode('iso-8859-1'))))
    
        # Base attributes are common to all messages
        self._add_base_msg_attributes(attributes_to_edit)
    
        # Keys in attributes cannot have certain characters like whitespaces or dashes for the http request
        attributes_to_edit = _replace_special_characters_in_attribute_keys(attributes_to_edit)
    
        # All string values in the attributes must be encoded in latin1
        attributes_to_edit = _encode_values(attributes_to_edit)
    
        try:
>           response = requests.post(self._url, data=attributes_to_edit, files=new_attachment_list,
                                     allow_redirects=False, verify=False, timeout=timeout)

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:288: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:115: in post
    return request("post", url, data=data, json=json, **kwargs)
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:59: in request
    return session.request(method=method, url=url, **kwargs)
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:589: in request
    resp = self.send(prep, **send_kwargs)
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:703: in send
    r = adapter.send(request, **kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <requests.adapters.HTTPAdapter object at 0x7feb09b79730>
request = <PreparedRequest [POST]>, stream = False
timeout = Timeout(connect=None, read=None, total=None), verify = False
cert = None, proxies = OrderedDict()

    def send(
        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
    ):
        """Sends PreparedRequest object. Returns Response object.
    
        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
        :param stream: (optional) Whether to stream the request content.
        :param timeout: (optional) How long to wait for the server to send
            data before giving up, as a float, or a :ref:`(connect timeout,
            read timeout) <timeouts>` tuple.
        :type timeout: float or tuple or urllib3 Timeout object
        :param verify: (optional) Either a boolean, in which case it controls whether
            we verify the server's TLS certificate, or a string, in which case it
            must be a path to a CA bundle to use
        :param cert: (optional) Any user-provided SSL certificate to be trusted.
        :param proxies: (optional) The proxies dictionary to apply to the request.
        :rtype: requests.Response
        """
    
        try:
            conn = self.get_connection_with_tls_context(
                request, verify, proxies=proxies, cert=cert
            )
        except LocationValueError as e:
            raise InvalidURL(e, request=request)
    
        self.cert_verify(conn, request.url, verify, cert)
        url = self.request_url(request, proxies)
        self.add_headers(
            request,
            stream=stream,
            timeout=timeout,
            verify=verify,
            cert=cert,
            proxies=proxies,
        )
    
        chunked = not (request.body is None or "Content-Length" in request.headers)
    
        if isinstance(timeout, tuple):
            try:
                connect, read = timeout
                timeout = TimeoutSauce(connect=connect, read=read)
            except ValueError:
                raise ValueError(
                    f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                    f"or a single float to set both timeouts to the same value."
                )
        elif isinstance(timeout, TimeoutSauce):
            pass
        else:
            timeout = TimeoutSauce(connect=timeout, read=timeout)
    
        try:
            resp = conn.urlopen(
                method=request.method,
                url=url,
                body=request.body,
                headers=request.headers,
                redirect=False,
                assert_same_host=False,
                preload_content=False,
                decode_content=False,
                retries=self.max_retries,
                timeout=timeout,
                chunked=chunked,
            )
    
        except (ProtocolError, OSError) as err:
            raise ConnectionError(err, request=request)
    
        except MaxRetryError as e:
            if isinstance(e.reason, ConnectTimeoutError):
                # TODO: Remove this in 3.0.0: see #2811
                if not isinstance(e.reason, NewConnectionError):
                    raise ConnectTimeout(e, request=request)
    
            if isinstance(e.reason, ResponseError):
                raise RetryError(e, request=request)
    
            if isinstance(e.reason, _ProxyError):
                raise ProxyError(e, request=request)
    
            if isinstance(e.reason, _SSLError):
                # This branch is for urllib3 v1.22 and later.
                raise SSLError(e, request=request)
    
>           raise ConnectionError(e, request=request)
E           requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/ (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09b79310>: Failed to establish a new connection: [Errno 111] Connection refused'))

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:700: ConnectionError

During handling of the above exception, another exception occurred:

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

    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,
            )

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:199: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/connection.py:85: in create_connection
    raise err
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

address = ('localhost', 8080), 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 111] Connection refused

/root/mambaforge/envs/ci-env/lib/python3.8/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 0x7feb09b7e820>
method = 'GET', url = '/demo/None', body = None
headers = {'User-Agent': 'python-requests/2.32.4', 'Accept-Encoding': 'gzip, deflate, br, zstd', 'Accept': '*/*', 'Connection': 'keep-alive', 'Cookie': 'unm=robot;upwd=me1T.2jUUqQNa1wNuey9zNBOmOa4eILOaPb.ZSZjpn4;'}
retries = Retry(total=0, connect=None, read=False, redirect=None, status=None)
redirect = False, assert_same_host = False
timeout = Timeout(connect=None, read=None, total=None), pool_timeout = None
release_conn = False, chunked = False, body_pos = None, preload_content = False
decode_content = False, response_kw = {}
parsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/demo/None', 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,
            )

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:789: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:495: in _make_request
    conn.request(
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:441: in request
    self.endheaders()
/root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1251: in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
/root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1011: in _send_output
    self.send(msg)
/root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:951: in send
    self.connect()
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:279: in connect
    self.sock = self._new_conn()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

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

    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 0x7feb09b7e4f0>: Failed to establish a new connection: [Errno 111] Connection refused

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:214: NewConnectionError

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

self = <requests.adapters.HTTPAdapter object at 0x7feb09b7ea00>
request = <PreparedRequest [GET]>, stream = False
timeout = Timeout(connect=None, read=None, total=None), verify = False
cert = None, proxies = OrderedDict()

    def send(
        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
    ):
        """Sends PreparedRequest object. Returns Response object.
    
        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
        :param stream: (optional) Whether to stream the request content.
        :param timeout: (optional) How long to wait for the server to send
            data before giving up, as a float, or a :ref:`(connect timeout,
            read timeout) <timeouts>` tuple.
        :type timeout: float or tuple or urllib3 Timeout object
        :param verify: (optional) Either a boolean, in which case it controls whether
            we verify the server's TLS certificate, or a string, in which case it
            must be a path to a CA bundle to use
        :param cert: (optional) Any user-provided SSL certificate to be trusted.
        :param proxies: (optional) The proxies dictionary to apply to the request.
        :rtype: requests.Response
        """
    
        try:
            conn = self.get_connection_with_tls_context(
                request, verify, proxies=proxies, cert=cert
            )
        except LocationValueError as e:
            raise InvalidURL(e, request=request)
    
        self.cert_verify(conn, request.url, verify, cert)
        url = self.request_url(request, proxies)
        self.add_headers(
            request,
            stream=stream,
            timeout=timeout,
            verify=verify,
            cert=cert,
            proxies=proxies,
        )
    
        chunked = not (request.body is None or "Content-Length" in request.headers)
    
        if isinstance(timeout, tuple):
            try:
                connect, read = timeout
                timeout = TimeoutSauce(connect=connect, read=read)
            except ValueError:
                raise ValueError(
                    f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                    f"or a single float to set both timeouts to the same value."
                )
        elif isinstance(timeout, TimeoutSauce):
            pass
        else:
            timeout = TimeoutSauce(connect=timeout, read=timeout)
    
        try:
>           resp = conn.urlopen(
                method=request.method,
                url=url,
                body=request.body,
                headers=request.headers,
                redirect=False,
                assert_same_host=False,
                preload_content=False,
                decode_content=False,
                retries=self.max_retries,
                timeout=timeout,
                chunked=chunked,
            )

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:667: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:843: in urlopen
    retries = retries.increment(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = Retry(total=0, connect=None, read=False, redirect=None, status=None)
method = 'GET', url = '/demo/None', response = None
error = NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09b7e4f0>: Failed to establish a new connection: [Errno 111] Connection refused')
_pool = <urllib3.connectionpool.HTTPConnectionPool object at 0x7feb09b7e820>
_stacktrace = <traceback object at 0x7feb09bbad40>

    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: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09b7e4f0>: Failed to establish a new connection: [Errno 111] Connection refused'))

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/retry.py:519: MaxRetryError

During handling of the above exception, another exception occurred:

self = <elog.logbook.Logbook object at 0x7feb09b79e80>, msg_id = None
timeout = None

    def _check_if_message_on_server(self, msg_id, timeout=None):
        """Try to load page for specific message. If there is a html tag like <td class="errormsg"> then there is no
        such message.
    
        :param msg_id: ID of message to be checked
        :params timeout: The value of timeout to be passed to the get request
        :return:
        """
    
        request_headers = dict()
        if self._user or self._password:
            request_headers['Cookie'] = self._make_user_and_pswd_cookie()
        try:
>           response = requests.get(self._url + str(msg_id), headers=request_headers, allow_redirects=False,
                                    verify=False, timeout=timeout)

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:581: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:73: in get
    return request("get", url, params=params, **kwargs)
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:59: in request
    return session.request(method=method, url=url, **kwargs)
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:589: in request
    resp = self.send(prep, **send_kwargs)
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:703: in send
    r = adapter.send(request, **kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <requests.adapters.HTTPAdapter object at 0x7feb09b7ea00>
request = <PreparedRequest [GET]>, stream = False
timeout = Timeout(connect=None, read=None, total=None), verify = False
cert = None, proxies = OrderedDict()

    def send(
        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
    ):
        """Sends PreparedRequest object. Returns Response object.
    
        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
        :param stream: (optional) Whether to stream the request content.
        :param timeout: (optional) How long to wait for the server to send
            data before giving up, as a float, or a :ref:`(connect timeout,
            read timeout) <timeouts>` tuple.
        :type timeout: float or tuple or urllib3 Timeout object
        :param verify: (optional) Either a boolean, in which case it controls whether
            we verify the server's TLS certificate, or a string, in which case it
            must be a path to a CA bundle to use
        :param cert: (optional) Any user-provided SSL certificate to be trusted.
        :param proxies: (optional) The proxies dictionary to apply to the request.
        :rtype: requests.Response
        """
    
        try:
            conn = self.get_connection_with_tls_context(
                request, verify, proxies=proxies, cert=cert
            )
        except LocationValueError as e:
            raise InvalidURL(e, request=request)
    
        self.cert_verify(conn, request.url, verify, cert)
        url = self.request_url(request, proxies)
        self.add_headers(
            request,
            stream=stream,
            timeout=timeout,
            verify=verify,
            cert=cert,
            proxies=proxies,
        )
    
        chunked = not (request.body is None or "Content-Length" in request.headers)
    
        if isinstance(timeout, tuple):
            try:
                connect, read = timeout
                timeout = TimeoutSauce(connect=connect, read=read)
            except ValueError:
                raise ValueError(
                    f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                    f"or a single float to set both timeouts to the same value."
                )
        elif isinstance(timeout, TimeoutSauce):
            pass
        else:
            timeout = TimeoutSauce(connect=timeout, read=timeout)
    
        try:
            resp = conn.urlopen(
                method=request.method,
                url=url,
                body=request.body,
                headers=request.headers,
                redirect=False,
                assert_same_host=False,
                preload_content=False,
                decode_content=False,
                retries=self.max_retries,
                timeout=timeout,
                chunked=chunked,
            )
    
        except (ProtocolError, OSError) as err:
            raise ConnectionError(err, request=request)
    
        except MaxRetryError as e:
            if isinstance(e.reason, ConnectTimeoutError):
                # TODO: Remove this in 3.0.0: see #2811
                if not isinstance(e.reason, NewConnectionError):
                    raise ConnectTimeout(e, request=request)
    
            if isinstance(e.reason, ResponseError):
                raise RetryError(e, request=request)
    
            if isinstance(e.reason, _ProxyError):
                raise ProxyError(e, request=request)
    
            if isinstance(e.reason, _SSLError):
                # This branch is for urllib3 v1.22 and later.
                raise SSLError(e, request=request)
    
>           raise ConnectionError(e, request=request)
E           requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09b7e4f0>: Failed to establish a new connection: [Errno 111] Connection refused'))

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:700: ConnectionError

During handling of the above exception, another exception occurred:

    def test_get_default_elog_instance_with_direct_password_and_real_check():
        url = "http://localhost:8080/demo"
        user = "robot"
        password = "testpassword"
        text = "This is a message1"
    
        elog = Elog("http://localhost:8080/demo", user=user, password=password)
    
        try:
>           msg_id = elog.post(text)

tests/test_utils_elog.py:22: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
slic/utils/elog.py:16: in post
    return self._log.post(*args, **kwargs)
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:307: in post
    self._check_if_message_on_server(msg_id)  # raises exceptions if no message or no response from server
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <elog.logbook.Logbook object at 0x7feb09b79e80>, msg_id = None
timeout = None

    def _check_if_message_on_server(self, msg_id, timeout=None):
        """Try to load page for specific message. If there is a html tag like <td class="errormsg"> then there is no
        such message.
    
        :param msg_id: ID of message to be checked
        :params timeout: The value of timeout to be passed to the get request
        :return:
        """
    
        request_headers = dict()
        if self._user or self._password:
            request_headers['Cookie'] = self._make_user_and_pswd_cookie()
        try:
            response = requests.get(self._url + str(msg_id), headers=request_headers, allow_redirects=False,
                                    verify=False, timeout=timeout)
    
            # If there is no message code 200 will be returned (OK) and _validate_response will not recognise it
            # but there will be some error in the html code.
            resp_message, resp_headers, resp_msg_id = _validate_response(response)
            # If there is no message, code 200 will be returned (OK) but there will be some error indication in
            # the html code.
            if re.findall('<td.*?class="errormsg".*?>.*?</td>',
                          resp_message.decode('utf-8', 'ignore'),
                          flags=re.DOTALL):
                raise LogbookInvalidMessageID('Message with ID: ' + str(msg_id) + ' does not exist on logbook.')
    
        except requests.Timeout as e:
            # Catch here a timeout o the post request.
            # Raise the logbook exception and let the user handle it
            raise LogbookServerTimeout('{0} method cannot be completed because of a network timeout:\n' +
                                       '{1}'.format(sys._getframe().f_code.co_name, e))
    
        except requests.RequestException as e:
>           raise LogbookServerProblem('No response from the logbook server.\nDetails: ' + '{0}'.format(e))
E           elog.logbook_exceptions.LogbookServerProblem: No response from the logbook server.
E           Details: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09b7e4f0>: Failed to establish a new connection: [Errno 111] Connection refused'))

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:601: LogbookServerProblem

During handling of the above exception, another exception occurred:

    def test_get_default_elog_instance_with_direct_password_and_real_check():
        url = "http://localhost:8080/demo"
        user = "robot"
        password = "testpassword"
        text = "This is a message1"
    
        elog = Elog("http://localhost:8080/demo", user=user, password=password)
    
        try:
            msg_id = elog.post(text)
        except Exception as e:
>           pytest.fail(f"elog.post() raised an unexpected exception: {e}")
E           Failed: elog.post() raised an unexpected exception: No response from the logbook server.
E           Details: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09b7e4f0>: Failed to establish a new connection: [Errno 111] Connection refused'))

tests/test_utils_elog.py:24: Failed
____________ test_get_default_elog_instance_asks_password_and_opens ____________

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

    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,
            )

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:199: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/connection.py:85: in create_connection
    raise err
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

address = ('localhost', 8080), 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 111] Connection refused

/root/mambaforge/envs/ci-env/lib/python3.8/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 0x7feb09830bb0>
method = 'POST', url = '/demo/'
body = b'--aa75161c22b288663152f49dada5f35f\r\nContent-Disposition: form-data; name="Author"\r\n\r\nrobot\r\n--aa75161c22b288...Disposition: form-data; name="Text"; filename=""\r\n\r\nThis is a message2\r\n--aa75161c22b288663152f49dada5f35f--\r\n'
headers = {'User-Agent': 'python-requests/2.32.4', 'Accept-Encoding': 'gzip, deflate, br, zstd', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '736', 'Content-Type': 'multipart/form-data; boundary=aa75161c22b288663152f49dada5f35f'}
retries = Retry(total=0, connect=None, read=False, redirect=None, status=None)
redirect = False, assert_same_host = False
timeout = Timeout(connect=None, read=None, total=None), pool_timeout = None
release_conn = False, chunked = False, body_pos = None, preload_content = False
decode_content = False, response_kw = {}
parsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/demo/', 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,
            )

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:789: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:495: in _make_request
    conn.request(
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:441: in request
    self.endheaders()
/root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1251: in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
/root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1011: in _send_output
    self.send(msg)
/root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:951: in send
    self.connect()
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:279: in connect
    self.sock = self._new_conn()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

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

    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 0x7feb09830f40>: Failed to establish a new connection: [Errno 111] Connection refused

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:214: NewConnectionError

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

self = <requests.adapters.HTTPAdapter object at 0x7feb0522b790>
request = <PreparedRequest [POST]>, stream = False
timeout = Timeout(connect=None, read=None, total=None), verify = False
cert = None, proxies = OrderedDict()

    def send(
        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
    ):
        """Sends PreparedRequest object. Returns Response object.
    
        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
        :param stream: (optional) Whether to stream the request content.
        :param timeout: (optional) How long to wait for the server to send
            data before giving up, as a float, or a :ref:`(connect timeout,
            read timeout) <timeouts>` tuple.
        :type timeout: float or tuple or urllib3 Timeout object
        :param verify: (optional) Either a boolean, in which case it controls whether
            we verify the server's TLS certificate, or a string, in which case it
            must be a path to a CA bundle to use
        :param cert: (optional) Any user-provided SSL certificate to be trusted.
        :param proxies: (optional) The proxies dictionary to apply to the request.
        :rtype: requests.Response
        """
    
        try:
            conn = self.get_connection_with_tls_context(
                request, verify, proxies=proxies, cert=cert
            )
        except LocationValueError as e:
            raise InvalidURL(e, request=request)
    
        self.cert_verify(conn, request.url, verify, cert)
        url = self.request_url(request, proxies)
        self.add_headers(
            request,
            stream=stream,
            timeout=timeout,
            verify=verify,
            cert=cert,
            proxies=proxies,
        )
    
        chunked = not (request.body is None or "Content-Length" in request.headers)
    
        if isinstance(timeout, tuple):
            try:
                connect, read = timeout
                timeout = TimeoutSauce(connect=connect, read=read)
            except ValueError:
                raise ValueError(
                    f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                    f"or a single float to set both timeouts to the same value."
                )
        elif isinstance(timeout, TimeoutSauce):
            pass
        else:
            timeout = TimeoutSauce(connect=timeout, read=timeout)
    
        try:
>           resp = conn.urlopen(
                method=request.method,
                url=url,
                body=request.body,
                headers=request.headers,
                redirect=False,
                assert_same_host=False,
                preload_content=False,
                decode_content=False,
                retries=self.max_retries,
                timeout=timeout,
                chunked=chunked,
            )

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:667: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:843: in urlopen
    retries = retries.increment(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = Retry(total=0, connect=None, read=False, redirect=None, status=None)
method = 'POST', url = '/demo/', response = None
error = NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09830f40>: Failed to establish a new connection: [Errno 111] Connection refused')
_pool = <urllib3.connectionpool.HTTPConnectionPool object at 0x7feb09830bb0>
_stacktrace = <traceback object at 0x7feb09590040>

    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: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/ (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09830f40>: Failed to establish a new connection: [Errno 111] Connection refused'))

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/retry.py:519: MaxRetryError

During handling of the above exception, another exception occurred:

self = <elog.logbook.Logbook object at 0x7feb05e26fd0>
message = 'This is a message2', msg_id = None, reply = False
attributes = {'Author': 'robot', 'When': 1756376002, 'cmd': 'Submit', 'exp': 'demo', ...}
attachments = [], suppress_email_notification = False, encoding = None
timeout = None, kwargs = {'Author': 'robot'}
new_attachment_list = [('Text', ('', b'This is a message2'))]
objects_to_close = []
attributes_to_edit = {'Author': b'robot', 'When': 1756376002, 'cmd': b'Submit', 'exp': b'demo', ...}

    def post(self, message, msg_id=None, reply=False, attributes=None, attachments=None,
             suppress_email_notification=False, encoding=None, timeout=None, **kwargs):
        """
        Posts message to the logbook. If msg_id is not specified new message will be created, otherwise existing
        message will be edited, or a reply (if reply=True) to it will be created. This method returns the msg_id
        of the newly created message.
    
        :param message: string with message text
        :param msg_id: ID number of message to edit or reply. If not specified new message is created.
        :param reply: If 'True' reply to existing message is created instead of editing it
        :param attributes: Dictionary of attributes. Following attributes are used internally by the elog and will be
                           ignored: Text, Date, Encoding, Reply to, In reply to, Locked by, Attachment
        :param attachments: list of:
                                  - file like objects which read() will return bytes (if file_like_object.name is not
                                    defined, default name "attachment<i>" will be used.
                                  - paths to the files
                            All items will be appended as attachment to the elog entry. In case of unknown
                            attachment an exception LogbookInvalidAttachment will be raised.
        :param suppress_email_notification: If set to True or 1, E-Mail notification will be suppressed, defaults to False.
        :param encoding: Defines encoding of the message. Can be: 'plain' -> plain text, 'html'->html-text,
                         'ELCode' --> elog formatting syntax
        :param timeout: Define the timeout to be used by the post request. Its value is directly passed to the requests
                        post. Use None to disable the request timeout.
        :param kwargs: Anything in the kwargs will be interpreted as attribute. e.g.: logbook.post('Test text',
                       Author='Rok Vintar), "Author" will be sent as an attribute. If named same as one of the
                       attributes defined in "attributes", kwargs will have priority.
    
        :return: msg_id
        """
    
        attributes = attributes or {}
        attributes = {**attributes, **kwargs}  # kwargs as attributes with higher priority
    
        attachments = attachments or []
    
        if encoding is not None:
            if encoding not in ['plain', 'HTML', 'ELCode']:
                raise LogbookMessageRejected('Invalid message encoding. Valid options: plain, HTML, ELCode.')
            attributes['Encoding'] = encoding
    
        if suppress_email_notification:
            attributes["suppress"] = 1
    
        # THE ATTACHMENT STRATEGY WHEN DEALING WITH POST MODIFICATION
        #
        # 1. Does the message on the server have already attachments?
        #    1.1 - We read the message getting the existing attachment list.
        #    1.2 - Add to the attributes dictionary one line for each attachment like this:
        #       attributes['attachmentN'] = timestamped_filename_name
        #
        # 2. Do we have new attachments?
        #    2.1 - Those are in the new_attachment_list. This is a list of this type:
        #       [ ('attfileN', ('filename', fileobject)) ]
        #    2.2 - We need to loop over all the new attachments:
        #       2.2.1 - Does a file already on the server with the same name exist?
        #         2.2.1.1 - No: OK. Then we go ahead with the next attachment.
        #         2.2.1.2 - Yes:
        #           2.2.1.2.1 - Are the two files identical?
        #               2.2.1.2.1.1 - Yes: then we remove this current entry from the new_attachment_list and we leave the one
        #                      already on server.
        #               2.2.1.2.1.2 - No:
        #                  2.2.1.2.1.2.1 - Then the file has been update.
        #                  2.2.1.2.1.2.2 - We need to remove the file on server first (using special post)
        #                  2.2.1.2.1.2.3 - We have to remove the old attachment from the attributes dictionary.
        #
    
        if attachments:
            # here we accomplish point 2.1.
            # new_attachment_list is something like [ ('attfileN', ('filename', fileobject)) ]
            new_attachment_list, objects_to_close = self._prepare_attachments(attachments)
        else:
            objects_to_close = list()
            new_attachment_list = list()
    
        attributes_to_edit = dict()
        if msg_id:
            # Message exists, we can continue
            if reply:
                # Verify that there is a message on the server, otherwise do not reply to it!
                self._check_if_message_on_server(msg_id)  # raises exception in case of none existing message
                attributes['reply_to'] = str(msg_id)
            else:  # Edit existing
                attributes['edit_id'] = str(msg_id)
                attributes['skiplock'] = '1'
    
                # here we accomplish point 1.1.
                # existing_attachments_list is something like:
                # [ 'https://elog.url.com/logbook/timestamped_filename' ]
                msg_to_edit, attributes_to_edit, existing_attachments_list = self.read(msg_id)
    
                for attribute, data in attributes.items():
                    new_data = attributes.get(attribute)
                    if new_data is not None:
                        attributes_to_edit[attribute] = new_data
    
                i = 0
                existing_attachments_filename_list = list()
                for attachment in existing_attachments_list:
                    # here we accomplish point 1.2. We strip the timestamped_filename from the whole URL.
                    attributes_to_edit[f'attachment{i}'] = os.path.basename(attachment)
                    existing_attachments_filename_list.append(os.path.basename(attachment)[14:])
                    i += 1
    
                # let's accomplish 2.2. Loop over all new attachment
                duplicate_attachment_list = list()
                for new_attachment in new_attachment_list:
                    # the new_attachment_list is something like:
                    # [ ('attfileN', ('filename', fileobject)) ]
                    new_attachment_filename = new_attachment[1][0]
                    if new_attachment_filename in existing_attachments_filename_list:
                        # a file with the same name existing already on the server.
                        # we need to check if the two files are the same.
                        # read the content of the new file
                        new_attachment_content = new_attachment[1][1].read()
                        # don't forget to reset the fileobj to the beginning of the file
                        new_attachment[1][1].seek(0)
                        # get the existing attachment content
                        attachment_index = existing_attachments_filename_list.index(new_attachment_filename)
                        existing_attachment_content = self.download_attachment(
                            url=existing_attachments_list[attachment_index],
                            timeout=timeout
                        )
                        # check if the two contents are the same
                        if new_attachment_content == existing_attachment_content:
                            # yes. then we don't upload a second copy. we remove the current entry from the list
                            duplicate_attachment_list.append(new_attachment)
                        else:
                            # no. they are not the same file. we will replace the existing file with the new one
                            # first: we need to remove the attachment from the server using the dedicated method
                            self.delete_attachment(msg_id, attributes=attributes_to_edit,
                                                   attachment_id=attachment_index,
                                                   timeout=timeout, text=msg_to_edit)
                            # now we can remove this attachment from the auxiliary lists.
                            existing_attachments_filename_list.pop(attachment_index)
                            existing_attachments_list.pop(attachment_index)
                            # now we need to rebuild the attributes dictionary for the part concerning the attachments.
                            # we remove all of them first
                            keys_to_be_removed = list()
                            for key in attributes_to_edit.keys():
                                if key.startswith('attachment'):
                                    keys_to_be_removed.append(key)
                                if key.startswith('delatt'):
                                    keys_to_be_removed.append(key)
                            for key in keys_to_be_removed:
                                del attributes_to_edit[key]
    
                            # now we rebuild it
                            for i, attachment in enumerate(existing_attachments_list):
                                attributes_to_edit[f'attachment{i}'] = os.path.basename(attachment)
    
                # remove all duplicate attachments from the new_attachment_list
                for attach in duplicate_attachment_list:
                    new_attachment_list.remove(attach)
    
        else:
            # As we create a new message, specify creation time if not already specified in attributes
            if 'When' not in attributes:
                attributes['When'] = int(datetime.now().timestamp())
    
        if not attributes_to_edit:
            attributes_to_edit = attributes
    
        # Remove any attributes that should not be sent
        _remove_reserved_attributes(attributes_to_edit)
    
        # Make requests module think that Text is a "file". This is the only way to force requests to send data as
        # multipart/form-data even if there are no attachments. Elog understands only multipart/form-data
        new_attachment_list.append(('Text', ('', message.encode('iso-8859-1'))))
    
        # Base attributes are common to all messages
        self._add_base_msg_attributes(attributes_to_edit)
    
        # Keys in attributes cannot have certain characters like whitespaces or dashes for the http request
        attributes_to_edit = _replace_special_characters_in_attribute_keys(attributes_to_edit)
    
        # All string values in the attributes must be encoded in latin1
        attributes_to_edit = _encode_values(attributes_to_edit)
    
        try:
>           response = requests.post(self._url, data=attributes_to_edit, files=new_attachment_list,
                                     allow_redirects=False, verify=False, timeout=timeout)

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:288: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:115: in post
    return request("post", url, data=data, json=json, **kwargs)
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:59: in request
    return session.request(method=method, url=url, **kwargs)
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:589: in request
    resp = self.send(prep, **send_kwargs)
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:703: in send
    r = adapter.send(request, **kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <requests.adapters.HTTPAdapter object at 0x7feb0522b790>
request = <PreparedRequest [POST]>, stream = False
timeout = Timeout(connect=None, read=None, total=None), verify = False
cert = None, proxies = OrderedDict()

    def send(
        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
    ):
        """Sends PreparedRequest object. Returns Response object.
    
        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
        :param stream: (optional) Whether to stream the request content.
        :param timeout: (optional) How long to wait for the server to send
            data before giving up, as a float, or a :ref:`(connect timeout,
            read timeout) <timeouts>` tuple.
        :type timeout: float or tuple or urllib3 Timeout object
        :param verify: (optional) Either a boolean, in which case it controls whether
            we verify the server's TLS certificate, or a string, in which case it
            must be a path to a CA bundle to use
        :param cert: (optional) Any user-provided SSL certificate to be trusted.
        :param proxies: (optional) The proxies dictionary to apply to the request.
        :rtype: requests.Response
        """
    
        try:
            conn = self.get_connection_with_tls_context(
                request, verify, proxies=proxies, cert=cert
            )
        except LocationValueError as e:
            raise InvalidURL(e, request=request)
    
        self.cert_verify(conn, request.url, verify, cert)
        url = self.request_url(request, proxies)
        self.add_headers(
            request,
            stream=stream,
            timeout=timeout,
            verify=verify,
            cert=cert,
            proxies=proxies,
        )
    
        chunked = not (request.body is None or "Content-Length" in request.headers)
    
        if isinstance(timeout, tuple):
            try:
                connect, read = timeout
                timeout = TimeoutSauce(connect=connect, read=read)
            except ValueError:
                raise ValueError(
                    f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                    f"or a single float to set both timeouts to the same value."
                )
        elif isinstance(timeout, TimeoutSauce):
            pass
        else:
            timeout = TimeoutSauce(connect=timeout, read=timeout)
    
        try:
            resp = conn.urlopen(
                method=request.method,
                url=url,
                body=request.body,
                headers=request.headers,
                redirect=False,
                assert_same_host=False,
                preload_content=False,
                decode_content=False,
                retries=self.max_retries,
                timeout=timeout,
                chunked=chunked,
            )
    
        except (ProtocolError, OSError) as err:
            raise ConnectionError(err, request=request)
    
        except MaxRetryError as e:
            if isinstance(e.reason, ConnectTimeoutError):
                # TODO: Remove this in 3.0.0: see #2811
                if not isinstance(e.reason, NewConnectionError):
                    raise ConnectTimeout(e, request=request)
    
            if isinstance(e.reason, ResponseError):
                raise RetryError(e, request=request)
    
            if isinstance(e.reason, _ProxyError):
                raise ProxyError(e, request=request)
    
            if isinstance(e.reason, _SSLError):
                # This branch is for urllib3 v1.22 and later.
                raise SSLError(e, request=request)
    
>           raise ConnectionError(e, request=request)
E           requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/ (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09830f40>: Failed to establish a new connection: [Errno 111] Connection refused'))

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:700: ConnectionError

During handling of the above exception, another exception occurred:

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

    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,
            )

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:199: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/connection.py:85: in create_connection
    raise err
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

address = ('localhost', 8080), 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 111] Connection refused

/root/mambaforge/envs/ci-env/lib/python3.8/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 0x7feb09830640>
method = 'GET', url = '/demo/None', body = None
headers = {'User-Agent': 'python-requests/2.32.4', 'Accept-Encoding': 'gzip, deflate, br, zstd', 'Accept': '*/*', 'Connection': 'keep-alive', 'Cookie': 'unm=robot;upwd=me1T.2jUUqQNa1wNuey9zNBOmOa4eILOaPb.ZSZjpn4;'}
retries = Retry(total=0, connect=None, read=False, redirect=None, status=None)
redirect = False, assert_same_host = False
timeout = Timeout(connect=None, read=None, total=None), pool_timeout = None
release_conn = False, chunked = False, body_pos = None, preload_content = False
decode_content = False, response_kw = {}
parsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/demo/None', 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,
            )

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:789: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:495: in _make_request
    conn.request(
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:441: in request
    self.endheaders()
/root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1251: in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
/root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1011: in _send_output
    self.send(msg)
/root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:951: in send
    self.connect()
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:279: in connect
    self.sock = self._new_conn()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

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

    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 0x7feb098025b0>: Failed to establish a new connection: [Errno 111] Connection refused

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:214: NewConnectionError

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

self = <requests.adapters.HTTPAdapter object at 0x7feb098307f0>
request = <PreparedRequest [GET]>, stream = False
timeout = Timeout(connect=None, read=None, total=None), verify = False
cert = None, proxies = OrderedDict()

    def send(
        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
    ):
        """Sends PreparedRequest object. Returns Response object.
    
        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
        :param stream: (optional) Whether to stream the request content.
        :param timeout: (optional) How long to wait for the server to send
            data before giving up, as a float, or a :ref:`(connect timeout,
            read timeout) <timeouts>` tuple.
        :type timeout: float or tuple or urllib3 Timeout object
        :param verify: (optional) Either a boolean, in which case it controls whether
            we verify the server's TLS certificate, or a string, in which case it
            must be a path to a CA bundle to use
        :param cert: (optional) Any user-provided SSL certificate to be trusted.
        :param proxies: (optional) The proxies dictionary to apply to the request.
        :rtype: requests.Response
        """
    
        try:
            conn = self.get_connection_with_tls_context(
                request, verify, proxies=proxies, cert=cert
            )
        except LocationValueError as e:
            raise InvalidURL(e, request=request)
    
        self.cert_verify(conn, request.url, verify, cert)
        url = self.request_url(request, proxies)
        self.add_headers(
            request,
            stream=stream,
            timeout=timeout,
            verify=verify,
            cert=cert,
            proxies=proxies,
        )
    
        chunked = not (request.body is None or "Content-Length" in request.headers)
    
        if isinstance(timeout, tuple):
            try:
                connect, read = timeout
                timeout = TimeoutSauce(connect=connect, read=read)
            except ValueError:
                raise ValueError(
                    f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                    f"or a single float to set both timeouts to the same value."
                )
        elif isinstance(timeout, TimeoutSauce):
            pass
        else:
            timeout = TimeoutSauce(connect=timeout, read=timeout)
    
        try:
>           resp = conn.urlopen(
                method=request.method,
                url=url,
                body=request.body,
                headers=request.headers,
                redirect=False,
                assert_same_host=False,
                preload_content=False,
                decode_content=False,
                retries=self.max_retries,
                timeout=timeout,
                chunked=chunked,
            )

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:667: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:843: in urlopen
    retries = retries.increment(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = Retry(total=0, connect=None, read=False, redirect=None, status=None)
method = 'GET', url = '/demo/None', response = None
error = NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb098025b0>: Failed to establish a new connection: [Errno 111] Connection refused')
_pool = <urllib3.connectionpool.HTTPConnectionPool object at 0x7feb09830640>
_stacktrace = <traceback object at 0x7feb09803440>

    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: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb098025b0>: Failed to establish a new connection: [Errno 111] Connection refused'))

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/retry.py:519: MaxRetryError

During handling of the above exception, another exception occurred:

self = <elog.logbook.Logbook object at 0x7feb05e26fd0>, msg_id = None
timeout = None

    def _check_if_message_on_server(self, msg_id, timeout=None):
        """Try to load page for specific message. If there is a html tag like <td class="errormsg"> then there is no
        such message.
    
        :param msg_id: ID of message to be checked
        :params timeout: The value of timeout to be passed to the get request
        :return:
        """
    
        request_headers = dict()
        if self._user or self._password:
            request_headers['Cookie'] = self._make_user_and_pswd_cookie()
        try:
>           response = requests.get(self._url + str(msg_id), headers=request_headers, allow_redirects=False,
                                    verify=False, timeout=timeout)

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:581: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:73: in get
    return request("get", url, params=params, **kwargs)
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:59: in request
    return session.request(method=method, url=url, **kwargs)
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:589: in request
    resp = self.send(prep, **send_kwargs)
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:703: in send
    r = adapter.send(request, **kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <requests.adapters.HTTPAdapter object at 0x7feb098307f0>
request = <PreparedRequest [GET]>, stream = False
timeout = Timeout(connect=None, read=None, total=None), verify = False
cert = None, proxies = OrderedDict()

    def send(
        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
    ):
        """Sends PreparedRequest object. Returns Response object.
    
        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
        :param stream: (optional) Whether to stream the request content.
        :param timeout: (optional) How long to wait for the server to send
            data before giving up, as a float, or a :ref:`(connect timeout,
            read timeout) <timeouts>` tuple.
        :type timeout: float or tuple or urllib3 Timeout object
        :param verify: (optional) Either a boolean, in which case it controls whether
            we verify the server's TLS certificate, or a string, in which case it
            must be a path to a CA bundle to use
        :param cert: (optional) Any user-provided SSL certificate to be trusted.
        :param proxies: (optional) The proxies dictionary to apply to the request.
        :rtype: requests.Response
        """
    
        try:
            conn = self.get_connection_with_tls_context(
                request, verify, proxies=proxies, cert=cert
            )
        except LocationValueError as e:
            raise InvalidURL(e, request=request)
    
        self.cert_verify(conn, request.url, verify, cert)
        url = self.request_url(request, proxies)
        self.add_headers(
            request,
            stream=stream,
            timeout=timeout,
            verify=verify,
            cert=cert,
            proxies=proxies,
        )
    
        chunked = not (request.body is None or "Content-Length" in request.headers)
    
        if isinstance(timeout, tuple):
            try:
                connect, read = timeout
                timeout = TimeoutSauce(connect=connect, read=read)
            except ValueError:
                raise ValueError(
                    f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                    f"or a single float to set both timeouts to the same value."
                )
        elif isinstance(timeout, TimeoutSauce):
            pass
        else:
            timeout = TimeoutSauce(connect=timeout, read=timeout)
    
        try:
            resp = conn.urlopen(
                method=request.method,
                url=url,
                body=request.body,
                headers=request.headers,
                redirect=False,
                assert_same_host=False,
                preload_content=False,
                decode_content=False,
                retries=self.max_retries,
                timeout=timeout,
                chunked=chunked,
            )
    
        except (ProtocolError, OSError) as err:
            raise ConnectionError(err, request=request)
    
        except MaxRetryError as e:
            if isinstance(e.reason, ConnectTimeoutError):
                # TODO: Remove this in 3.0.0: see #2811
                if not isinstance(e.reason, NewConnectionError):
                    raise ConnectTimeout(e, request=request)
    
            if isinstance(e.reason, ResponseError):
                raise RetryError(e, request=request)
    
            if isinstance(e.reason, _ProxyError):
                raise ProxyError(e, request=request)
    
            if isinstance(e.reason, _SSLError):
                # This branch is for urllib3 v1.22 and later.
                raise SSLError(e, request=request)
    
>           raise ConnectionError(e, request=request)
E           requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb098025b0>: Failed to establish a new connection: [Errno 111] Connection refused'))

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:700: ConnectionError

During handling of the above exception, another exception occurred:

mock_home = <MagicMock name='home' id='140647452478240'>
mock_getpass = <MagicMock name='getpass' id='140647452477088'>

    @patch("slic.utils.elog.getpass")
    @patch("slic.utils.elog.Path.home")
    def test_get_default_elog_instance_asks_password_and_opens(mock_home, mock_getpass):
        mock_home.return_value = Path("/does/not/exist")  # Fausse home → lecture échoue
        mock_getpass.return_value = "testpassword"
        user = "robot"
        text = "This is a message2"
        url = "http://localhost:8080/demo"
    
        elog = Elog("http://localhost:8080/demo", user=user)
    
        try:
>           msd_id = elog.post(text)

tests/test_utils_elog.py:55: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
slic/utils/elog.py:16: in post
    return self._log.post(*args, **kwargs)
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:307: in post
    self._check_if_message_on_server(msg_id)  # raises exceptions if no message or no response from server
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <elog.logbook.Logbook object at 0x7feb05e26fd0>, msg_id = None
timeout = None

    def _check_if_message_on_server(self, msg_id, timeout=None):
        """Try to load page for specific message. If there is a html tag like <td class="errormsg"> then there is no
        such message.
    
        :param msg_id: ID of message to be checked
        :params timeout: The value of timeout to be passed to the get request
        :return:
        """
    
        request_headers = dict()
        if self._user or self._password:
            request_headers['Cookie'] = self._make_user_and_pswd_cookie()
        try:
            response = requests.get(self._url + str(msg_id), headers=request_headers, allow_redirects=False,
                                    verify=False, timeout=timeout)
    
            # If there is no message code 200 will be returned (OK) and _validate_response will not recognise it
            # but there will be some error in the html code.
            resp_message, resp_headers, resp_msg_id = _validate_response(response)
            # If there is no message, code 200 will be returned (OK) but there will be some error indication in
            # the html code.
            if re.findall('<td.*?class="errormsg".*?>.*?</td>',
                          resp_message.decode('utf-8', 'ignore'),
                          flags=re.DOTALL):
                raise LogbookInvalidMessageID('Message with ID: ' + str(msg_id) + ' does not exist on logbook.')
    
        except requests.Timeout as e:
            # Catch here a timeout o the post request.
            # Raise the logbook exception and let the user handle it
            raise LogbookServerTimeout('{0} method cannot be completed because of a network timeout:\n' +
                                       '{1}'.format(sys._getframe().f_code.co_name, e))
    
        except requests.RequestException as e:
>           raise LogbookServerProblem('No response from the logbook server.\nDetails: ' + '{0}'.format(e))
E           elog.logbook_exceptions.LogbookServerProblem: No response from the logbook server.
E           Details: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb098025b0>: Failed to establish a new connection: [Errno 111] Connection refused'))

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:601: LogbookServerProblem

During handling of the above exception, another exception occurred:

mock_home = <MagicMock name='home' id='140647452478240'>
mock_getpass = <MagicMock name='getpass' id='140647452477088'>

    @patch("slic.utils.elog.getpass")
    @patch("slic.utils.elog.Path.home")
    def test_get_default_elog_instance_asks_password_and_opens(mock_home, mock_getpass):
        mock_home.return_value = Path("/does/not/exist")  # Fausse home → lecture échoue
        mock_getpass.return_value = "testpassword"
        user = "robot"
        text = "This is a message2"
        url = "http://localhost:8080/demo"
    
        elog = Elog("http://localhost:8080/demo", user=user)
    
        try:
            msd_id = elog.post(text)
        except Exception as e:
>           pytest.fail(f"elog.post() raised an unexpected exception: {e}")
E           Failed: elog.post() raised an unexpected exception: No response from the logbook server.
E           Details: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb098025b0>: Failed to establish a new connection: [Errno 111] Connection refused'))

tests/test_utils_elog.py:57: Failed
----------------------------- Captured stdout call -----------------------------
Enter elog password for user: robot
_____________________ test_get_default_elog_with_path_home _____________________

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

    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,
            )

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:199: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/connection.py:85: in create_connection
    raise err
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

address = ('localhost', 8080), 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 111] Connection refused

/root/mambaforge/envs/ci-env/lib/python3.8/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 0x7feb09937670>
method = 'POST', url = '/demo/'
body = b'--e76de29c11540daf53cb0ad4febce9b6\r\nContent-Disposition: form-data; name="Author"\r\n\r\nrobot\r\n--e76de29c11540d...Disposition: form-data; name="Text"; filename=""\r\n\r\nThis is a message3\r\n--e76de29c11540daf53cb0ad4febce9b6--\r\n'
headers = {'User-Agent': 'python-requests/2.32.4', 'Accept-Encoding': 'gzip, deflate, br, zstd', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '736', 'Content-Type': 'multipart/form-data; boundary=e76de29c11540daf53cb0ad4febce9b6'}
retries = Retry(total=0, connect=None, read=False, redirect=None, status=None)
redirect = False, assert_same_host = False
timeout = Timeout(connect=None, read=None, total=None), pool_timeout = None
release_conn = False, chunked = False, body_pos = None, preload_content = False
decode_content = False, response_kw = {}
parsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/demo/', 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,
            )

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:789: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:495: in _make_request
    conn.request(
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:441: in request
    self.endheaders()
/root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1251: in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
/root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1011: in _send_output
    self.send(msg)
/root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:951: in send
    self.connect()
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:279: in connect
    self.sock = self._new_conn()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

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

    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 0x7feb09937130>: Failed to establish a new connection: [Errno 111] Connection refused

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:214: NewConnectionError

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

self = <requests.adapters.HTTPAdapter object at 0x7feb09937850>
request = <PreparedRequest [POST]>, stream = False
timeout = Timeout(connect=None, read=None, total=None), verify = False
cert = None, proxies = OrderedDict()

    def send(
        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
    ):
        """Sends PreparedRequest object. Returns Response object.
    
        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
        :param stream: (optional) Whether to stream the request content.
        :param timeout: (optional) How long to wait for the server to send
            data before giving up, as a float, or a :ref:`(connect timeout,
            read timeout) <timeouts>` tuple.
        :type timeout: float or tuple or urllib3 Timeout object
        :param verify: (optional) Either a boolean, in which case it controls whether
            we verify the server's TLS certificate, or a string, in which case it
            must be a path to a CA bundle to use
        :param cert: (optional) Any user-provided SSL certificate to be trusted.
        :param proxies: (optional) The proxies dictionary to apply to the request.
        :rtype: requests.Response
        """
    
        try:
            conn = self.get_connection_with_tls_context(
                request, verify, proxies=proxies, cert=cert
            )
        except LocationValueError as e:
            raise InvalidURL(e, request=request)
    
        self.cert_verify(conn, request.url, verify, cert)
        url = self.request_url(request, proxies)
        self.add_headers(
            request,
            stream=stream,
            timeout=timeout,
            verify=verify,
            cert=cert,
            proxies=proxies,
        )
    
        chunked = not (request.body is None or "Content-Length" in request.headers)
    
        if isinstance(timeout, tuple):
            try:
                connect, read = timeout
                timeout = TimeoutSauce(connect=connect, read=read)
            except ValueError:
                raise ValueError(
                    f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                    f"or a single float to set both timeouts to the same value."
                )
        elif isinstance(timeout, TimeoutSauce):
            pass
        else:
            timeout = TimeoutSauce(connect=timeout, read=timeout)
    
        try:
>           resp = conn.urlopen(
                method=request.method,
                url=url,
                body=request.body,
                headers=request.headers,
                redirect=False,
                assert_same_host=False,
                preload_content=False,
                decode_content=False,
                retries=self.max_retries,
                timeout=timeout,
                chunked=chunked,
            )

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:667: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:843: in urlopen
    retries = retries.increment(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = Retry(total=0, connect=None, read=False, redirect=None, status=None)
method = 'POST', url = '/demo/', response = None
error = NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09937130>: Failed to establish a new connection: [Errno 111] Connection refused')
_pool = <urllib3.connectionpool.HTTPConnectionPool object at 0x7feb09937670>
_stacktrace = <traceback object at 0x7feb0965e740>

    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: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/ (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09937130>: Failed to establish a new connection: [Errno 111] Connection refused'))

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/retry.py:519: MaxRetryError

During handling of the above exception, another exception occurred:

self = <elog.logbook.Logbook object at 0x7feb09937280>
message = 'This is a message3', msg_id = None, reply = False
attributes = {'Author': 'robot', 'When': 1756376002, 'cmd': 'Submit', 'exp': 'demo', ...}
attachments = [], suppress_email_notification = False, encoding = None
timeout = None, kwargs = {'Author': 'robot'}
new_attachment_list = [('Text', ('', b'This is a message3'))]
objects_to_close = []
attributes_to_edit = {'Author': b'robot', 'When': 1756376002, 'cmd': b'Submit', 'exp': b'demo', ...}

    def post(self, message, msg_id=None, reply=False, attributes=None, attachments=None,
             suppress_email_notification=False, encoding=None, timeout=None, **kwargs):
        """
        Posts message to the logbook. If msg_id is not specified new message will be created, otherwise existing
        message will be edited, or a reply (if reply=True) to it will be created. This method returns the msg_id
        of the newly created message.
    
        :param message: string with message text
        :param msg_id: ID number of message to edit or reply. If not specified new message is created.
        :param reply: If 'True' reply to existing message is created instead of editing it
        :param attributes: Dictionary of attributes. Following attributes are used internally by the elog and will be
                           ignored: Text, Date, Encoding, Reply to, In reply to, Locked by, Attachment
        :param attachments: list of:
                                  - file like objects which read() will return bytes (if file_like_object.name is not
                                    defined, default name "attachment<i>" will be used.
                                  - paths to the files
                            All items will be appended as attachment to the elog entry. In case of unknown
                            attachment an exception LogbookInvalidAttachment will be raised.
        :param suppress_email_notification: If set to True or 1, E-Mail notification will be suppressed, defaults to False.
        :param encoding: Defines encoding of the message. Can be: 'plain' -> plain text, 'html'->html-text,
                         'ELCode' --> elog formatting syntax
        :param timeout: Define the timeout to be used by the post request. Its value is directly passed to the requests
                        post. Use None to disable the request timeout.
        :param kwargs: Anything in the kwargs will be interpreted as attribute. e.g.: logbook.post('Test text',
                       Author='Rok Vintar), "Author" will be sent as an attribute. If named same as one of the
                       attributes defined in "attributes", kwargs will have priority.
    
        :return: msg_id
        """
    
        attributes = attributes or {}
        attributes = {**attributes, **kwargs}  # kwargs as attributes with higher priority
    
        attachments = attachments or []
    
        if encoding is not None:
            if encoding not in ['plain', 'HTML', 'ELCode']:
                raise LogbookMessageRejected('Invalid message encoding. Valid options: plain, HTML, ELCode.')
            attributes['Encoding'] = encoding
    
        if suppress_email_notification:
            attributes["suppress"] = 1
    
        # THE ATTACHMENT STRATEGY WHEN DEALING WITH POST MODIFICATION
        #
        # 1. Does the message on the server have already attachments?
        #    1.1 - We read the message getting the existing attachment list.
        #    1.2 - Add to the attributes dictionary one line for each attachment like this:
        #       attributes['attachmentN'] = timestamped_filename_name
        #
        # 2. Do we have new attachments?
        #    2.1 - Those are in the new_attachment_list. This is a list of this type:
        #       [ ('attfileN', ('filename', fileobject)) ]
        #    2.2 - We need to loop over all the new attachments:
        #       2.2.1 - Does a file already on the server with the same name exist?
        #         2.2.1.1 - No: OK. Then we go ahead with the next attachment.
        #         2.2.1.2 - Yes:
        #           2.2.1.2.1 - Are the two files identical?
        #               2.2.1.2.1.1 - Yes: then we remove this current entry from the new_attachment_list and we leave the one
        #                      already on server.
        #               2.2.1.2.1.2 - No:
        #                  2.2.1.2.1.2.1 - Then the file has been update.
        #                  2.2.1.2.1.2.2 - We need to remove the file on server first (using special post)
        #                  2.2.1.2.1.2.3 - We have to remove the old attachment from the attributes dictionary.
        #
    
        if attachments:
            # here we accomplish point 2.1.
            # new_attachment_list is something like [ ('attfileN', ('filename', fileobject)) ]
            new_attachment_list, objects_to_close = self._prepare_attachments(attachments)
        else:
            objects_to_close = list()
            new_attachment_list = list()
    
        attributes_to_edit = dict()
        if msg_id:
            # Message exists, we can continue
            if reply:
                # Verify that there is a message on the server, otherwise do not reply to it!
                self._check_if_message_on_server(msg_id)  # raises exception in case of none existing message
                attributes['reply_to'] = str(msg_id)
            else:  # Edit existing
                attributes['edit_id'] = str(msg_id)
                attributes['skiplock'] = '1'
    
                # here we accomplish point 1.1.
                # existing_attachments_list is something like:
                # [ 'https://elog.url.com/logbook/timestamped_filename' ]
                msg_to_edit, attributes_to_edit, existing_attachments_list = self.read(msg_id)
    
                for attribute, data in attributes.items():
                    new_data = attributes.get(attribute)
                    if new_data is not None:
                        attributes_to_edit[attribute] = new_data
    
                i = 0
                existing_attachments_filename_list = list()
                for attachment in existing_attachments_list:
                    # here we accomplish point 1.2. We strip the timestamped_filename from the whole URL.
                    attributes_to_edit[f'attachment{i}'] = os.path.basename(attachment)
                    existing_attachments_filename_list.append(os.path.basename(attachment)[14:])
                    i += 1
    
                # let's accomplish 2.2. Loop over all new attachment
                duplicate_attachment_list = list()
                for new_attachment in new_attachment_list:
                    # the new_attachment_list is something like:
                    # [ ('attfileN', ('filename', fileobject)) ]
                    new_attachment_filename = new_attachment[1][0]
                    if new_attachment_filename in existing_attachments_filename_list:
                        # a file with the same name existing already on the server.
                        # we need to check if the two files are the same.
                        # read the content of the new file
                        new_attachment_content = new_attachment[1][1].read()
                        # don't forget to reset the fileobj to the beginning of the file
                        new_attachment[1][1].seek(0)
                        # get the existing attachment content
                        attachment_index = existing_attachments_filename_list.index(new_attachment_filename)
                        existing_attachment_content = self.download_attachment(
                            url=existing_attachments_list[attachment_index],
                            timeout=timeout
                        )
                        # check if the two contents are the same
                        if new_attachment_content == existing_attachment_content:
                            # yes. then we don't upload a second copy. we remove the current entry from the list
                            duplicate_attachment_list.append(new_attachment)
                        else:
                            # no. they are not the same file. we will replace the existing file with the new one
                            # first: we need to remove the attachment from the server using the dedicated method
                            self.delete_attachment(msg_id, attributes=attributes_to_edit,
                                                   attachment_id=attachment_index,
                                                   timeout=timeout, text=msg_to_edit)
                            # now we can remove this attachment from the auxiliary lists.
                            existing_attachments_filename_list.pop(attachment_index)
                            existing_attachments_list.pop(attachment_index)
                            # now we need to rebuild the attributes dictionary for the part concerning the attachments.
                            # we remove all of them first
                            keys_to_be_removed = list()
                            for key in attributes_to_edit.keys():
                                if key.startswith('attachment'):
                                    keys_to_be_removed.append(key)
                                if key.startswith('delatt'):
                                    keys_to_be_removed.append(key)
                            for key in keys_to_be_removed:
                                del attributes_to_edit[key]
    
                            # now we rebuild it
                            for i, attachment in enumerate(existing_attachments_list):
                                attributes_to_edit[f'attachment{i}'] = os.path.basename(attachment)
    
                # remove all duplicate attachments from the new_attachment_list
                for attach in duplicate_attachment_list:
                    new_attachment_list.remove(attach)
    
        else:
            # As we create a new message, specify creation time if not already specified in attributes
            if 'When' not in attributes:
                attributes['When'] = int(datetime.now().timestamp())
    
        if not attributes_to_edit:
            attributes_to_edit = attributes
    
        # Remove any attributes that should not be sent
        _remove_reserved_attributes(attributes_to_edit)
    
        # Make requests module think that Text is a "file". This is the only way to force requests to send data as
        # multipart/form-data even if there are no attachments. Elog understands only multipart/form-data
        new_attachment_list.append(('Text', ('', message.encode('iso-8859-1'))))
    
        # Base attributes are common to all messages
        self._add_base_msg_attributes(attributes_to_edit)
    
        # Keys in attributes cannot have certain characters like whitespaces or dashes for the http request
        attributes_to_edit = _replace_special_characters_in_attribute_keys(attributes_to_edit)
    
        # All string values in the attributes must be encoded in latin1
        attributes_to_edit = _encode_values(attributes_to_edit)
    
        try:
>           response = requests.post(self._url, data=attributes_to_edit, files=new_attachment_list,
                                     allow_redirects=False, verify=False, timeout=timeout)

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:288: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:115: in post
    return request("post", url, data=data, json=json, **kwargs)
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:59: in request
    return session.request(method=method, url=url, **kwargs)
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:589: in request
    resp = self.send(prep, **send_kwargs)
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:703: in send
    r = adapter.send(request, **kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <requests.adapters.HTTPAdapter object at 0x7feb09937850>
request = <PreparedRequest [POST]>, stream = False
timeout = Timeout(connect=None, read=None, total=None), verify = False
cert = None, proxies = OrderedDict()

    def send(
        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
    ):
        """Sends PreparedRequest object. Returns Response object.
    
        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
        :param stream: (optional) Whether to stream the request content.
        :param timeout: (optional) How long to wait for the server to send
            data before giving up, as a float, or a :ref:`(connect timeout,
            read timeout) <timeouts>` tuple.
        :type timeout: float or tuple or urllib3 Timeout object
        :param verify: (optional) Either a boolean, in which case it controls whether
            we verify the server's TLS certificate, or a string, in which case it
            must be a path to a CA bundle to use
        :param cert: (optional) Any user-provided SSL certificate to be trusted.
        :param proxies: (optional) The proxies dictionary to apply to the request.
        :rtype: requests.Response
        """
    
        try:
            conn = self.get_connection_with_tls_context(
                request, verify, proxies=proxies, cert=cert
            )
        except LocationValueError as e:
            raise InvalidURL(e, request=request)
    
        self.cert_verify(conn, request.url, verify, cert)
        url = self.request_url(request, proxies)
        self.add_headers(
            request,
            stream=stream,
            timeout=timeout,
            verify=verify,
            cert=cert,
            proxies=proxies,
        )
    
        chunked = not (request.body is None or "Content-Length" in request.headers)
    
        if isinstance(timeout, tuple):
            try:
                connect, read = timeout
                timeout = TimeoutSauce(connect=connect, read=read)
            except ValueError:
                raise ValueError(
                    f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                    f"or a single float to set both timeouts to the same value."
                )
        elif isinstance(timeout, TimeoutSauce):
            pass
        else:
            timeout = TimeoutSauce(connect=timeout, read=timeout)
    
        try:
            resp = conn.urlopen(
                method=request.method,
                url=url,
                body=request.body,
                headers=request.headers,
                redirect=False,
                assert_same_host=False,
                preload_content=False,
                decode_content=False,
                retries=self.max_retries,
                timeout=timeout,
                chunked=chunked,
            )
    
        except (ProtocolError, OSError) as err:
            raise ConnectionError(err, request=request)
    
        except MaxRetryError as e:
            if isinstance(e.reason, ConnectTimeoutError):
                # TODO: Remove this in 3.0.0: see #2811
                if not isinstance(e.reason, NewConnectionError):
                    raise ConnectTimeout(e, request=request)
    
            if isinstance(e.reason, ResponseError):
                raise RetryError(e, request=request)
    
            if isinstance(e.reason, _ProxyError):
                raise ProxyError(e, request=request)
    
            if isinstance(e.reason, _SSLError):
                # This branch is for urllib3 v1.22 and later.
                raise SSLError(e, request=request)
    
>           raise ConnectionError(e, request=request)
E           requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/ (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09937130>: Failed to establish a new connection: [Errno 111] Connection refused'))

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:700: ConnectionError

During handling of the above exception, another exception occurred:

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

    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,
            )

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:199: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/connection.py:85: in create_connection
    raise err
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

address = ('localhost', 8080), 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 111] Connection refused

/root/mambaforge/envs/ci-env/lib/python3.8/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 0x7feb098b2730>
method = 'GET', url = '/demo/None', body = None
headers = {'User-Agent': 'python-requests/2.32.4', 'Accept-Encoding': 'gzip, deflate, br, zstd', 'Accept': '*/*', 'Connection': 'keep-alive', 'Cookie': 'unm=robot;upwd=me1T.2jUUqQNa1wNuey9zNBOmOa4eILOaPb.ZSZjpn4;'}
retries = Retry(total=0, connect=None, read=False, redirect=None, status=None)
redirect = False, assert_same_host = False
timeout = Timeout(connect=None, read=None, total=None), pool_timeout = None
release_conn = False, chunked = False, body_pos = None, preload_content = False
decode_content = False, response_kw = {}
parsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/demo/None', 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,
            )

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:789: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:495: in _make_request
    conn.request(
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:441: in request
    self.endheaders()
/root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1251: in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
/root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1011: in _send_output
    self.send(msg)
/root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:951: in send
    self.connect()
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:279: in connect
    self.sock = self._new_conn()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

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

    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 0x7feb098b2bb0>: Failed to establish a new connection: [Errno 111] Connection refused

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:214: NewConnectionError

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

self = <requests.adapters.HTTPAdapter object at 0x7feb098b25b0>
request = <PreparedRequest [GET]>, stream = False
timeout = Timeout(connect=None, read=None, total=None), verify = False
cert = None, proxies = OrderedDict()

    def send(
        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
    ):
        """Sends PreparedRequest object. Returns Response object.
    
        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
        :param stream: (optional) Whether to stream the request content.
        :param timeout: (optional) How long to wait for the server to send
            data before giving up, as a float, or a :ref:`(connect timeout,
            read timeout) <timeouts>` tuple.
        :type timeout: float or tuple or urllib3 Timeout object
        :param verify: (optional) Either a boolean, in which case it controls whether
            we verify the server's TLS certificate, or a string, in which case it
            must be a path to a CA bundle to use
        :param cert: (optional) Any user-provided SSL certificate to be trusted.
        :param proxies: (optional) The proxies dictionary to apply to the request.
        :rtype: requests.Response
        """
    
        try:
            conn = self.get_connection_with_tls_context(
                request, verify, proxies=proxies, cert=cert
            )
        except LocationValueError as e:
            raise InvalidURL(e, request=request)
    
        self.cert_verify(conn, request.url, verify, cert)
        url = self.request_url(request, proxies)
        self.add_headers(
            request,
            stream=stream,
            timeout=timeout,
            verify=verify,
            cert=cert,
            proxies=proxies,
        )
    
        chunked = not (request.body is None or "Content-Length" in request.headers)
    
        if isinstance(timeout, tuple):
            try:
                connect, read = timeout
                timeout = TimeoutSauce(connect=connect, read=read)
            except ValueError:
                raise ValueError(
                    f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                    f"or a single float to set both timeouts to the same value."
                )
        elif isinstance(timeout, TimeoutSauce):
            pass
        else:
            timeout = TimeoutSauce(connect=timeout, read=timeout)
    
        try:
>           resp = conn.urlopen(
                method=request.method,
                url=url,
                body=request.body,
                headers=request.headers,
                redirect=False,
                assert_same_host=False,
                preload_content=False,
                decode_content=False,
                retries=self.max_retries,
                timeout=timeout,
                chunked=chunked,
            )

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:667: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:843: in urlopen
    retries = retries.increment(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = Retry(total=0, connect=None, read=False, redirect=None, status=None)
method = 'GET', url = '/demo/None', response = None
error = NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb098b2bb0>: Failed to establish a new connection: [Errno 111] Connection refused')
_pool = <urllib3.connectionpool.HTTPConnectionPool object at 0x7feb098b2730>
_stacktrace = <traceback object at 0x7feb097c29c0>

    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: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb098b2bb0>: Failed to establish a new connection: [Errno 111] Connection refused'))

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/retry.py:519: MaxRetryError

During handling of the above exception, another exception occurred:

self = <elog.logbook.Logbook object at 0x7feb09937280>, msg_id = None
timeout = None

    def _check_if_message_on_server(self, msg_id, timeout=None):
        """Try to load page for specific message. If there is a html tag like <td class="errormsg"> then there is no
        such message.
    
        :param msg_id: ID of message to be checked
        :params timeout: The value of timeout to be passed to the get request
        :return:
        """
    
        request_headers = dict()
        if self._user or self._password:
            request_headers['Cookie'] = self._make_user_and_pswd_cookie()
        try:
>           response = requests.get(self._url + str(msg_id), headers=request_headers, allow_redirects=False,
                                    verify=False, timeout=timeout)

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:581: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:73: in get
    return request("get", url, params=params, **kwargs)
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:59: in request
    return session.request(method=method, url=url, **kwargs)
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:589: in request
    resp = self.send(prep, **send_kwargs)
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:703: in send
    r = adapter.send(request, **kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <requests.adapters.HTTPAdapter object at 0x7feb098b25b0>
request = <PreparedRequest [GET]>, stream = False
timeout = Timeout(connect=None, read=None, total=None), verify = False
cert = None, proxies = OrderedDict()

    def send(
        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
    ):
        """Sends PreparedRequest object. Returns Response object.
    
        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
        :param stream: (optional) Whether to stream the request content.
        :param timeout: (optional) How long to wait for the server to send
            data before giving up, as a float, or a :ref:`(connect timeout,
            read timeout) <timeouts>` tuple.
        :type timeout: float or tuple or urllib3 Timeout object
        :param verify: (optional) Either a boolean, in which case it controls whether
            we verify the server's TLS certificate, or a string, in which case it
            must be a path to a CA bundle to use
        :param cert: (optional) Any user-provided SSL certificate to be trusted.
        :param proxies: (optional) The proxies dictionary to apply to the request.
        :rtype: requests.Response
        """
    
        try:
            conn = self.get_connection_with_tls_context(
                request, verify, proxies=proxies, cert=cert
            )
        except LocationValueError as e:
            raise InvalidURL(e, request=request)
    
        self.cert_verify(conn, request.url, verify, cert)
        url = self.request_url(request, proxies)
        self.add_headers(
            request,
            stream=stream,
            timeout=timeout,
            verify=verify,
            cert=cert,
            proxies=proxies,
        )
    
        chunked = not (request.body is None or "Content-Length" in request.headers)
    
        if isinstance(timeout, tuple):
            try:
                connect, read = timeout
                timeout = TimeoutSauce(connect=connect, read=read)
            except ValueError:
                raise ValueError(
                    f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                    f"or a single float to set both timeouts to the same value."
                )
        elif isinstance(timeout, TimeoutSauce):
            pass
        else:
            timeout = TimeoutSauce(connect=timeout, read=timeout)
    
        try:
            resp = conn.urlopen(
                method=request.method,
                url=url,
                body=request.body,
                headers=request.headers,
                redirect=False,
                assert_same_host=False,
                preload_content=False,
                decode_content=False,
                retries=self.max_retries,
                timeout=timeout,
                chunked=chunked,
            )
    
        except (ProtocolError, OSError) as err:
            raise ConnectionError(err, request=request)
    
        except MaxRetryError as e:
            if isinstance(e.reason, ConnectTimeoutError):
                # TODO: Remove this in 3.0.0: see #2811
                if not isinstance(e.reason, NewConnectionError):
                    raise ConnectTimeout(e, request=request)
    
            if isinstance(e.reason, ResponseError):
                raise RetryError(e, request=request)
    
            if isinstance(e.reason, _ProxyError):
                raise ProxyError(e, request=request)
    
            if isinstance(e.reason, _SSLError):
                # This branch is for urllib3 v1.22 and later.
                raise SSLError(e, request=request)
    
>           raise ConnectionError(e, request=request)
E           requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb098b2bb0>: Failed to establish a new connection: [Errno 111] Connection refused'))

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:700: ConnectionError

During handling of the above exception, another exception occurred:

mock_home = <MagicMock name='home' id='140647451303744'>
mock_getuser = <MagicMock name='getuser' id='140647451733824'>
mock_getpass = <MagicMock name='getpass' id='140647453841488'>

    @patch("slic.utils.elog.getpass")
    @patch("slic.utils.elog.getuser")
    @patch("slic.utils.elog.Path.home")
    def test_get_default_elog_with_path_home(mock_home, mock_getuser, mock_getpass):
        fake_user = "robot"
        fake_pw = "testpassword"
        mock_getuser.return_value = fake_user
        mock_getpass.return_value = fake_pw  # fallback safety
        text = "This is a message3"
        url = "http://localhost:8080/demo"
    
        tmp_home = Path("/tmp/fake_home_for_robot")
        tmp_home.mkdir(parents=True, exist_ok=True)
        pw_file = tmp_home / ".elog_psi"
        pw_file.write_text(fake_pw)
        mock_home.return_value = tmp_home
    
        try:
            elog = Elog("http://localhost:8080/demo")
            try:
>               msg_id = elog.post(text)

tests/test_utils_elog.py:90: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
slic/utils/elog.py:16: in post
    return self._log.post(*args, **kwargs)
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:307: in post
    self._check_if_message_on_server(msg_id)  # raises exceptions if no message or no response from server
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <elog.logbook.Logbook object at 0x7feb09937280>, msg_id = None
timeout = None

    def _check_if_message_on_server(self, msg_id, timeout=None):
        """Try to load page for specific message. If there is a html tag like <td class="errormsg"> then there is no
        such message.
    
        :param msg_id: ID of message to be checked
        :params timeout: The value of timeout to be passed to the get request
        :return:
        """
    
        request_headers = dict()
        if self._user or self._password:
            request_headers['Cookie'] = self._make_user_and_pswd_cookie()
        try:
            response = requests.get(self._url + str(msg_id), headers=request_headers, allow_redirects=False,
                                    verify=False, timeout=timeout)
    
            # If there is no message code 200 will be returned (OK) and _validate_response will not recognise it
            # but there will be some error in the html code.
            resp_message, resp_headers, resp_msg_id = _validate_response(response)
            # If there is no message, code 200 will be returned (OK) but there will be some error indication in
            # the html code.
            if re.findall('<td.*?class="errormsg".*?>.*?</td>',
                          resp_message.decode('utf-8', 'ignore'),
                          flags=re.DOTALL):
                raise LogbookInvalidMessageID('Message with ID: ' + str(msg_id) + ' does not exist on logbook.')
    
        except requests.Timeout as e:
            # Catch here a timeout o the post request.
            # Raise the logbook exception and let the user handle it
            raise LogbookServerTimeout('{0} method cannot be completed because of a network timeout:\n' +
                                       '{1}'.format(sys._getframe().f_code.co_name, e))
    
        except requests.RequestException as e:
>           raise LogbookServerProblem('No response from the logbook server.\nDetails: ' + '{0}'.format(e))
E           elog.logbook_exceptions.LogbookServerProblem: No response from the logbook server.
E           Details: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb098b2bb0>: Failed to establish a new connection: [Errno 111] Connection refused'))

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:601: LogbookServerProblem

During handling of the above exception, another exception occurred:

mock_home = <MagicMock name='home' id='140647451303744'>
mock_getuser = <MagicMock name='getuser' id='140647451733824'>
mock_getpass = <MagicMock name='getpass' id='140647453841488'>

    @patch("slic.utils.elog.getpass")
    @patch("slic.utils.elog.getuser")
    @patch("slic.utils.elog.Path.home")
    def test_get_default_elog_with_path_home(mock_home, mock_getuser, mock_getpass):
        fake_user = "robot"
        fake_pw = "testpassword"
        mock_getuser.return_value = fake_user
        mock_getpass.return_value = fake_pw  # fallback safety
        text = "This is a message3"
        url = "http://localhost:8080/demo"
    
        tmp_home = Path("/tmp/fake_home_for_robot")
        tmp_home.mkdir(parents=True, exist_ok=True)
        pw_file = tmp_home / ".elog_psi"
        pw_file.write_text(fake_pw)
        mock_home.return_value = tmp_home
    
        try:
            elog = Elog("http://localhost:8080/demo")
            try:
                msg_id = elog.post(text)
            except Exception as e:
>               pytest.fail(f"elog.post() raised an unexpected exception: {e}")
E               Failed: elog.post() raised an unexpected exception: No response from the logbook server.
E               Details: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb098b2bb0>: Failed to establish a new connection: [Errno 111] Connection refused'))

tests/test_utils_elog.py:92: Failed
_______________________________ test_screenshot ________________________________

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

    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,
            )

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:199: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/connection.py:85: in create_connection
    raise err
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

address = ('localhost', 8080), 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 111] Connection refused

/root/mambaforge/envs/ci-env/lib/python3.8/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 0x7feb0977c0a0>
method = 'POST', url = '/demo/'
body = b'--1194c6bfc5b78a946fff64f5d06636c0\r\nContent-Disposition: form-data; name="Author"\r\n\r\nrobot\r\n--1194c6bfc5b78a...-data; name="Text"; filename=""\r\n\r\nSCREENSHOT_INTEGRATION_TEST_MSG_456\r\n--1194c6bfc5b78a946fff64f5d06636c0--\r\n'
headers = {'User-Agent': 'python-requests/2.32.4', 'Accept-Encoding': 'gzip, deflate, br, zstd', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '889', 'Content-Type': 'multipart/form-data; boundary=1194c6bfc5b78a946fff64f5d06636c0'}
retries = Retry(total=0, connect=None, read=False, redirect=None, status=None)
redirect = False, assert_same_host = False
timeout = Timeout(connect=None, read=None, total=None), pool_timeout = None
release_conn = False, chunked = False, body_pos = None, preload_content = False
decode_content = False, response_kw = {}
parsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/demo/', 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,
            )

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:789: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:495: in _make_request
    conn.request(
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:441: in request
    self.endheaders()
/root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1251: in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
/root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1011: in _send_output
    self.send(msg)
/root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:951: in send
    self.connect()
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:279: in connect
    self.sock = self._new_conn()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

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

    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 0x7feb0958cb20>: Failed to establish a new connection: [Errno 111] Connection refused

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:214: NewConnectionError

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

self = <requests.adapters.HTTPAdapter object at 0x7feb0958c490>
request = <PreparedRequest [POST]>, stream = False
timeout = Timeout(connect=None, read=None, total=None), verify = False
cert = None, proxies = OrderedDict()

    def send(
        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
    ):
        """Sends PreparedRequest object. Returns Response object.
    
        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
        :param stream: (optional) Whether to stream the request content.
        :param timeout: (optional) How long to wait for the server to send
            data before giving up, as a float, or a :ref:`(connect timeout,
            read timeout) <timeouts>` tuple.
        :type timeout: float or tuple or urllib3 Timeout object
        :param verify: (optional) Either a boolean, in which case it controls whether
            we verify the server's TLS certificate, or a string, in which case it
            must be a path to a CA bundle to use
        :param cert: (optional) Any user-provided SSL certificate to be trusted.
        :param proxies: (optional) The proxies dictionary to apply to the request.
        :rtype: requests.Response
        """
    
        try:
            conn = self.get_connection_with_tls_context(
                request, verify, proxies=proxies, cert=cert
            )
        except LocationValueError as e:
            raise InvalidURL(e, request=request)
    
        self.cert_verify(conn, request.url, verify, cert)
        url = self.request_url(request, proxies)
        self.add_headers(
            request,
            stream=stream,
            timeout=timeout,
            verify=verify,
            cert=cert,
            proxies=proxies,
        )
    
        chunked = not (request.body is None or "Content-Length" in request.headers)
    
        if isinstance(timeout, tuple):
            try:
                connect, read = timeout
                timeout = TimeoutSauce(connect=connect, read=read)
            except ValueError:
                raise ValueError(
                    f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                    f"or a single float to set both timeouts to the same value."
                )
        elif isinstance(timeout, TimeoutSauce):
            pass
        else:
            timeout = TimeoutSauce(connect=timeout, read=timeout)
    
        try:
>           resp = conn.urlopen(
                method=request.method,
                url=url,
                body=request.body,
                headers=request.headers,
                redirect=False,
                assert_same_host=False,
                preload_content=False,
                decode_content=False,
                retries=self.max_retries,
                timeout=timeout,
                chunked=chunked,
            )

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:667: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:843: in urlopen
    retries = retries.increment(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = Retry(total=0, connect=None, read=False, redirect=None, status=None)
method = 'POST', url = '/demo/', response = None
error = NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb0958cb20>: Failed to establish a new connection: [Errno 111] Connection refused')
_pool = <urllib3.connectionpool.HTTPConnectionPool object at 0x7feb0977c0a0>
_stacktrace = <traceback object at 0x7feb09808600>

    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: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/ (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb0958cb20>: Failed to establish a new connection: [Errno 111] Connection refused'))

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/retry.py:519: MaxRetryError

During handling of the above exception, another exception occurred:

self = <elog.logbook.Logbook object at 0x7feb0977c5b0>
message = 'SCREENSHOT_INTEGRATION_TEST_MSG_456', msg_id = None, reply = False
attributes = {'Author': 'robot', 'When': 1756376002, 'cmd': 'Submit', 'exp': 'demo', ...}
attachments = ['/tmp/fake_screenshot.png'], suppress_email_notification = False
encoding = None, timeout = None, kwargs = {'Author': 'robot'}
new_attachment_list = [('attfile0', ('fake_screenshot.png', <_io.BufferedReader name='/tmp/fake_screenshot.png'>)), ('Text', ('', b'SCREENSHOT_INTEGRATION_TEST_MSG_456'))]
objects_to_close = [<_io.BufferedReader name='/tmp/fake_screenshot.png'>]
attributes_to_edit = {'Author': b'robot', 'When': 1756376002, 'cmd': b'Submit', 'exp': b'demo', ...}

    def post(self, message, msg_id=None, reply=False, attributes=None, attachments=None,
             suppress_email_notification=False, encoding=None, timeout=None, **kwargs):
        """
        Posts message to the logbook. If msg_id is not specified new message will be created, otherwise existing
        message will be edited, or a reply (if reply=True) to it will be created. This method returns the msg_id
        of the newly created message.
    
        :param message: string with message text
        :param msg_id: ID number of message to edit or reply. If not specified new message is created.
        :param reply: If 'True' reply to existing message is created instead of editing it
        :param attributes: Dictionary of attributes. Following attributes are used internally by the elog and will be
                           ignored: Text, Date, Encoding, Reply to, In reply to, Locked by, Attachment
        :param attachments: list of:
                                  - file like objects which read() will return bytes (if file_like_object.name is not
                                    defined, default name "attachment<i>" will be used.
                                  - paths to the files
                            All items will be appended as attachment to the elog entry. In case of unknown
                            attachment an exception LogbookInvalidAttachment will be raised.
        :param suppress_email_notification: If set to True or 1, E-Mail notification will be suppressed, defaults to False.
        :param encoding: Defines encoding of the message. Can be: 'plain' -> plain text, 'html'->html-text,
                         'ELCode' --> elog formatting syntax
        :param timeout: Define the timeout to be used by the post request. Its value is directly passed to the requests
                        post. Use None to disable the request timeout.
        :param kwargs: Anything in the kwargs will be interpreted as attribute. e.g.: logbook.post('Test text',
                       Author='Rok Vintar), "Author" will be sent as an attribute. If named same as one of the
                       attributes defined in "attributes", kwargs will have priority.
    
        :return: msg_id
        """
    
        attributes = attributes or {}
        attributes = {**attributes, **kwargs}  # kwargs as attributes with higher priority
    
        attachments = attachments or []
    
        if encoding is not None:
            if encoding not in ['plain', 'HTML', 'ELCode']:
                raise LogbookMessageRejected('Invalid message encoding. Valid options: plain, HTML, ELCode.')
            attributes['Encoding'] = encoding
    
        if suppress_email_notification:
            attributes["suppress"] = 1
    
        # THE ATTACHMENT STRATEGY WHEN DEALING WITH POST MODIFICATION
        #
        # 1. Does the message on the server have already attachments?
        #    1.1 - We read the message getting the existing attachment list.
        #    1.2 - Add to the attributes dictionary one line for each attachment like this:
        #       attributes['attachmentN'] = timestamped_filename_name
        #
        # 2. Do we have new attachments?
        #    2.1 - Those are in the new_attachment_list. This is a list of this type:
        #       [ ('attfileN', ('filename', fileobject)) ]
        #    2.2 - We need to loop over all the new attachments:
        #       2.2.1 - Does a file already on the server with the same name exist?
        #         2.2.1.1 - No: OK. Then we go ahead with the next attachment.
        #         2.2.1.2 - Yes:
        #           2.2.1.2.1 - Are the two files identical?
        #               2.2.1.2.1.1 - Yes: then we remove this current entry from the new_attachment_list and we leave the one
        #                      already on server.
        #               2.2.1.2.1.2 - No:
        #                  2.2.1.2.1.2.1 - Then the file has been update.
        #                  2.2.1.2.1.2.2 - We need to remove the file on server first (using special post)
        #                  2.2.1.2.1.2.3 - We have to remove the old attachment from the attributes dictionary.
        #
    
        if attachments:
            # here we accomplish point 2.1.
            # new_attachment_list is something like [ ('attfileN', ('filename', fileobject)) ]
            new_attachment_list, objects_to_close = self._prepare_attachments(attachments)
        else:
            objects_to_close = list()
            new_attachment_list = list()
    
        attributes_to_edit = dict()
        if msg_id:
            # Message exists, we can continue
            if reply:
                # Verify that there is a message on the server, otherwise do not reply to it!
                self._check_if_message_on_server(msg_id)  # raises exception in case of none existing message
                attributes['reply_to'] = str(msg_id)
            else:  # Edit existing
                attributes['edit_id'] = str(msg_id)
                attributes['skiplock'] = '1'
    
                # here we accomplish point 1.1.
                # existing_attachments_list is something like:
                # [ 'https://elog.url.com/logbook/timestamped_filename' ]
                msg_to_edit, attributes_to_edit, existing_attachments_list = self.read(msg_id)
    
                for attribute, data in attributes.items():
                    new_data = attributes.get(attribute)
                    if new_data is not None:
                        attributes_to_edit[attribute] = new_data
    
                i = 0
                existing_attachments_filename_list = list()
                for attachment in existing_attachments_list:
                    # here we accomplish point 1.2. We strip the timestamped_filename from the whole URL.
                    attributes_to_edit[f'attachment{i}'] = os.path.basename(attachment)
                    existing_attachments_filename_list.append(os.path.basename(attachment)[14:])
                    i += 1
    
                # let's accomplish 2.2. Loop over all new attachment
                duplicate_attachment_list = list()
                for new_attachment in new_attachment_list:
                    # the new_attachment_list is something like:
                    # [ ('attfileN', ('filename', fileobject)) ]
                    new_attachment_filename = new_attachment[1][0]
                    if new_attachment_filename in existing_attachments_filename_list:
                        # a file with the same name existing already on the server.
                        # we need to check if the two files are the same.
                        # read the content of the new file
                        new_attachment_content = new_attachment[1][1].read()
                        # don't forget to reset the fileobj to the beginning of the file
                        new_attachment[1][1].seek(0)
                        # get the existing attachment content
                        attachment_index = existing_attachments_filename_list.index(new_attachment_filename)
                        existing_attachment_content = self.download_attachment(
                            url=existing_attachments_list[attachment_index],
                            timeout=timeout
                        )
                        # check if the two contents are the same
                        if new_attachment_content == existing_attachment_content:
                            # yes. then we don't upload a second copy. we remove the current entry from the list
                            duplicate_attachment_list.append(new_attachment)
                        else:
                            # no. they are not the same file. we will replace the existing file with the new one
                            # first: we need to remove the attachment from the server using the dedicated method
                            self.delete_attachment(msg_id, attributes=attributes_to_edit,
                                                   attachment_id=attachment_index,
                                                   timeout=timeout, text=msg_to_edit)
                            # now we can remove this attachment from the auxiliary lists.
                            existing_attachments_filename_list.pop(attachment_index)
                            existing_attachments_list.pop(attachment_index)
                            # now we need to rebuild the attributes dictionary for the part concerning the attachments.
                            # we remove all of them first
                            keys_to_be_removed = list()
                            for key in attributes_to_edit.keys():
                                if key.startswith('attachment'):
                                    keys_to_be_removed.append(key)
                                if key.startswith('delatt'):
                                    keys_to_be_removed.append(key)
                            for key in keys_to_be_removed:
                                del attributes_to_edit[key]
    
                            # now we rebuild it
                            for i, attachment in enumerate(existing_attachments_list):
                                attributes_to_edit[f'attachment{i}'] = os.path.basename(attachment)
    
                # remove all duplicate attachments from the new_attachment_list
                for attach in duplicate_attachment_list:
                    new_attachment_list.remove(attach)
    
        else:
            # As we create a new message, specify creation time if not already specified in attributes
            if 'When' not in attributes:
                attributes['When'] = int(datetime.now().timestamp())
    
        if not attributes_to_edit:
            attributes_to_edit = attributes
    
        # Remove any attributes that should not be sent
        _remove_reserved_attributes(attributes_to_edit)
    
        # Make requests module think that Text is a "file". This is the only way to force requests to send data as
        # multipart/form-data even if there are no attachments. Elog understands only multipart/form-data
        new_attachment_list.append(('Text', ('', message.encode('iso-8859-1'))))
    
        # Base attributes are common to all messages
        self._add_base_msg_attributes(attributes_to_edit)
    
        # Keys in attributes cannot have certain characters like whitespaces or dashes for the http request
        attributes_to_edit = _replace_special_characters_in_attribute_keys(attributes_to_edit)
    
        # All string values in the attributes must be encoded in latin1
        attributes_to_edit = _encode_values(attributes_to_edit)
    
        try:
>           response = requests.post(self._url, data=attributes_to_edit, files=new_attachment_list,
                                     allow_redirects=False, verify=False, timeout=timeout)

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:288: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:115: in post
    return request("post", url, data=data, json=json, **kwargs)
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:59: in request
    return session.request(method=method, url=url, **kwargs)
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:589: in request
    resp = self.send(prep, **send_kwargs)
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:703: in send
    r = adapter.send(request, **kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <requests.adapters.HTTPAdapter object at 0x7feb0958c490>
request = <PreparedRequest [POST]>, stream = False
timeout = Timeout(connect=None, read=None, total=None), verify = False
cert = None, proxies = OrderedDict()

    def send(
        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
    ):
        """Sends PreparedRequest object. Returns Response object.
    
        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
        :param stream: (optional) Whether to stream the request content.
        :param timeout: (optional) How long to wait for the server to send
            data before giving up, as a float, or a :ref:`(connect timeout,
            read timeout) <timeouts>` tuple.
        :type timeout: float or tuple or urllib3 Timeout object
        :param verify: (optional) Either a boolean, in which case it controls whether
            we verify the server's TLS certificate, or a string, in which case it
            must be a path to a CA bundle to use
        :param cert: (optional) Any user-provided SSL certificate to be trusted.
        :param proxies: (optional) The proxies dictionary to apply to the request.
        :rtype: requests.Response
        """
    
        try:
            conn = self.get_connection_with_tls_context(
                request, verify, proxies=proxies, cert=cert
            )
        except LocationValueError as e:
            raise InvalidURL(e, request=request)
    
        self.cert_verify(conn, request.url, verify, cert)
        url = self.request_url(request, proxies)
        self.add_headers(
            request,
            stream=stream,
            timeout=timeout,
            verify=verify,
            cert=cert,
            proxies=proxies,
        )
    
        chunked = not (request.body is None or "Content-Length" in request.headers)
    
        if isinstance(timeout, tuple):
            try:
                connect, read = timeout
                timeout = TimeoutSauce(connect=connect, read=read)
            except ValueError:
                raise ValueError(
                    f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                    f"or a single float to set both timeouts to the same value."
                )
        elif isinstance(timeout, TimeoutSauce):
            pass
        else:
            timeout = TimeoutSauce(connect=timeout, read=timeout)
    
        try:
            resp = conn.urlopen(
                method=request.method,
                url=url,
                body=request.body,
                headers=request.headers,
                redirect=False,
                assert_same_host=False,
                preload_content=False,
                decode_content=False,
                retries=self.max_retries,
                timeout=timeout,
                chunked=chunked,
            )
    
        except (ProtocolError, OSError) as err:
            raise ConnectionError(err, request=request)
    
        except MaxRetryError as e:
            if isinstance(e.reason, ConnectTimeoutError):
                # TODO: Remove this in 3.0.0: see #2811
                if not isinstance(e.reason, NewConnectionError):
                    raise ConnectTimeout(e, request=request)
    
            if isinstance(e.reason, ResponseError):
                raise RetryError(e, request=request)
    
            if isinstance(e.reason, _ProxyError):
                raise ProxyError(e, request=request)
    
            if isinstance(e.reason, _SSLError):
                # This branch is for urllib3 v1.22 and later.
                raise SSLError(e, request=request)
    
>           raise ConnectionError(e, request=request)
E           requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/ (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb0958cb20>: Failed to establish a new connection: [Errno 111] Connection refused'))

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:700: ConnectionError

During handling of the above exception, another exception occurred:

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

    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,
            )

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:199: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/connection.py:85: in create_connection
    raise err
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

address = ('localhost', 8080), 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 111] Connection refused

/root/mambaforge/envs/ci-env/lib/python3.8/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 0x7feb09b7e640>
method = 'GET', url = '/demo/None', body = None
headers = {'User-Agent': 'python-requests/2.32.4', 'Accept-Encoding': 'gzip, deflate, br, zstd', 'Accept': '*/*', 'Connection': 'keep-alive', 'Cookie': 'unm=robot;upwd=me1T.2jUUqQNa1wNuey9zNBOmOa4eILOaPb.ZSZjpn4;'}
retries = Retry(total=0, connect=None, read=False, redirect=None, status=None)
redirect = False, assert_same_host = False
timeout = Timeout(connect=None, read=None, total=None), pool_timeout = None
release_conn = False, chunked = False, body_pos = None, preload_content = False
decode_content = False, response_kw = {}
parsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/demo/None', 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,
            )

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:789: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:495: in _make_request
    conn.request(
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:441: in request
    self.endheaders()
/root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1251: in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
/root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1011: in _send_output
    self.send(msg)
/root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:951: in send
    self.connect()
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:279: in connect
    self.sock = self._new_conn()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

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

    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 0x7feb09b7ea60>: Failed to establish a new connection: [Errno 111] Connection refused

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:214: NewConnectionError

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

self = <requests.adapters.HTTPAdapter object at 0x7feb09b7eaf0>
request = <PreparedRequest [GET]>, stream = False
timeout = Timeout(connect=None, read=None, total=None), verify = False
cert = None, proxies = OrderedDict()

    def send(
        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
    ):
        """Sends PreparedRequest object. Returns Response object.
    
        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
        :param stream: (optional) Whether to stream the request content.
        :param timeout: (optional) How long to wait for the server to send
            data before giving up, as a float, or a :ref:`(connect timeout,
            read timeout) <timeouts>` tuple.
        :type timeout: float or tuple or urllib3 Timeout object
        :param verify: (optional) Either a boolean, in which case it controls whether
            we verify the server's TLS certificate, or a string, in which case it
            must be a path to a CA bundle to use
        :param cert: (optional) Any user-provided SSL certificate to be trusted.
        :param proxies: (optional) The proxies dictionary to apply to the request.
        :rtype: requests.Response
        """
    
        try:
            conn = self.get_connection_with_tls_context(
                request, verify, proxies=proxies, cert=cert
            )
        except LocationValueError as e:
            raise InvalidURL(e, request=request)
    
        self.cert_verify(conn, request.url, verify, cert)
        url = self.request_url(request, proxies)
        self.add_headers(
            request,
            stream=stream,
            timeout=timeout,
            verify=verify,
            cert=cert,
            proxies=proxies,
        )
    
        chunked = not (request.body is None or "Content-Length" in request.headers)
    
        if isinstance(timeout, tuple):
            try:
                connect, read = timeout
                timeout = TimeoutSauce(connect=connect, read=read)
            except ValueError:
                raise ValueError(
                    f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                    f"or a single float to set both timeouts to the same value."
                )
        elif isinstance(timeout, TimeoutSauce):
            pass
        else:
            timeout = TimeoutSauce(connect=timeout, read=timeout)
    
        try:
>           resp = conn.urlopen(
                method=request.method,
                url=url,
                body=request.body,
                headers=request.headers,
                redirect=False,
                assert_same_host=False,
                preload_content=False,
                decode_content=False,
                retries=self.max_retries,
                timeout=timeout,
                chunked=chunked,
            )

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:667: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:843: in urlopen
    retries = retries.increment(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = Retry(total=0, connect=None, read=False, redirect=None, status=None)
method = 'GET', url = '/demo/None', response = None
error = NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09b7ea60>: Failed to establish a new connection: [Errno 111] Connection refused')
_pool = <urllib3.connectionpool.HTTPConnectionPool object at 0x7feb09b7e640>
_stacktrace = <traceback object at 0x7feb09906780>

    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: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09b7ea60>: Failed to establish a new connection: [Errno 111] Connection refused'))

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/retry.py:519: MaxRetryError

During handling of the above exception, another exception occurred:

self = <elog.logbook.Logbook object at 0x7feb0977c5b0>, msg_id = None
timeout = None

    def _check_if_message_on_server(self, msg_id, timeout=None):
        """Try to load page for specific message. If there is a html tag like <td class="errormsg"> then there is no
        such message.
    
        :param msg_id: ID of message to be checked
        :params timeout: The value of timeout to be passed to the get request
        :return:
        """
    
        request_headers = dict()
        if self._user or self._password:
            request_headers['Cookie'] = self._make_user_and_pswd_cookie()
        try:
>           response = requests.get(self._url + str(msg_id), headers=request_headers, allow_redirects=False,
                                    verify=False, timeout=timeout)

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:581: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:73: in get
    return request("get", url, params=params, **kwargs)
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:59: in request
    return session.request(method=method, url=url, **kwargs)
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:589: in request
    resp = self.send(prep, **send_kwargs)
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:703: in send
    r = adapter.send(request, **kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <requests.adapters.HTTPAdapter object at 0x7feb09b7eaf0>
request = <PreparedRequest [GET]>, stream = False
timeout = Timeout(connect=None, read=None, total=None), verify = False
cert = None, proxies = OrderedDict()

    def send(
        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
    ):
        """Sends PreparedRequest object. Returns Response object.
    
        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
        :param stream: (optional) Whether to stream the request content.
        :param timeout: (optional) How long to wait for the server to send
            data before giving up, as a float, or a :ref:`(connect timeout,
            read timeout) <timeouts>` tuple.
        :type timeout: float or tuple or urllib3 Timeout object
        :param verify: (optional) Either a boolean, in which case it controls whether
            we verify the server's TLS certificate, or a string, in which case it
            must be a path to a CA bundle to use
        :param cert: (optional) Any user-provided SSL certificate to be trusted.
        :param proxies: (optional) The proxies dictionary to apply to the request.
        :rtype: requests.Response
        """
    
        try:
            conn = self.get_connection_with_tls_context(
                request, verify, proxies=proxies, cert=cert
            )
        except LocationValueError as e:
            raise InvalidURL(e, request=request)
    
        self.cert_verify(conn, request.url, verify, cert)
        url = self.request_url(request, proxies)
        self.add_headers(
            request,
            stream=stream,
            timeout=timeout,
            verify=verify,
            cert=cert,
            proxies=proxies,
        )
    
        chunked = not (request.body is None or "Content-Length" in request.headers)
    
        if isinstance(timeout, tuple):
            try:
                connect, read = timeout
                timeout = TimeoutSauce(connect=connect, read=read)
            except ValueError:
                raise ValueError(
                    f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                    f"or a single float to set both timeouts to the same value."
                )
        elif isinstance(timeout, TimeoutSauce):
            pass
        else:
            timeout = TimeoutSauce(connect=timeout, read=timeout)
    
        try:
            resp = conn.urlopen(
                method=request.method,
                url=url,
                body=request.body,
                headers=request.headers,
                redirect=False,
                assert_same_host=False,
                preload_content=False,
                decode_content=False,
                retries=self.max_retries,
                timeout=timeout,
                chunked=chunked,
            )
    
        except (ProtocolError, OSError) as err:
            raise ConnectionError(err, request=request)
    
        except MaxRetryError as e:
            if isinstance(e.reason, ConnectTimeoutError):
                # TODO: Remove this in 3.0.0: see #2811
                if not isinstance(e.reason, NewConnectionError):
                    raise ConnectTimeout(e, request=request)
    
            if isinstance(e.reason, ResponseError):
                raise RetryError(e, request=request)
    
            if isinstance(e.reason, _ProxyError):
                raise ProxyError(e, request=request)
    
            if isinstance(e.reason, _SSLError):
                # This branch is for urllib3 v1.22 and later.
                raise SSLError(e, request=request)
    
>           raise ConnectionError(e, request=request)
E           requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09b7ea60>: Failed to establish a new connection: [Errno 111] Connection refused'))

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:700: ConnectionError

During handling of the above exception, another exception occurred:

mock_screenshot_class = <MagicMock name='Screenshot' id='140647452388896'>

    @patch("slic.utils.elog.Screenshot")
    def test_screenshot(mock_screenshot_class):
        fake_path = "/tmp/fake_screenshot.png"
        with open(fake_path, "wb") as f:
            f.write(b"fake image data")
    
        mock_instance = mock_screenshot_class.return_value
        mock_instance.shoot.return_value = [fake_path]
    
        elog = Elog("http://localhost:8080/demo", user="robot", password="testpassword")
    
        test_msg = "SCREENSHOT_INTEGRATION_TEST_MSG_456"
>       msg_id = elog.screenshot(message=test_msg)

tests/test_utils_elog.py:116: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
slic/utils/elog.py:21: in screenshot
    return self.post(message, **kwargs)
slic/utils/elog.py:16: in post
    return self._log.post(*args, **kwargs)
/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:307: in post
    self._check_if_message_on_server(msg_id)  # raises exceptions if no message or no response from server
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <elog.logbook.Logbook object at 0x7feb0977c5b0>, msg_id = None
timeout = None

    def _check_if_message_on_server(self, msg_id, timeout=None):
        """Try to load page for specific message. If there is a html tag like <td class="errormsg"> then there is no
        such message.
    
        :param msg_id: ID of message to be checked
        :params timeout: The value of timeout to be passed to the get request
        :return:
        """
    
        request_headers = dict()
        if self._user or self._password:
            request_headers['Cookie'] = self._make_user_and_pswd_cookie()
        try:
            response = requests.get(self._url + str(msg_id), headers=request_headers, allow_redirects=False,
                                    verify=False, timeout=timeout)
    
            # If there is no message code 200 will be returned (OK) and _validate_response will not recognise it
            # but there will be some error in the html code.
            resp_message, resp_headers, resp_msg_id = _validate_response(response)
            # If there is no message, code 200 will be returned (OK) but there will be some error indication in
            # the html code.
            if re.findall('<td.*?class="errormsg".*?>.*?</td>',
                          resp_message.decode('utf-8', 'ignore'),
                          flags=re.DOTALL):
                raise LogbookInvalidMessageID('Message with ID: ' + str(msg_id) + ' does not exist on logbook.')
    
        except requests.Timeout as e:
            # Catch here a timeout o the post request.
            # Raise the logbook exception and let the user handle it
            raise LogbookServerTimeout('{0} method cannot be completed because of a network timeout:\n' +
                                       '{1}'.format(sys._getframe().f_code.co_name, e))
    
        except requests.RequestException as e:
>           raise LogbookServerProblem('No response from the logbook server.\nDetails: ' + '{0}'.format(e))
E           elog.logbook_exceptions.LogbookServerProblem: No response from the logbook server.
E           Details: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09b7ea60>: Failed to establish a new connection: [Errno 111] Connection refused'))

/root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:601: LogbookServerProblem
_____________________________ test_get_adjs_filter _____________________________

    def test_get_adjs_filter():
        a4 = SubAdjustable("mid_brightness",         units="%", limit_low=0,   limit_high=100)
        a5 = SubAdjustable("debug_internal",   internal=True)
        public = get_adjs()
>       assert set(public) == {'brightness', 'contrast', 'mid_contrast', 'mid_brightness'}
E       AssertionError: assert {'contrast', ...mid_contrast'} == {'brightness'...mid_contrast'}
E         
E         Extra items in the right set:
E         'brightness'
E         
E         Full diff:
E           {
E         -     'brightness',
E               'contrast',
E               'mid_brightness',
E               'mid_contrast',
E           }

tests/test_utils_get_adj.py:42: AssertionError
_____________________ test_import_logging_once_per_module ______________________

    def test_import_logging_once_per_module():
        code = textwrap.dedent("""
            from slic.utils.logcfg import *
            import math
            import io
            import random
        """)
    
        with tempfile.NamedTemporaryFile("w", suffix=".py", delete=False) as tmp:
            tmp.write(code)
            tmp_path = tmp.name
    
        env = os.environ.copy()
        root_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
        env["PYTHONPATH"] = root_path + os.pathsep + env.get("PYTHONPATH", "")
    
        result = subprocess.run([sys.executable, tmp_path], capture_output=True, text=True, env=env)
        os.remove(tmp_path)
    
        assert result.returncode == 0, f"Script failed:\n{result.stderr}"
    
        stderr = result.stderr
        print(stderr)
        lines = stderr.splitlines()
        for mod in ["math", "io", "random"]:
            count = sum(1 for line in lines if f"importing: {mod}" in line)
>           assert count == 1, f"Expected 1 import log for '{mod}', found {count}"
E           AssertionError: Expected 1 import log for 'math', found 0
E           assert 0 == 1

tests/test_utils_logcfg.py:78: AssertionError
----------------------------- Captured stdout call -----------------------------
[E 250828 10:15:55 tools:40] cannot assign endstation to IP 172.18.0.3 (038eaf845eac)

___________________ TestShortcutsSingleton.test_registration ___________________

self = <test_utils_shortcut.TestShortcutsSingleton object at 0x7feb09bdfee0>

    def test_registration(self):
        # Test automatic registration
        @as_shortcut(name="FuncA")
        def func_a():
            pass
    
        @as_shortcut(name="FuncB")
        def func_b():
            pass
    
>       assert len(shortcuts._get()) == 2
E       assert 3 == 2
E        +  where 3 = len({'<lambda>': Shortcut "<lambda>", 'FuncA': Shortcut "FuncA", 'FuncB': Shortcut "FuncB"})
E        +    where {'<lambda>': Shortcut "<lambda>", 'FuncA': Shortcut "FuncA", 'FuncB': Shortcut "FuncB"} = _get()
E        +      where _get = <lambda>: Shortcut "<lambda>"\nFuncA:    Shortcut "FuncA"\nFuncB:    Shortcut "FuncB"\n._get

tests/test_utils_shortcut.py:138: AssertionError
_________________ TestFullIntegration.test_multiple_shortcuts __________________

self = <test_utils_shortcut.TestFullIntegration object at 0x7feb09cdfcd0>

    def test_multiple_shortcuts(self):
        # Test multiple shortcuts coexistence
        @as_shortcut(name="First")
        def first():
            return 1
    
        @as_shortcut(name="Second")
        def second():
            return 2
    
        assert shortcuts["First"].func() == 1
        assert shortcuts["Second"].func() == 2
>       assert len(shortcuts._get()) == 2
E       assert 5 == 2
E        +  where 5 = len({'<lambda>': Shortcut "<lambda>", 'First': Shortcut "First", 'FuncA': Shortcut "FuncA", 'FuncB': Shortcut "FuncB", ...})
E        +    where {'<lambda>': Shortcut "<lambda>", 'First': Shortcut "First", 'FuncA': Shortcut "FuncA", 'FuncB': Shortcut "FuncB", ...} = _get()
E        +      where _get = <lambda>: Shortcut "<lambda>"\nFirst:    Shortcut "First"\nFuncA:    Shortcut "FuncA"\nFuncB:    Shortcut "FuncB"\nSecond:   Shortcut "Second"\n._get

tests/test_utils_shortcut.py:203: AssertionError
_________________________ test_float_alignment_in_bar __________________________

    def test_float_alignment_in_bar():
        # Capture the tqdm output into a string buffer
        f = io.StringIO()
        with redirect_stdout(f):
            bar = tqdm_mod(total=100.12, desc="AlignBar", file=f, miniters=1, mininterval=0)
            bar.set(1.3333)
            bar.set(12.5)
            bar.set(99.89)
            bar.set(100.12)
            bar.close()
    
        # Extract lines containing the label
        lines = extract_lines(f.getvalue(), "AlignBar")
    
        # Expected formatted values using format_sizeof
        expected_values = [
            "1.3/100.1",
            "12.5/100.1",
            "99.9/100.1",
            "100.1/100.1",
        ]
    
        # Extract the actual padded float/total strings from the full lines
        values = []
        for line in lines:
            match = re.search(r"(\d{1,3}\.\d)/100\.1", line)
            if match:
                values.append(match.group(0))
    
        # Ensure raw 100.12 never appears : format_sizeof must have truncated it
        assert all("100.12" not in line for line in lines), "Unrounded value '100.12' found in output!"
    
        # Check all expected values appear rounded as expected by format_sizeof
        for expected in expected_values:
            assert expected in values, f"Missing expected value: {expected}"
    
        # Check that all values are visually aligned, output with same length, to ensure that format_sizeof add the good number avec spaces
        print("\n")
        bar_segments = []
        for line in lines:
            match = re.search(r".*?\]", line)
            if match:
                bar_segments.append(match.group(0))
                print(match.group(0))
    
        lengths = [len(seg) for seg in bar_segments]
>       assert len(set(lengths)) == 1
E       assert 3 == 1
E        +  where 3 = len({50, 64, 65})
E        +    where {50, 64, 65} = set([50, 64, 64, 65, 65])

tests/test_utils_tqdm_mod.py:130: AssertionError
----------------------------- Captured stdout call -----------------------------


AlignBar:   0%|          | 0/100.1 [00:00<?, ? Hz]
AlignBar:   1%|1         |   1.3/100.1 [00:00<00:00, 57652.2 Hz]
AlignBar:  12%|#2        |  12.5/100.1 [00:00<00:00, 81738.0 Hz]
AlignBar: 100%|#########9|  99.9/100.1 [00:00<00:00, 420734.0 Hz]
AlignBar: 100%|##########| 100.1/100.1 [00:00<00:00, 217807.9 Hz]
=============================== warnings summary ===============================
../../../root/mambaforge/envs/ci-env/lib/python3.8/site-packages/scipy/fft/__init__.py:97
  /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/scipy/fft/__init__.py:97: DeprecationWarning: The module numpy.dual is deprecated.  Instead of using dual, use the functions directly from numpy or scipy.
    from numpy.dual import register_func

tests/test_utils_pv.py:12
  /workspace/tligui_y/slic/tests/test_utils_pv.py:12: DeprecationWarning: invalid escape sequence \[
    '''

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html

Generated on 2025-08-28 12:16:05 CEST

🧾 General Info

  • duration: 161.07588052749634
  • root: /workspace/tligui_y/slic
  • environment: {}

📋 Summary

  • Passed: 518
  • Failed: 11
  • Total: 529
  • Collected: 529

🔎 Tests

Passed (518)
  • 📄 morbidissimo/morbidissimo/morioc/test_infer_type.py

    Function: test_it_type_str

    • Test 1

      📌 Setup phase

      duration:

      0.0008492115885019302
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00028853677213191986
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002390863373875618
      

      outcome:

      passed
      

    Function: test_it_type_float

    • Test 2

      📌 Setup phase

      duration:

      0.00016960874199867249
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018779374659061432
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00014367513358592987
      

      outcome:

      passed
      

    Function: test_it_type_int

    • Test 3

      📌 Setup phase

      duration:

      0.00015050452202558517
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002009579911828041
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00015898514539003372
      

      outcome:

      passed
      

    Function: test_it_value_str

    • Test 4

      📌 Setup phase

      duration:

      0.0001521427184343338
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001798029989004135
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001422381028532982
      

      outcome:

      passed
      

    Function: test_it_value_long_str

    • Test 5

      📌 Setup phase

      duration:

      0.00014987587928771973
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001828102394938469
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001388099044561386
      

      outcome:

      passed
      

    Function: test_it_value_float

    • Test 6

      📌 Setup phase

      duration:

      0.00014726724475622177
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002255188301205635
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00014698971062898636
      

      outcome:

      passed
      

    Function: test_it_value_int

    • Test 7

      📌 Setup phase

      duration:

      0.00017888564616441727
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002636425197124481
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00014178454875946045
      

      outcome:

      passed
      

    Function: test_it_empty_value_str

    • Test 8

      📌 Setup phase

      duration:

      0.00015732459723949432
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018253177404403687
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00013552885502576828
      

      outcome:

      passed
      

    Function: test_it_empty_value_float

    • Test 9

      📌 Setup phase

      duration:

      0.00014503486454486847
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001764744520187378
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00013448670506477356
      

      outcome:

      passed
      

    Function: test_it_empty_value_int

    • Test 10

      📌 Setup phase

      duration:

      0.0001433100551366806
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00016853585839271545
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001297472044825554
      

      outcome:

      passed
      

    Function: test_pstrue_str

    • Test 11

      📌 Setup phase

      duration:

      0.00014315545558929443
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001804698258638382
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00014874618500471115
      

      outcome:

      passed
      

    Function: test_pstrue_float

    • Test 12

      📌 Setup phase

      duration:

      0.0001861676573753357
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017831847071647644
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00013916287571191788
      

      outcome:

      passed
      

    Function: test_pstrue_int

    • Test 13

      📌 Setup phase

      duration:

      0.0001414380967617035
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017048045992851257
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00013455841690301895
      

      outcome:

      passed
      

    Function: test_psfalse_str

    • Test 14

      📌 Setup phase

      duration:

      0.00014704465866088867
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001721540465950966
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00013556703925132751
      

      outcome:

      passed
      

    Function: test_psfalse_float

    • Test 15

      📌 Setup phase

      duration:

      0.0001393575221300125
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017584767192602158
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00013235583901405334
      

      outcome:

      passed
      

    Function: test_psfalse_int

    • Test 16

      📌 Setup phase

      duration:

      0.0001479675993323326
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00021432247012853622
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00013510696589946747
      

      outcome:

      passed
      

    Function: test_it_None

    • Test 17

      📌 Setup phase

      duration:

      0.00013822317123413086
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00022944528609514236
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00014167185872793198
      

      outcome:

      passed
      

    Function: test_it_True

    • Test 18

      📌 Setup phase

      duration:

      0.00014280807226896286
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017523113638162613
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00012876931577920914
      

      outcome:

      passed
      

    Function: test_it_False

    • Test 19

      📌 Setup phase

      duration:

      0.0001469263806939125
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002308376133441925
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001902719959616661
      

      outcome:

      passed
      

    Function: test_it_nan

    • Test 20

      📌 Setup phase

      duration:

      0.000439605675637722
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002726307138800621
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017759297043085098
      

      outcome:

      passed
      

    Function: test_it_np_nan

    • Test 21

      📌 Setup phase

      duration:

      0.00022440683096647263
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018002837896347046
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00014685280621051788
      

      outcome:

      passed
      

    Function: test_it_np1D_int

    • Test 22

      📌 Setup phase

      duration:

      0.00015140417963266373
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002526352182030678
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00014894641935825348
      

      outcome:

      passed
      

    Function: test_it_np2D_int

    • Test 23

      📌 Setup phase

      duration:

      0.0001408737152814865
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002279793843626976
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00014532171189785004
      

      outcome:

      passed
      

    Function: test_it_np1D_float

    • Test 24

      📌 Setup phase

      duration:

      0.0001736050471663475
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00032355543226003647
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00013871211558580399
      

      outcome:

      passed
      

    Function: test_it_np2D_float

    • Test 25

      📌 Setup phase

      duration:

      0.00015734322369098663
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002528103068470955
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00013892445713281631
      

      outcome:

      passed
      

    Function: test_it_np1D_bool

    • Test 26

      📌 Setup phase

      duration:

      0.00017307698726654053
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00020481180399656296
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00013688579201698303
      

      outcome:

      passed
      

    Function: test_it_np1D_object

    • Test 27

      📌 Setup phase

      duration:

      0.000151841901242733
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019360054284334183
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00013342685997486115
      

      outcome:

      passed
      

    Function: test_it_np_scalar_int

    • Test 28

      📌 Setup phase

      duration:

      0.00014191865921020508
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00021919235587120056
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00013150274753570557
      

      outcome:

      passed
      

    Function: test_it_np_scalar_float

    • Test 29

      📌 Setup phase

      duration:

      0.00014956574887037277
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00021452363580465317
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00014550518244504929
      

      outcome:

      passed
      

    Function: test_it_np_scalar_bool

    • Test 30

      📌 Setup phase

      duration:

      0.00014221202582120895
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00022305455058813095
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00014491844922304153
      

      outcome:

      passed
      

    Function: test_it_list

    • Test 31

      📌 Setup phase

      duration:

      0.0001393323764204979
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018355902284383774
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00014203041791915894
      

      outcome:

      passed
      

    Function: test_it_tuple

    • Test 32

      📌 Setup phase

      duration:

      0.00014260876923799515
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018188171088695526
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001498861238360405
      

      outcome:

      passed
      
  • 📄 test_utils_argfwd.py

    Function: test_split_at

    • Test 33
      params: lst=["a", "b", "c", "d"], index=2, expected=[["a", "b"], ["c", "d"]]

      📌 Parameters

      params:
        lst: ["a", "b", "c", "d"]
        index: 2
        expected: [["a", "b"], ["c", "d"]]
      id: "lst0-2-expected0"
      

      📌 Setup phase

      duration:

      0.00047350209206342697
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019927509129047394
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00021731015294790268
      

      outcome:

      passed
      
    • Test 34
      params: lst=["x", "y"], index=1, expected=[["x"], ["y"]]

      📌 Parameters

      params:
        lst: ["x", "y"]
        index: 1
        expected: [["x"], ["y"]]
      id: "lst1-1-expected1"
      

      📌 Setup phase

      duration:

      0.00032537151128053665
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001871725544333458
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002054646611213684
      

      outcome:

      passed
      
    • Test 35
      params: lst=[], index=0, expected=[[], []]

      📌 Parameters

      params:
        lst: []
        index: 0
        expected: [[], []]
      id: "lst2-0-expected2"
      

      📌 Setup phase

      duration:

      0.00032277218997478485
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017444230616092682
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001965295523405075
      

      outcome:

      passed
      

    Function: test_merge_lists_unique

    • Test 36
      params: a=["a", "b"], b=["b", "c"], expected=["a", "b", "c"]

      📌 Parameters

      params:
        a: ["a", "b"]
        b: ["b", "c"]
        expected: ["a", "b", "c"]
      id: "a0-b0-expected0"
      

      📌 Setup phase

      duration:

      0.0003235694020986557
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017551425844430923
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00021209102123975754
      

      outcome:

      passed
      
    • Test 37
      params: a=[], b=["x"], expected=["x"]

      📌 Parameters

      params:
        a: []
        b: ["x"]
        expected: ["x"]
      id: "a1-b1-expected1"
      

      📌 Setup phase

      duration:

      0.0003076251596212387
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018645543605089188
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001875096932053566
      

      outcome:

      passed
      
    • Test 38
      params: a=["x", "y"], b=["x", "y"], expected=["x", "y"]

      📌 Parameters

      params:
        a: ["x", "y"]
        b: ["x", "y"]
        expected: ["x", "y"]
      id: "a2-b2-expected2"
      

      📌 Setup phase

      duration:

      0.00031824223697185516
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017457548528909683
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001897420734167099
      

      outcome:

      passed
      

    Function: test_merge_dicts_unique

    • Test 39
      params: a={"a": 1}, b={"b": 2}, expected={"a": 1, "b": 2}

      📌 Parameters

      params:
        a: {"a": 1}
        b: {"b": 2}
        expected: {"a": 1, "b": 2}
      id: "a0-b0-expected0"
      

      📌 Setup phase

      duration:

      0.0003154994919896126
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018051546066999435
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002170829102396965
      

      outcome:

      passed
      
    • Test 40
      params: a={"x": 1}, b={"x": 9, "y": 3}, expected={"x": 1, "y": 3}

      📌 Parameters

      params:
        a: {"x": 1}
        b: {"x": 9, "y": 3}
        expected: {"x": 1, "y": 3}
      id: "a1-b1-expected1"
      

      📌 Setup phase

      duration:

      0.0003124549984931946
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001886766403913498
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018966849893331528
      

      outcome:

      passed
      
    • Test 41
      params: a={}, b={"k": 4}, expected={"k": 4}

      📌 Parameters

      params:
        a: {}
        b: {"k": 4}
        expected: {"k": 4}
      id: "a2-b2-expected2"
      

      📌 Setup phase

      duration:

      0.00032521411776542664
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017796270549297333
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0003001820296049118
      

      outcome:

      passed
      

    Function: test_make_params_pos_basic

    • Test 42
      params: pos=["a", "b"], expected_names=["a", "b"]

      📌 Parameters

      params:
        pos: ["a", "b"]
        expected_names: ["a", "b"]
      id: "pos0-expected_names0"
      

      📌 Setup phase

      duration:

      0.0002869032323360443
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00021937023848295212
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018197577446699142
      

      outcome:

      passed
      
    • Test 43
      params: pos=["param1", "value_2", "Z"], expected_names=["param1", "value_2", "Z"]

      📌 Parameters

      params:
        pos: ["param1", "value_2", "Z"]
        expected_names: ["param1", "value_2", "Z"]
      id: "pos1-expected_names1"
      

      📌 Setup phase

      duration:

      0.00026125460863113403
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00021721329540014267
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.000178532674908638
      

      outcome:

      passed
      
    • Test 44
      params: pos=[], expected_names=[]

      📌 Parameters

      params:
        pos: []
        expected_names: []
      id: "pos2-expected_names2"
      

      📌 Setup phase

      duration:

      0.000279928557574749
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018133874982595444
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001762276515364647
      

      outcome:

      passed
      

    Function: test_make_params_kw_basic

    • Test 45
      params: kw={"a": 1, "b": 2}, expected_keys=["a", "b"], expected_defaults=[1, 2]

      📌 Parameters

      params:
        kw: {"a": 1, "b": 2}
        expected_keys: ["a", "b"]
        expected_defaults: [1, 2]
      id: "kw0-expected_keys0-expected_defaults0"
      

      📌 Setup phase

      duration:

      0.00031310226768255234
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019277166575193405
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020230188965797424
      

      outcome:

      passed
      
    • Test 46
      params: kw={"param_x": 0}, expected_keys=["param_x"], expected_defaults=[0]

      📌 Parameters

      params:
        kw: {"param_x": 0}
        expected_keys: ["param_x"]
        expected_defaults: [0]
      id: "kw1-expected_keys1-expected_defaults1"
      

      📌 Setup phase

      duration:

      0.00030715949833393097
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002019917592406273
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019695516675710678
      

      outcome:

      passed
      
    • Test 47
      params: kw={}, expected_keys=[], expected_defaults=[]

      📌 Parameters

      params:
        kw: {}
        expected_keys: []
        expected_defaults: []
      id: "kw2-expected_keys2-expected_defaults2"
      

      📌 Setup phase

      duration:

      0.00032265298068523407
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018729642033576965
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020504556596279144
      

      outcome:

      passed
      

    Function: test_make_signature_parametrized

    • Test 48
      params: pos=["x", "y"], kw={"z": 3}, expected_signature="(x, y, z=3)"

      📌 Parameters

      params:
        pos: ["x", "y"]
        kw: {"z": 3}
        expected_signature: "(x, y, z=3)"
      id: "pos0-kw0-(x, y, z=3)"
      

      📌 Setup phase

      duration:

      0.0003156689926981926
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00022267736494541168
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019366107881069183
      

      outcome:

      passed
      
    • Test 49
      params: pos=["a"], kw={"b": 1, "c": 2}, expected_signature="(a, b=1, c=2)"

      📌 Parameters

      params:
        pos: ["a"]
        kw: {"b": 1, "c": 2}
        expected_signature: "(a, b=1, c=2)"
      id: "pos1-kw1-(a, b=1, c=2)"
      

      📌 Setup phase

      duration:

      0.0003072097897529602
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00022211764007806778
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019348599016666412
      

      outcome:

      passed
      
    • Test 50
      params: pos=[], kw={"flag": false}, expected_signature="(flag=False)"

      📌 Parameters

      params:
        pos: []
        kw: {"flag": false}
        expected_signature: "(flag=False)"
      id: "pos2-kw2-(flag=False)"
      

      📌 Setup phase

      duration:

      0.0003270106390118599
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002046152949333191
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020399410277605057
      

      outcome:

      passed
      

    Function: test_get_args_parametrized

    • Test 51
      params: func="<function <lambda> at 0x7feb0ab58040>", expected_pos=["a", "b"], expected_kw={"c": 3, "d": 4}

      📌 Parameters

      params:
        func: "<function <lambda> at 0x7feb0ab58040>"
        expected_pos: ["a", "b"]
        expected_kw: {"c": 3, "d": 4}
      id: "<lambda>-expected_pos0-expected_kw0"
      

      📌 Setup phase

      duration:

      0.0003008134663105011
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002547306939959526
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002012457698583603
      

      outcome:

      passed
      
    • Test 52
      params: func="<function <lambda> at 0x7feb0ab58f70>", expected_pos=[], expected_kw="{'x': 1, 'y': <class 'inspect._empty'>, 'z': 0}"

      📌 Parameters

      params:
        func: "<function <lambda> at 0x7feb0ab58f70>"
        expected_pos: []
        expected_kw: "{'x': 1, 'y': <class 'inspect._empty'>, 'z': 0}"
      id: "<lambda>-expected_pos1-expected_kw1"
      

      📌 Setup phase

      duration:

      0.00031566526740789413
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00022898521274328232
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002016201615333557
      

      outcome:

      passed
      
    • Test 53
      params: func="<function <lambda> at 0x7feb0ab5b0d0>", expected_pos=[], expected_kw={}

      📌 Parameters

      params:
        func: "<function <lambda> at 0x7feb0ab5b0d0>"
        expected_pos: []
        expected_kw: {}
      id: "<lambda>-expected_pos2-expected_kw2"
      

      📌 Setup phase

      duration:

      0.00031538214534521103
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00020868796855211258
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002007409930229187
      

      outcome:

      passed
      

    Function: test_signature_visible

    • Test 54
      params: func="<function wrap_all at 0x7feb0ab5b310>", expected_sig="(a, b, d=30, c=10)"

      📌 Parameters

      params:
        func: "<function wrap_all at 0x7feb0ab5b310>"
        expected_sig: "(a, b, d=30, c=10)"
      id: "wrap_all-(a, b, d=30, c=10)"
      

      📌 Setup phase

      duration:

      0.0002719815820455551
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00022020097821950912
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018278323113918304
      

      outcome:

      passed
      
    • Test 55
      params: func="<function wrap_skip at 0x7feb0ab5b3a0>", expected_sig="(a, b, c=10, d=20)"

      📌 Parameters

      params:
        func: "<function wrap_skip at 0x7feb0ab5b3a0>"
        expected_sig: "(a, b, c=10, d=20)"
      id: "wrap_skip-(a, b, c=10, d=20)"
      

      📌 Setup phase

      duration:

      0.00026768632233142853
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001864023506641388
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018760841339826584
      

      outcome:

      passed
      
    • Test 56
      params: func="<function wrap_ignore_all at 0x7feb0ab5b430>", expected_sig="(x, y, c=10, d=20)"

      📌 Parameters

      params:
        func: "<function wrap_ignore_all at 0x7feb0ab5b430>"
        expected_sig: "(x, y, c=10, d=20)"
      id: "wrap_ignore_all-(x, y, c=10, d=20)"
      

      📌 Setup phase

      duration:

      0.000266294926404953
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018823985010385513
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018959958106279373
      

      outcome:

      passed
      

    Function: test_wrapper_behavior

    • Test 57
      params: func="<function wrap_all at 0x7feb0ab5b310>", args=[1, 2, 3], kwargs={}, expected_result=36

      📌 Parameters

      params:
        func: "<function wrap_all at 0x7feb0ab5b310>"
        args: [1, 2, 3]
        kwargs: {}
        expected_result: 36
      id: "wrap_all-args0-kwargs0-36"
      

      📌 Setup phase

      duration:

      0.0003584623336791992
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019318610429763794
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.000208328478038311
      

      outcome:

      passed
      
    • Test 58
      params: func="<function wrap_all at 0x7feb0ab5b310>", args=[1, 2, 3], kwargs={"d": 5}, expected_result=11

      📌 Parameters

      params:
        func: "<function wrap_all at 0x7feb0ab5b310>"
        args: [1, 2, 3]
        kwargs: {"d": 5}
        expected_result: 11
      id: "wrap_all-args1-kwargs1-11"
      

      📌 Setup phase

      duration:

      0.0003572562709450722
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017806701362133026
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00021044723689556122
      

      outcome:

      passed
      
    • Test 59
      params: func="<function wrap_skip at 0x7feb0ab5b3a0>", args=[0, 0], kwargs={"c": 3, "d": 4}, expected_result=10

      📌 Parameters

      params:
        func: "<function wrap_skip at 0x7feb0ab5b3a0>"
        args: [0, 0]
        kwargs: {"c": 3, "d": 4}
        expected_result: 10
      id: "wrap_skip-args2-kwargs2-10"
      

      📌 Setup phase

      duration:

      0.0003505023196339607
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001687249168753624
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002217283472418785
      

      outcome:

      passed
      
    • Test 60
      params: func="<function wrap_ignore_all at 0x7feb0ab5b430>", args=[0, 0], kwargs={}, expected_result=10

      📌 Parameters

      params:
        func: "<function wrap_ignore_all at 0x7feb0ab5b430>"
        args: [0, 0]
        kwargs: {}
        expected_result: 10
      id: "wrap_ignore_all-args3-kwargs3-10"
      

      📌 Setup phase

      duration:

      0.0003528110682964325
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017293915152549744
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020739994943141937
      

      outcome:

      passed
      
  • 📄 test_utils_ask_yes_no.py

    Function: test_ask_yes_no

    • Test 61
      params: default=null, user_input="y", expected_output=true, expected_prompt="Question? [y/n] "

      📌 Parameters

      params:
        default: null
        user_input: "y"
        expected_output: true
        expected_prompt: "Question? [y/n] "
      id: "None-y-True-Question? [y/n] "
      

      📌 Setup phase

      duration:

      0.00039163045585155487
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0009704111143946648
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002596825361251831
      

      outcome:

      passed
      
    • Test 62
      params: default=null, user_input="yes", expected_output=true, expected_prompt="Question? [y/n] "

      📌 Parameters

      params:
        default: null
        user_input: "yes"
        expected_output: true
        expected_prompt: "Question? [y/n] "
      id: "None-yes-True-Question? [y/n] "
      

      📌 Setup phase

      duration:

      0.0003703795373439789
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0006387867033481598
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00023720692843198776
      

      outcome:

      passed
      
    • Test 63
      params: default=null, user_input="n", expected_output=false, expected_prompt="Question? [y/n] "

      📌 Parameters

      params:
        default: null
        user_input: "n"
        expected_output: false
        expected_prompt: "Question? [y/n] "
      id: "None-n-False-Question? [y/n] "
      

      📌 Setup phase

      duration:

      0.00036588776856660843
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0005895337089896202
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00024140626192092896
      

      outcome:

      passed
      
    • Test 64
      params: default=null, user_input="no", expected_output=false, expected_prompt="Question? [y/n] "

      📌 Parameters

      params:
        default: null
        user_input: "no"
        expected_output: false
        expected_prompt: "Question? [y/n] "
      id: "None-no-False-Question? [y/n] "
      

      📌 Setup phase

      duration:

      0.00036413781344890594
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0006846310570836067
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002493159845471382
      

      outcome:

      passed
      
    • Test 65
      params: default=null, user_input=["maybe", "y"], expected_output=true, expected_prompt="Question? [y/n] "

      📌 Parameters

      params:
        default: null
        user_input: ["maybe", "y"]
        expected_output: true
        expected_prompt: "Question? [y/n] "
      id: "None-user_input4-True-Question? [y/n] "
      

      📌 Setup phase

      duration:

      0.0003711208701133728
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0006335172802209854
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00024958979338407516
      

      outcome:

      passed
      
    • Test 66
      params: default=null, user_input=["", "no"], expected_output=false, expected_prompt="Question? [y/n] "

      📌 Parameters

      params:
        default: null
        user_input: ["", "no"]
        expected_output: false
        expected_prompt: "Question? [y/n] "
      id: "None-user_input5-False-Question? [y/n] "
      

      📌 Setup phase

      duration:

      0.0003680204972624779
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0006720423698425293
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002484312281012535
      

      outcome:

      passed
      
    • Test 67
      params: default=null, user_input=["invalid", "", "invalid", "yes"], expected_output=true, expected_prompt="Question? [y/n] "

      📌 Parameters

      params:
        default: null
        user_input: ["invalid", "", "invalid", "yes"]
        expected_output: true
        expected_prompt: "Question? [y/n] "
      id: "None-user_input6-True-Question? [y/n] "
      

      📌 Setup phase

      duration:

      0.00036552827805280685
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0006300825625658035
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00023937691003084183
      

      outcome:

      passed
      
    • Test 68
      params: default="y", user_input="y", expected_output=true, expected_prompt="Question? [Y/n] "

      📌 Parameters

      params:
        default: "y"
        user_input: "y"
        expected_output: true
        expected_prompt: "Question? [Y/n] "
      id: "y-y-True-Question? [Y/n] "
      

      📌 Setup phase

      duration:

      0.00037391483783721924
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0006918814033269882
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00031389016658067703
      

      outcome:

      passed
      
    • Test 69
      params: default="y", user_input="n", expected_output=false, expected_prompt="Question? [Y/n] "

      📌 Parameters

      params:
        default: "y"
        user_input: "n"
        expected_output: false
        expected_prompt: "Question? [Y/n] "
      id: "y-n-False-Question? [Y/n] "
      

      📌 Setup phase

      duration:

      0.0003663068637251854
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0005773017182946205
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002341819927096367
      

      outcome:

      passed
      
    • Test 70
      params: default="y", user_input="", expected_output=true, expected_prompt="Question? [Y/n] "

      📌 Parameters

      params:
        default: "y"
        user_input: ""
        expected_output: true
        expected_prompt: "Question? [Y/n] "
      id: "y--True-Question? [Y/n] "
      

      📌 Setup phase

      duration:

      0.0003656148910522461
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0005584582686424255
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00022018607705831528
      

      outcome:

      passed
      
    • Test 71
      params: default="n", user_input="y", expected_output=true, expected_prompt="Question? [y/N] "

      📌 Parameters

      params:
        default: "n"
        user_input: "y"
        expected_output: true
        expected_prompt: "Question? [y/N] "
      id: "n-y-True-Question? [y/N] "
      

      📌 Setup phase

      duration:

      0.0003519579768180847
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0005792174488306046
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00024229567497968674
      

      outcome:

      passed
      
    • Test 72
      params: default="n", user_input="n", expected_output=false, expected_prompt="Question? [y/N] "

      📌 Parameters

      params:
        default: "n"
        user_input: "n"
        expected_output: false
        expected_prompt: "Question? [y/N] "
      id: "n-n-False-Question? [y/N] "
      

      📌 Setup phase

      duration:

      0.0003627752885222435
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.000691484659910202
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00022077281028032303
      

      outcome:

      passed
      
    • Test 73
      params: default="n", user_input="", expected_output=false, expected_prompt="Question? [y/N] "

      📌 Parameters

      params:
        default: "n"
        user_input: ""
        expected_output: false
        expected_prompt: "Question? [y/N] "
      id: "n--False-Question? [y/N] "
      

      📌 Setup phase

      duration:

      0.00038279034197330475
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0005721980705857277
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002336297184228897
      

      outcome:

      passed
      

    Function: test_ask_yes_no_ctrl_c

    • Test 74
      params: default=null, user_input="<class 'KeyboardInterrupt'>", expected_output=false, ctrl_c="n"

      📌 Parameters

      params:
        default: null
        user_input: "<class 'KeyboardInterrupt'>"
        expected_output: false
        ctrl_c: "n"
      id: "None-KeyboardInterrupt-False-n"
      

      📌 Setup phase

      duration:

      0.00039671268314123154
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0011618370190262794
      

      outcome:

      passed
      

      stdout:

      
      
      

      📌 Teardown phase

      duration:

      0.000264790840446949
      

      outcome:

      passed
      
    • Test 75
      params: default=null, user_input="<class 'KeyboardInterrupt'>", expected_output=true, ctrl_c="y"

      📌 Parameters

      params:
        default: null
        user_input: "<class 'KeyboardInterrupt'>"
        expected_output: true
        ctrl_c: "y"
      id: "None-KeyboardInterrupt-True-y"
      

      📌 Setup phase

      duration:

      0.0003820238634943962
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0011475170031189919
      

      outcome:

      passed
      

      stdout:

      
      
      

      📌 Teardown phase

      duration:

      0.00023440178483724594
      

      outcome:

      passed
      
    • Test 76
      params: default="y", user_input="<class 'KeyboardInterrupt'>", expected_output=false, ctrl_c="n"

      📌 Parameters

      params:
        default: "y"
        user_input: "<class 'KeyboardInterrupt'>"
        expected_output: false
        ctrl_c: "n"
      id: "y-KeyboardInterrupt-False-n"
      

      📌 Setup phase

      duration:

      0.0004116250202059746
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0010054968297481537
      

      outcome:

      passed
      

      stdout:

      
      
      

      📌 Teardown phase

      duration:

      0.00026118941605091095
      

      outcome:

      passed
      
    • Test 77
      params: default="y", user_input="<class 'KeyboardInterrupt'>", expected_output=true, ctrl_c="y"

      📌 Parameters

      params:
        default: "y"
        user_input: "<class 'KeyboardInterrupt'>"
        expected_output: true
        ctrl_c: "y"
      id: "y-KeyboardInterrupt-True-y"
      

      📌 Setup phase

      duration:

      0.0003730505704879761
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0009170044213533401
      

      outcome:

      passed
      

      stdout:

      
      
      

      📌 Teardown phase

      duration:

      0.00024047959595918655
      

      outcome:

      passed
      
    • Test 78
      params: default="n", user_input="<class 'KeyboardInterrupt'>", expected_output=false, ctrl_c="n"

      📌 Parameters

      params:
        default: "n"
        user_input: "<class 'KeyboardInterrupt'>"
        expected_output: false
        ctrl_c: "n"
      id: "n-KeyboardInterrupt-False-n"
      

      📌 Setup phase

      duration:

      0.0003815172240138054
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0009303539991378784
      

      outcome:

      passed
      

      stdout:

      
      
      

      📌 Teardown phase

      duration:

      0.0002467762678861618
      

      outcome:

      passed
      
    • Test 79
      params: default=null, user_input="['invalid', '', 'invalid', <class 'KeyboardInterrupt'>]", expected_output=false, ctrl_c="n"

      📌 Parameters

      params:
        default: null
        user_input: "['invalid', '', 'invalid', <class 'KeyboardInterrupt'>]"
        expected_output: false
        ctrl_c: "n"
      id: "None-user_input5-False-n"
      

      📌 Setup phase

      duration:

      0.00039336737245321274
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0011023785918951035
      

      outcome:

      passed
      

      stdout:

      
      
      

      📌 Teardown phase

      duration:

      0.0002518966794013977
      

      outcome:

      passed
      
    • Test 80
      params: default=null, user_input="['invalid', '', 'invalid', <class 'KeyboardInterrupt'>]", expected_output=true, ctrl_c="y"

      📌 Parameters

      params:
        default: null
        user_input: "['invalid', '', 'invalid', <class 'KeyboardInterrupt'>]"
        expected_output: true
        ctrl_c: "y"
      id: "None-user_input6-True-y"
      

      📌 Setup phase

      duration:

      0.00036707986146211624
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00258572306483984
      

      outcome:

      passed
      

      stdout:

      
      
      

      📌 Teardown phase

      duration:

      0.0002529555931687355
      

      outcome:

      passed
      
    • Test 81
      params: default=null, user_input="['foo', '', <class 'KeyboardInterrupt'>, '', 'invalid', <class 'KeyboardInterrupt'>, 'no']", expected_output=false, ctrl_c=null

      📌 Parameters

      params:
        default: null
        user_input: "['foo', '', <class 'KeyboardInterrupt'>, '', 'invalid', <class 'KeyboardInterrupt'>, 'no']"
        expected_output: false
        ctrl_c: null
      id: "None-user_input7-False-None"
      

      📌 Setup phase

      duration:

      0.0003852378576993942
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0010348595678806305
      

      outcome:

      passed
      

      stdout:

      
      
      
      

      📌 Teardown phase

      duration:

      0.00023961905390024185
      

      outcome:

      passed
      
    • Test 82
      params: default="n", user_input="[<class 'KeyboardInterrupt'>, <class 'KeyboardInterrupt'>, <class 'KeyboardInterrupt'>, '']", expected_output=false, ctrl_c=null

      📌 Parameters

      params:
        default: "n"
        user_input: "[<class 'KeyboardInterrupt'>, <class 'KeyboardInterrupt'>, <class 'KeyboardInterrupt'>, '']"
        expected_output: false
        ctrl_c: null
      id: "n-user_input8-False-None"
      

      📌 Setup phase

      duration:

      0.00038191303610801697
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0016371775418519974
      

      outcome:

      passed
      

      stdout:

      
      
      
      
      

      📌 Teardown phase

      duration:

      0.00024224445223808289
      

      outcome:

      passed
      
    • Test 83
      params: default="n", user_input="[<class 'KeyboardInterrupt'>, <class 'KeyboardInterrupt'>, <class 'KeyboardInterrupt'>, '']", expected_output=false, ctrl_c="Invalid"

      📌 Parameters

      params:
        default: "n"
        user_input: "[<class 'KeyboardInterrupt'>, <class 'KeyboardInterrupt'>, <class 'KeyboardInterrupt'>, '']"
        expected_output: false
        ctrl_c: "Invalid"
      id: "n-user_input9-False-Invalid"
      

      📌 Setup phase

      duration:

      0.0003876863047480583
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0008964315056800842
      

      outcome:

      passed
      

      stdout:

      
      
      
      
      

      📌 Teardown phase

      duration:

      0.00023733451962471008
      

      outcome:

      passed
      

    Function: test_ask_yes_no_ctrl_d

    • Test 84
      params: default=null, user_input="<class 'EOFError'>", expected_output=false, ctrl_d="n"

      📌 Parameters

      params:
        default: null
        user_input: "<class 'EOFError'>"
        expected_output: false
        ctrl_d: "n"
      id: "None-EOFError-False-n"
      

      📌 Setup phase

      duration:

      0.0003726175054907799
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0008871555328369141
      

      outcome:

      passed
      

      stdout:

      
      
      

      📌 Teardown phase

      duration:

      0.0002542613074183464
      

      outcome:

      passed
      
    • Test 85
      params: default=null, user_input="<class 'EOFError'>", expected_output=true, ctrl_d="y"

      📌 Parameters

      params:
        default: null
        user_input: "<class 'EOFError'>"
        expected_output: true
        ctrl_d: "y"
      id: "None-EOFError-True-y"
      

      📌 Setup phase

      duration:

      0.0003627082332968712
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0008972557261586189
      

      outcome:

      passed
      

      stdout:

      
      
      

      📌 Teardown phase

      duration:

      0.00023705698549747467
      

      outcome:

      passed
      
    • Test 86
      params: default="y", user_input="<class 'EOFError'>", expected_output=true, ctrl_d="y"

      📌 Parameters

      params:
        default: "y"
        user_input: "<class 'EOFError'>"
        expected_output: true
        ctrl_d: "y"
      id: "y-EOFError-True-y"
      

      📌 Setup phase

      duration:

      0.0004184022545814514
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0009787585586309433
      

      outcome:

      passed
      

      stdout:

      
      
      

      📌 Teardown phase

      duration:

      0.00023046694695949554
      

      outcome:

      passed
      
    • Test 87
      params: default="n", user_input="<class 'EOFError'>", expected_output=true, ctrl_d="y"

      📌 Parameters

      params:
        default: "n"
        user_input: "<class 'EOFError'>"
        expected_output: true
        ctrl_d: "y"
      id: "n-EOFError-True-y"
      

      📌 Setup phase

      duration:

      0.0003843940794467926
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0008781375363469124
      

      outcome:

      passed
      

      stdout:

      
      
      

      📌 Teardown phase

      duration:

      0.0002259640023112297
      

      outcome:

      passed
      
    • Test 88
      params: default="n", user_input="<class 'EOFError'>", expected_output=false, ctrl_d="n"

      📌 Parameters

      params:
        default: "n"
        user_input: "<class 'EOFError'>"
        expected_output: false
        ctrl_d: "n"
      id: "n-EOFError-False-n"
      

      📌 Setup phase

      duration:

      0.0003888756036758423
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0008959807455539703
      

      outcome:

      passed
      

      stdout:

      
      
      

      📌 Teardown phase

      duration:

      0.0002534901723265648
      

      outcome:

      passed
      
    • Test 89
      params: default=null, user_input="['foo', <class 'EOFError'>]", expected_output=true, ctrl_d="y"

      📌 Parameters

      params:
        default: null
        user_input: "['foo', <class 'EOFError'>]"
        expected_output: true
        ctrl_d: "y"
      id: "None-user_input5-True-y"
      

      📌 Setup phase

      duration:

      0.0003615645691752434
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.000899776816368103
      

      outcome:

      passed
      

      stdout:

      
      
      

      📌 Teardown phase

      duration:

      0.00023662764579057693
      

      outcome:

      passed
      
    • Test 90
      params: default=null, user_input="['foo', <class 'EOFError'>]", expected_output=false, ctrl_d="n"

      📌 Parameters

      params:
        default: null
        user_input: "['foo', <class 'EOFError'>]"
        expected_output: false
        ctrl_d: "n"
      id: "None-user_input6-False-n"
      

      📌 Setup phase

      duration:

      0.00041280873119831085
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0009732767939567566
      

      outcome:

      passed
      

      stdout:

      
      
      

      📌 Teardown phase

      duration:

      0.00023824907839298248
      

      outcome:

      passed
      
    • Test 91
      params: default="y", user_input="<class 'EOFError'>", expected_output=true, ctrl_d=null

      📌 Parameters

      params:
        default: "y"
        user_input: "<class 'EOFError'>"
        expected_output: true
        ctrl_d: null
      id: "y-EOFError-True-None"
      

      📌 Setup phase

      duration:

      0.0003694538027048111
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0008951779454946518
      

      outcome:

      passed
      

      stdout:

      
      
      

      📌 Teardown phase

      duration:

      0.00024981889873743057
      

      outcome:

      passed
      
    • Test 92
      params: default="n", user_input="<class 'EOFError'>", expected_output=false, ctrl_d=null

      📌 Parameters

      params:
        default: "n"
        user_input: "<class 'EOFError'>"
        expected_output: false
        ctrl_d: null
      id: "n-EOFError-False-None"
      

      📌 Setup phase

      duration:

      0.0003621745854616165
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0014246618375182152
      

      outcome:

      passed
      

      stdout:

      
      
      

      📌 Teardown phase

      duration:

      0.00023971684277057648
      

      outcome:

      passed
      
    • Test 93
      params: default=null, user_input="['invalid', 'ok', '', <class 'EOFError'>, 'ok', 'y']", expected_output=true, ctrl_d=null

      📌 Parameters

      params:
        default: null
        user_input: "['invalid', 'ok', '', <class 'EOFError'>, 'ok', 'y']"
        expected_output: true
        ctrl_d: null
      id: "None-user_input9-True-None"
      

      📌 Setup phase

      duration:

      0.0003715064376592636
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.001607096754014492
      

      outcome:

      passed
      

      stdout:

      
      
      

      📌 Teardown phase

      duration:

      0.0002424679696559906
      

      outcome:

      passed
      
    • Test 94
      params: default="n", user_input="['no', <class 'EOFError'>]", expected_output=false, ctrl_d=null

      📌 Parameters

      params:
        default: "n"
        user_input: "['no', <class 'EOFError'>]"
        expected_output: false
        ctrl_d: null
      id: "n-user_input10-False-None"
      

      📌 Setup phase

      duration:

      0.00036812759935855865
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0005777738988399506
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00023484881967306137
      

      outcome:

      passed
      
    • Test 95
      params: default=null, user_input="[<class 'EOFError'>, <class 'EOFError'>, <class 'EOFError'>, 'y']", expected_output=true, ctrl_d=null

      📌 Parameters

      params:
        default: null
        user_input: "[<class 'EOFError'>, <class 'EOFError'>, <class 'EOFError'>, 'y']"
        expected_output: true
        ctrl_d: null
      id: "None-user_input11-True-None"
      

      📌 Setup phase

      duration:

      0.0003673471510410309
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0009757718071341515
      

      outcome:

      passed
      

      stdout:

      
      
      
      
      

      📌 Teardown phase

      duration:

      0.0002485932782292366
      

      outcome:

      passed
      
    • Test 96
      params: default=null, user_input="['invalid', '', 'nope', <class 'EOFError'>]", expected_output=false, ctrl_d="n"

      📌 Parameters

      params:
        default: null
        user_input: "['invalid', '', 'nope', <class 'EOFError'>]"
        expected_output: false
        ctrl_d: "n"
      id: "None-user_input12-False-n"
      

      📌 Setup phase

      duration:

      0.00036809779703617096
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0009618541225790977
      

      outcome:

      passed
      

      stdout:

      
      
      

      📌 Teardown phase

      duration:

      0.00023052189499139786
      

      outcome:

      passed
      
    • Test 97
      params: default=null, user_input="['nope', 'nope', <class 'EOFError'>]", expected_output=true, ctrl_d="y"

      📌 Parameters

      params:
        default: null
        user_input: "['nope', 'nope', <class 'EOFError'>]"
        expected_output: true
        ctrl_d: "y"
      id: "None-user_input13-True-y"
      

      📌 Setup phase

      duration:

      0.0003831610083580017
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0010563209652900696
      

      outcome:

      passed
      

      stdout:

      
      
      

      📌 Teardown phase

      duration:

      0.00024065840989351273
      

      outcome:

      passed
      

    Function: test_ask_yes_no_mixed_sequences

    • Test 98
      params: default=null, ctrl_c="invalid", ctrl_d=null, user_input="['what', '', 'nope', <class 'KeyboardInterrupt'>, 'ok', <class 'EOFError'>, 'no']", expected_output=false

      📌 Parameters

      params:
        default: null
        ctrl_c: "invalid"
        ctrl_d: null
        user_input: "['what', '', 'nope', <class 'KeyboardInterrupt'>, 'ok', <class 'EOFError'>, 'no']"
        expected_output: false
      id: "None-invalid-None-user_input0-False"
      

      📌 Setup phase

      duration:

      0.00041622482240200043
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0010157553479075432
      

      outcome:

      passed
      

      stdout:

      
      
      
      

      📌 Teardown phase

      duration:

      0.0002604592591524124
      

      outcome:

      passed
      
    • Test 99
      params: default=null, ctrl_c=null, ctrl_d="notananswer", user_input="['maybe', <class 'KeyboardInterrupt'>, 'nop', 'yep', <class 'EOFError'>, 'yes']", expected_output=true

      📌 Parameters

      params:
        default: null
        ctrl_c: null
        ctrl_d: "notananswer"
        user_input: "['maybe', <class 'KeyboardInterrupt'>, 'nop', 'yep', <class 'EOFError'>, 'yes']"
        expected_output: true
      id: "None-None-notananswer-user_input1-True"
      

      📌 Setup phase

      duration:

      0.00040698330849409103
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0009638303890824318
      

      outcome:

      passed
      

      stdout:

      
      
      
      

      📌 Teardown phase

      duration:

      0.0002526436001062393
      

      outcome:

      passed
      
    • Test 100
      params: default=null, ctrl_c="n", ctrl_d="nop", user_input="['ok', <class 'EOFError'>, <class 'EOFError'>, 'maybe', <class 'EOFError'>, 'nah', <class 'KeyboardInterrupt'>]", expected_output=false

      📌 Parameters

      params:
        default: null
        ctrl_c: "n"
        ctrl_d: "nop"
        user_input: "['ok', <class 'EOFError'>, <class 'EOFError'>, 'maybe', <class 'EOFError'>, 'nah', <class 'KeyboardInterrupt'>]"
        expected_output: false
      id: "None-n-nop-user_input2-False"
      

      📌 Setup phase

      duration:

      0.00043327175080776215
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0013270247727632523
      

      outcome:

      passed
      

      stdout:

      
      
      
      
      
      

      📌 Teardown phase

      duration:

      0.0002634022384881973
      

      outcome:

      passed
      
  • 📄 test_utils_channels.py

    Function: test_load_channels_and_channels_class_with_professional_names

    • Test 101

      📌 Setup phase

      duration:

      0.00018401723355054855
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0008257022127509117
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00015549547970294952
      

      outcome:

      passed
      
  • 📄 test_utils_config.py

    Function: test_config_with_nested_and_list_data

    • Test 102

      📌 Setup phase

      duration:

      0.000216582790017128
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0006183367222547531
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00015449151396751404
      

      outcome:

      passed
      

    Function: test_config_with_strange_and_edge_keys

    • Test 103

      📌 Setup phase

      duration:

      0.0001468062400817871
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0007917210459709167
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017132610082626343
      

      outcome:

      passed
      
  • 📄 test_utils_cpint.py

    Function: test_load_color_variants_all_keys_and_types

    • Test 104
      params: base_color="red"

      📌 Parameters

      params:
        base_color: "red"
      id: "red"
      

      📌 Setup phase

      duration:

      0.0002757906913757324
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00027075596153736115
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001768181100487709
      

      outcome:

      passed
      
    • Test 105
      params: base_color="blue"

      📌 Parameters

      params:
        base_color: "blue"
      id: "blue"
      

      📌 Setup phase

      duration:

      0.00024858489632606506
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019746087491512299
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00016057025641202927
      

      outcome:

      passed
      
    • Test 106
      params: base_color="yellow"

      📌 Parameters

      params:
        base_color: "yellow"
      id: "yellow"
      

      📌 Setup phase

      duration:

      0.0002231420949101448
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018832087516784668
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001714443787932396
      

      outcome:

      passed
      
    • Test 107
      params: base_color="green"

      📌 Parameters

      params:
        base_color: "green"
      id: "green"
      

      📌 Setup phase

      duration:

      0.00021129846572875977
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001940568909049034
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00016852375119924545
      

      outcome:

      passed
      
    • Test 108
      params: base_color="cyan"

      📌 Parameters

      params:
        base_color: "cyan"
      id: "cyan"
      

      📌 Setup phase

      duration:

      0.00021124444901943207
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00020111817866563797
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00016603432595729828
      

      outcome:

      passed
      
    • Test 109
      params: base_color="magenta"

      📌 Parameters

      params:
        base_color: "magenta"
      id: "magenta"
      

      📌 Setup phase

      duration:

      0.0002137674018740654
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019227247685194016
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00016937777400016785
      

      outcome:

      passed
      
    • Test 110
      params: base_color="white"

      📌 Parameters

      params:
        base_color: "white"
      id: "white"
      

      📌 Setup phase

      duration:

      0.00023118779063224792
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019463151693344116
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001563066616654396
      

      outcome:

      passed
      
    • Test 111
      params: base_color="black"

      📌 Parameters

      params:
        base_color: "black"
      id: "black"
      

      📌 Setup phase

      duration:

      0.00021959375590085983
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002045910805463791
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017527956515550613
      

      outcome:

      passed
      

    Function: test_cprint_all_cases_fancy

    • Test 112
      params: objects=[["Fancy", "list"], {"a": 7}, null], color_spec=["red", "+"], sep=" | ", expected_flatten="['Fancy', 'list'] | {'a': 7} | None", expected_error=null

      📌 Parameters

      params:
        objects: [["Fancy", "list"], {"a": 7}, null]
        color_spec: ["red", "+"]
        sep: " | "
        expected_flatten: "['Fancy', 'list'] | {'a': 7} | None"
        expected_error: null
      id: "objects0-color_spec0- | -['Fancy', 'list'] | {'a': 7} | None-None"
      

      📌 Setup phase

      duration:

      0.0007306616753339767
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00029857363551855087
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00031745340675115585
      

      outcome:

      passed
      
    • Test 113
      params: objects=[{"k": [1, 2]}, 99, ["X", ["Y"]]], color_spec=["blue", "++"], sep=" - ", expected_flatten="{'k': [1, 2]} - 99 - ['X', ['Y']]", expected_error=null

      📌 Parameters

      params:
        objects: [{"k": [1, 2]}, 99, ["X", ["Y"]]]
        color_spec: ["blue", "++"]
        sep: " - "
        expected_flatten: "{'k': [1, 2]} - 99 - ['X', ['Y']]"
        expected_error: null
      id: "objects1-color_spec1- - -{'k': [1, 2]} - 99 - ['X', ['Y']]-None"
      

      📌 Setup phase

      duration:

      0.0005028415471315384
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002788146957755089
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002873959019780159
      

      outcome:

      passed
      
    • Test 114
      params: objects=[[], {}, "End"], color_spec=["magenta", "--"], sep=" / ", expected_flatten="[] / {} / End", expected_error=null

      📌 Parameters

      params:
        objects: [[], {}, "End"]
        color_spec: ["magenta", "--"]
        sep: " / "
        expected_flatten: "[] / {} / End"
        expected_error: null
      id: "objects2-color_spec2- / -[] / {} / End-None"
      

      📌 Setup phase

      duration:

      0.0005251215770840645
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002839835360646248
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00029595382511615753
      

      outcome:

      passed
      
    • Test 115
      params: objects=[["", [3, 4]], "done", 0], color_spec=["green", ""], sep=";", expected_flatten="['', [3, 4]];done;0", expected_error=null

      📌 Parameters

      params:
        objects: [["", [3, 4]], "done", 0]
        color_spec: ["green", ""]
        sep: ";"
        expected_flatten: "['', [3, 4]];done;0"
        expected_error: null
      id: "objects3-color_spec3-;-['', [3, 4]];done;0-None"
      

      📌 Setup phase

      duration:

      0.0005118260160088539
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00026065390557050705
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00028977636247873306
      

      outcome:

      passed
      
    • Test 116
      params: objects=[["alpha", null], ["beta", {}], "stop"], color_spec=["yellow", ""], sep="::", expected_flatten="['alpha', None]::['beta', {}]::stop", expected_error=null

      📌 Parameters

      params:
        objects: [["alpha", null], ["beta", {}], "stop"]
        color_spec: ["yellow", ""]
        sep: "::"
        expected_flatten: "['alpha', None]::['beta', {}]::stop"
        expected_error: null
      id: "objects4-color_spec4-::-['alpha', None]::['beta', {}]::stop-None"
      

      📌 Setup phase

      duration:

      0.000518798828125
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002632616087794304
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00033649057149887085
      

      outcome:

      passed
      
    • Test 117
      params: objects=[["deep", ["deeper", ["deepest"]]], "X"], color_spec=["cyan", "+"], sep=" ... ", expected_flatten="['deep', ['deeper', ['deepest']]] ... X", expected_error=null

      📌 Parameters

      params:
        objects: [["deep", ["deeper", ["deepest"]]], "X"]
        color_spec: ["cyan", "+"]
        sep: " ... "
        expected_flatten: "['deep', ['deeper', ['deepest']]] ... X"
        expected_error: null
      id: "objects5-color_spec5- ... -['deep', ['deeper', ['deepest']]] ... X-None"
      

      📌 Setup phase

      duration:

      0.0005203504115343094
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00025780685245990753
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00030151475220918655
      

      outcome:

      passed
      
    • Test 118
      params: objects=[{"dict": {"nested": [4, 5]}}, [true, false], 6.28], color_spec=["white", "++"], sep=" // ", expected_flatten="{'dict': {'nested': [4, 5]}} // [True, False] // 6.28", expected_error=null

      📌 Parameters

      params:
        objects: [{"dict": {"nested": [4, 5]}}, [true, false], 6.28]
        color_spec: ["white", "++"]
        sep: " // "
        expected_flatten: "{'dict': {'nested': [4, 5]}} // [True, False] // 6.28"
        expected_error: null
      id: "objects6-color_spec6- // -{'dict': {'nested': [4, 5]}} // [True, False] // 6.28-None"
      

      📌 Setup phase

      duration:

      0.0005175741389393806
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002792244777083397
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002819318324327469
      

      outcome:

      passed
      
    • Test 119
      params: objects=[["A", ["B"]], "string", "C"], color_spec=["red", "--"], sep="==", expected_flatten="['A', ['B']]==string==C", expected_error=null

      📌 Parameters

      params:
        objects: [["A", ["B"]], "string", "C"]
        color_spec: ["red", "--"]
        sep: "=="
        expected_flatten: "['A', ['B']]==string==C"
        expected_error: null
      id: "objects7-color_spec7-==-['A', ['B']]==string==C-None"
      

      📌 Setup phase

      duration:

      0.0005251849070191383
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002711135894060135
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00028059910982847214
      

      outcome:

      passed
      
    • Test 120
      params: objects=[["Test", null, []], {"v": 0}], color_spec=["green", "++"], sep=" ++ ", expected_flatten="['Test', None, []] ++ {'v': 0}", expected_error=null

      📌 Parameters

      params:
        objects: [["Test", null, []], {"v": 0}]
        color_spec: ["green", "++"]
        sep: " ++ "
        expected_flatten: "['Test', None, []] ++ {'v': 0}"
        expected_error: null
      id: "objects8-color_spec8- ++ -['Test', None, []] ++ {'v': 0}-None"
      

      📌 Setup phase

      duration:

      0.0005137398838996887
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002524787560105324
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0004157042130827904
      

      outcome:

      passed
      
    • Test 121
      params: objects=[["no", "color"], "plain"], color_spec=null, sep=";", expected_flatten="['no', 'color'];plain", expected_error=null

      📌 Parameters

      params:
        objects: [["no", "color"], "plain"]
        color_spec: null
        sep: ";"
        expected_flatten: "['no', 'color'];plain"
        expected_error: null
      id: "objects9-None-;-['no', 'color'];plain-None"
      

      📌 Setup phase

      duration:

      0.0005211103707551956
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002501504495739937
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00030966661870479584
      

      outcome:

      passed
      
    • Test 122
      params: objects=[["simple"], "", 12], color_spec=null, sep=" | ", expected_flatten="['simple'] | | 12", expected_error=null

      📌 Parameters

      params:
        objects: [["simple"], "", 12]
        color_spec: null
        sep: " | "
        expected_flatten: "['simple'] |  | 12"
        expected_error: null
      id: "objects10-None- | -['simple'] |  | 12-None"
      

      📌 Setup phase

      duration:

      0.0005443096160888672
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002549579367041588
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002954360097646713
      

      outcome:

      passed
      
    • Test 123
      params: objects=[[["very", "deep"]], {"ok": true}], color_spec=null, sep=" : ", expected_flatten="[['very', 'deep']] : {'ok': True}", expected_error=null

      📌 Parameters

      params:
        objects: [[["very", "deep"]], {"ok": true}]
        color_spec: null
        sep: " : "
        expected_flatten: "[['very', 'deep']] : {'ok': True}"
        expected_error: null
      id: "objects11-None- : -[['very', 'deep']] : {'ok': True}-None"
      

      📌 Setup phase

      duration:

      0.0004990492016077042
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002622082829475403
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002947114408016205
      

      outcome:

      passed
      
    • Test 124
      params: objects=[["fail", "color"], 123], color_spec=["green", "!!"], sep="|", expected_flatten="['fail', 'color']|123", expected_error="<class 'ValueError'>"

      📌 Parameters

      params:
        objects: [["fail", "color"], 123]
        color_spec: ["green", "!!"]
        sep: "|"
        expected_flatten: "['fail', 'color']|123"
        expected_error: "<class 'ValueError'>"
      id: "objects12-color_spec12-|-['fail', 'color']|123-ValueError"
      

      📌 Setup phase

      duration:

      0.0005187559872865677
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0003010965883731842
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0003099655732512474
      

      outcome:

      passed
      
    • Test 125
      params: objects=[["error"], {}], color_spec=["cyan", "xxx"], sep=" * ", expected_flatten="['error'] * {}", expected_error="<class 'ValueError'>"

      📌 Parameters

      params:
        objects: [["error"], {}]
        color_spec: ["cyan", "xxx"]
        sep: " * "
        expected_flatten: "['error'] * {}"
        expected_error: "<class 'ValueError'>"
      id: "objects13-color_spec13- * -['error'] * {}-ValueError"
      

      📌 Setup phase

      duration:

      0.0005266331136226654
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002756882458925247
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0003040144219994545
      

      outcome:

      passed
      
    • Test 126
      params: objects=[["nope"], ["bad"]], color_spec=["magenta", "invalid"], sep="//", expected_flatten="['nope']//['bad']", expected_error="<class 'ValueError'>"

      📌 Parameters

      params:
        objects: [["nope"], ["bad"]]
        color_spec: ["magenta", "invalid"]
        sep: "//"
        expected_flatten: "['nope']//['bad']"
        expected_error: "<class 'ValueError'>"
      id: "objects14-color_spec14-//-['nope']//['bad']-ValueError"
      

      📌 Setup phase

      duration:

      0.0005216943100094795
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002763299271464348
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0003075888380408287
      

      outcome:

      passed
      
    • Test 127
      params: objects=["wrong", "base"], color_spec=["notacolor", ""], sep="--", expected_flatten="wrong--base", expected_error="<class 'ValueError'>"

      📌 Parameters

      params:
        objects: ["wrong", "base"]
        color_spec: ["notacolor", ""]
        sep: "--"
        expected_flatten: "wrong--base"
        expected_error: "<class 'ValueError'>"
      id: "objects15-color_spec15----wrong--base-ValueError"
      

      📌 Setup phase

      duration:

      0.0005154097452759743
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002562450245022774
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00031027384102344513
      

      outcome:

      passed
      
  • 📄 test_utils_dbusnotify.py

    Function: test_notify_create

    • Test 128

      📌 Setup phase

      duration:

      0.0006854627281427383
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.005087520927190781
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018891040235757828
      

      outcome:

      passed
      

    Function: test_notify_update

    • Test 129

      📌 Setup phase

      duration:

      0.0002070050686597824
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.01696749124675989
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00026872381567955017
      

      outcome:

      passed
      

    Function: test_get_server_info

    • Test 130

      📌 Setup phase

      duration:

      0.00026488397270441055
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.000705355778336525
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00021848082542419434
      

      outcome:

      passed
      

    Function: test_get_capabilities

    • Test 131

      📌 Setup phase

      duration:

      0.0003793351352214813
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0008136937394738197
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002942681312561035
      

      outcome:

      passed
      

    Function: test_notify_and_close

    • Test 132

      📌 Setup phase

      duration:

      0.0002825409173965454
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.20464586652815342
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00026594940572977066
      

      outcome:

      passed
      

    Function: test_notify_invalid_value

    • Test 133

      📌 Setup phase

      duration:

      0.00023364368826150894
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0005289716646075249
      

      outcome:

      passed
      

      log:

      -   name: dbus.connection
        msg: Unable to set arguments ('', 0, '', 'Invalid Test', 1234, (), {}, 0) according to signature 'susssasa{sv}i': <class 'TypeError'>: Expected a string or unicode object
        args: []
        levelname: ERROR
        levelno: 40
        pathname: /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/dbus/connection.py
        filename: connection.py
        module: connection
        exc_info: []
        exc_text: []
        stack_info: []
        lineno: 628
        funcName: call_blocking
        created: 1756376001.4968197
        msecs: 496.81973457336426
        relativeCreated: 3824.5084285736084
        thread: 140648901174784
        threadName: MainThread
        processName: MainProcess
        process: 2977
      

      📌 Teardown phase

      duration:

      0.0001817094162106514
      

      outcome:

      passed
      

    Function: test_convert_dbus_strings

    • Test 134

      📌 Setup phase

      duration:

      0.00015726592391729355
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00024477671831846237
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001427438110113144
      

      outcome:

      passed
      
  • 📄 test_utils_debug.py

    Function: test_traceable

    • Test 135
      params: cls="<class 'test_utils_debug.A'>", entry=[[10, 20], {}], expected="creating: A(10, 20)"

      📌 Parameters

      params:
        cls: "<class 'test_utils_debug.A'>"
        entry: [[10, 20], {}]
        expected: "creating: A(10, 20)"
      id: "A-entry0-creating: A(10, 20)"
      

      📌 Setup phase

      duration:

      0.00040617678314447403
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.001128663308918476
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00024067796766757965
      

      outcome:

      passed
      
    • Test 136
      params: cls="<class 'test_utils_debug.A'>", entry=[[10, 20], {"e": 100}], expected="creating: A(10, 20, e=100)"

      📌 Parameters

      params:
        cls: "<class 'test_utils_debug.A'>"
        entry: [[10, 20], {"e": 100}]
        expected: "creating: A(10, 20, e=100)"
      id: "A-entry1-creating: A(10, 20, e=100)"
      

      📌 Setup phase

      duration:

      0.0003371266648173332
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0009148353710770607
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00022287014871835709
      

      outcome:

      passed
      
    • Test 137
      params: cls="<class 'test_utils_debug.A'>", entry=[["foo", [1, 2, 3]], {"flag": true, "data": {"x": 9}}], expected="creating: A('foo', [1, 2, 3], flag=True, data={'x': 9})"

      📌 Parameters

      params:
        cls: "<class 'test_utils_debug.A'>"
        entry: [["foo", [1, 2, 3]], {"flag": true, "data": {"x": 9}}]
        expected: "creating: A('foo', [1, 2, 3], flag=True, data={'x': 9})"
      id: "A-entry2-creating: A('foo', [1, 2, 3], flag=True, data={'x': 9})"
      

      📌 Setup phase

      duration:

      0.000337798148393631
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0009904159232974052
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00022893212735652924
      

      outcome:

      passed
      
    • Test 138
      params: cls="<class 'test_utils_debug.A'>", entry="([CustomObj(big), [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], {'name': 'test', 'meta': 'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'})", expected="creating: A(CustomObj(big), [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], name='test', meta='yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy...)"

      📌 Parameters

      params:
        cls: "<class 'test_utils_debug.A'>"
        entry: "([CustomObj(big), [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], {'name': 'test', 'meta': 'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'})"
        expected: "creating: A(CustomObj(big), [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], name='test', meta='yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy...)"
      id: "A-entry3-creating: A(CustomObj(big), [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], name='test', meta='yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy...)"
      

      📌 Setup phase

      duration:

      0.0003446759656071663
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0009119650349020958
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002269558608531952
      

      outcome:

      passed
      
    • Test 139
      params: cls="<class 'test_utils_debug.A'>", entry=[["AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", [0, 0, 0, 0, 0]], {}], expected="creating: A('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA..., [0, 0, 0, 0, 0])"

      📌 Parameters

      params:
        cls: "<class 'test_utils_debug.A'>"
        entry: [["AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", [0, 0, 0, 0, 0]], {}]
        expected: "creating: A('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA..., [0, 0, 0, 0, 0])"
      id: "A-entry4-creating: A('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA..., [0, 0, 0, 0, 0])"
      

      📌 Setup phase

      duration:

      0.00033375341445207596
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0009415149688720703
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002396106719970703
      

      outcome:

      passed
      

    Function: test_short_repr

    • Test 140
      params: value="abc", cutoff=10, expected="'abc'"

      📌 Parameters

      params:
        value: "abc"
        cutoff: 10
        expected: "'abc'"
      id: "abc-10-'abc'"
      

      📌 Setup phase

      duration:

      0.00032036658376455307
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002113664522767067
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002040807157754898
      

      outcome:

      passed
      
    • Test 142
      params: value=12345, cutoff=10, expected="12345"

      📌 Parameters

      params:
        value: 12345
        cutoff: 10
        expected: "12345"
      id: "12345-10-12345"
      

      📌 Setup phase

      duration:

      0.0006428128108382225
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0004043998196721077
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0003981897607445717
      

      outcome:

      passed
      
    • Test 143
      params: value=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], cutoff=15, expected="[0, 0, 0, 0, 0,..."

      📌 Parameters

      params:
        value: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
        cutoff: 15
        expected: "[0, 0, 0, 0, 0,..."
      id: "value3-15-[0, 0, 0, 0, 0,..."
      

      📌 Setup phase

      duration:

      0.0005013672634959221
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00034567341208457947
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0003566080704331398
      

      outcome:

      passed
      
    • Test 144
      params: value=null, cutoff=10, expected="None"

      📌 Parameters

      params:
        value: null
        cutoff: 10
        expected: "None"
      id: "None-10-None"
      

      📌 Setup phase

      duration:

      0.000403841957449913
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00020684674382209778
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00024171825498342514
      

      outcome:

      passed
      
  • 📄 test_utils_dictext.py

    Function: test_attrdict_getattr

    • Test 146
      params: data={"x": 1, "y": 2}, attr="x", expected=1

      📌 Parameters

      params:
        data: {"x": 1, "y": 2}
        attr: "x"
        expected: 1
      id: "data0-x-1"
      

      📌 Setup phase

      duration:

      0.0004962170496582985
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0003164084628224373
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.000430879183113575
      

      outcome:

      passed
      
    • Test 147
      params: data={"world": "ok"}, attr="world", expected="ok"

      📌 Parameters

      params:
        data: {"world": "ok"}
        attr: "world"
        expected: "ok"
      id: "data1-world-ok"
      

      📌 Setup phase

      duration:

      0.0005793515592813492
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0003451230004429817
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0003024907782673836
      

      outcome:

      passed
      
    • Test 148
      params: data={"outer": {"inner": 42}}, attr="outer", expected={"inner": 42}

      📌 Parameters

      params:
        data: {"outer": {"inner": 42}}
        attr: "outer"
        expected: {"inner": 42}
      id: "data2-outer-expected2"
      

      📌 Setup phase

      duration:

      0.0004766695201396942
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002464447170495987
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00026236195117235184
      

      outcome:

      passed
      

    Function: test_attrdict_setattr

    • Test 149
      params: initial={}, attr="nouveau", value=123

      📌 Parameters

      params:
        initial: {}
        attr: "nouveau"
        value: 123
      id: "initial0-nouveau-123"
      

      📌 Setup phase

      duration:

      0.0003591710701584816
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00021881051361560822
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002867523580789566
      

      outcome:

      passed
      
    • Test 150
      params: initial={"a": 1}, attr="b", value="valeur"

      📌 Parameters

      params:
        initial: {"a": 1}
        attr: "b"
        value: "valeur"
      id: "initial1-b-valeur"
      

      📌 Setup phase

      duration:

      0.00047320034354925156
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00025423895567655563
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00023606326431035995
      

      outcome:

      passed
      

    Function: test_attrdict_delattr

    • Test 151
      params: initial={"a": 1, "b": 2}, to_del="a", expected_keys=["b"]

      📌 Parameters

      params:
        initial: {"a": 1, "b": 2}
        to_del: "a"
        expected_keys: ["b"]
      id: "initial0-a-expected_keys0"
      

      📌 Setup phase

      duration:

      0.0003133527934551239
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002696588635444641
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002498682588338852
      

      outcome:

      passed
      
    • Test 152
      params: initial={"k": "v"}, to_del="k", expected_keys=[]

      📌 Parameters

      params:
        initial: {"k": "v"}
        to_del: "k"
        expected_keys: []
      id: "initial1-k-expected_keys1"
      

      📌 Setup phase

      duration:

      0.00040162820369005203
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.000245068222284317
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020593125373125076
      

      outcome:

      passed
      

    Function: test_attrdict_dir

    • Test 153
      params: data={"alpha": 1, "beta": 2}, expected_keys="{'beta', 'alpha'}"

      📌 Parameters

      params:
        data: {"alpha": 1, "beta": 2}
        expected_keys: "{'beta', 'alpha'}"
      id: "data0-expected_keys0"
      

      📌 Setup phase

      duration:

      0.00036404654383659363
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00032124854624271393
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00024531129747629166
      

      outcome:

      passed
      
    • Test 154
      params: data={}, expected_keys="set()"

      📌 Parameters

      params:
        data: {}
        expected_keys: "set()"
      id: "data1-expected_keys1"
      

      📌 Setup phase

      duration:

      0.0003797682002186775
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00030283816158771515
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00024407170712947845
      

      outcome:

      passed
      

    Function: test_attrdict_getattr_and_missing

    • Test 155
      params: data={"x": 1, "y": 2}, attr="x", expect_value=1, expect_error=null

      📌 Parameters

      params:
        data: {"x": 1, "y": 2}
        attr: "x"
        expect_value: 1
        expect_error: null
      id: "data0-x-1-None"
      

      📌 Setup phase

      duration:

      0.0005677379667758942
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002822699025273323
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00029976852238178253
      

      outcome:

      passed
      
    • Test 156
      params: data={"number": 42}, attr="missing", expect_value=null, expect_error="'MyDict' object has no attribute 'missing'"

      📌 Parameters

      params:
        data: {"number": 42}
        attr: "missing"
        expect_value: null
        expect_error: "'MyDict' object has no attribute 'missing'"
      id: "data1-missing-None-'MyDict' object has no attribute 'missing'"
      

      📌 Setup phase

      duration:

      0.0005960464477539062
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00026692822575569153
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00041577965021133423
      

      outcome:

      passed
      

    Function: test_dictupdatemixin_init_and_update

    • Test 157
      params: init_kwargs={"a": 1, "b": 2}, other=null, kwargs={}, expected={"a": 1, "b": 2}

      📌 Parameters

      params:
        init_kwargs: {"a": 1, "b": 2}
        other: null
        kwargs: {}
        expected: {"a": 1, "b": 2}
      id: "init_kwargs0-None-kwargs0-expected0"
      

      📌 Setup phase

      duration:

      0.0005042180418968201
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00032423995435237885
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002432074397802353
      

      outcome:

      passed
      
    • Test 158
      params: init_kwargs={}, other={"x": 10, "y": 20}, kwargs={}, expected={"x": 10, "y": 20}

      📌 Parameters

      params:
        init_kwargs: {}
        other: {"x": 10, "y": 20}
        kwargs: {}
        expected: {"x": 10, "y": 20}
      id: "init_kwargs1-other1-kwargs1-expected1"
      

      📌 Setup phase

      duration:

      0.0004223734140396118
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002208491787314415
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002480205148458481
      

      outcome:

      passed
      
    • Test 159
      params: init_kwargs={"world": "ok"}, other={"number": 42}, kwargs={"num2": 100}, expected={"world": "ok", "number": 42, "num2": 100}

      📌 Parameters

      params:
        init_kwargs: {"world": "ok"}
        other: {"number": 42}
        kwargs: {"num2": 100}
        expected: {"world": "ok", "number": 42, "num2": 100}
      id: "init_kwargs2-other2-kwargs2-expected2"
      

      📌 Setup phase

      duration:

      0.00042845960706472397
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00021429825574159622
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00021904334425926208
      

      outcome:

      passed
      
    • Test 160
      params: init_kwargs={}, other=null, kwargs={"alpha": "beta"}, expected={"alpha": "beta"}

      📌 Parameters

      params:
        init_kwargs: {}
        other: null
        kwargs: {"alpha": "beta"}
        expected: {"alpha": "beta"}
      id: "init_kwargs3-None-kwargs3-expected3"
      

      📌 Setup phase

      duration:

      0.00041524507105350494
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002485997974872589
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00024088844656944275
      

      outcome:

      passed
      
    • Test 161
      params: init_kwargs={}, other={"key": "value"}, kwargs={"extra": 1}, expected={"key": "value", "extra": 1}

      📌 Parameters

      params:
        init_kwargs: {}
        other: {"key": "value"}
        kwargs: {"extra": 1}
        expected: {"key": "value", "extra": 1}
      id: "init_kwargs4-other4-kwargs4-expected4"
      

      📌 Setup phase

      duration:

      0.0003793109208345413
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002526538446545601
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00023614056408405304
      

      outcome:

      passed
      
    • Test 162
      params: init_kwargs={}, other=[["key", "value"], ["list", [5, 6]]], kwargs={"extra": {"subkey": 123}}, expected={"key": "value", "list": [5, 6], "extra": {"subkey": 123}}

      📌 Parameters

      params:
        init_kwargs: {}
        other: [["key", "value"], ["list", [5, 6]]]
        kwargs: {"extra": {"subkey": 123}}
        expected: {"key": "value", "list": [5, 6], "extra": {"subkey": 123}}
      id: "init_kwargs5-other5-kwargs5-expected5"
      

      📌 Setup phase

      duration:

      0.0004470245912671089
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0003634681925177574
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00026802532374858856
      

      outcome:

      passed
      
  • 📄 test_utils_dotdir.py

    Function: test_dotdir_creation_and_base_exists

    • Test 163

      📌 Setup phase

      duration:

      0.0015016142278909683
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00043480284512043
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00038635265082120895
      

      outcome:

      passed
      

    Function: test_dotdir_repr_returns_path_str

    • Test 164

      📌 Setup phase

      duration:

      0.0007829107344150543
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002950131893157959
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00031824130564928055
      

      outcome:

      passed
      

    Function: test_dotdir_call

    • Test 165

      📌 Setup phase

      duration:

      0.0008252719417214394
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0011571869254112244
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00026491377502679825
      

      outcome:

      passed
      
  • 📄 test_utils_duo.py

    Function: TestPickledDictReal

    • Test 166

      📌 Setup phase

      duration:

      0.00017429422587156296
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0026126131415367126
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017393287271261215
      

      outcome:

      passed
      
    • Test 167

      📌 Setup phase

      duration:

      0.0001611625775694847
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.008062758482992649
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00026553962379693985
      

      outcome:

      passed
      

    Function: TestSecrets

    • Test 168

      📌 Setup phase

      duration:

      0.0009338594973087311
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.012359211221337318
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0012211808934807777
      

      outcome:

      passed
      
    • Test 169

      📌 Setup phase

      duration:

      0.0007458347827196121
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0027843955904245377
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0003632251173257828
      

      outcome:

      passed
      
    • Test 170

      📌 Setup phase

      duration:

      0.000639844685792923
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.001321401447057724
      

      outcome:

      passed
      

      stdout:

      
      
      

      📌 Teardown phase

      duration:

      0.00040127523243427277
      

      outcome:

      passed
      

    Function: test_get_pgroup_raises_if_no_key

    • Test 171

      📌 Setup phase

      duration:

      0.00030512455850839615
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0006421636790037155
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002711750566959381
      

      outcome:

      passed
      

    Function: test_get_pgroup_info_with_props_same_name_and_pi

    • Test 172

      📌 Setup phase

      duration:

      0.00032791122794151306
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002810917794704437
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.000183851458132267
      

      outcome:

      passed
      

    Function: test_get_pgroup_info_with_props_different_pi

    • Test 173

      📌 Setup phase

      duration:

      0.00022998079657554626
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00021796301007270813
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001754285767674446
      

      outcome:

      passed
      

    Function: test_get_pgroup_info_without_props_with_owner

    • Test 174

      📌 Setup phase

      duration:

      0.00021580327302217484
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002480586990714073
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00016600359231233597
      

      outcome:

      passed
      

    Function: test_get_pgroup_info_without_props_no_owner

    • Test 175

      📌 Setup phase

      duration:

      0.0002299286425113678
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002155369147658348
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001680459827184677
      

      outcome:

      passed
      

    Function: test_get_pgroup_info_mock

    • Test 176

      📌 Setup phase

      duration:

      0.00021883472800254822
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00020692311227321625
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017917994409799576
      

      outcome:

      passed
      
  • 📄 test_utils_elog.py

    Function: test_get_default_elog_instance_with_wrong_password_and_real_check

    • Test 178

      📌 Setup phase

      duration:

      0.00020082946866750717
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.007667813450098038
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002079075202345848
      

      outcome:

      passed
      
  • 📄 test_utils_eval.py

    Function: test_arithmetic_eval_valid

    • Test 182
      params: expr="1 + 2", expected=3

      📌 Parameters

      params:
        expr: "1 + 2"
        expected: 3
      id: "1 + 2-3"
      

      📌 Setup phase

      duration:

      0.00041782110929489136
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002766633406281471
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020018219947814941
      

      outcome:

      passed
      
    • Test 183
      params: expr="4 - 2", expected=2

      📌 Parameters

      params:
        expr: "4 - 2"
        expected: 2
      id: "4 - 2-2"
      

      📌 Setup phase

      duration:

      0.000297006219625473
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00020484160631895065
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018071196973323822
      

      outcome:

      passed
      
    • Test 184
      params: expr="3 * 5", expected=15

      📌 Parameters

      params:
        expr: "3 * 5"
        expected: 15
      id: "3 * 5-15"
      

      📌 Setup phase

      duration:

      0.00026360154151916504
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019094441086053848
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019138306379318237
      

      outcome:

      passed
      
    • Test 185
      params: expr="10 / 2", expected=5.0

      📌 Parameters

      params:
        expr: "10 / 2"
        expected: 5.0
      id: "10 / 2-5.0"
      

      📌 Setup phase

      duration:

      0.00026543252170085907
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002075526863336563
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017395615577697754
      

      outcome:

      passed
      
    • Test 186
      params: expr="10 % 3", expected=1

      📌 Parameters

      params:
        expr: "10 % 3"
        expected: 1
      id: "10 % 3-1"
      

      📌 Setup phase

      duration:

      0.00027392245829105377
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.000199844129383564
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019279774278402328
      

      outcome:

      passed
      
    • Test 187
      params: expr="-5", expected=-5

      📌 Parameters

      params:
        expr: "-5"
        expected: -5
      id: "-5--5"
      

      📌 Setup phase

      duration:

      0.0002624206244945526
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.000197606161236763
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001937495544552803
      

      outcome:

      passed
      
    • Test 188
      params: expr="+7", expected=7

      📌 Parameters

      params:
        expr: "+7"
        expected: 7
      id: "+7-7"
      

      📌 Setup phase

      duration:

      0.0002616792917251587
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018545519560575485
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017793010920286179
      

      outcome:

      passed
      
    • Test 189
      params: expr="1 + 2 * 3", expected=7

      📌 Parameters

      params:
        expr: "1 + 2 * 3"
        expected: 7
      id: "1 + 2 * 3-7"
      

      📌 Setup phase

      duration:

      0.0002636881545186043
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002010529860854149
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017993804067373276
      

      outcome:

      passed
      
    • Test 190
      params: expr="(1 + 2) * 3", expected=9

      📌 Parameters

      params:
        expr: "(1 + 2) * 3"
        expected: 9
      id: "(1 + 2) * 3-9"
      

      📌 Setup phase

      duration:

      0.0002666302025318146
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019652768969535828
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018306542187929153
      

      outcome:

      passed
      
    • Test 191
      params: expr="-(-3)", expected=3

      📌 Parameters

      params:
        expr: "-(-3)"
        expected: 3
      id: "-(-3)-3"
      

      📌 Setup phase

      duration:

      0.0002659643068909645
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019340869039297104
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001820167526602745
      

      outcome:

      passed
      
    • Test 192
      params: expr="-2 + 4 * 2", expected=6

      📌 Parameters

      params:
        expr: "-2 + 4 * 2"
        expected: 6
      id: "-2 + 4 * 2-6"
      

      📌 Setup phase

      duration:

      0.0002614827826619148
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00021327286958694458
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017581041902303696
      

      outcome:

      passed
      
    • Test 193
      params: expr="(4 + 5) * (6 - 1)", expected=45

      📌 Parameters

      params:
        expr: "(4 + 5) * (6 - 1)"
        expected: 45
      id: "(4 + 5) * (6 - 1)-45"
      

      📌 Setup phase

      duration:

      0.00027731992304325104
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00021094270050525665
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017810240387916565
      

      outcome:

      passed
      
    • Test 194
      params: expr="(((3)))", expected=3

      📌 Parameters

      params:
        expr: "(((3)))"
        expected: 3
      id: "(((3)))-3"
      

      📌 Setup phase

      duration:

      0.0002632550895214081
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019176490604877472
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001907050609588623
      

      outcome:

      passed
      
    • Test 195
      params: expr="-(-(-2))", expected=-2

      📌 Parameters

      params:
        expr: "-(-(-2))"
        expected: -2
      id: "-(-(-2))--2"
      

      📌 Setup phase

      duration:

      0.0002546226605772972
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001939963549375534
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018606707453727722
      

      outcome:

      passed
      
    • Test 196
      params: expr="3 + +4", expected=7

      📌 Parameters

      params:
        expr: "3 + +4"
        expected: 7
      id: "3 + +4-7"
      

      📌 Setup phase

      duration:

      0.00026069022715091705
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00024283677339553833
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018803030252456665
      

      outcome:

      passed
      
    • Test 197
      params: expr="3 + -4", expected=-1

      📌 Parameters

      params:
        expr: "3 + -4"
        expected: -1
      id: "3 + -4--1"
      

      📌 Setup phase

      duration:

      0.00027363933622837067
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019357912242412567
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018515903502702713
      

      outcome:

      passed
      
    • Test 198
      params: expr="True + 1", expected=2

      📌 Parameters

      params:
        expr: "True + 1"
        expected: 2
      id: "True + 1-2"
      

      📌 Setup phase

      duration:

      0.00027304142713546753
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019461847841739655
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018056295812129974
      

      outcome:

      passed
      
    • Test 199
      params: expr="'string'", expected="string"

      📌 Parameters

      params:
        expr: "'string'"
        expected: "string"
      id: "'string'-string"
      

      📌 Setup phase

      duration:

      0.0002606501802802086
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002023782581090927
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017745234072208405
      

      outcome:

      passed
      
    • Test 200
      params: expr="1e1000 * 1e1000", expected=Infinity

      📌 Parameters

      params:
        expr: "1e1000 * 1e1000"
        expected: Infinity
      id: "1e1000 * 1e1000-inf"
      

      📌 Setup phase

      duration:

      0.0002669040113687515
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001880154013633728
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001855362206697464
      

      outcome:

      passed
      
    • Test 201
      params: expr="'a' + 'b'", expected="ab"

      📌 Parameters

      params:
        expr: "'a' + 'b'"
        expected: "ab"
      id: "'a' + 'b'-ab"
      

      📌 Setup phase

      duration:

      0.00030419696122407913
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019974540919065475
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019262544810771942
      

      outcome:

      passed
      

    Function: test_arithmetic_eval_raises_with_message

    • Test 202
      params: expr="2 ** 3", expected_message="Unsupported BinOp Pow"

      📌 Parameters

      params:
        expr: "2 ** 3"
        expected_message: "Unsupported BinOp Pow"
      id: "2 ** 3-Unsupported BinOp Pow"
      

      📌 Setup phase

      duration:

      0.00029427744448184967
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00045494455844163895
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018509943038225174
      

      outcome:

      passed
      
    • Test 203
      params: expr="3 << 1", expected_message="Unsupported BinOp LShift"

      📌 Parameters

      params:
        expr: "3 << 1"
        expected_message: "Unsupported BinOp LShift"
      id: "3 << 1-Unsupported BinOp LShift"
      

      📌 Setup phase

      duration:

      0.00027391593903303146
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00039758067578077316
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018644332885742188
      

      outcome:

      passed
      
    • Test 204
      params: expr="1 < 2", expected_message="Unsupported node type Compare"

      📌 Parameters

      params:
        expr: "1 < 2"
        expected_message: "Unsupported node type Compare"
      id: "1 < 2-Unsupported node type Compare"
      

      📌 Setup phase

      duration:

      0.0002546999603509903
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0004278114065527916
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018517859280109406
      

      outcome:

      passed
      
    • Test 205
      params: expr="abs(3)", expected_message="Unsupported node type Call"

      📌 Parameters

      params:
        expr: "abs(3)"
        expected_message: "Unsupported node type Call"
      id: "abs(3)-Unsupported node type Call"
      

      📌 Setup phase

      duration:

      0.0002696700394153595
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00038123689591884613
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019400566816329956
      

      outcome:

      passed
      
    • Test 206
      params: expr="a + 2", expected_message="Unsupported node type Name"

      📌 Parameters

      params:
        expr: "a + 2"
        expected_message: "Unsupported node type Name"
      id: "a + 2-Unsupported node type Name"
      

      📌 Setup phase

      duration:

      0.00029622670263051987
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0004009092226624489
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001933649182319641
      

      outcome:

      passed
      
    • Test 207
      params: expr="string", expected_message="Unsupported node type Name"

      📌 Parameters

      params:
        expr: "string"
        expected_message: "Unsupported node type Name"
      id: "string-Unsupported node type Name"
      

      📌 Setup phase

      duration:

      0.00027129147201776505
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00022644829005002975
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001919679343700409
      

      outcome:

      passed
      
    • Test 208
      params: expr="[1, 2] + [3]", expected_message="Unsupported node type List"

      📌 Parameters

      params:
        expr: "[1, 2] + [3]"
        expected_message: "Unsupported node type List"
      id: "[1, 2] + [3]-Unsupported node type List"
      

      📌 Setup phase

      duration:

      0.0002646055072546005
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0005967067554593086
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020565558224916458
      

      outcome:

      passed
      
    • Test 209
      params: expr="{1: 2}", expected_message="Unsupported node type Dict"

      📌 Parameters

      params:
        expr: "{1: 2}"
        expected_message: "Unsupported node type Dict"
      id: "{1: 2}-Unsupported node type Dict"
      

      📌 Setup phase

      duration:

      0.0002773404121398926
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0003940919414162636
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001843450590968132
      

      outcome:

      passed
      

    Function: test_arithmetic_eval_runtime_errors

    • Test 210
      params: expr="1 / 0", exception="<class 'ZeroDivisionError'>"

      📌 Parameters

      params:
        expr: "1 / 0"
        exception: "<class 'ZeroDivisionError'>"
      id: "1 / 0-ZeroDivisionError"
      

      📌 Setup phase

      duration:

      0.0002865530550479889
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00021854974329471588
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017940625548362732
      

      outcome:

      passed
      
    • Test 211
      params: expr="10 % 0", exception="<class 'ZeroDivisionError'>"

      📌 Parameters

      params:
        expr: "10 % 0"
        exception: "<class 'ZeroDivisionError'>"
      id: "10 % 0-ZeroDivisionError"
      

      📌 Setup phase

      duration:

      0.00026124995201826096
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002084365114569664
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020090676844120026
      

      outcome:

      passed
      

    Function: test_forgiving_eval

    • Test 212
      params: expr="1 + 2", expected=3

      📌 Parameters

      params:
        expr: "1 + 2"
        expected: 3
      id: "1 + 2-3"
      

      📌 Setup phase

      duration:

      0.00026413053274154663
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002049347385764122
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017539504915475845
      

      outcome:

      passed
      
    • Test 213
      params: expr="bad + 2", expected="bad + 2"

      📌 Parameters

      params:
        expr: "bad + 2"
        expected: "bad + 2"
      id: "bad + 2-bad + 2"
      

      📌 Setup phase

      duration:

      0.0002605309709906578
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00020782556384801865
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001779431477189064
      

      outcome:

      passed
      
    • Test 214
      params: expr="1 / 0", expected="1 / 0"

      📌 Parameters

      params:
        expr: "1 / 0"
        expected: "1 / 0"
      id: "1 / 0-1 / 0"
      

      📌 Setup phase

      duration:

      0.0002740621566772461
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019888859242200851
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017656851559877396
      

      outcome:

      passed
      
    • Test 215
      params: expr="2 ** 10", expected="2 ** 10"

      📌 Parameters

      params:
        expr: "2 ** 10"
        expected: "2 ** 10"
      id: "2 ** 10-2 ** 10"
      

      📌 Setup phase

      duration:

      0.00025577470660209656
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019797775894403458
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.000181589275598526
      

      outcome:

      passed
      

    Function: test_defaulting_eval

    • Test 216
      params: expr="3 * 4", default=0, expected=12

      📌 Parameters

      params:
        expr: "3 * 4"
        default: 0
        expected: 12
      id: "3 * 4-0-12"
      

      📌 Setup phase

      duration:

      0.00031125638633966446
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00021144654601812363
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019667576998472214
      

      outcome:

      passed
      
    • Test 217
      params: expr="invalid + 1", default=99, expected=99

      📌 Parameters

      params:
        expr: "invalid + 1"
        default: 99
        expected: 99
      id: "invalid + 1-99-99"
      

      📌 Setup phase

      duration:

      0.00031953025609254837
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00020374543964862823
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001962948590517044
      

      outcome:

      passed
      
    • Test 218
      params: expr="1 / 0", default=-1, expected=-1

      📌 Parameters

      params:
        expr: "1 / 0"
        default: -1
        expected: -1
      id: "1 / 0--1--1"
      

      📌 Setup phase

      duration:

      0.000331035815179348
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001972094178199768
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020135007798671722
      

      outcome:

      passed
      
    • Test 219
      params: expr="2 ** 10", default=42, expected=42

      📌 Parameters

      params:
        expr: "2 ** 10"
        default: 42
        expected: 42
      id: "2 ** 10-42-42"
      

      📌 Setup phase

      duration:

      0.00030743982642889023
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001955972984433174
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.000202828086912632
      

      outcome:

      passed
      
  • 📄 test_utils_exceptions.py

    Function: test_chained_exception_various

    • Test 220
      params: func="<function cause_key_error at 0x7feb0aa50a60>", expected_output="High-level task failed\ncaused by KeyError: 'missing'"

      📌 Parameters

      params:
        func: "<function cause_key_error at 0x7feb0aa50a60>"
        expected_output: "High-level task failed\ncaused by KeyError: 'missing'"
      id: "cause_key_error-High-level task failed\\ncaused by KeyError: 'missing'"
      

      📌 Setup phase

      duration:

      0.0002917833626270294
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019184034317731857
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018107425421476364
      

      outcome:

      passed
      
    • Test 221
      params: func="<function cause_index_error at 0x7feb0a40ac10>", expected_output="High-level task failed\ncaused by IndexError: list index out of range"

      📌 Parameters

      params:
        func: "<function cause_index_error at 0x7feb0a40ac10>"
        expected_output: "High-level task failed\ncaused by IndexError: list index out of range"
      id: "cause_index_error-High-level task failed\\ncaused by IndexError: list index out of range"
      

      📌 Setup phase

      duration:

      0.0002714525908231735
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00020081084221601486
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017896946519613266
      

      outcome:

      passed
      
    • Test 222
      params: func="<function cause_zero_division at 0x7feb0a40aca0>", expected_output="High-level task failed\ncaused by ZeroDivisionError: division by zero"

      📌 Parameters

      params:
        func: "<function cause_zero_division at 0x7feb0a40aca0>"
        expected_output: "High-level task failed\ncaused by ZeroDivisionError: division by zero"
      id: "cause_zero_division-High-level task failed\\ncaused by ZeroDivisionError: division by zero"
      

      📌 Setup phase

      duration:

      0.00026755034923553467
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017936527729034424
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001819208264350891
      

      outcome:

      passed
      
    • Test 223
      params: func="<function cause_value_error at 0x7feb0a40ad30>", expected_output="High-level task failed\ncaused by ValueError: invalid literal for int() with base 10: 'not_a_number'"

      📌 Parameters

      params:
        func: "<function cause_value_error at 0x7feb0a40ad30>"
        expected_output: "High-level task failed\ncaused by ValueError: invalid literal for int() with base 10: 'not_a_number'"
      id: "cause_value_error-High-level task failed\\ncaused by ValueError: invalid literal for int() with base 10: 'not_a_number'"
      

      📌 Setup phase

      duration:

      0.00026558060199022293
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018336530774831772
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020583905279636383
      

      outcome:

      passed
      
    • Test 224
      params: func="<function cause_type_error at 0x7feb0a40adc0>", expected_output="High-level task failed\ncaused by TypeError: can only concatenate str (not \"int\") to str"

      📌 Parameters

      params:
        func: "<function cause_type_error at 0x7feb0a40adc0>"
        expected_output: "High-level task failed\ncaused by TypeError: can only concatenate str (not \"int\") to str"
      id: "cause_type_error-High-level task failed\\ncaused by TypeError: can only concatenate str (not \"int\") to str"
      

      📌 Setup phase

      duration:

      0.0002652732655405998
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018240511417388916
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017846561968326569
      

      outcome:

      passed
      

    Function: test_printed_exception

    • Test 225
      params: func="<function cause_key_error at 0x7feb0aa50a60>", expected_output="KeyError: 'missing'"

      📌 Parameters

      params:
        func: "<function cause_key_error at 0x7feb0aa50a60>"
        expected_output: "KeyError: 'missing'"
      id: "cause_key_error-KeyError: 'missing'"
      

      📌 Setup phase

      duration:

      0.0007697539404034615
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0010050423443317413
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0004943301901221275
      

      outcome:

      passed
      
    • Test 226
      params: func="<function cause_index_error at 0x7feb0a40ac10>", expected_output="IndexError: list index out of range"

      📌 Parameters

      params:
        func: "<function cause_index_error at 0x7feb0a40ac10>"
        expected_output: "IndexError: list index out of range"
      id: "cause_index_error-IndexError: list index out of range"
      

      📌 Setup phase

      duration:

      0.0006279358640313148
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0008212374523282051
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0005252780392765999
      

      outcome:

      passed
      
    • Test 227
      params: func="<function cause_zero_division at 0x7feb0a40aca0>", expected_output="ZeroDivisionError: division by zero"

      📌 Parameters

      params:
        func: "<function cause_zero_division at 0x7feb0a40aca0>"
        expected_output: "ZeroDivisionError: division by zero"
      id: "cause_zero_division-ZeroDivisionError: division by zero"
      

      📌 Setup phase

      duration:

      0.0005743596702814102
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0007774438709020615
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00046464987099170685
      

      outcome:

      passed
      
    • Test 228
      params: func="<function cause_value_error at 0x7feb0a40ad30>", expected_output="ValueError: invalid literal for int() with base 10: 'not_a_number'"

      📌 Parameters

      params:
        func: "<function cause_value_error at 0x7feb0a40ad30>"
        expected_output: "ValueError: invalid literal for int() with base 10: 'not_a_number'"
      id: "cause_value_error-ValueError: invalid literal for int() with base 10: 'not_a_number'"
      

      📌 Setup phase

      duration:

      0.0006184186786413193
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0008559180423617363
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0004581911489367485
      

      outcome:

      passed
      
    • Test 229
      params: func="<function cause_type_error at 0x7feb0a40adc0>", expected_output="TypeError: can only concatenate str (not \"int\") to str"

      📌 Parameters

      params:
        func: "<function cause_type_error at 0x7feb0a40adc0>"
        expected_output: "TypeError: can only concatenate str (not \"int\") to str"
      id: "cause_type_error-TypeError: can only concatenate str (not \"int\") to str"
      

      📌 Setup phase

      duration:

      0.0006029661744832993
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.000798461027443409
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00047109462320804596
      

      outcome:

      passed
      
  • 📄 test_utils_get_adj.py

    Function: test_get_adj_success

    • Test 230

      📌 Setup phase

      duration:

      0.00017236825078725815
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0008259480819106102
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001577446237206459
      

      outcome:

      passed
      

    Function: test_get_adj_not_found

    • Test 231

      📌 Setup phase

      duration:

      0.0005764169618487358
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.000984998419880867
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0004398319870233536
      

      outcome:

      passed
      

    Function: test_ensure_adjs_mixed

    • Test 232

      📌 Setup phase

      duration:

      0.0001711016520857811
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0008076559752225876
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00014907494187355042
      

      outcome:

      passed
      
  • 📄 test_utils_ipy.py

    Function: test_devices_repr_fallback_and_ignore

    • Test 234

      📌 Setup phase

      duration:

      0.0004907501861453056
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0010883482173085213
      

      outcome:

      passed
      

      stdout:

      test_desc: desc ok
      test_doc:  doc ok
      test_id:   D4
      test_name: name ok
      
      
      

      📌 Teardown phase

      duration:

      0.0003043757751584053
      

      outcome:

      passed
      
  • 📄 test_utils_jsonext.py

    Function: test_json_validate_save_load

    • Test 235
      params: input_obj="[1 2 3]", expected=[1, 2, 3]

      📌 Parameters

      params:
        input_obj: "[1 2 3]"
        expected: [1, 2, 3]
      id: "input_obj0-expected0"
      

      📌 Setup phase

      duration:

      0.0007651355117559433
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0004907818511128426
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00025903433561325073
      

      outcome:

      passed
      
    • Test 236
      params: input_obj="42", expected=42

      📌 Parameters

      params:
        input_obj: "42"
        expected: 42
      id: "input_obj1-42"
      

      📌 Setup phase

      duration:

      0.0007057245820760727
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0004361635074019432
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00026330258697271347
      

      outcome:

      passed
      
    • Test 237
      params: input_obj="(1-1j)", expected={"real": 1.0, "imag": -1.0}

      📌 Parameters

      params:
        input_obj: "(1-1j)"
        expected: {"real": 1.0, "imag": -1.0}
      id: "(1-1j)-expected2"
      

      📌 Setup phase

      duration:

      0.0006354087963700294
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00045669544488191605
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00023453030735254288
      

      outcome:

      passed
      
    • Test 238
      params: input_obj="/tmp/file.txt", expected="/tmp/file.txt"

      📌 Parameters

      params:
        input_obj: "/tmp/file.txt"
        expected: "/tmp/file.txt"
      id: "input_obj3-/tmp/file.txt"
      

      📌 Setup phase

      duration:

      0.0006722910329699516
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0004058787599205971
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00022372975945472717
      

      outcome:

      passed
      
    • Test 239
      params: input_obj="{1, 2, 3}", expected=[1, 2, 3]

      📌 Parameters

      params:
        input_obj: "{1, 2, 3}"
        expected: [1, 2, 3]
      id: "input_obj4-expected4"
      

      📌 Setup phase

      duration:

      0.0006602490320801735
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0004401998594403267
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00022577401250600815
      

      outcome:

      passed
      
    • Test 240
      params: input_obj="{'a': array([10, 20])}", expected={"a": [10, 20]}

      📌 Parameters

      params:
        input_obj: "{'a': array([10, 20])}"
        expected: {"a": [10, 20]}
      id: "input_obj5-expected5"
      

      📌 Setup phase

      duration:

      0.000688435509800911
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00045117922127246857
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002353135496377945
      

      outcome:

      passed
      
    • Test 241
      params: input_obj="{'c': (2+3j)}", expected={"c": {"real": 2.0, "imag": 3.0}}

      📌 Parameters

      params:
        input_obj: "{'c': (2+3j)}"
        expected: {"c": {"real": 2.0, "imag": 3.0}}
      id: "input_obj6-expected6"
      

      📌 Setup phase

      duration:

      0.0007104640826582909
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0004640268161892891
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002208976075053215
      

      outcome:

      passed
      
    • Test 242
      params: input_obj="{'nested': {'arr': array([[10, 20],\n [30, 40]]), 'complex_num': (-1+5j), 'files': [PosixPath('/file1'), PosixPath('/file2')], 'set_values': {200, 100}, 'inner': {'num': 7}}}", expected={"nested": {"arr": [[10, 20], [30, 40]], "complex_num": {"real": -1.0, "imag": 5.0}, "files": ["/file1", "/file2"], "set_values": [100, 200], "inner": {"num": 7}}}

      📌 Parameters

      params:
        input_obj: "{'nested': {'arr': array([[10, 20],\n       [30, 40]]), 'complex_num': (-1+5j), 'files': [PosixPath('/file1'), PosixPath('/file2')], 'set_values': {200, 100}, 'inner': {'num': 7}}}"
        expected: {"nested": {"arr": [[10, 20], [30, 40]], "complex_num": {"real": -1.0, "imag": 5.0}, "files": ["/file1", "/file2"], "set_values": [100, 200], "inner": {"num": 7}}}
      id: "input_obj7-expected7"
      

      📌 Setup phase

      duration:

      0.0006501683965325356
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0007592644542455673
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00024243909865617752
      

      outcome:

      passed
      
  • 📄 test_utils_lazypv.py

    Function: test_getattr

    • Test 243

      📌 Setup phase

      duration:

      0.00017841067165136337
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      151.3954442385584
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00031461194157600403
      

      outcome:

      passed
      
  • 📄 test_utils_logcfg.py

    Function: test_custom_log_outputs

    • Test 244
      params: levelname="LONG", logfunc="<function <lambda> at 0x7feb09da0160>", message="This is a LONG message"

      📌 Parameters

      params:
        levelname: "LONG"
        logfunc: "<function <lambda> at 0x7feb09da0160>"
        message: "This is a LONG message"
      id: "LONG-<lambda>-This is a LONG message"
      

      📌 Setup phase

      duration:

      0.001408495008945465
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0012766234576702118
      

      outcome:

      passed
      

      stdout:

      Captured stderr: '[L 250828 10:15:54 test_utils_logcfg:41] This is a LONG message\n'
      
      

      📌 Teardown phase

      duration:

      0.0004579313099384308
      

      outcome:

      passed
      
    • Test 245
      params: levelname="ENLARGE", logfunc="<function <lambda> at 0x7feb09da01f0>", message="Please ENLARGE this!"

      📌 Parameters

      params:
        levelname: "ENLARGE"
        logfunc: "<function <lambda> at 0x7feb09da01f0>"
        message: "Please ENLARGE this!"
      id: "ENLARGE-<lambda>-Please ENLARGE this!"
      

      📌 Setup phase

      duration:

      0.0006312122568488121
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0009828191250562668
      

      outcome:

      passed
      

      stdout:

      Captured stderr: '[E 250828 10:15:54 test_utils_logcfg:41] Please ENLARGE this!\n'
      
      

      📌 Teardown phase

      duration:

      0.00031099840998649597
      

      outcome:

      passed
      
  • 📄 test_utils_logign.py

    Function: test_ignore_log_msg_behavior

    • Test 247
      params: levelname="WARNING", msg_to_ignore="This should be ignored", msg_to_keep="This should appear"

      📌 Parameters

      params:
        levelname: "WARNING"
        msg_to_ignore: "This should be ignored"
        msg_to_keep: "This should appear"
      id: "WARNING-This should be ignored-This should appear"
      

      📌 Setup phase

      duration:

      0.0006395550444722176
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0008427537977695465
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00030824728310108185
      

      outcome:

      passed
      
    • Test 248
      params: levelname="ENLARGE", msg_to_ignore="ENLARGE this", msg_to_keep="Keep this ENLARGE"

      📌 Parameters

      params:
        levelname: "ENLARGE"
        msg_to_ignore: "ENLARGE this"
        msg_to_keep: "Keep this ENLARGE"
      id: "ENLARGE-ENLARGE this-Keep this ENLARGE"
      

      📌 Setup phase

      duration:

      0.00046116020530462265
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0005076434463262558
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002826368436217308
      

      outcome:

      passed
      

    Function: test_ignore_only_by_level

    • Test 249

      📌 Setup phase

      duration:

      0.0002803727984428406
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00046435464173555374
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002130027860403061
      

      outcome:

      passed
      

    Function: test_ignore_only_by_msg

    • Test 250

      📌 Setup phase

      duration:

      0.00028053298592567444
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0004361579194664955
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020905770361423492
      

      outcome:

      passed
      

    Function: test_filter_removed_after_context

    • Test 251

      📌 Setup phase

      duration:

      0.0002823648974299431
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00042544305324554443
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002305973321199417
      

      outcome:

      passed
      
  • 📄 test_utils_marker.py

    Function: test_format_value_with_units

    • Test 252

      📌 Setup phase

      duration:

      0.00016749463975429535
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002111317589879036
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00014679506421089172
      

      outcome:

      passed
      

    Function: test_format_value_without_units

    • Test 253

      📌 Setup phase

      duration:

      0.00016143452376127243
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00020717456936836243
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00016266386955976486
      

      outcome:

      passed
      

    Function: test_marker_name_default

    • Test 254

      📌 Setup phase

      duration:

      0.0002158014103770256
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00031486619263887405
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018708407878875732
      

      outcome:

      passed
      

    Function: test_marker_name_custom

    • Test 255

      📌 Setup phase

      duration:

      0.00018797721713781357
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00025486480444669724
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001846523955464363
      

      outcome:

      passed
      

    Function: test_marker_repr_format

    • Test 256

      📌 Setup phase

      duration:

      0.0001903977245092392
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0003222646191716194
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017275940626859665
      

      outcome:

      passed
      

    Function: test_marker_update_changes_value

    • Test 257

      📌 Setup phase

      duration:

      0.0001958310604095459
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00024024024605751038
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017174333333969116
      

      outcome:

      passed
      

    Function: test_marker_update_with_explicit_value

    • Test 258

      📌 Setup phase

      duration:

      0.0001722872257232666
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00024454109370708466
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00015797186642885208
      

      outcome:

      passed
      

    Function: test_marker_goto_sets_value_and_returns_result

    • Test 259

      📌 Setup phase

      duration:

      0.00018707197159528732
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0007072584703564644
      

      outcome:

      passed
      

      stdout:

      Going to "Device_TGG at 3.3 V"
      
      

      📌 Teardown phase

      duration:

      0.00019473955035209656
      

      outcome:

      passed
      

    Function: test_marker_call_is_alias_of_goto

    • Test 260

      📌 Setup phase

      duration:

      0.00017725583165884018
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.000613105483353138
      

      outcome:

      passed
      

      stdout:

      Going to "Device_TAC at 3.3 V"
      
      

      📌 Teardown phase

      duration:

      0.00016724132001399994
      

      outcome:

      passed
      

    Function: test_markers_register_and_access

    • Test 261

      📌 Setup phase

      duration:

      0.000164092518389225
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0003393329679965973
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00015369709581136703
      

      outcome:

      passed
      

    Function: test_markers_repr_contains_all

    • Test 262

      📌 Setup phase

      duration:

      0.00016462337225675583
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0003760438412427902
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00015283375978469849
      

      outcome:

      passed
      

    Function: test_marker_registry_dict_is_printable_dict

    • Test 263

      📌 Setup phase

      duration:

      0.00015860982239246368
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00026455149054527283
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00014755409210920334
      

      outcome:

      passed
      

    Function: test_markers_getitem_invalid_key_raises

    • Test 264

      📌 Setup phase

      duration:

      0.0001590736210346222
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002753427252173424
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00014892034232616425
      

      outcome:

      passed
      
  • 📄 test_utils_metaclasses.py

    Function: test_combine_classes_combines_methods

    • Test 265

      📌 Setup phase

      duration:

      0.00019108504056930542
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00022565852850675583
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00016507133841514587
      

      outcome:

      passed
      

    Function: test_registryabc_combines_registrymeta_and_abcmeta

    • Test 266

      📌 Setup phase

      duration:

      0.00015187356621026993
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.002683660015463829
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017129722982645035
      

      outcome:

      passed
      
  • 📄 test_utils_namespace.py

    Function: test_namespace_pretty_repr_mixed_and_nested

    • Test 267

      📌 Setup phase

      duration:

      0.00018950551748275757
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00030793994665145874
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001787366345524788
      

      outcome:

      passed
      
  • 📄 test_utils_npy.py

    Function: test_nice_arange

    • Test 268
      params: start=0, stop=5, step=1, expected=[0, 1, 2, 3, 4, 5]

      📌 Parameters

      params:
        start: 0
        stop: 5
        step: 1
        expected: [0, 1, 2, 3, 4, 5]
      id: "0-5-1-expected0"
      

      📌 Setup phase

      duration:

      0.00043272972106933594
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.005520062521100044
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002744821831583977
      

      outcome:

      passed
      
    • Test 269
      params: start=5, stop=0, step=-1, expected=[0, 1, 2, 3, 4, 5]

      📌 Parameters

      params:
        start: 5
        stop: 0
        step: -1
        expected: [0, 1, 2, 3, 4, 5]
      id: "5-0--1-expected1"
      

      📌 Setup phase

      duration:

      0.00040444266051054
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0004925262182950974
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002642069011926651
      

      outcome:

      passed
      
    • Test 270
      params: start=1, stop=2, step=0.3, expected=[1, 1.3333333333333333, 1.6666666666666667, 2]

      📌 Parameters

      params:
        start: 1
        stop: 2
        step: 0.3
        expected: [1, 1.3333333333333333, 1.6666666666666667, 2]
      id: "1-2-0.3-expected2"
      

      📌 Setup phase

      duration:

      0.0003951415419578552
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0006285598501563072
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00025017280131578445
      

      outcome:

      passed
      
    • Test 271
      params: start=-2, stop=2, step=1.5, expected=[-2, -0.6666666666666666, 0.6666666666666666, 2]

      📌 Parameters

      params:
        start: -2
        stop: 2
        step: 1.5
        expected: [-2, -0.6666666666666666, 0.6666666666666666, 2]
      id: "-2-2-1.5-expected3"
      

      📌 Setup phase

      duration:

      0.00041262339800596237
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0004546837881207466
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00024906639009714127
      

      outcome:

      passed
      
    • Test 272
      params: start=2.5, stop=0.5, step=-0.4, expected=[0.5, 0.9, 1.3, 1.7, 2.1, 2.5]

      📌 Parameters

      params:
        start: 2.5
        stop: 0.5
        step: -0.4
        expected: [0.5, 0.9, 1.3, 1.7, 2.1, 2.5]
      id: "2.5-0.5--0.4-expected4"
      

      📌 Setup phase

      duration:

      0.0003885924816131592
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0004294170066714287
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002329787239432335
      

      outcome:

      passed
      

    Function: test_nice_linspace

    • Test 273
      params: start=0, stop=10, num=4, expected="[ 0. 2.5 5. 7.5 10. ]"

      📌 Parameters

      params:
        start: 0
        stop: 10
        num: 4
        expected: "[ 0.   2.5  5.   7.5 10. ]"
      id: "0-10-4-expected0"
      

      📌 Setup phase

      duration:

      0.0003890218213200569
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0004116576164960861
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00026735011488199234
      

      outcome:

      passed
      
    • Test 274
      params: start=5, stop=15, num=2, expected="[ 5. 10. 15.]"

      📌 Parameters

      params:
        start: 5
        stop: 15
        num: 2
        expected: "[ 5. 10. 15.]"
      id: "5-15-2-expected1"
      

      📌 Setup phase

      duration:

      0.0004012472927570343
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0004338519647717476
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002560904249548912
      

      outcome:

      passed
      
    • Test 275
      params: start=-5, stop=5, num=4, expected="[-5. -2.5 0. 2.5 5. ]"

      📌 Parameters

      params:
        start: -5
        stop: 5
        num: 4
        expected: "[-5.  -2.5  0.   2.5  5. ]"
      id: "-5-5-4-expected2"
      

      📌 Setup phase

      duration:

      0.0004037488251924515
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00040995609015226364
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00023584067821502686
      

      outcome:

      passed
      
    • Test 276
      params: start=0, stop=1, num=3, expected="[0. 0.33333333 0.66666667 1. ]"

      📌 Parameters

      params:
        start: 0
        stop: 1
        num: 3
        expected: "[0.         0.33333333 0.66666667 1.        ]"
      id: "0-1-3-expected3"
      

      📌 Setup phase

      duration:

      0.0003910670056939125
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0004059039056301117
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002358071506023407
      

      outcome:

      passed
      
    • Test 277
      params: start=2, stop=2, num=3, expected="[2. 2. 2. 2.]"

      📌 Parameters

      params:
        start: 2
        stop: 2
        num: 3
        expected: "[2. 2. 2. 2.]"
      id: "2-2-3-expected4"
      

      📌 Setup phase

      duration:

      0.0003807181492447853
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.000410386361181736
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002474868670105934
      

      outcome:

      passed
      
    • Test 278
      params: start=3, stop=0, num=3, expected="[3. 2. 1. 0.]"

      📌 Parameters

      params:
        start: 3
        stop: 0
        num: 3
        expected: "[3. 2. 1. 0.]"
      id: "3-0-3-expected5"
      

      📌 Setup phase

      duration:

      0.0003945911303162575
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00041286181658506393
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00023608841001987457
      

      outcome:

      passed
      
    • Test 279
      params: start=0, stop=1, num=0, expected="[0.]"

      📌 Parameters

      params:
        start: 0
        stop: 1
        num: 0
        expected: "[0.]"
      id: "0-1-0-expected6"
      

      📌 Setup phase

      duration:

      0.00039051566272974014
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00040220655500888824
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00024004466831684113
      

      outcome:

      passed
      
    • Test 280
      params: start=-2, stop=2, num=3, expected="[-2. -0.66666667 0.66666667 2. ]"

      📌 Parameters

      params:
        start: -2
        stop: 2
        num: 3
        expected: "[-2.         -0.66666667  0.66666667  2.        ]"
      id: "-2-2-3-expected7"
      

      📌 Setup phase

      duration:

      0.0004071425646543503
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.000400039367377758
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002515781670808792
      

      outcome:

      passed
      

    Function: test_nice_steps_centered

    • Test 281
      params: start=-2, stop=2, step=2, endpoint=true, expected="[-2. 0. 2.]"

      📌 Parameters

      params:
        start: -2
        stop: 2
        step: 2
        endpoint: true
        expected: "[-2.  0.  2.]"
      id: "-2-2-2-True-expected0"
      

      📌 Setup phase

      duration:

      0.0004654582589864731
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0004252437502145767
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002570170909166336
      

      outcome:

      passed
      
    • Test 282
      params: start=0, stop=5, step=2, endpoint=true, expected="[0. 2. 4.]"

      📌 Parameters

      params:
        start: 0
        stop: 5
        step: 2
        endpoint: true
        expected: "[0. 2. 4.]"
      id: "0-5-2-True-expected1"
      

      📌 Setup phase

      duration:

      0.0004547722637653351
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00039336085319519043
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002635344862937927
      

      outcome:

      passed
      
    • Test 283
      params: start=0, stop=5, step=2, endpoint=false, expected="[0. 2.]"

      📌 Parameters

      params:
        start: 0
        stop: 5
        step: 2
        endpoint: false
        expected: "[0. 2.]"
      id: "0-5-2-False-expected2"
      

      📌 Setup phase

      duration:

      0.00045314617455005646
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00040230248123407364
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00026334356516599655
      

      outcome:

      passed
      
    • Test 284
      params: start=-1, stop=2, step=1.5, endpoint=true, expected="[-1.5 0. 1.5]"

      📌 Parameters

      params:
        start: -1
        stop: 2
        step: 1.5
        endpoint: true
        expected: "[-1.5  0.   1.5]"
      id: "-1-2-1.5-True-expected3"
      

      📌 Setup phase

      duration:

      0.00042972713708877563
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00039712339639663696
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002613235265016556
      

      outcome:

      passed
      
    • Test 285
      params: start=-1, stop=2, step=-1.5, endpoint=true, expected="[ 1.5 0. -1.5]"

      📌 Parameters

      params:
        start: -1
        stop: 2
        step: -1.5
        endpoint: true
        expected: "[ 1.5  0.  -1.5]"
      id: "-1-2--1.5-True-expected4"
      

      📌 Setup phase

      duration:

      0.00044645369052886963
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00038844719529151917
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00025347061455249786
      

      outcome:

      passed
      
    • Test 286
      params: start=5, stop=0, step=-2, endpoint=true, expected="[0. 2. 4.]"

      📌 Parameters

      params:
        start: 5
        stop: 0
        step: -2
        endpoint: true
        expected: "[0. 2. 4.]"
      id: "5-0--2-True-expected5"
      

      📌 Setup phase

      duration:

      0.0004448890686035156
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00039639417082071304
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00026718340814113617
      

      outcome:

      passed
      

    Function: test_nice_steps_left_aligned

    • Test 287
      params: start=0, stop=5, step=2, endpoint=true, expected="[0. 2. 4.]"

      📌 Parameters

      params:
        start: 0
        stop: 5
        step: 2
        endpoint: true
        expected: "[0. 2. 4.]"
      id: "0-5-2-True-expected0"
      

      📌 Setup phase

      duration:

      0.00043951068073511124
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0004055909812450409
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00025737471878528595
      

      outcome:

      passed
      
    • Test 288
      params: start=0, stop=5, step=2, endpoint=false, expected="[0. 2.]"

      📌 Parameters

      params:
        start: 0
        stop: 5
        step: 2
        endpoint: false
        expected: "[0. 2.]"
      id: "0-5-2-False-expected1"
      

      📌 Setup phase

      duration:

      0.0004473831504583359
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0003942437469959259
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002496633678674698
      

      outcome:

      passed
      
    • Test 289
      params: start=-1, stop=2, step=1.5, endpoint=true, expected="[-1. 0.5 2. ]"

      📌 Parameters

      params:
        start: -1
        stop: 2
        step: 1.5
        endpoint: true
        expected: "[-1.   0.5  2. ]"
      id: "-1-2-1.5-True-expected2"
      

      📌 Setup phase

      duration:

      0.00043468642979860306
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0003848690539598465
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002621859312057495
      

      outcome:

      passed
      
    • Test 290
      params: start=-1, stop=2, step=1.5, endpoint=false, expected="[-1. 0.5]"

      📌 Parameters

      params:
        start: -1
        stop: 2
        step: 1.5
        endpoint: false
        expected: "[-1.   0.5]"
      id: "-1-2-1.5-False-expected3"
      

      📌 Setup phase

      duration:

      0.0004540104418992996
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00038496311753988266
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00026197172701358795
      

      outcome:

      passed
      
    • Test 291
      params: start=-2, stop=1, step=1.2, endpoint=true, expected="[-2. -0.8 0.4]"

      📌 Parameters

      params:
        start: -2
        stop: 1
        step: 1.2
        endpoint: true
        expected: "[-2.  -0.8  0.4]"
      id: "-2-1-1.2-True-expected4"
      

      📌 Setup phase

      duration:

      0.0004398934543132782
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0003900211304426193
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00025874003767967224
      

      outcome:

      passed
      
    • Test 292
      params: start=5, stop=0, step=-2, endpoint=true, expected="[0. 2. 4.]"

      📌 Parameters

      params:
        start: 5
        stop: 0
        step: -2
        endpoint: true
        expected: "[0. 2. 4.]"
      id: "5-0--2-True-expected5"
      

      📌 Setup phase

      duration:

      0.0004480397328734398
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0003903741016983986
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00026257336139678955
      

      outcome:

      passed
      
    • Test 293
      params: start=5, stop=0, step=-2, endpoint=false, expected="[0. 2.]"

      📌 Parameters

      params:
        start: 5
        stop: 0
        step: -2
        endpoint: false
        expected: "[0. 2.]"
      id: "5-0--2-False-expected6"
      

      📌 Setup phase

      duration:

      0.00041790958493947983
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0003816811367869377
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002738572657108307
      

      outcome:

      passed
      

    Function: test_nice_steps_right_aligned

    • Test 294
      params: start=0, stop=5, step=2, endpoint=true, expected="[1. 3. 5.]"

      📌 Parameters

      params:
        start: 0
        stop: 5
        step: 2
        endpoint: true
        expected: "[1. 3. 5.]"
      id: "0-5-2-True-expected0"
      

      📌 Setup phase

      duration:

      0.00042881816625595093
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0005025360733270645
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00027466844767332077
      

      outcome:

      passed
      
    • Test 295
      params: start=0, stop=5, step=2, endpoint=false, expected="[3. 5.]"

      📌 Parameters

      params:
        start: 0
        stop: 5
        step: 2
        endpoint: false
        expected: "[3. 5.]"
      id: "0-5-2-False-expected1"
      

      📌 Setup phase

      duration:

      0.0004348214715719223
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0004015043377876282
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002688895910978317
      

      outcome:

      passed
      
    • Test 296
      params: start=-1, stop=2, step=1.5, endpoint=true, expected="[-1. 0.5 2. ]"

      📌 Parameters

      params:
        start: -1
        stop: 2
        step: 1.5
        endpoint: true
        expected: "[-1.   0.5  2. ]"
      id: "-1-2-1.5-True-expected2"
      

      📌 Setup phase

      duration:

      0.00045419950038194656
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0004007713869214058
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00026607047766447067
      

      outcome:

      passed
      
    • Test 297
      params: start=-1, stop=2, step=1.5, endpoint=false, expected="[0.5 2. ]"

      📌 Parameters

      params:
        start: -1
        stop: 2
        step: 1.5
        endpoint: false
        expected: "[0.5 2. ]"
      id: "-1-2-1.5-False-expected3"
      

      📌 Setup phase

      duration:

      0.0004438776522874832
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00039994344115257263
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002754228189587593
      

      outcome:

      passed
      
    • Test 298
      params: start=5, stop=0, step=-2, endpoint=true, expected="[1. 3. 5.]"

      📌 Parameters

      params:
        start: 5
        stop: 0
        step: -2
        endpoint: true
        expected: "[1. 3. 5.]"
      id: "5-0--2-True-expected4"
      

      📌 Setup phase

      duration:

      0.00045099202543497086
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0003963615745306015
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002738693729043007
      

      outcome:

      passed
      
    • Test 299
      params: start=5, stop=0, step=-2, endpoint=false, expected="[3. 5.]"

      📌 Parameters

      params:
        start: 5
        stop: 0
        step: -2
        endpoint: false
        expected: "[3. 5.]"
      id: "5-0--2-False-expected5"
      

      📌 Setup phase

      duration:

      0.0004164092242717743
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.000391143374145031
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00027095526456832886
      

      outcome:

      passed
      
    • Test 300
      params: start=-3, stop=3, step=2, endpoint=true, expected="[-3. -1. 1. 3.]"

      📌 Parameters

      params:
        start: -3
        stop: 3
        step: 2
        endpoint: true
        expected: "[-3. -1.  1.  3.]"
      id: "-3-3-2-True-expected6"
      

      📌 Setup phase

      duration:

      0.0004271306097507477
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00040322262793779373
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002727750688791275
      

      outcome:

      passed
      

    Function: test_within_scalar

    • Test 301
      params: val=5, vmin=0, vmax=10, expected=true

      📌 Parameters

      params:
        val: 5
        vmin: 0
        vmax: 10
        expected: true
      id: "5-0-10-True"
      

      📌 Setup phase

      duration:

      0.0003852546215057373
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019492395222187042
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002155117690563202
      

      outcome:

      passed
      
    • Test 302
      params: val=5, vmin=6, vmax=10, expected=false

      📌 Parameters

      params:
        val: 5
        vmin: 6
        vmax: 10
        expected: false
      id: "5-6-10-False"
      

      📌 Setup phase

      duration:

      0.00039101671427488327
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017819739878177643
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00022894609719514847
      

      outcome:

      passed
      
    • Test 303
      params: val=5, vmin=null, vmax=10, expected=true

      📌 Parameters

      params:
        val: 5
        vmin: null
        vmax: 10
        expected: true
      id: "5-None-10-True"
      

      📌 Setup phase

      duration:

      0.00036317575722932816
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019834190607070923
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00021536368876695633
      

      outcome:

      passed
      
    • Test 304
      params: val=5, vmin=0, vmax=null, expected=true

      📌 Parameters

      params:
        val: 5
        vmin: 0
        vmax: null
        expected: true
      id: "5-0-None-True"
      

      📌 Setup phase

      duration:

      0.00037882663309574127
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018384866416454315
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00022497307509183884
      

      outcome:

      passed
      
    • Test 305
      params: val=5, vmin=null, vmax=null, expected=true

      📌 Parameters

      params:
        val: 5
        vmin: null
        vmax: null
        expected: true
      id: "5-None-None-True"
      

      📌 Setup phase

      duration:

      0.0003651585429906845
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00020106323063373566
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002211015671491623
      

      outcome:

      passed
      

    Function: test_within_fraction

    • Test 306
      params: data=[1, 2, 3, 4, 5], vmin=2, vmax=5, expected=0.6

      📌 Parameters

      params:
        data: [1, 2, 3, 4, 5]
        vmin: 2
        vmax: 5
        expected: 0.6
      id: "data0-2-5-0.6"
      

      📌 Setup phase

      duration:

      0.00037157535552978516
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0004018917679786682
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002502715215086937
      

      outcome:

      passed
      
    • Test 307
      params: data=[10, 20, 30], vmin=5, vmax=25, expected=0.6666666666666666

      📌 Parameters

      params:
        data: [10, 20, 30]
        vmin: 5
        vmax: 25
        expected: 0.6666666666666666
      id: "data1-5-25-0.6666666666666666"
      

      📌 Setup phase

      duration:

      0.0003825780004262924
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00037051551043987274
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00022663362324237823
      

      outcome:

      passed
      
    • Test 308
      params: data=[1, 2, 3], vmin=null, vmax=2, expected=0.3333333333333333

      📌 Parameters

      params:
        data: [1, 2, 3]
        vmin: null
        vmax: 2
        expected: 0.3333333333333333
      id: "data2-None-2-0.3333333333333333"
      

      📌 Setup phase

      duration:

      0.0003706077113747597
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00034191180020570755
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00023324694484472275
      

      outcome:

      passed
      
    • Test 309
      params: data=[], vmin=0, vmax=1, expected=0

      📌 Parameters

      params:
        data: []
        vmin: 0
        vmax: 1
        expected: 0
      id: "data3-0-1-0"
      

      📌 Setup phase

      duration:

      0.00038699526339769363
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0003242362290620804
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00023883208632469177
      

      outcome:

      passed
      

    Function: test_fraction_to_percentage

    • Test 310
      params: fraction=0.456, ndigits=1, expected=45.6

      📌 Parameters

      params:
        fraction: 0.456
        ndigits: 1
        expected: 45.6
      id: "0.456-1-45.6"
      

      📌 Setup phase

      duration:

      0.0003415467217564583
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0003310795873403549
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00031228549778461456
      

      outcome:

      passed
      
    • Test 311
      params: fraction=0.12345, ndigits=2, expected=12.35

      📌 Parameters

      params:
        fraction: 0.12345
        ndigits: 2
        expected: 12.35
      id: "0.12345-2-12.35"
      

      📌 Setup phase

      duration:

      0.0004530288279056549
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00021735671907663345
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002106139436364174
      

      outcome:

      passed
      
    • Test 312
      params: fraction=0.9999, ndigits=0, expected=100.0

      📌 Parameters

      params:
        fraction: 0.9999
        ndigits: 0
        expected: 100.0
      id: "0.9999-0-100.0"
      

      📌 Setup phase

      duration:

      0.0003208965063095093
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018568150699138641
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00025910697877407074
      

      outcome:

      passed
      

    Function: test_get_dtype

    • Test 313
      params: val="[1 2 3]", expected="<class 'numpy.ndarray'>"

      📌 Parameters

      params:
        val: "[1 2 3]"
        expected: "<class 'numpy.ndarray'>"
      id: "val0-ndarray"
      

      📌 Setup phase

      duration:

      0.0002809092402458191
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00020250771194696426
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020481273531913757
      

      outcome:

      passed
      
    • Test 314
      params: val=[1, 2, 3], expected="<class 'list'>"

      📌 Parameters

      params:
        val: [1, 2, 3]
        expected: "<class 'list'>"
      id: "val1-list"
      

      📌 Setup phase

      duration:

      0.0002939123660326004
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001805424690246582
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019543897360563278
      

      outcome:

      passed
      
    • Test 315
      params: val=3.14, expected="<class 'float'>"

      📌 Parameters

      params:
        val: 3.14
        expected: "<class 'float'>"
      id: "3.14-float"
      

      📌 Setup phase

      duration:

      0.0002798018977046013
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.000186040997505188
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018349383026361465
      

      outcome:

      passed
      

    Function: test_get_shape

    • Test 316
      params: val="[[1 2]\n [3 4]]", expected=[2, 2]

      📌 Parameters

      params:
        val: "[[1 2]\n [3 4]]"
        expected: [2, 2]
      id: "val0-expected0"
      

      📌 Setup phase

      duration:

      0.000282912515103817
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018250476568937302
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00021442491561174393
      

      outcome:

      passed
      
    • Test 317
      params: val=[1, 2, 3], expected=[]

      📌 Parameters

      params:
        val: [1, 2, 3]
        expected: []
      id: "val1-expected1"
      

      📌 Setup phase

      duration:

      0.00028837844729423523
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019081495702266693
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018540676683187485
      

      outcome:

      passed
      
    • Test 318
      params: val=42, expected=[]

      📌 Parameters

      params:
        val: 42
        expected: []
      id: "42-expected2"
      

      📌 Setup phase

      duration:

      0.00027629081159830093
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001818845048546791
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017570890486240387
      

      outcome:

      passed
      

    Function: test_is_array

    • Test 319
      params: val="[1 2 3]", expected=true

      📌 Parameters

      params:
        val: "[1 2 3]"
        expected: true
      id: "val0-True"
      

      📌 Setup phase

      duration:

      0.00037368107587099075
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019305851310491562
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002066856250166893
      

      outcome:

      passed
      
    • Test 320
      params: val=[1, 2, 3], expected=false

      📌 Parameters

      params:
        val: [1, 2, 3]
        expected: false
      id: "val1-False"
      

      📌 Setup phase

      duration:

      0.00028215721249580383
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018015503883361816
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001922324299812317
      

      outcome:

      passed
      
    • Test 321
      params: val=42, expected=false

      📌 Parameters

      params:
        val: 42
        expected: false
      id: "42-False"
      

      📌 Setup phase

      duration:

      0.00028515327721834183
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001749526709318161
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001806747168302536
      

      outcome:

      passed
      
  • 📄 test_utils_path.py

    Function: test_can_create_all_files_user_says_yes

    • Test 322

      📌 Setup phase

      duration:

      0.00018262304365634918
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0019050752744078636
      

      outcome:

      passed
      

      stdout:

      Deleting "/tmp/tmpav9t572j/a.txt".
      Deleting "/tmp/tmpav9t572j/c.txt".
      
      

      📌 Teardown phase

      duration:

      0.00023382343351840973
      

      outcome:

      passed
      

    Function: test_can_create_all_files_user_says_no

    • Test 323

      📌 Setup phase

      duration:

      0.00016407296061515808
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0004925811663269997
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00015195179730653763
      

      outcome:

      passed
      

    Function: test_make_missing_dir_creates_folder

    • Test 324

      📌 Setup phase

      duration:

      0.00015495996922254562
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0012688403949141502
      

      outcome:

      passed
      

      stdout:

      Directory "/tmp/tmpnh7mwzhl/nested/dir" does not exist, creating it...
      
      

      📌 Teardown phase

      duration:

      0.000247882679104805
      

      outcome:

      passed
      

    Function: test_glob_files_returns_matching_files_only

    • Test 325

      📌 Setup phase

      duration:

      0.00015728827565908432
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0009944234043359756
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00016167666763067245
      

      outcome:

      passed
      

    Function: test_filter_files_excludes_directories

    • Test 326

      📌 Setup phase

      duration:

      0.00016267132014036179
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00068642757833004
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00015434622764587402
      

      outcome:

      passed
      
  • 📄 test_utils_picklio.py

    Function: test_pickle_and_unpickle

    • Test 327
      params: test_obj={"a": 1, "b": [2, 3], "c": {"world": "ok"}}

      📌 Parameters

      params:
        test_obj: {"a": 1, "b": [2, 3], "c": {"world": "ok"}}
      id: "test_obj0"
      

      📌 Setup phase

      duration:

      0.0008100178092718124
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00037818215787410736
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00022704247385263443
      

      outcome:

      passed
      
    • Test 328
      params: test_obj=[1, 2, 3, 4, 5]

      📌 Parameters

      params:
        test_obj: [1, 2, 3, 4, 5]
      id: "test_obj1"
      

      📌 Setup phase

      duration:

      0.0006310539320111275
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00034017860889434814
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00022399425506591797
      

      outcome:

      passed
      
    • Test 329
      params: test_obj="simple string"

      📌 Parameters

      params:
        test_obj: "simple string"
      id: "simple string"
      

      📌 Setup phase

      duration:

      0.0005602790042757988
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0003324197605252266
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00021005142480134964
      

      outcome:

      passed
      
    • Test 330
      params: test_obj=42

      📌 Parameters

      params:
        test_obj: 42
      id: "42"
      

      📌 Setup phase

      duration:

      0.0005591530352830887
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0004046391695737839
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020876899361610413
      

      outcome:

      passed
      
    • Test 331
      params: test_obj=3.14159

      📌 Parameters

      params:
        test_obj: 3.14159
      id: "3.14159"
      

      📌 Setup phase

      duration:

      0.0005732206627726555
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0003624316304922104
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00021655112504959106
      

      outcome:

      passed
      
    • Test 332
      params: test_obj=[true, false, null]

      📌 Parameters

      params:
        test_obj: [true, false, null]
      id: "test_obj5"
      

      📌 Setup phase

      duration:

      0.0006073880940675735
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00039693061262369156
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00021502003073692322
      

      outcome:

      passed
      
    • Test 333
      params: test_obj={"complex": [{"list": [1, 2]}, {"dict": {"x": 10}}]}

      📌 Parameters

      params:
        test_obj: {"complex": [{"list": [1, 2]}, {"dict": {"x": 10}}]}
      id: "test_obj6"
      

      📌 Setup phase

      duration:

      0.0006176820024847984
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0003823889419436455
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002175513654947281
      

      outcome:

      passed
      
  • 📄 test_utils_printing.py

    Function: test_maxlen_valid

    • Test 334
      params: seq=["a", "abc", ""], expected=3

      📌 Parameters

      params:
        seq: ["a", "abc", ""]
        expected: 3
      id: "seq0-3"
      

      📌 Setup phase

      duration:

      0.0003082379698753357
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019573047757148743
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00021085888147354126
      

      outcome:

      passed
      
    • Test 335
      params: seq=[], expected=0

      📌 Parameters

      params:
        seq: []
        expected: 0
      id: "seq1-0"
      

      📌 Setup phase

      duration:

      0.00027927104383707047
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001839352771639824
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017895270138978958
      

      outcome:

      passed
      
    • Test 336
      params: seq=[[1, 2], [3], [4, 5, 6]], expected=3

      📌 Parameters

      params:
        seq: [[1, 2], [3], [4, 5, 6]]
        expected: 3
      id: "seq2-3"
      

      📌 Setup phase

      duration:

      0.0002924129366874695
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001832926645874977
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019487924873828888
      

      outcome:

      passed
      
    • Test 337
      params: seq=[{"a": 2, "b": 3}, {}, {"c": 4}], expected=2

      📌 Parameters

      params:
        seq: [{"a": 2, "b": 3}, {}, {"c": 4}]
        expected: 2
      id: "seq3-2"
      

      📌 Setup phase

      duration:

      0.000261940062046051
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001835934817790985
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019978079944849014
      

      outcome:

      passed
      

    Function: test_strlen

    • Test 338
      params: value=42, expected=2

      📌 Parameters

      params:
        value: 42
        expected: 2
      id: "42-2"
      

      📌 Setup phase

      duration:

      0.0002653142437338829
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017881859093904495
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001776237040758133
      

      outcome:

      passed
      
    • Test 339
      params: value="hello", expected=5

      📌 Parameters

      params:
        value: "hello"
        expected: 5
      id: "hello-5"
      

      📌 Setup phase

      duration:

      0.00028577540069818497
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018875394016504288
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00031988881528377533
      

      outcome:

      passed
      
    • Test 340
      params: value=false, expected=5

      📌 Parameters

      params:
        value: false
        expected: 5
      id: "False-5"
      

      📌 Setup phase

      duration:

      0.00026805978268384933
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017097406089305878
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019041914492845535
      

      outcome:

      passed
      
    • Test 341
      params: value=null, expected=4

      📌 Parameters

      params:
        value: null
        expected: 4
      id: "None-4"
      

      📌 Setup phase

      duration:

      0.0002686604857444763
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017811637371778488
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018122047185897827
      

      outcome:

      passed
      
    • Test 342
      params: value=[1, 2, 3], expected=9

      📌 Parameters

      params:
        value: [1, 2, 3]
        expected: 9
      id: "value4-9"
      

      📌 Setup phase

      duration:

      0.0002778535708785057
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019312836229801178
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019446108490228653
      

      outcome:

      passed
      
    • Test 343
      params: value={"a": 1}, expected=8

      📌 Parameters

      params:
        value: {"a": 1}
        expected: 8
      id: "value5-8"
      

      📌 Setup phase

      duration:

      0.0002575879916548729
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017529074102640152
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018850620836019516
      

      outcome:

      passed
      
    • Test 344
      params: value=[1, 2], expected=6

      📌 Parameters

      params:
        value: [1, 2]
        expected: 6
      id: "value6-6"
      

      📌 Setup phase

      duration:

      0.0002662753686308861
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018111150711774826
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001745261251926422
      

      outcome:

      passed
      
    • Test 345
      params: value="", expected=0

      📌 Parameters

      params:
        value: ""
        expected: 0
      id: "-0"
      

      📌 Setup phase

      duration:

      0.0002849586308002472
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017805956304073334
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017933454364538193
      

      outcome:

      passed
      
    • Test 346
      params: value="this is a phrase", expected=16

      📌 Parameters

      params:
        value: "this is a phrase"
        expected: 16
      id: "this is a phrase-16"
      

      📌 Setup phase

      duration:

      0.00025924667716026306
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017331819981336594
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019727367907762527
      

      outcome:

      passed
      

    Function: test_maxstrlen

    • Test 347
      params: seq=[1, true, 3.1415], expected=6

      📌 Parameters

      params:
        seq: [1, true, 3.1415]
        expected: 6
      id: "seq0-6"
      

      📌 Setup phase

      duration:

      0.00026233773678541183
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001996755599975586
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017934292554855347
      

      outcome:

      passed
      
    • Test 348
      params: seq=["aa", "bbb", "c"], expected=3

      📌 Parameters

      params:
        seq: ["aa", "bbb", "c"]
        expected: 3
      id: "seq1-3"
      

      📌 Setup phase

      duration:

      0.0002829059958457947
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00021064653992652893
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018684379756450653
      

      outcome:

      passed
      
    • Test 349
      params: seq=[[1, 2], [], [1, 2, 3]], expected=9

      📌 Parameters

      params:
        seq: [[1, 2], [], [1, 2, 3]]
        expected: 9
      id: "seq2-9"
      

      📌 Setup phase

      duration:

      0.00027456972748041153
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00021025072783231735
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001975707709789276
      

      outcome:

      passed
      
    • Test 350
      params: seq=[{"a": 1}, {}, {"a": 1, "b": 2}], expected=16

      📌 Parameters

      params:
        seq: [{"a": 1}, {}, {"a": 1, "b": 2}]
        expected: 16
      id: "seq3-16"
      

      📌 Setup phase

      duration:

      0.00025700032711029053
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019359495490789413
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019301194697618484
      

      outcome:

      passed
      
    • Test 351
      params: seq=[null, false, 12345], expected=5

      📌 Parameters

      params:
        seq: [null, false, 12345]
        expected: 5
      id: "seq4-5"
      

      📌 Setup phase

      duration:

      0.0002826498821377754
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018592458218336105
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018248148262500763
      

      outcome:

      passed
      

    Function: test_transpose_matrix

    • Test 352
      params: data=[[1, 2], [3, 4]], expected=[[1, 3], [2, 4]]

      📌 Parameters

      params:
        data: [[1, 2], [3, 4]]
        expected: [[1, 3], [2, 4]]
      id: "data0-expected0"
      

      📌 Setup phase

      duration:

      0.000281468965113163
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018134992569684982
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019231997430324554
      

      outcome:

      passed
      
    • Test 353
      params: data=[["a", "b"], ["c", "d"]], expected=[["a", "c"], ["b", "d"]]

      📌 Parameters

      params:
        data: [["a", "b"], ["c", "d"]]
        expected: [["a", "c"], ["b", "d"]]
      id: "data1-expected1"
      

      📌 Setup phase

      duration:

      0.0002629058435559273
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017240457236766815
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018875300884246826
      

      outcome:

      passed
      
    • Test 354
      params: data=[[{"x": 1}, {"y": 2}], [{"x": 3}, {"y": 4}]], expected=[[{"x": 1}, {"x": 3}], [{"y": 2}, {"y": 4}]]

      📌 Parameters

      params:
        data: [[{"x": 1}, {"y": 2}], [{"x": 3}, {"y": 4}]]
        expected: [[{"x": 1}, {"x": 3}], [{"y": 2}, {"y": 4}]]
      id: "data2-expected2"
      

      📌 Setup phase

      duration:

      0.00026540178805589676
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017795059829950333
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017922837287187576
      

      outcome:

      passed
      

    Function: test_prepend

    • Test 355
      params: initial=[1, 2, 3], prepend=1, expected=[1, 2, 3]

      📌 Parameters

      params:
        initial: [1, 2, 3]
        prepend: 1
        expected: [1, 2, 3]
      id: "initial0-1-expected0"
      

      📌 Setup phase

      duration:

      0.0003384789451956749
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018114037811756134
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002076961100101471
      

      outcome:

      passed
      
    • Test 356
      params: initial=["a", "b", "c"], prepend="a", expected=["a", "b", "c"]

      📌 Parameters

      params:
        initial: ["a", "b", "c"]
        prepend: "a"
        expected: ["a", "b", "c"]
      id: "initial1-a-expected1"
      

      📌 Setup phase

      duration:

      0.00030688755214214325
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017094332724809647
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002080155536532402
      

      outcome:

      passed
      
    • Test 357
      params: initial=[{"a": 1}, {"b": 2}], prepend={"a": 1}, expected=[{"a": 1}, {"b": 2}]

      📌 Parameters

      params:
        initial: [{"a": 1}, {"b": 2}]
        prepend: {"a": 1}
        expected: [{"a": 1}, {"b": 2}]
      id: "initial2-prepend2-expected2"
      

      📌 Setup phase

      duration:

      0.0003110375255346298
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017871707677841187
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002088630571961403
      

      outcome:

      passed
      
    • Test 358
      params: initial=[[1], [2], [3]], prepend=[1], expected=[[1], [2], [3]]

      📌 Parameters

      params:
        initial: [[1], [2], [3]]
        prepend: [1]
        expected: [[1], [2], [3]]
      id: "initial3-prepend3-expected3"
      

      📌 Setup phase

      duration:

      0.00032189302146434784
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017442461103200912
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020736642181873322
      

      outcome:

      passed
      

    Function: test_fmt_table_line

    • Test 359
      params: entries=["a", "bbb"], widths=[3, 5], expected=" a bbb"

      📌 Parameters

      params:
        entries: ["a", "bbb"]
        widths: [3, 5]
        expected: "  a   bbb"
      id: "entries0-widths0-  a   bbb"
      

      📌 Setup phase

      duration:

      0.00031786970794200897
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00021624844521284103
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020835455507040024
      

      outcome:

      passed
      
    • Test 360
      params: entries=[1, 2], widths=[2, 2], expected=" 1 2"

      📌 Parameters

      params:
        entries: [1, 2]
        widths: [2, 2]
        expected: " 1  2"
      id: "entries1-widths1- 1  2"
      

      📌 Setup phase

      duration:

      0.0003279782831668854
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001855427399277687
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002012643963098526
      

      outcome:

      passed
      
    • Test 361
      params: entries=["long", "val"], widths=[6, 4], expected=" long val"

      📌 Parameters

      params:
        entries: ["long", "val"]
        widths: [6, 4]
        expected: "  long  val"
      id: "entries2-widths2-  long  val"
      

      📌 Setup phase

      duration:

      0.00032909493893384933
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018479209393262863
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020287279039621353
      

      outcome:

      passed
      
    • Test 362
      params: entries=[true, false], widths=[5, 6], expected=" True False"

      📌 Parameters

      params:
        entries: [true, false]
        widths: [5, 6]
        expected: " True  False"
      id: "entries3-widths3- True  False"
      

      📌 Setup phase

      duration:

      0.00033091194927692413
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001874621957540512
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020068231970071793
      

      outcome:

      passed
      
    • Test 363
      params: entries=[123, 4567], widths=[5, 5], expected=" 123 4567"

      📌 Parameters

      params:
        entries: [123, 4567]
        widths: [5, 5]
        expected: "  123  4567"
      id: "entries4-widths4-  123  4567"
      

      📌 Setup phase

      duration:

      0.00033292267471551895
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018179602921009064
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002016862854361534
      

      outcome:

      passed
      
    • Test 364
      params: entries=["text with space", "end"], widths=[16, 5], expected=" text with space end"

      📌 Parameters

      params:
        entries: ["text with space", "end"]
        widths: [16, 5]
        expected: " text with space   end"
      id: "entries5-widths5- text with space   end"
      

      📌 Setup phase

      duration:

      0.00032591819763183594
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00029618944972753525
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020897295325994492
      

      outcome:

      passed
      
    • Test 365
      params: entries=[{"a": 1}, {"b": 2}], widths=[10, 10], expected=" {'a': 1} {'b': 2}"

      📌 Parameters

      params:
        entries: [{"a": 1}, {"b": 2}]
        widths: [10, 10]
        expected: "  {'a': 1}   {'b': 2}"
      id: "entries6-widths6-  {'a': 1}   {'b': 2}"
      

      📌 Setup phase

      duration:

      0.0003226427361369133
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018796510994434357
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019729789346456528
      

      outcome:

      passed
      
    • Test 366
      params: entries=[[1, 2], [3, 4]], widths=[10, 10], expected=" [1, 2] [3, 4]"

      📌 Parameters

      params:
        entries: [[1, 2], [3, 4]]
        widths: [10, 10]
        expected: "    [1, 2]     [3, 4]"
      id: "entries7-widths7-    [1, 2]     [3, 4]"
      

      📌 Setup phase

      duration:

      0.0003166086971759796
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019481033086776733
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020612124353647232
      

      outcome:

      passed
      

    Function: test_fmt_label_sep

    • Test 367
      params: widths=[3, 4], line="-", expected="--- ----"

      📌 Parameters

      params:
        widths: [3, 4]
        line: "-"
        expected: "--- ----"
      id: "widths0------ ----"
      

      📌 Setup phase

      duration:

      0.0003119213506579399
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017887819558382034
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001974916085600853
      

      outcome:

      passed
      
    • Test 368
      params: widths=[2, 3], line="=", expected="== ==="

      📌 Parameters

      params:
        widths: [2, 3]
        line: "="
        expected: "== ==="
      id: "widths1-=-== ==="
      

      📌 Setup phase

      duration:

      0.0003263670951128006
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018601026386022568
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019209738820791245
      

      outcome:

      passed
      
    • Test 369
      params: widths=[5, 2], line="*", expected="***** **"

      📌 Parameters

      params:
        widths: [5, 2]
        line: "*"
        expected: "***** **"
      id: "widths2-*-***** **"
      

      📌 Setup phase

      duration:

      0.0003206860274076462
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018698815256357193
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00023760180920362473
      

      outcome:

      passed
      

    Function: test_printable_dict_with_header

    • Test 370
      params: d={"medium": true, "very_long_key": 3.14, "x": 1}, header="HeaderTest", expected_lines=["HeaderTest:", "-----------", "medium: True", "very_long_key: 3.14", "x: 1", ""]

      📌 Parameters

      params:
        d: {"medium": true, "very_long_key": 3.14, "x": 1}
        header: "HeaderTest"
        expected_lines: ["HeaderTest:", "-----------", "medium:        True", "very_long_key: 3.14", "x:             1", ""]
      id: "d0-HeaderTest-expected_lines0"
      

      📌 Setup phase

      duration:

      0.0003601759672164917
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00028285011649131775
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00022088084369897842
      

      outcome:

      passed
      

    Function: test_printable_dict_of_dicts

    • Test 371

      📌 Setup phase

      duration:

      0.00017418991774320602
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0003168918192386627
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018531084060668945
      

      outcome:

      passed
      

    Function: test_printable_table

    • Test 372
      params: data=[["X1", true, 0.1234, {"meta": "ok"}], ["AnotherSample", false, 98765.4321, {"meta": [1, 2, 3]}], ["Z", null, 0.0, {"meta": {"nested_key": 42}}]], labels=["ID", "✓ Success?", "SuperPrecisionValue", "Result Metadata"], expected="A: ID\nB: ✓ Success?\nC: SuperPrecisionValue\nD: Result Metadata\n\n# A B C D\n- ------------- ----- ---------- ----------------------------\n0 X1 True 0.1234 {'meta': 'ok'}\n1 AnotherSample False 98765.4321 {'meta': [1, 2, 3]}\n2 Z None 0.0 {'meta': {'nested_key': 42}}"

      📌 Parameters

      params:
        data: [["X1", true, 0.1234, {"meta": "ok"}], ["AnotherSample", false, 98765.4321, {"meta": [1, 2, 3]}], ["Z", null, 0.0, {"meta": {"nested_key": 42}}]]
        labels: ["ID", "✓ Success?", "SuperPrecisionValue", "Result Metadata"]
        expected: "A: ID\nB: ✓ Success?\nC: SuperPrecisionValue\nD: Result Metadata\n\n#             A     B          C                            D\n- ------------- ----- ---------- ----------------------------\n0            X1  True     0.1234               {'meta': 'ok'}\n1 AnotherSample False 98765.4321          {'meta': [1, 2, 3]}\n2             Z  None        0.0 {'meta': {'nested_key': 42}}"
      id: "data0-labels0-A: ID\\nB: \\u2713 Success?\\nC: SuperPrecisionValue\\nD: Result Metadata\\n\\n#             A     B          C                            D\\n- ------------- ----- ---------- ----------------------------\\n0            X1  True     0.1234               {'meta': 'ok'}\\n1 AnotherSample False 98765.4321          {'meta': [1, 2, 3]}\\n2             Z  None        0.0 {'meta': {'nested_key': 42}}"
      

      📌 Setup phase

      duration:

      0.00040270015597343445
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0009598797187209129
      

      outcome:

      passed
      

      stdout:

      "A: ID\nB: ✓ Success?\nC: SuperPrecisionValue\nD: Result Metadata\n\n#             A     B          C                            D\n- ------------- ----- ---------- ----------------------------\n0            X1  True     0.1234               {'meta': 'ok'}\n1 AnotherSample False 98765.4321          {'meta': [1, 2, 3]}\n2             Z  None        0.0 {'meta': {'nested_key': 42}}"
      "A: ID\nB: ✓ Success?\nC: SuperPrecisionValue\nD: Result Metadata\n\n#             A     B          C                            D\n- ------------- ----- ---------- ----------------------------\n0            X1  True     0.1234               {'meta': 'ok'}\n1 AnotherSample False 98765.4321          {'meta': [1, 2, 3]}\n2             Z  None        0.0 {'meta': {'nested_key': 42}}"
      
      

      📌 Teardown phase

      duration:

      0.00025779008865356445
      

      outcome:

      passed
      
  • 📄 test_utils_rangebar.py

    Function: test_full_progress_bar

    • Test 373

      📌 Setup phase

      duration:

      0.00037714093923568726
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0004237247630953789
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002473881468176842
      

      outcome:

      passed
      

    Function: test_half_progress_bar

    • Test 374

      📌 Setup phase

      duration:

      0.00031964201480150223
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00034843478351831436
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002344902604818344
      

      outcome:

      passed
      

    Function: test_zero_progress_bar

    • Test 375

      📌 Setup phase

      duration:

      0.0003020334988832474
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0003155414015054703
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002504996955394745
      

      outcome:

      passed
      

    Function: test_overflow_bar

    • Test 376

      📌 Setup phase

      duration:

      0.00028259120881557465
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0003201281651854515
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00023700017482042313
      

      outcome:

      passed
      

    Function: test_underflow_bar

    • Test 377

      📌 Setup phase

      duration:

      0.00030382443219423294
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00028922874480485916
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00024807173758745193
      

      outcome:

      passed
      

    Function: test_repr

    • Test 378

      📌 Setup phase

      duration:

      0.0001561138778924942
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00020906701683998108
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00015017762780189514
      

      outcome:

      passed
      

    Function: test_each_value_separately

    • Test 379
      params: value=0, expected_bar_part=" "

      📌 Parameters

      params:
        value: 0
        expected_bar_part: "          "
      id: "0-          "
      

      📌 Setup phase

      duration:

      0.00041365623474121094
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.000322144478559494
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00026783812791109085
      

      outcome:

      passed
      
    • Test 380
      params: value=10, expected_bar_part="█ "

      📌 Parameters

      params:
        value: 10
        expected_bar_part: "█         "
      id: "10-\\u2588         "
      

      📌 Setup phase

      duration:

      0.00040978938341140747
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00035447534173727036
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002650618553161621
      

      outcome:

      passed
      
    • Test 381
      params: value=25, expected_bar_part="██▌ "

      📌 Parameters

      params:
        value: 25
        expected_bar_part: "██▌       "
      id: "25-\\u2588\\u2588\\u258c       "
      

      📌 Setup phase

      duration:

      0.00037463661283254623
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0003107599914073944
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002733049914240837
      

      outcome:

      passed
      
    • Test 382
      params: value=27, expected_bar_part="██▊ "

      📌 Parameters

      params:
        value: 27
        expected_bar_part: "██▊       "
      id: "27-\\u2588\\u2588\\u258a       "
      

      📌 Setup phase

      duration:

      0.0004058629274368286
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0003096172586083412
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002819793298840523
      

      outcome:

      passed
      
    • Test 383
      params: value=49, expected_bar_part="████▉ "

      📌 Parameters

      params:
        value: 49
        expected_bar_part: "████▉     "
      id: "49-\\u2588\\u2588\\u2588\\u2588\\u2589     "
      

      📌 Setup phase

      duration:

      0.00038386788219213486
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0003000497817993164
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00024235527962446213
      

      outcome:

      passed
      
    • Test 384
      params: value=50, expected_bar_part="█████ "

      📌 Parameters

      params:
        value: 50
        expected_bar_part: "█████     "
      id: "50-\\u2588\\u2588\\u2588\\u2588\\u2588     "
      

      📌 Setup phase

      duration:

      0.00041327811777591705
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00032085832208395004
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00024381279945373535
      

      outcome:

      passed
      
    • Test 385
      params: value=51, expected_bar_part="█████▏ "

      📌 Parameters

      params:
        value: 51
        expected_bar_part: "█████▏    "
      id: "51-\\u2588\\u2588\\u2588\\u2588\\u2588\\u258f    "
      

      📌 Setup phase

      duration:

      0.000391373410820961
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.000297030434012413
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002931226044893265
      

      outcome:

      passed
      
    • Test 386
      params: value=73, expected_bar_part="███████▎ "

      📌 Parameters

      params:
        value: 73
        expected_bar_part: "███████▎  "
      id: "73-\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u258e  "
      

      📌 Setup phase

      duration:

      0.0003734556958079338
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00031639356166124344
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.000250302255153656
      

      outcome:

      passed
      
    • Test 387
      params: value=75, expected_bar_part="███████▌ "

      📌 Parameters

      params:
        value: 75
        expected_bar_part: "███████▌  "
      id: "75-\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u258c  "
      

      📌 Setup phase

      duration:

      0.0003808876499533653
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0003053685650229454
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0003347983583807945
      

      outcome:

      passed
      
    • Test 388
      params: value=90, expected_bar_part="█████████ "

      📌 Parameters

      params:
        value: 90
        expected_bar_part: "█████████ "
      id: "90-\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588 "
      

      📌 Setup phase

      duration:

      0.0003916611894965172
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00029730889946222305
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00025415048003196716
      

      outcome:

      passed
      
    • Test 389
      params: value=100, expected_bar_part="██████████"

      📌 Parameters

      params:
        value: 100
        expected_bar_part: "██████████"
      id: "100-\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588"
      

      📌 Setup phase

      duration:

      0.00036335084587335587
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002810228615999222
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002653133124113083
      

      outcome:

      passed
      
  • 📄 test_utils_readable.py

    Function: test_readable_seconds

    • Test 390
      params: seconds=59.4, expected="59 seconds"

      📌 Parameters

      params:
        seconds: 59.4
        expected: "59 seconds"
      id: "59.4-59 seconds"
      

      📌 Setup phase

      duration:

      0.0003138221800327301
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00022480078041553497
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00021800212562084198
      

      outcome:

      passed
      
    • Test 391
      params: seconds=59.9, expected="60 seconds"

      📌 Parameters

      params:
        seconds: 59.9
        expected: "60 seconds"
      id: "59.9-60 seconds"
      

      📌 Setup phase

      duration:

      0.00031657423824071884
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00020070839673280716
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001998376101255417
      

      outcome:

      passed
      
    • Test 392
      params: seconds=119.9, expected="120 seconds"

      📌 Parameters

      params:
        seconds: 119.9
        expected: "120 seconds"
      id: "119.9-120 seconds"
      

      📌 Setup phase

      duration:

      0.0003180950880050659
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00021444447338581085
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002055717632174492
      

      outcome:

      passed
      
    • Test 393
      params: seconds=120.1, expected="2 minutes"

      📌 Parameters

      params:
        seconds: 120.1
        expected: "2 minutes"
      id: "120.1-2 minutes"
      

      📌 Setup phase

      duration:

      0.00030079204589128494
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002114204689860344
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00021409336477518082
      

      outcome:

      passed
      
    • Test 394
      params: seconds=3599.9, expected="60 minutes"

      📌 Parameters

      params:
        seconds: 3599.9
        expected: "60 minutes"
      id: "3599.9-60 minutes"
      

      📌 Setup phase

      duration:

      0.00030194129794836044
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00020453613251447678
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00021558813750743866
      

      outcome:

      passed
      
    • Test 395
      params: seconds=3600.1, expected="60 minutes"

      📌 Parameters

      params:
        seconds: 3600.1
        expected: "60 minutes"
      id: "3600.1-60 minutes"
      

      📌 Setup phase

      duration:

      0.0002900008112192154
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00022143498063087463
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00022386573255062103
      

      outcome:

      passed
      
    • Test 396
      params: seconds=7199.9, expected="120 minutes"

      📌 Parameters

      params:
        seconds: 7199.9
        expected: "120 minutes"
      id: "7199.9-120 minutes"
      

      📌 Setup phase

      duration:

      0.00029870402067899704
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018621422350406647
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019866228103637695
      

      outcome:

      passed
      
    • Test 397
      params: seconds=7200.1, expected="2 hours"

      📌 Parameters

      params:
        seconds: 7200.1
        expected: "2 hours"
      id: "7200.1-2 hours"
      

      📌 Setup phase

      duration:

      0.00029171910136938095
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00020640064030885696
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018928013741970062
      

      outcome:

      passed
      
    • Test 398
      params: seconds=90.4, expected="90 seconds"

      📌 Parameters

      params:
        seconds: 90.4
        expected: "90 seconds"
      id: "90.4-90 seconds"
      

      📌 Setup phase

      duration:

      0.0002764444798231125
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018789619207382202
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019883457571268082
      

      outcome:

      passed
      
    • Test 399
      params: seconds=90.6, expected="91 seconds"

      📌 Parameters

      params:
        seconds: 90.6
        expected: "91 seconds"
      id: "90.6-91 seconds"
      

      📌 Setup phase

      duration:

      0.00026923418045043945
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001758243888616562
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00021437089890241623
      

      outcome:

      passed
      
    • Test 400
      params: seconds=121.9, expected="2 minutes"

      📌 Parameters

      params:
        seconds: 121.9
        expected: "2 minutes"
      id: "121.9-2 minutes"
      

      📌 Setup phase

      duration:

      0.0002694185823202133
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00021050777286291122
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018417462706565857
      

      outcome:

      passed
      
    • Test 401
      params: seconds=1296000.0, expected="2 weeks"

      📌 Parameters

      params:
        seconds: 1296000.0
        expected: "2 weeks"
      id: "1296000.0-2 weeks"
      

      📌 Setup phase

      duration:

      0.00028632115572690964
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019096769392490387
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017675384879112244
      

      outcome:

      passed
      
    • Test 402
      params: seconds=2592000.0, expected="4 weeks"

      📌 Parameters

      params:
        seconds: 2592000.0
        expected: "4 weeks"
      id: "2592000.0-4 weeks"
      

      📌 Setup phase

      duration:

      0.00026632845401763916
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001775696873664856
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019577611237764359
      

      outcome:

      passed
      
    • Test 403
      params: seconds=2800000.0, expected="5 weeks"

      📌 Parameters

      params:
        seconds: 2800000.0
        expected: "5 weeks"
      id: "2800000.0-5 weeks"
      

      📌 Setup phase

      duration:

      0.00025820452719926834
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017582066357135773
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001860056072473526
      

      outcome:

      passed
      
    • Test 404
      params: seconds=3888000.0, expected="6 weeks"

      📌 Parameters

      params:
        seconds: 3888000.0
        expected: "6 weeks"
      id: "3888000.0-6 weeks"
      

      📌 Setup phase

      duration:

      0.00026435405015945435
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019328109920024872
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019618868827819824
      

      outcome:

      passed
      
    • Test 405
      params: seconds=5097600.0, expected="8 weeks"

      📌 Parameters

      params:
        seconds: 5097600.0
        expected: "8 weeks"
      id: "5097600.0-8 weeks"
      

      📌 Setup phase

      duration:

      0.0003143260255455971
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00020302832126617432
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.000203033909201622
      

      outcome:

      passed
      
    • Test 406
      params: seconds=5184000.0, expected="9 weeks"

      📌 Parameters

      params:
        seconds: 5184000.0
        expected: "9 weeks"
      id: "5184000.0-9 weeks"
      

      📌 Setup phase

      duration:

      0.0002817045897245407
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002089487388730049
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001916978508234024
      

      outcome:

      passed
      
    • Test 407
      params: seconds=5270400.0, expected="2 months"

      📌 Parameters

      params:
        seconds: 5270400.0
        expected: "2 months"
      id: "5270400.0-2 months"
      

      📌 Setup phase

      duration:

      0.00029099639505147934
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002061808481812477
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018191244453191757
      

      outcome:

      passed
      
    • Test 408
      params: seconds=23328000.0, expected="9 months"

      📌 Parameters

      params:
        seconds: 23328000.0
        expected: "9 months"
      id: "23328000.0-9 months"
      

      📌 Setup phase

      duration:

      0.0002943156287074089
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00020530074834823608
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018773693591356277
      

      outcome:

      passed
      
    • Test 409
      params: seconds=31104000.0, expected="12 months"

      📌 Parameters

      params:
        seconds: 31104000.0
        expected: "12 months"
      id: "31104000.0-12 months"
      

      📌 Setup phase

      duration:

      0.00026233773678541183
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001992601901292801
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001871492713689804
      

      outcome:

      passed
      
    • Test 410
      params: seconds=33696000.0, expected="13 months"

      📌 Parameters

      params:
        seconds: 33696000.0
        expected: "13 months"
      id: "33696000.0-13 months"
      

      📌 Setup phase

      duration:

      0.00029864534735679626
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018602143973112106
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020373519510030746
      

      outcome:

      passed
      
    • Test 411
      params: seconds=59616000.0, expected="23 months"

      📌 Parameters

      params:
        seconds: 59616000.0
        expected: "23 months"
      id: "59616000.0-23 months"
      

      📌 Setup phase

      duration:

      0.0002858443185687065
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018497556447982788
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002050669863820076
      

      outcome:

      passed
      
    • Test 412
      params: seconds=62208000.0, expected="24 months"

      📌 Parameters

      params:
        seconds: 62208000.0
        expected: "24 months"
      id: "62208000.0-24 months"
      

      📌 Setup phase

      duration:

      0.00027197226881980896
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019845180213451385
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00027712155133485794
      

      outcome:

      passed
      
    • Test 413
      params: seconds=64208000.0, expected="2 years"

      📌 Parameters

      params:
        seconds: 64208000.0
        expected: "2 years"
      id: "64208000.0-2 years"
      

      📌 Setup phase

      duration:

      0.00029013585299253464
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018754694610834122
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018777325749397278
      

      outcome:

      passed
      
  • 📄 test_utils_registry.py

    Function: test_metaclass_creates_weakset

    • Test 414

      📌 Setup phase

      duration:

      0.00016773492097854614
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0006941072642803192
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017187558114528656
      

      outcome:

      passed
      

    Function: test_metaclass_tracks_instances

    • Test 415

      📌 Setup phase

      duration:

      0.00016823504120111465
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002742977812886238
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00015669409185647964
      

      outcome:

      passed
      

    Function: test_registry_inheritance

    • Test 416

      📌 Setup phase

      duration:

      0.0002751573920249939
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0007515931501984596
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002087559551000595
      

      outcome:

      passed
      

    Function: test_instance_tracking

    • Test 417

      📌 Setup phase

      duration:

      0.0002518771216273308
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00029723532497882843
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018538814038038254
      

      outcome:

      passed
      

    Function: test_collect_instances_recursive

    • Test 418

      📌 Setup phase

      duration:

      0.00024632643908262253
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0011574635282158852
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020015332847833633
      

      outcome:

      passed
      

    Function: test_instances_function

    • Test 419

      📌 Setup phase

      duration:

      0.0002624429762363434
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0011836448684334755
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020292215049266815
      

      outcome:

      passed
      

    Function: test_non_registry_class_error

    • Test 420

      📌 Setup phase

      duration:

      0.00018721912056207657
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00027151405811309814
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00014911498874425888
      

      outcome:

      passed
      

    Function: test_signature_preservation

    • Test 421

      📌 Setup phase

      duration:

      0.00017163529992103577
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00030252616852521896
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00016244594007730484
      

      outcome:

      passed
      
  • 📄 test_utils_richcfg.py

    Function: test_rich_inspector_outputs_more_than_builtin

    • Test 422

      📌 Setup phase

      duration:

      0.0002968553453683853
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.09684761241078377
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00032688211649656296
      

      outcome:

      passed
      
  • 📄 test_utils_run_later.py

    Function: test_init_and_repr

    • Test 423

      📌 Setup phase

      duration:

      0.00020857807248830795
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00025030970573425293
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001671425998210907
      

      outcome:

      passed
      

    Function: test_call

    • Test 424

      📌 Setup phase

      duration:

      0.0001661926507949829
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00021208170801401138
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001463964581489563
      

      outcome:

      passed
      

    Function: test_matmul_with_string

    • Test 425

      📌 Setup phase

      duration:

      0.0001441650092601776
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00020553451031446457
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00014722347259521484
      

      outcome:

      passed
      

    Function: test_matmul_with_list

    • Test 426

      📌 Setup phase

      duration:

      0.00015130918473005295
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002226307988166809
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00014619529247283936
      

      outcome:

      passed
      

    Function: test_matmul_with_single_int

    • Test 427

      📌 Setup phase

      duration:

      0.00016473140567541122
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00020120199769735336
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001443019136786461
      

      outcome:

      passed
      

    Function: test_run_at_future_triggered_and_logs

    • Test 428

      📌 Setup phase

      duration:

      0.00037251412868499756
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.2041758866980672
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0003512650728225708
      

      outcome:

      passed
      

    Function: test_run_at_already_past

    • Test 429

      📌 Setup phase

      duration:

      0.0003832811489701271
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0003831852227449417
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00022527296096086502
      

      outcome:

      passed
      

    Function: test_run_in_future_triggered_and_logs

    • Test 430

      📌 Setup phase

      duration:

      0.0002957656979560852
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.2020842181518674
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00034115370362997055
      

      outcome:

      passed
      

    Function: test_run_in_past

    • Test 431

      📌 Setup phase

      duration:

      0.0003701159730553627
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0004230951890349388
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002292301505804062
      

      outcome:

      passed
      

    Function: test_run_later_with_seconds

    • Test 432

      📌 Setup phase

      duration:

      0.00030142348259687424
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.20210157614201307
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0003714142367243767
      

      outcome:

      passed
      

    Function: test_run_later_with_past_datetime

    • Test 433

      📌 Setup phase

      duration:

      0.00037454627454280853
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0004364829510450363
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00024178996682167053
      

      outcome:

      passed
      

    Function: test_run_at_tqdm_multiple_updates

    • Test 434

      📌 Setup phase

      duration:

      0.00038225390017032623
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.20198021922260523
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0003622882068157196
      

      outcome:

      passed
      

    Function: test_today_basic

    • Test 435

      📌 Setup phase

      duration:

      0.0001916075125336647
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0007424075156450272
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001611672341823578
      

      outcome:

      passed
      

    Function: test_tomorrow_basic

    • Test 436

      📌 Setup phase

      duration:

      0.00017350446432828903
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0004210248589515686
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00015190709382295609
      

      outcome:

      passed
      

    Function: test_yesterday_basic

    • Test 437

      📌 Setup phase

      duration:

      0.0001482982188463211
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0004157479852437973
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00015239231288433075
      

      outcome:

      passed
      

    Function: test_today_matmul_string

    • Test 438

      📌 Setup phase

      duration:

      0.0001571429893374443
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00038092397153377533
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001485198736190796
      

      outcome:

      passed
      

    Function: test_tomorrow_matmul_list

    • Test 439

      📌 Setup phase

      duration:

      0.00015611015260219574
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0005970671772956848
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00014739017933607101
      

      outcome:

      passed
      

    Function: test_yesterday_matmul_single

    • Test 440

      📌 Setup phase

      duration:

      0.00015234202146530151
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00039090216159820557
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00015112664550542831
      

      outcome:

      passed
      
  • 📄 test_utils_sendmail.py

    Function: test_sendmail_local_delivery

    • Test 441

      📌 Setup phase

      duration:

      0.00017531868070363998
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.12127373553812504
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0003046216443181038
      

      outcome:

      passed
      

    Function: test_sendmail_raises_on_sendmail_failure

    • Test 442

      📌 Setup phase

      duration:

      0.0004067299887537956
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0008269818499684334
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002271728590130806
      

      outcome:

      passed
      
  • 📄 test_utils_sendsms.py

    Function: test_sendsms_local_delivery

    • Test 443

      📌 Setup phase

      duration:

      0.00017751473933458328
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.11858505848795176
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.000314297154545784
      

      outcome:

      passed
      
  • 📄 test_utils_shortcut.py

    Function: TestShortcutInitialization

    • Test 444

      📌 Setup phase

      duration:

      0.00046906713396310806
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00031425803899765015
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002003619447350502
      

      outcome:

      passed
      
    • Test 445

      📌 Setup phase

      duration:

      0.00025065336376428604
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019852351397275925
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001841289922595024
      

      outcome:

      passed
      

    Function: test_run_method

    • Test 446

      📌 Setup phase

      duration:

      0.0004248861223459244
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0007668305188417435
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00026889052242040634
      

      outcome:

      passed
      

    Function: test_repr_output

    • Test 447

      📌 Setup phase

      duration:

      0.00024757348001003265
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.000207425095140934
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001961439847946167
      

      outcome:

      passed
      

    Function: test_source_with_regular_function

    • Test 448

      📌 Setup phase

      duration:

      0.00023345183581113815
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0013425201177597046
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019204430282115936
      

      outcome:

      passed
      

    Function: test_source_error_handling

    • Test 449

      📌 Setup phase

      duration:

      0.00023711379617452621
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0011542122811079025
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020823348313570023
      

      outcome:

      passed
      

    Function: test_as_shortcut_basic

    • Test 450

      📌 Setup phase

      duration:

      0.00024557579308748245
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002122214064002037
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017667561769485474
      

      outcome:

      passed
      

    Function: test_as_shortcut_with_name

    • Test 451

      📌 Setup phase

      duration:

      0.00022527389228343964
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002011144533753395
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018620584160089493
      

      outcome:

      passed
      

    Function: test_as_shortcut_factory_pattern

    • Test 452

      📌 Setup phase

      duration:

      0.00021681003272533417
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018133409321308136
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00016799569129943848
      

      outcome:

      passed
      

    Function: TestShortcutsSingleton

    • Test 453

      📌 Setup phase

      duration:

      0.0003332430496811867
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.000186956487596035
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019214767962694168
      

      outcome:

      passed
      
    • Test 455

      📌 Setup phase

      duration:

      0.0003495793789625168
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002503441646695137
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020842161029577255
      

      outcome:

      passed
      
    • Test 456

      📌 Setup phase

      duration:

      0.0003012167289853096
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.000250483863055706
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019186921417713165
      

      outcome:

      passed
      
    • Test 457

      📌 Setup phase

      duration:

      0.00031526945531368256
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00029521621763706207
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020668096840381622
      

      outcome:

      passed
      

    Function: TestFullIntegration

    • Test 458

      📌 Setup phase

      duration:

      0.0004349770024418831
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0011692848056554794
      

      outcome:

      passed
      

      stdout:

      Calculating 3 + 4
      
      

      📌 Teardown phase

      duration:

      0.00028903596103191376
      

      outcome:

      passed
      

    Function: test_registry_inheritance

    • Test 460

      📌 Setup phase

      duration:

      0.0002915775403380394
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001970706507563591
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019791815429925919
      

      outcome:

      passed
      
  • 📄 test_utils_snapshot.py

    Function: test_snapshot

    • Test 461
      params: test_input=[["v1", "Visible", false], ["h1", "Hidden", true]], expected=["Visible"], kwargs={}

      📌 Parameters

      params:
        test_input: [["v1", "Visible", false], ["h1", "Hidden", true]]
        expected: ["Visible"]
        kwargs: {}
      id: "exclude_internals"
      

      📌 Setup phase

      duration:

      0.00038327742367982864
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0006749983876943588
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002248017117381096
      

      outcome:

      passed
      
    • Test 462
      params: test_input=[["v1", "Visible", false], ["h1", "Hidden", true]], expected=["Visible", "Hidden"], kwargs={"include_internal": true}

      📌 Parameters

      params:
        test_input: [["v1", "Visible", false], ["h1", "Hidden", true]]
        expected: ["Visible", "Hidden"]
        kwargs: {"include_internal": true}
      id: "include_internals"
      

      📌 Setup phase

      duration:

      0.00034182798117399216
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0005067214369773865
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00021888595074415207
      

      outcome:

      passed
      
    • Test 463
      params: test_input=[], expected=[], kwargs={}

      📌 Parameters

      params:
        test_input: []
        expected: []
        kwargs: {}
      id: "empty_case"
      

      📌 Setup phase

      duration:

      0.00032636988908052444
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019330158829689026
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020355172455310822
      

      outcome:

      passed
      
    • Test 464
      params: test_input=[["3", "Charlie"], ["1", "Alpha"], ["2", "Beta"]], expected=["Alpha", "Beta", "Charlie"], kwargs="{'sort_key': <class 'str'>}"

      📌 Parameters

      params:
        test_input: [["3", "Charlie"], ["1", "Alpha"], ["2", "Beta"]]
        expected: ["Alpha", "Beta", "Charlie"]
        kwargs: "{'sort_key': <class 'str'>}"
      id: "sort_str"
      

      📌 Setup phase

      duration:

      0.0003245966508984566
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00063319131731987
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00021393503993749619
      

      outcome:

      passed
      
    • Test 465
      params: test_input=[["z3", "C"], ["a1", "A"], ["m2", "B"]], expected=["A", "B", "C"], kwargs="{'sort_key': <function <lambda> at 0x7feb09cd7310>}"

      📌 Parameters

      params:
        test_input: [["z3", "C"], ["a1", "A"], ["m2", "B"]]
        expected: ["A", "B", "C"]
        kwargs: "{'sort_key': <function <lambda> at 0x7feb09cd7310>}"
      id: "sort_id"
      

      📌 Setup phase

      duration:

      0.0003246814012527466
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0006214724853634834
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00021344609558582306
      

      outcome:

      passed
      
    • Test 466
      params: test_input=[["3", "Charlie"], ["1", "alpha"], ["2", "Beta"]], expected=["alpha", "Beta", "Charlie"], kwargs="{'sort_key': <function <lambda> at 0x7feb09cd73a0>}"

      📌 Parameters

      params:
        test_input: [["3", "Charlie"], ["1", "alpha"], ["2", "Beta"]]
        expected: ["alpha", "Beta", "Charlie"]
        kwargs: "{'sort_key': <function <lambda> at 0x7feb09cd73a0>}"
      id: "sort_case_insensitive"
      

      📌 Setup phase

      duration:

      0.00032947398722171783
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0006153350695967674
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020976737141609192
      

      outcome:

      passed
      
    • Test 467
      params: test_input=[["1", "A"], ["2", "BB"], ["3", "CCC"]], expected=["A", "BB", "CCC"], kwargs="{'sort_key': <function <lambda> at 0x7feb09cd7430>}"

      📌 Parameters

      params:
        test_input: [["1", "A"], ["2", "BB"], ["3", "CCC"]]
        expected: ["A", "BB", "CCC"]
        kwargs: "{'sort_key': <function <lambda> at 0x7feb09cd7430>}"
      id: "sort_length"
      

      📌 Setup phase

      duration:

      0.0003279149532318115
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0006207823753356934
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00022152718156576157
      

      outcome:

      passed
      
    • Test 468
      params: test_input=[["1", "A"], ["2", "B"], ["3", "C"]], expected=["C", "B", "A"], kwargs="{'sort_key': <function <lambda> at 0x7feb09cd74c0>}"

      📌 Parameters

      params:
        test_input: [["1", "A"], ["2", "B"], ["3", "C"]]
        expected: ["C", "B", "A"]
        kwargs: "{'sort_key': <function <lambda> at 0x7feb09cd74c0>}"
      id: "sort_reverse"
      

      📌 Setup phase

      duration:

      0.0003222888335585594
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0006293850019574165
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002262098714709282
      

      outcome:

      passed
      
  • 📄 test_utils_termtitle.py

    Function: test_terminal_title_with_tmux

    • Test 469

      📌 Setup phase

      duration:

      0.00019367597997188568
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.018981858156621456
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0003194352611899376
      

      outcome:

      passed
      
  • 📄 test_utils_tqdm_mod.py

    Function: test_complete_progress_bar

    • Test 470

      📌 Setup phase

      duration:

      0.0002346700057387352
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0042618652805686
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018843263387680054
      

      outcome:

      passed
      

    Function: test_set_progress_multiple_points

    • Test 471

      📌 Setup phase

      duration:

      0.00017390400171279907
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0019596489146351814
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019361544400453568
      

      outcome:

      passed
      

    Function: test_format_sizeof_alignment

    • Test 472

      📌 Setup phase

      duration:

      0.00017280690371990204
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002129664644598961
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001519676297903061
      

      outcome:

      passed
      

    Function: test_custom_unit

    • Test 474

      📌 Setup phase

      duration:

      0.00019384920597076416
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.005001497454941273
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00016845762729644775
      

      outcome:

      passed
      

    Function: test_clamp_above_total

    • Test 475

      📌 Setup phase

      duration:

      0.00019558798521757126
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0006101960316300392
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001548323780298233
      

      outcome:

      passed
      

    Function: test_clamp_below_zero

    • Test 476

      📌 Setup phase

      duration:

      0.00016428250819444656
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0007148310542106628
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00015729479491710663
      

      outcome:

      passed
      
  • 📄 test_utils_trinary.py

    Function: test_check_trinary_valid_values

    • Test 477

      📌 Setup phase

      duration:

      0.00018956884741783142
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019540078938007355
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00013936497271060944
      

      outcome:

      passed
      

    Function: test_check_trinary_invalid_value

    • Test 478

      📌 Setup phase

      duration:

      0.00014570634812116623
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00044011790305376053
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00015186332166194916
      

      outcome:

      passed
      

    Function: test_check_trinary_with_custom_allowed_values

    • Test 479

      📌 Setup phase

      duration:

      0.00014861486852169037
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00020589306950569153
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.000138135626912117
      

      outcome:

      passed
      
  • 📄 test_utils_typecast.py

    Function: test_downcast_success

    • Test 480

      📌 Setup phase

      duration:

      0.0001777568832039833
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00020448770374059677
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001525580883026123
      

      outcome:

      passed
      

    Function: test_upcast_success

    • Test 481

      📌 Setup phase

      duration:

      0.00014890171587467194
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001921607181429863
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001458786427974701
      

      outcome:

      passed
      

    Function: test_downcast_invalid

    • Test 482

      📌 Setup phase

      duration:

      0.0001454707235097885
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.000439714640378952
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001532621681690216
      

      outcome:

      passed
      

    Function: test_upcast_invalid

    • Test 483

      📌 Setup phase

      duration:

      0.00015473738312721252
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00021784566342830658
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00013852957636117935
      

      outcome:

      passed
      

    Function: test_object_identity_preserved

    • Test 484

      📌 Setup phase

      duration:

      0.00015909504145383835
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001858845353126526
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001406325027346611
      

      outcome:

      passed
      

    Function: test_ensure_subclass_valid

    • Test 485

      📌 Setup phase

      duration:

      0.00014024879783391953
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001738937571644783
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00014271028339862823
      

      outcome:

      passed
      

    Function: test_ensure_subclass_invalid

    • Test 486

      📌 Setup phase

      duration:

      0.0001507354900240898
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0002164868637919426
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001374194398522377
      

      outcome:

      passed
      

    Function: test_cast_changes_class

    • Test 487

      📌 Setup phase

      duration:

      0.00015542376786470413
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018319208174943924
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00013968441635370255
      

      outcome:

      passed
      

    Function: test_cast_preserves_identity

    • Test 488

      📌 Setup phase

      duration:

      0.00014663301408290863
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00016838312149047852
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001413905993103981
      

      outcome:

      passed
      
  • 📄 test_utils_utils.py

    Function: test_singleton_instance

    • Test 489

      📌 Setup phase

      duration:

      0.00017802976071834564
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019732490181922913
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00014154240489006042
      

      outcome:

      passed
      

    Function: test_singleton_identity

    • Test 490

      📌 Setup phase

      duration:

      0.00014685094356536865
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001815827563405037
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00013835541903972626
      

      outcome:

      passed
      

    Function: test_typename

    • Test 491
      params: obj=null, expected="NoneType"

      📌 Parameters

      params:
        obj: null
        expected: "NoneType"
      id: "None-NoneType"
      

      📌 Setup phase

      duration:

      0.0003714459016919136
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018587429076433182
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00021265540271997452
      

      outcome:

      passed
      
    • Test 492
      params: obj=true, expected="bool"

      📌 Parameters

      params:
        obj: true
        expected: "bool"
      id: "True-bool"
      

      📌 Setup phase

      duration:

      0.0002755848690867424
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019382312893867493
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018442515283823013
      

      outcome:

      passed
      
    • Test 493
      params: obj=42, expected="int"

      📌 Parameters

      params:
        obj: 42
        expected: "int"
      id: "42-int"
      

      📌 Setup phase

      duration:

      0.0002830410376191139
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017241481691598892
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018270593136548996
      

      outcome:

      passed
      
    • Test 494
      params: obj=3.14, expected="float"

      📌 Parameters

      params:
        obj: 3.14
        expected: "float"
      id: "3.14-float"
      

      📌 Setup phase

      duration:

      0.0002698088064789772
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017377827316522598
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019336771219968796
      

      outcome:

      passed
      
    • Test 495
      params: obj="text", expected="str"

      📌 Parameters

      params:
        obj: "text"
        expected: "str"
      id: "text-str"
      

      📌 Setup phase

      duration:

      0.0002666367217898369
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017684325575828552
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001746276393532753
      

      outcome:

      passed
      
    • Test 496
      params: obj="{1, 2, 3}", expected="set"

      📌 Parameters

      params:
        obj: "{1, 2, 3}"
        expected: "set"
      id: "obj5-set"
      

      📌 Setup phase

      duration:

      0.00027497392147779465
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001774970442056656
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001946818083524704
      

      outcome:

      passed
      
    • Test 497
      params: obj=[[1], [2, 3]], expected="list"

      📌 Parameters

      params:
        obj: [[1], [2, 3]]
        expected: "list"
      id: "obj6-list"
      

      📌 Setup phase

      duration:

      0.00025684572756290436
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018990878015756607
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018556974828243256
      

      outcome:

      passed
      
    • Test 498
      params: obj=[{"a": [1, 2]}, {"b": [3, 4]}], expected="list"

      📌 Parameters

      params:
        obj: [{"a": [1, 2]}, {"b": [3, 4]}]
        expected: "list"
      id: "obj7-list"
      

      📌 Setup phase

      duration:

      0.00027788616716861725
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001714024692773819
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018005724996328354
      

      outcome:

      passed
      
    • Test 499
      params: obj={"key": [{"nested": 1}, [2, 3]]}, expected="dict"

      📌 Parameters

      params:
        obj: {"key": [{"nested": 1}, [2, 3]]}
        expected: "dict"
      id: "obj8-dict"
      

      📌 Setup phase

      duration:

      0.00027439091354608536
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017805583775043488
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018903892487287521
      

      outcome:

      passed
      
    • Test 500
      params: obj="<function <lambda> at 0x7feb09cebc10>", expected="function"

      📌 Parameters

      params:
        obj: "<function <lambda> at 0x7feb09cebc10>"
        expected: "function"
      id: "<lambda>-function"
      

      📌 Setup phase

      duration:

      0.0002655861899256706
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019093602895736694
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018602237105369568
      

      outcome:

      passed
      
    • Test 501
      params: obj="<function sample_function at 0x7feb09cebb80>", expected="function"

      📌 Parameters

      params:
        obj: "<function sample_function at 0x7feb09cebb80>"
        expected: "function"
      id: "sample_function-function"
      

      📌 Setup phase

      duration:

      0.00027579814195632935
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017857085913419724
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001959158107638359
      

      outcome:

      passed
      
    • Test 502
      params: obj="<function sample_function.<locals>.nested at 0x7feb09cebca0>", expected="function"

      📌 Parameters

      params:
        obj: "<function sample_function.<locals>.nested at 0x7feb09cebca0>"
        expected: "function"
      id: "nested-function"
      

      📌 Setup phase

      duration:

      0.00038846954703330994
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018608104437589645
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018203537911176682
      

      outcome:

      passed
      
    • Test 503
      params: obj="<built-in function len>", expected="builtin_function_or_method"

      📌 Parameters

      params:
        obj: "<built-in function len>"
        expected: "builtin_function_or_method"
      id: "len-builtin_function_or_method"
      

      📌 Setup phase

      duration:

      0.0002792738378047943
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001774132251739502
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001941164955496788
      

      outcome:

      passed
      
    • Test 504
      params: obj="<built-in function sum>", expected="builtin_function_or_method"

      📌 Parameters

      params:
        obj: "<built-in function sum>"
        expected: "builtin_function_or_method"
      id: "sum-builtin_function_or_method"
      

      📌 Setup phase

      duration:

      0.00025474000722169876
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018316134810447693
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018133968114852905
      

      outcome:

      passed
      
    • Test 505
      params: obj="<module 'math' from '/root/mambaforge/envs/ci-env/lib/python3.8/lib-dynload/math.cpython-38-x86_64-linux-gnu.so'>", expected="module"

      📌 Parameters

      params:
        obj: "<module 'math' from '/root/mambaforge/envs/ci-env/lib/python3.8/lib-dynload/math.cpython-38-x86_64-linux-gnu.so'>"
        expected: "module"
      id: "math-module"
      

      📌 Setup phase

      duration:

      0.0002760225906968117
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017341412603855133
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020028557628393173
      

      outcome:

      passed
      
    • Test 506
      params: obj="<module 'sys' (built-in)>", expected="module"

      📌 Parameters

      params:
        obj: "<module 'sys' (built-in)>"
        expected: "module"
      id: "sys-module"
      

      📌 Setup phase

      duration:

      0.00026947353035211563
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017322320491075516
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018423981964588165
      

      outcome:

      passed
      
    • Test 507
      params: obj="<class 'function'>", expected="type"

      📌 Parameters

      params:
        obj: "<class 'function'>"
        expected: "type"
      id: "function-type"
      

      📌 Setup phase

      duration:

      0.00026755034923553467
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.000180819071829319
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018321536481380463
      

      outcome:

      passed
      
    • Test 508
      params: obj="<generator object <genexpr> at 0x7feb09bcec10>", expected="generator"

      📌 Parameters

      params:
        obj: "<generator object <genexpr> at 0x7feb09bcec10>"
        expected: "generator"
      id: "<genexpr>-generator"
      

      📌 Setup phase

      duration:

      0.00026103854179382324
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00016846228390932083
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020331423729658127
      

      outcome:

      passed
      
    • Test 509
      params: obj="<list_iterator object at 0x7feb09c785e0>", expected="list_iterator"

      📌 Parameters

      params:
        obj: "<list_iterator object at 0x7feb09c785e0>"
        expected: "list_iterator"
      id: "obj18-list_iterator"
      

      📌 Setup phase

      duration:

      0.00026931334286928177
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018553808331489563
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018282979726791382
      

      outcome:

      passed
      

    Function: test_next_int

    • Test 510
      params: nums=[1, 2, 3], expected=4

      📌 Parameters

      params:
        nums: [1, 2, 3]
        expected: 4
      id: "nums0-4"
      

      📌 Setup phase

      duration:

      0.00028667040169239044
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018168147653341293
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019428692758083344
      

      outcome:

      passed
      
    • Test 511
      params: nums=[10, 20], expected=21

      📌 Parameters

      params:
        nums: [10, 20]
        expected: 21
      id: "nums1-21"
      

      📌 Setup phase

      duration:

      0.00027309078723192215
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017748214304447174
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001831473782658577
      

      outcome:

      passed
      
    • Test 512
      params: nums=[], expected=0

      📌 Parameters

      params:
        nums: []
        expected: 0
      id: "nums2-0"
      

      📌 Setup phase

      duration:

      0.00026734545826911926
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018641911447048187
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018342584371566772
      

      outcome:

      passed
      

    Function: test_zero_pad

    • Test 513
      params: i=7, n=3, expected="007"

      📌 Parameters

      params:
        i: 7
        n: 3
        expected: "007"
      id: "7-3-007"
      

      📌 Setup phase

      duration:

      0.00030928757041692734
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001851087436079979
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002100858837366104
      

      outcome:

      passed
      
    • Test 514
      params: i=123, n=5, expected="00123"

      📌 Parameters

      params:
        i: 123
        n: 5
        expected: "00123"
      id: "123-5-00123"
      

      📌 Setup phase

      duration:

      0.0003066128119826317
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018456857651472092
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019272230565547943
      

      outcome:

      passed
      
    • Test 515
      params: i=0, n=2, expected="00"

      📌 Parameters

      params:
        i: 0
        n: 2
        expected: "00"
      id: "0-2-00"
      

      📌 Setup phase

      duration:

      0.0003362474963068962
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017605815082788467
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00021626148372888565
      

      outcome:

      passed
      

    Function: test_iround

    • Test 516
      params: val=3.6, expected=4

      📌 Parameters

      params:
        val: 3.6
        expected: 4
      id: "3.6-4"
      

      📌 Setup phase

      duration:

      0.0002670893445611
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018953531980514526
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017960835248231888
      

      outcome:

      passed
      
    • Test 517
      params: val=2.1, expected=2

      📌 Parameters

      params:
        val: 2.1
        expected: 2
      id: "2.1-2"
      

      📌 Setup phase

      duration:

      0.00026748981326818466
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017599016427993774
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001852121204137802
      

      outcome:

      passed
      
    • Test 518
      params: val=-1.5, expected=-2

      📌 Parameters

      params:
        val: -1.5
        expected: -2
      id: "-1.5--2"
      

      📌 Setup phase

      duration:

      0.000261940062046051
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00017040222883224487
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0001784488558769226
      

      outcome:

      passed
      
    • Test 519
      params: val=-1.4, expected=-1

      📌 Parameters

      params:
        val: -1.4
        expected: -1
      id: "-1.4--1"
      

      📌 Setup phase

      duration:

      0.0002670334652066231
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00019069761037826538
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00017879344522953033
      

      outcome:

      passed
      

    Function: test_sorted_naturally

    • Test 520
      params: items=["file1", "file10", "file2"], expected=["file1", "file2", "file10"]

      📌 Parameters

      params:
        items: ["file1", "file10", "file2"]
        expected: ["file1", "file2", "file10"]
      id: "items0-expected0"
      

      📌 Setup phase

      duration:

      0.00028410833328962326
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00022188108414411545
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020156055688858032
      

      outcome:

      passed
      
    • Test 521
      params: items=["z9", "z10", "z2", "z1"], expected=["z1", "z2", "z9", "z10"]

      📌 Parameters

      params:
        items: ["z9", "z10", "z2", "z1"]
        expected: ["z1", "z2", "z9", "z10"]
      id: "items1-expected1"
      

      📌 Setup phase

      duration:

      0.0002579018473625183
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00021862424910068512
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018369406461715698
      

      outcome:

      passed
      

    Function: test_sorted_naturally_reverse

    • Test 522
      params: items=["file1", "file10", "file2"], expected=["file10", "file2", "file1"]

      📌 Parameters

      params:
        items: ["file1", "file10", "file2"]
        expected: ["file10", "file2", "file1"]
      id: "items0-expected0"
      

      📌 Setup phase

      duration:

      0.00027686450630426407
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00020112097263336182
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00018761120736598969
      

      outcome:

      passed
      
  • 📄 test_utils_xrange.py

    Function: test_xrange_finite

    • Test 523
      params: args=[10], kwargs={}, expected=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

      📌 Parameters

      params:
        args: [10]
        kwargs: {}
        expected: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
      id: "args0-kwargs0-expected0"
      

      📌 Setup phase

      duration:

      0.00033854320645332336
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00020172912627458572
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002064034342765808
      

      outcome:

      passed
      
    • Test 524
      params: args=[0, 10], kwargs={}, expected=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

      📌 Parameters

      params:
        args: [0, 10]
        kwargs: {}
        expected: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
      id: "args1-kwargs1-expected1"
      

      📌 Setup phase

      duration:

      0.0003257840871810913
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001764567568898201
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00021591782569885254
      

      outcome:

      passed
      
    • Test 525
      params: args=[0, 10, 2], kwargs={}, expected=[0, 2, 4, 6, 8]

      📌 Parameters

      params:
        args: [0, 10, 2]
        kwargs: {}
        expected: [0, 2, 4, 6, 8]
      id: "args2-kwargs2-expected2"
      

      📌 Setup phase

      duration:

      0.0003087390214204788
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001918664202094078
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00019357167184352875
      

      outcome:

      passed
      
    • Test 526
      params: args=[10], kwargs={"step": 2}, expected=[0, 2, 4, 6, 8]

      📌 Parameters

      params:
        args: [10]
        kwargs: {"step": 2}
        expected: [0, 2, 4, 6, 8]
      id: "args3-kwargs3-expected3"
      

      📌 Setup phase

      duration:

      0.0003307731822133064
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0001806207001209259
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.00020755920559167862
      

      outcome:

      passed
      

    Function: test_xrange_infinite

    • Test 527
      params: args=[], kwargs={}, expected_repr="count(0)"

      📌 Parameters

      params:
        args: []
        kwargs: {}
        expected_repr: "count(0)"
      id: "args0-kwargs0-count(0)"
      

      📌 Setup phase

      duration:

      0.0003159577026963234
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00020732637494802475
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002815639600157738
      

      outcome:

      passed
      
    • Test 528
      params: args=[], kwargs={"step": 2}, expected_repr="count(0, 2)"

      📌 Parameters

      params:
        args: []
        kwargs: {"step": 2}
        expected_repr: "count(0, 2)"
      id: "args1-kwargs1-count(0, 2)"
      

      📌 Setup phase

      duration:

      0.00031597260385751724
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.00018497370183467865
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0002176240086555481
      

      outcome:

      passed
      

    Function: test_xrange_too_many_args

    • Test 529
      params: args=[1, 2, 3, 4]

      📌 Parameters

      params:
        args: [1, 2, 3, 4]
      id: "args0"
      

      📌 Setup phase

      duration:

      0.0002137674018740654
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0005807345733046532
      

      outcome:

      passed
      

      📌 Teardown phase

      duration:

      0.0007893117144703865
      

      outcome:

      passed
      
Failed (11)
  • 📄 test_utils_debug.py

    Function: test_short_repr

    • Test 141
      params: value="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", cutoff=10, expected="'aaaaaaaaaa..."

      📌 Parameters

      params:
        value: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
        cutoff: 10
        expected: "'aaaaaaaaaa..."
      id: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-10-'aaaaaaaaaa..."
      

      📌 Setup phase

      duration:

      0.00033028610050678253
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0009202640503644943
      

      outcome:

      failed
      

      crash:

      path: /workspace/tligui_y/slic/tests/test_utils_debug.py
      lineno: 66
      message: assert "'aaaaaaaaa..." == "'aaaaaaaaaa..."
      
        - 'aaaaaaaaaa...
        ?  -
        + 'aaaaaaaaa...
      

      traceback:

      -   path: tests/test_utils_debug.py
        lineno: 66
        message: AssertionError
      

      longrepr:

      value = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
      cutoff = 10, expected = "'aaaaaaaaaa..."
      
          @pytest.mark.parametrize(
              "value, cutoff, expected",
              [
                  ("abc", 10, "'abc'"),
                  ("a" * 100, 10, "'aaaaaaaaaa..."),
                  (12345, 10, "12345"),
                  ([0]*100, 15, str(repr([0]*100))[:15] + "..."),
                  (None, 10, "None"),
                  (type("Obj", (), {"__repr__": lambda self: "Obj(" + "x"*50 + ")"})(), 20, "Obj(xxxxxxxxxxxxxxxxx..."),
              ]
          )
      
          def test_short_repr(value, cutoff, expected):
      >       assert short_repr(value, cutoff) == expected
      E       assert "'aaaaaaaaa..." == "'aaaaaaaaaa..."
      E         
      E         - 'aaaaaaaaaa...
      E         ?  -
      E         + 'aaaaaaaaa...
      
      tests/test_utils_debug.py:66: AssertionError
      

      📌 Teardown phase

      duration:

      0.0006833542138338089
      

      outcome:

      passed
      
    • Test 145
      params: value="Obj(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)", cutoff=20, expected="Obj(xxxxxxxxxxxxxxxxx..."

      📌 Parameters

      params:
        value: "Obj(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)"
        cutoff: 20
        expected: "Obj(xxxxxxxxxxxxxxxxx..."
      id: "value5-20-Obj(xxxxxxxxxxxxxxxxx..."
      

      📌 Setup phase

      duration:

      0.0004992326721549034
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0008177496492862701
      

      outcome:

      failed
      

      crash:

      path: /workspace/tligui_y/slic/tests/test_utils_debug.py
      lineno: 66
      message: AssertionError: assert 'Obj(xxxxxxxxxxxxxxxx...' == 'Obj(xxxxxxxxxxxxxxxxx...'
      
        - Obj(xxxxxxxxxxxxxxxxx...
        ?                     -
        + Obj(xxxxxxxxxxxxxxxx...
      

      traceback:

      -   path: tests/test_utils_debug.py
        lineno: 66
        message: AssertionError
      

      longrepr:

      value = Obj(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx), cutoff = 20
      expected = 'Obj(xxxxxxxxxxxxxxxxx...'
      
          @pytest.mark.parametrize(
              "value, cutoff, expected",
              [
                  ("abc", 10, "'abc'"),
                  ("a" * 100, 10, "'aaaaaaaaaa..."),
                  (12345, 10, "12345"),
                  ([0]*100, 15, str(repr([0]*100))[:15] + "..."),
                  (None, 10, "None"),
                  (type("Obj", (), {"__repr__": lambda self: "Obj(" + "x"*50 + ")"})(), 20, "Obj(xxxxxxxxxxxxxxxxx..."),
              ]
          )
      
          def test_short_repr(value, cutoff, expected):
      >       assert short_repr(value, cutoff) == expected
      E       AssertionError: assert 'Obj(xxxxxxxxxxxxxxxx...' == 'Obj(xxxxxxxxxxxxxxxxx...'
      E         
      E         - Obj(xxxxxxxxxxxxxxxxx...
      E         ?                     -
      E         + Obj(xxxxxxxxxxxxxxxx...
      
      tests/test_utils_debug.py:66: AssertionError
      

      📌 Teardown phase

      duration:

      0.0003174496814608574
      

      outcome:

      passed
      
  • 📄 test_utils_elog.py

    Function: test_get_default_elog_instance_with_direct_password_and_real_check

    • Test 177

      📌 Setup phase

      duration:

      0.00017974711954593658
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.009863845072686672
      

      outcome:

      failed
      

      crash:

      path: /workspace/tligui_y/slic/tests/test_utils_elog.py
      lineno: 24
      message: Failed: elog.post() raised an unexpected exception: No response from the logbook server.
      Details: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09b7e4f0>: Failed to establish a new connection: [Errno 111] Connection refused'))
      

      traceback:

      -   path: tests/test_utils_elog.py
        lineno: 24
        message: Failed
      

      longrepr:

      self = <urllib3.connection.HTTPConnection object at 0x7feb09b79310>
      
          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,
                  )
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:199: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/connection.py:85: in create_connection
          raise err
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      address = ('localhost', 8080), 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 111] Connection refused
      
      /root/mambaforge/envs/ci-env/lib/python3.8/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 0x7feb09b79910>
      method = 'POST', url = '/demo/'
      body = b'--06a2aba8224344deb19cc358b997508b\r\nContent-Disposition: form-data; name="Author"\r\n\r\nrobot\r\n--06a2aba8224344...Disposition: form-data; name="Text"; filename=""\r\n\r\nThis is a message1\r\n--06a2aba8224344deb19cc358b997508b--\r\n'
      headers = {'User-Agent': 'python-requests/2.32.4', 'Accept-Encoding': 'gzip, deflate, br, zstd', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '736', 'Content-Type': 'multipart/form-data; boundary=06a2aba8224344deb19cc358b997508b'}
      retries = Retry(total=0, connect=None, read=False, redirect=None, status=None)
      redirect = False, assert_same_host = False
      timeout = Timeout(connect=None, read=None, total=None), pool_timeout = None
      release_conn = False, chunked = False, body_pos = None, preload_content = False
      decode_content = False, response_kw = {}
      parsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/demo/', 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,
                  )
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:789: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:495: in _make_request
          conn.request(
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:441: in request
          self.endheaders()
      /root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1251: in endheaders
          self._send_output(message_body, encode_chunked=encode_chunked)
      /root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1011: in _send_output
          self.send(msg)
      /root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:951: in send
          self.connect()
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:279: in connect
          self.sock = self._new_conn()
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      self = <urllib3.connection.HTTPConnection object at 0x7feb09b79310>
      
          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 0x7feb09b79310>: Failed to establish a new connection: [Errno 111] Connection refused
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:214: NewConnectionError
      
      The above exception was the direct cause of the following exception:
      
      self = <requests.adapters.HTTPAdapter object at 0x7feb09b79730>
      request = <PreparedRequest [POST]>, stream = False
      timeout = Timeout(connect=None, read=None, total=None), verify = False
      cert = None, proxies = OrderedDict()
      
          def send(
              self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
          ):
              """Sends PreparedRequest object. Returns Response object.
      
              :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
              :param stream: (optional) Whether to stream the request content.
              :param timeout: (optional) How long to wait for the server to send
                  data before giving up, as a float, or a :ref:`(connect timeout,
                  read timeout) <timeouts>` tuple.
              :type timeout: float or tuple or urllib3 Timeout object
              :param verify: (optional) Either a boolean, in which case it controls whether
                  we verify the server's TLS certificate, or a string, in which case it
                  must be a path to a CA bundle to use
              :param cert: (optional) Any user-provided SSL certificate to be trusted.
              :param proxies: (optional) The proxies dictionary to apply to the request.
              :rtype: requests.Response
              """
      
              try:
                  conn = self.get_connection_with_tls_context(
                      request, verify, proxies=proxies, cert=cert
                  )
              except LocationValueError as e:
                  raise InvalidURL(e, request=request)
      
              self.cert_verify(conn, request.url, verify, cert)
              url = self.request_url(request, proxies)
              self.add_headers(
                  request,
                  stream=stream,
                  timeout=timeout,
                  verify=verify,
                  cert=cert,
                  proxies=proxies,
              )
      
              chunked = not (request.body is None or "Content-Length" in request.headers)
      
              if isinstance(timeout, tuple):
                  try:
                      connect, read = timeout
                      timeout = TimeoutSauce(connect=connect, read=read)
                  except ValueError:
                      raise ValueError(
                          f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                          f"or a single float to set both timeouts to the same value."
                      )
              elif isinstance(timeout, TimeoutSauce):
                  pass
              else:
                  timeout = TimeoutSauce(connect=timeout, read=timeout)
      
              try:
      >           resp = conn.urlopen(
                      method=request.method,
                      url=url,
                      body=request.body,
                      headers=request.headers,
                      redirect=False,
                      assert_same_host=False,
                      preload_content=False,
                      decode_content=False,
                      retries=self.max_retries,
                      timeout=timeout,
                      chunked=chunked,
                  )
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:667: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:843: in urlopen
          retries = retries.increment(
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      self = Retry(total=0, connect=None, read=False, redirect=None, status=None)
      method = 'POST', url = '/demo/', response = None
      error = NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09b79310>: Failed to establish a new connection: [Errno 111] Connection refused')
      _pool = <urllib3.connectionpool.HTTPConnectionPool object at 0x7feb09b79910>
      _stacktrace = <traceback object at 0x7feb09b744c0>
      
          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: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/ (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09b79310>: Failed to establish a new connection: [Errno 111] Connection refused'))
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/retry.py:519: MaxRetryError
      
      During handling of the above exception, another exception occurred:
      
      self = <elog.logbook.Logbook object at 0x7feb09b79e80>
      message = 'This is a message1', msg_id = None, reply = False
      attributes = {'Author': 'robot', 'When': 1756376001, 'cmd': 'Submit', 'exp': 'demo', ...}
      attachments = [], suppress_email_notification = False, encoding = None
      timeout = None, kwargs = {'Author': 'robot'}
      new_attachment_list = [('Text', ('', b'This is a message1'))]
      objects_to_close = []
      attributes_to_edit = {'Author': b'robot', 'When': 1756376001, 'cmd': b'Submit', 'exp': b'demo', ...}
      
          def post(self, message, msg_id=None, reply=False, attributes=None, attachments=None,
                   suppress_email_notification=False, encoding=None, timeout=None, **kwargs):
              """
              Posts message to the logbook. If msg_id is not specified new message will be created, otherwise existing
              message will be edited, or a reply (if reply=True) to it will be created. This method returns the msg_id
              of the newly created message.
      
              :param message: string with message text
              :param msg_id: ID number of message to edit or reply. If not specified new message is created.
              :param reply: If 'True' reply to existing message is created instead of editing it
              :param attributes: Dictionary of attributes. Following attributes are used internally by the elog and will be
                                 ignored: Text, Date, Encoding, Reply to, In reply to, Locked by, Attachment
              :param attachments: list of:
                                        - file like objects which read() will return bytes (if file_like_object.name is not
                                          defined, default name "attachment<i>" will be used.
                                        - paths to the files
                                  All items will be appended as attachment to the elog entry. In case of unknown
                                  attachment an exception LogbookInvalidAttachment will be raised.
              :param suppress_email_notification: If set to True or 1, E-Mail notification will be suppressed, defaults to False.
              :param encoding: Defines encoding of the message. Can be: 'plain' -> plain text, 'html'->html-text,
                               'ELCode' --> elog formatting syntax
              :param timeout: Define the timeout to be used by the post request. Its value is directly passed to the requests
                              post. Use None to disable the request timeout.
              :param kwargs: Anything in the kwargs will be interpreted as attribute. e.g.: logbook.post('Test text',
                             Author='Rok Vintar), "Author" will be sent as an attribute. If named same as one of the
                             attributes defined in "attributes", kwargs will have priority.
      
              :return: msg_id
              """
      
              attributes = attributes or {}
              attributes = {**attributes, **kwargs}  # kwargs as attributes with higher priority
      
              attachments = attachments or []
      
              if encoding is not None:
                  if encoding not in ['plain', 'HTML', 'ELCode']:
                      raise LogbookMessageRejected('Invalid message encoding. Valid options: plain, HTML, ELCode.')
                  attributes['Encoding'] = encoding
      
              if suppress_email_notification:
                  attributes["suppress"] = 1
      
              # THE ATTACHMENT STRATEGY WHEN DEALING WITH POST MODIFICATION
              #
              # 1. Does the message on the server have already attachments?
              #    1.1 - We read the message getting the existing attachment list.
              #    1.2 - Add to the attributes dictionary one line for each attachment like this:
              #       attributes['attachmentN'] = timestamped_filename_name
              #
              # 2. Do we have new attachments?
              #    2.1 - Those are in the new_attachment_list. This is a list of this type:
              #       [ ('attfileN', ('filename', fileobject)) ]
              #    2.2 - We need to loop over all the new attachments:
              #       2.2.1 - Does a file already on the server with the same name exist?
              #         2.2.1.1 - No: OK. Then we go ahead with the next attachment.
              #         2.2.1.2 - Yes:
              #           2.2.1.2.1 - Are the two files identical?
              #               2.2.1.2.1.1 - Yes: then we remove this current entry from the new_attachment_list and we leave the one
              #                      already on server.
              #               2.2.1.2.1.2 - No:
              #                  2.2.1.2.1.2.1 - Then the file has been update.
              #                  2.2.1.2.1.2.2 - We need to remove the file on server first (using special post)
              #                  2.2.1.2.1.2.3 - We have to remove the old attachment from the attributes dictionary.
              #
      
              if attachments:
                  # here we accomplish point 2.1.
                  # new_attachment_list is something like [ ('attfileN', ('filename', fileobject)) ]
                  new_attachment_list, objects_to_close = self._prepare_attachments(attachments)
              else:
                  objects_to_close = list()
                  new_attachment_list = list()
      
              attributes_to_edit = dict()
              if msg_id:
                  # Message exists, we can continue
                  if reply:
                      # Verify that there is a message on the server, otherwise do not reply to it!
                      self._check_if_message_on_server(msg_id)  # raises exception in case of none existing message
                      attributes['reply_to'] = str(msg_id)
                  else:  # Edit existing
                      attributes['edit_id'] = str(msg_id)
                      attributes['skiplock'] = '1'
      
                      # here we accomplish point 1.1.
                      # existing_attachments_list is something like:
                      # [ 'https://elog.url.com/logbook/timestamped_filename' ]
                      msg_to_edit, attributes_to_edit, existing_attachments_list = self.read(msg_id)
      
                      for attribute, data in attributes.items():
                          new_data = attributes.get(attribute)
                          if new_data is not None:
                              attributes_to_edit[attribute] = new_data
      
                      i = 0
                      existing_attachments_filename_list = list()
                      for attachment in existing_attachments_list:
                          # here we accomplish point 1.2. We strip the timestamped_filename from the whole URL.
                          attributes_to_edit[f'attachment{i}'] = os.path.basename(attachment)
                          existing_attachments_filename_list.append(os.path.basename(attachment)[14:])
                          i += 1
      
                      # let's accomplish 2.2. Loop over all new attachment
                      duplicate_attachment_list = list()
                      for new_attachment in new_attachment_list:
                          # the new_attachment_list is something like:
                          # [ ('attfileN', ('filename', fileobject)) ]
                          new_attachment_filename = new_attachment[1][0]
                          if new_attachment_filename in existing_attachments_filename_list:
                              # a file with the same name existing already on the server.
                              # we need to check if the two files are the same.
                              # read the content of the new file
                              new_attachment_content = new_attachment[1][1].read()
                              # don't forget to reset the fileobj to the beginning of the file
                              new_attachment[1][1].seek(0)
                              # get the existing attachment content
                              attachment_index = existing_attachments_filename_list.index(new_attachment_filename)
                              existing_attachment_content = self.download_attachment(
                                  url=existing_attachments_list[attachment_index],
                                  timeout=timeout
                              )
                              # check if the two contents are the same
                              if new_attachment_content == existing_attachment_content:
                                  # yes. then we don't upload a second copy. we remove the current entry from the list
                                  duplicate_attachment_list.append(new_attachment)
                              else:
                                  # no. they are not the same file. we will replace the existing file with the new one
                                  # first: we need to remove the attachment from the server using the dedicated method
                                  self.delete_attachment(msg_id, attributes=attributes_to_edit,
                                                         attachment_id=attachment_index,
                                                         timeout=timeout, text=msg_to_edit)
                                  # now we can remove this attachment from the auxiliary lists.
                                  existing_attachments_filename_list.pop(attachment_index)
                                  existing_attachments_list.pop(attachment_index)
                                  # now we need to rebuild the attributes dictionary for the part concerning the attachments.
                                  # we remove all of them first
                                  keys_to_be_removed = list()
                                  for key in attributes_to_edit.keys():
                                      if key.startswith('attachment'):
                                          keys_to_be_removed.append(key)
                                      if key.startswith('delatt'):
                                          keys_to_be_removed.append(key)
                                  for key in keys_to_be_removed:
                                      del attributes_to_edit[key]
      
                                  # now we rebuild it
                                  for i, attachment in enumerate(existing_attachments_list):
                                      attributes_to_edit[f'attachment{i}'] = os.path.basename(attachment)
      
                      # remove all duplicate attachments from the new_attachment_list
                      for attach in duplicate_attachment_list:
                          new_attachment_list.remove(attach)
      
              else:
                  # As we create a new message, specify creation time if not already specified in attributes
                  if 'When' not in attributes:
                      attributes['When'] = int(datetime.now().timestamp())
      
              if not attributes_to_edit:
                  attributes_to_edit = attributes
      
              # Remove any attributes that should not be sent
              _remove_reserved_attributes(attributes_to_edit)
      
              # Make requests module think that Text is a "file". This is the only way to force requests to send data as
              # multipart/form-data even if there are no attachments. Elog understands only multipart/form-data
              new_attachment_list.append(('Text', ('', message.encode('iso-8859-1'))))
      
              # Base attributes are common to all messages
              self._add_base_msg_attributes(attributes_to_edit)
      
              # Keys in attributes cannot have certain characters like whitespaces or dashes for the http request
              attributes_to_edit = _replace_special_characters_in_attribute_keys(attributes_to_edit)
      
              # All string values in the attributes must be encoded in latin1
              attributes_to_edit = _encode_values(attributes_to_edit)
      
              try:
      >           response = requests.post(self._url, data=attributes_to_edit, files=new_attachment_list,
                                           allow_redirects=False, verify=False, timeout=timeout)
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:288: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:115: in post
          return request("post", url, data=data, json=json, **kwargs)
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:59: in request
          return session.request(method=method, url=url, **kwargs)
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:589: in request
          resp = self.send(prep, **send_kwargs)
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:703: in send
          r = adapter.send(request, **kwargs)
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      self = <requests.adapters.HTTPAdapter object at 0x7feb09b79730>
      request = <PreparedRequest [POST]>, stream = False
      timeout = Timeout(connect=None, read=None, total=None), verify = False
      cert = None, proxies = OrderedDict()
      
          def send(
              self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
          ):
              """Sends PreparedRequest object. Returns Response object.
      
              :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
              :param stream: (optional) Whether to stream the request content.
              :param timeout: (optional) How long to wait for the server to send
                  data before giving up, as a float, or a :ref:`(connect timeout,
                  read timeout) <timeouts>` tuple.
              :type timeout: float or tuple or urllib3 Timeout object
              :param verify: (optional) Either a boolean, in which case it controls whether
                  we verify the server's TLS certificate, or a string, in which case it
                  must be a path to a CA bundle to use
              :param cert: (optional) Any user-provided SSL certificate to be trusted.
              :param proxies: (optional) The proxies dictionary to apply to the request.
              :rtype: requests.Response
              """
      
              try:
                  conn = self.get_connection_with_tls_context(
                      request, verify, proxies=proxies, cert=cert
                  )
              except LocationValueError as e:
                  raise InvalidURL(e, request=request)
      
              self.cert_verify(conn, request.url, verify, cert)
              url = self.request_url(request, proxies)
              self.add_headers(
                  request,
                  stream=stream,
                  timeout=timeout,
                  verify=verify,
                  cert=cert,
                  proxies=proxies,
              )
      
              chunked = not (request.body is None or "Content-Length" in request.headers)
      
              if isinstance(timeout, tuple):
                  try:
                      connect, read = timeout
                      timeout = TimeoutSauce(connect=connect, read=read)
                  except ValueError:
                      raise ValueError(
                          f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                          f"or a single float to set both timeouts to the same value."
                      )
              elif isinstance(timeout, TimeoutSauce):
                  pass
              else:
                  timeout = TimeoutSauce(connect=timeout, read=timeout)
      
              try:
                  resp = conn.urlopen(
                      method=request.method,
                      url=url,
                      body=request.body,
                      headers=request.headers,
                      redirect=False,
                      assert_same_host=False,
                      preload_content=False,
                      decode_content=False,
                      retries=self.max_retries,
                      timeout=timeout,
                      chunked=chunked,
                  )
      
              except (ProtocolError, OSError) as err:
                  raise ConnectionError(err, request=request)
      
              except MaxRetryError as e:
                  if isinstance(e.reason, ConnectTimeoutError):
                      # TODO: Remove this in 3.0.0: see #2811
                      if not isinstance(e.reason, NewConnectionError):
                          raise ConnectTimeout(e, request=request)
      
                  if isinstance(e.reason, ResponseError):
                      raise RetryError(e, request=request)
      
                  if isinstance(e.reason, _ProxyError):
                      raise ProxyError(e, request=request)
      
                  if isinstance(e.reason, _SSLError):
                      # This branch is for urllib3 v1.22 and later.
                      raise SSLError(e, request=request)
      
      >           raise ConnectionError(e, request=request)
      E           requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/ (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09b79310>: Failed to establish a new connection: [Errno 111] Connection refused'))
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:700: ConnectionError
      
      During handling of the above exception, another exception occurred:
      
      self = <urllib3.connection.HTTPConnection object at 0x7feb09b7e4f0>
      
          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,
                  )
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:199: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/connection.py:85: in create_connection
          raise err
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      address = ('localhost', 8080), 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 111] Connection refused
      
      /root/mambaforge/envs/ci-env/lib/python3.8/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 0x7feb09b7e820>
      method = 'GET', url = '/demo/None', body = None
      headers = {'User-Agent': 'python-requests/2.32.4', 'Accept-Encoding': 'gzip, deflate, br, zstd', 'Accept': '*/*', 'Connection': 'keep-alive', 'Cookie': 'unm=robot;upwd=me1T.2jUUqQNa1wNuey9zNBOmOa4eILOaPb.ZSZjpn4;'}
      retries = Retry(total=0, connect=None, read=False, redirect=None, status=None)
      redirect = False, assert_same_host = False
      timeout = Timeout(connect=None, read=None, total=None), pool_timeout = None
      release_conn = False, chunked = False, body_pos = None, preload_content = False
      decode_content = False, response_kw = {}
      parsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/demo/None', 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,
                  )
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:789: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:495: in _make_request
          conn.request(
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:441: in request
          self.endheaders()
      /root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1251: in endheaders
          self._send_output(message_body, encode_chunked=encode_chunked)
      /root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1011: in _send_output
          self.send(msg)
      /root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:951: in send
          self.connect()
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:279: in connect
          self.sock = self._new_conn()
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      self = <urllib3.connection.HTTPConnection object at 0x7feb09b7e4f0>
      
          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 0x7feb09b7e4f0>: Failed to establish a new connection: [Errno 111] Connection refused
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:214: NewConnectionError
      
      The above exception was the direct cause of the following exception:
      
      self = <requests.adapters.HTTPAdapter object at 0x7feb09b7ea00>
      request = <PreparedRequest [GET]>, stream = False
      timeout = Timeout(connect=None, read=None, total=None), verify = False
      cert = None, proxies = OrderedDict()
      
          def send(
              self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
          ):
              """Sends PreparedRequest object. Returns Response object.
      
              :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
              :param stream: (optional) Whether to stream the request content.
              :param timeout: (optional) How long to wait for the server to send
                  data before giving up, as a float, or a :ref:`(connect timeout,
                  read timeout) <timeouts>` tuple.
              :type timeout: float or tuple or urllib3 Timeout object
              :param verify: (optional) Either a boolean, in which case it controls whether
                  we verify the server's TLS certificate, or a string, in which case it
                  must be a path to a CA bundle to use
              :param cert: (optional) Any user-provided SSL certificate to be trusted.
              :param proxies: (optional) The proxies dictionary to apply to the request.
              :rtype: requests.Response
              """
      
              try:
                  conn = self.get_connection_with_tls_context(
                      request, verify, proxies=proxies, cert=cert
                  )
              except LocationValueError as e:
                  raise InvalidURL(e, request=request)
      
              self.cert_verify(conn, request.url, verify, cert)
              url = self.request_url(request, proxies)
              self.add_headers(
                  request,
                  stream=stream,
                  timeout=timeout,
                  verify=verify,
                  cert=cert,
                  proxies=proxies,
              )
      
              chunked = not (request.body is None or "Content-Length" in request.headers)
      
              if isinstance(timeout, tuple):
                  try:
                      connect, read = timeout
                      timeout = TimeoutSauce(connect=connect, read=read)
                  except ValueError:
                      raise ValueError(
                          f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                          f"or a single float to set both timeouts to the same value."
                      )
              elif isinstance(timeout, TimeoutSauce):
                  pass
              else:
                  timeout = TimeoutSauce(connect=timeout, read=timeout)
      
              try:
      >           resp = conn.urlopen(
                      method=request.method,
                      url=url,
                      body=request.body,
                      headers=request.headers,
                      redirect=False,
                      assert_same_host=False,
                      preload_content=False,
                      decode_content=False,
                      retries=self.max_retries,
                      timeout=timeout,
                      chunked=chunked,
                  )
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:667: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:843: in urlopen
          retries = retries.increment(
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      self = Retry(total=0, connect=None, read=False, redirect=None, status=None)
      method = 'GET', url = '/demo/None', response = None
      error = NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09b7e4f0>: Failed to establish a new connection: [Errno 111] Connection refused')
      _pool = <urllib3.connectionpool.HTTPConnectionPool object at 0x7feb09b7e820>
      _stacktrace = <traceback object at 0x7feb09bbad40>
      
          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: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09b7e4f0>: Failed to establish a new connection: [Errno 111] Connection refused'))
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/retry.py:519: MaxRetryError
      
      During handling of the above exception, another exception occurred:
      
      self = <elog.logbook.Logbook object at 0x7feb09b79e80>, msg_id = None
      timeout = None
      
          def _check_if_message_on_server(self, msg_id, timeout=None):
              """Try to load page for specific message. If there is a html tag like <td class="errormsg"> then there is no
              such message.
      
              :param msg_id: ID of message to be checked
              :params timeout: The value of timeout to be passed to the get request
              :return:
              """
      
              request_headers = dict()
              if self._user or self._password:
                  request_headers['Cookie'] = self._make_user_and_pswd_cookie()
              try:
      >           response = requests.get(self._url + str(msg_id), headers=request_headers, allow_redirects=False,
                                          verify=False, timeout=timeout)
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:581: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:73: in get
          return request("get", url, params=params, **kwargs)
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:59: in request
          return session.request(method=method, url=url, **kwargs)
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:589: in request
          resp = self.send(prep, **send_kwargs)
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:703: in send
          r = adapter.send(request, **kwargs)
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      self = <requests.adapters.HTTPAdapter object at 0x7feb09b7ea00>
      request = <PreparedRequest [GET]>, stream = False
      timeout = Timeout(connect=None, read=None, total=None), verify = False
      cert = None, proxies = OrderedDict()
      
          def send(
              self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
          ):
              """Sends PreparedRequest object. Returns Response object.
      
              :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
              :param stream: (optional) Whether to stream the request content.
              :param timeout: (optional) How long to wait for the server to send
                  data before giving up, as a float, or a :ref:`(connect timeout,
                  read timeout) <timeouts>` tuple.
              :type timeout: float or tuple or urllib3 Timeout object
              :param verify: (optional) Either a boolean, in which case it controls whether
                  we verify the server's TLS certificate, or a string, in which case it
                  must be a path to a CA bundle to use
              :param cert: (optional) Any user-provided SSL certificate to be trusted.
              :param proxies: (optional) The proxies dictionary to apply to the request.
              :rtype: requests.Response
              """
      
              try:
                  conn = self.get_connection_with_tls_context(
                      request, verify, proxies=proxies, cert=cert
                  )
              except LocationValueError as e:
                  raise InvalidURL(e, request=request)
      
              self.cert_verify(conn, request.url, verify, cert)
              url = self.request_url(request, proxies)
              self.add_headers(
                  request,
                  stream=stream,
                  timeout=timeout,
                  verify=verify,
                  cert=cert,
                  proxies=proxies,
              )
      
              chunked = not (request.body is None or "Content-Length" in request.headers)
      
              if isinstance(timeout, tuple):
                  try:
                      connect, read = timeout
                      timeout = TimeoutSauce(connect=connect, read=read)
                  except ValueError:
                      raise ValueError(
                          f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                          f"or a single float to set both timeouts to the same value."
                      )
              elif isinstance(timeout, TimeoutSauce):
                  pass
              else:
                  timeout = TimeoutSauce(connect=timeout, read=timeout)
      
              try:
                  resp = conn.urlopen(
                      method=request.method,
                      url=url,
                      body=request.body,
                      headers=request.headers,
                      redirect=False,
                      assert_same_host=False,
                      preload_content=False,
                      decode_content=False,
                      retries=self.max_retries,
                      timeout=timeout,
                      chunked=chunked,
                  )
      
              except (ProtocolError, OSError) as err:
                  raise ConnectionError(err, request=request)
      
              except MaxRetryError as e:
                  if isinstance(e.reason, ConnectTimeoutError):
                      # TODO: Remove this in 3.0.0: see #2811
                      if not isinstance(e.reason, NewConnectionError):
                          raise ConnectTimeout(e, request=request)
      
                  if isinstance(e.reason, ResponseError):
                      raise RetryError(e, request=request)
      
                  if isinstance(e.reason, _ProxyError):
                      raise ProxyError(e, request=request)
      
                  if isinstance(e.reason, _SSLError):
                      # This branch is for urllib3 v1.22 and later.
                      raise SSLError(e, request=request)
      
      >           raise ConnectionError(e, request=request)
      E           requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09b7e4f0>: Failed to establish a new connection: [Errno 111] Connection refused'))
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:700: ConnectionError
      
      During handling of the above exception, another exception occurred:
      
          def test_get_default_elog_instance_with_direct_password_and_real_check():
              url = "http://localhost:8080/demo"
              user = "robot"
              password = "testpassword"
              text = "This is a message1"
      
              elog = Elog("http://localhost:8080/demo", user=user, password=password)
      
              try:
      >           msg_id = elog.post(text)
      
      tests/test_utils_elog.py:22: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      slic/utils/elog.py:16: in post
          return self._log.post(*args, **kwargs)
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:307: in post
          self._check_if_message_on_server(msg_id)  # raises exceptions if no message or no response from server
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      self = <elog.logbook.Logbook object at 0x7feb09b79e80>, msg_id = None
      timeout = None
      
          def _check_if_message_on_server(self, msg_id, timeout=None):
              """Try to load page for specific message. If there is a html tag like <td class="errormsg"> then there is no
              such message.
      
              :param msg_id: ID of message to be checked
              :params timeout: The value of timeout to be passed to the get request
              :return:
              """
      
              request_headers = dict()
              if self._user or self._password:
                  request_headers['Cookie'] = self._make_user_and_pswd_cookie()
              try:
                  response = requests.get(self._url + str(msg_id), headers=request_headers, allow_redirects=False,
                                          verify=False, timeout=timeout)
      
                  # If there is no message code 200 will be returned (OK) and _validate_response will not recognise it
                  # but there will be some error in the html code.
                  resp_message, resp_headers, resp_msg_id = _validate_response(response)
                  # If there is no message, code 200 will be returned (OK) but there will be some error indication in
                  # the html code.
                  if re.findall('<td.*?class="errormsg".*?>.*?</td>',
                                resp_message.decode('utf-8', 'ignore'),
                                flags=re.DOTALL):
                      raise LogbookInvalidMessageID('Message with ID: ' + str(msg_id) + ' does not exist on logbook.')
      
              except requests.Timeout as e:
                  # Catch here a timeout o the post request.
                  # Raise the logbook exception and let the user handle it
                  raise LogbookServerTimeout('{0} method cannot be completed because of a network timeout:\n' +
                                             '{1}'.format(sys._getframe().f_code.co_name, e))
      
              except requests.RequestException as e:
      >           raise LogbookServerProblem('No response from the logbook server.\nDetails: ' + '{0}'.format(e))
      E           elog.logbook_exceptions.LogbookServerProblem: No response from the logbook server.
      E           Details: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09b7e4f0>: Failed to establish a new connection: [Errno 111] Connection refused'))
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:601: LogbookServerProblem
      
      During handling of the above exception, another exception occurred:
      
          def test_get_default_elog_instance_with_direct_password_and_real_check():
              url = "http://localhost:8080/demo"
              user = "robot"
              password = "testpassword"
              text = "This is a message1"
      
              elog = Elog("http://localhost:8080/demo", user=user, password=password)
      
              try:
                  msg_id = elog.post(text)
              except Exception as e:
      >           pytest.fail(f"elog.post() raised an unexpected exception: {e}")
      E           Failed: elog.post() raised an unexpected exception: No response from the logbook server.
      E           Details: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09b7e4f0>: Failed to establish a new connection: [Errno 111] Connection refused'))
      
      tests/test_utils_elog.py:24: Failed
      

      📌 Teardown phase

      duration:

      0.000399087555706501
      

      outcome:

      passed
      

    Function: test_get_default_elog_instance_asks_password_and_opens

    • Test 179

      📌 Setup phase

      duration:

      0.00018332060426473618
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.009587502107024193
      

      outcome:

      failed
      

      crash:

      path: /workspace/tligui_y/slic/tests/test_utils_elog.py
      lineno: 57
      message: Failed: elog.post() raised an unexpected exception: No response from the logbook server.
      Details: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb098025b0>: Failed to establish a new connection: [Errno 111] Connection refused'))
      

      traceback:

      -   path: tests/test_utils_elog.py
        lineno: 57
        message: Failed
      

      stdout:

      Enter elog password for user: robot
      
      

      longrepr:

      self = <urllib3.connection.HTTPConnection object at 0x7feb09830f40>
      
          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,
                  )
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:199: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/connection.py:85: in create_connection
          raise err
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      address = ('localhost', 8080), 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 111] Connection refused
      
      /root/mambaforge/envs/ci-env/lib/python3.8/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 0x7feb09830bb0>
      method = 'POST', url = '/demo/'
      body = b'--aa75161c22b288663152f49dada5f35f\r\nContent-Disposition: form-data; name="Author"\r\n\r\nrobot\r\n--aa75161c22b288...Disposition: form-data; name="Text"; filename=""\r\n\r\nThis is a message2\r\n--aa75161c22b288663152f49dada5f35f--\r\n'
      headers = {'User-Agent': 'python-requests/2.32.4', 'Accept-Encoding': 'gzip, deflate, br, zstd', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '736', 'Content-Type': 'multipart/form-data; boundary=aa75161c22b288663152f49dada5f35f'}
      retries = Retry(total=0, connect=None, read=False, redirect=None, status=None)
      redirect = False, assert_same_host = False
      timeout = Timeout(connect=None, read=None, total=None), pool_timeout = None
      release_conn = False, chunked = False, body_pos = None, preload_content = False
      decode_content = False, response_kw = {}
      parsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/demo/', 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,
                  )
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:789: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:495: in _make_request
          conn.request(
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:441: in request
          self.endheaders()
      /root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1251: in endheaders
          self._send_output(message_body, encode_chunked=encode_chunked)
      /root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1011: in _send_output
          self.send(msg)
      /root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:951: in send
          self.connect()
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:279: in connect
          self.sock = self._new_conn()
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      self = <urllib3.connection.HTTPConnection object at 0x7feb09830f40>
      
          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 0x7feb09830f40>: Failed to establish a new connection: [Errno 111] Connection refused
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:214: NewConnectionError
      
      The above exception was the direct cause of the following exception:
      
      self = <requests.adapters.HTTPAdapter object at 0x7feb0522b790>
      request = <PreparedRequest [POST]>, stream = False
      timeout = Timeout(connect=None, read=None, total=None), verify = False
      cert = None, proxies = OrderedDict()
      
          def send(
              self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
          ):
              """Sends PreparedRequest object. Returns Response object.
      
              :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
              :param stream: (optional) Whether to stream the request content.
              :param timeout: (optional) How long to wait for the server to send
                  data before giving up, as a float, or a :ref:`(connect timeout,
                  read timeout) <timeouts>` tuple.
              :type timeout: float or tuple or urllib3 Timeout object
              :param verify: (optional) Either a boolean, in which case it controls whether
                  we verify the server's TLS certificate, or a string, in which case it
                  must be a path to a CA bundle to use
              :param cert: (optional) Any user-provided SSL certificate to be trusted.
              :param proxies: (optional) The proxies dictionary to apply to the request.
              :rtype: requests.Response
              """
      
              try:
                  conn = self.get_connection_with_tls_context(
                      request, verify, proxies=proxies, cert=cert
                  )
              except LocationValueError as e:
                  raise InvalidURL(e, request=request)
      
              self.cert_verify(conn, request.url, verify, cert)
              url = self.request_url(request, proxies)
              self.add_headers(
                  request,
                  stream=stream,
                  timeout=timeout,
                  verify=verify,
                  cert=cert,
                  proxies=proxies,
              )
      
              chunked = not (request.body is None or "Content-Length" in request.headers)
      
              if isinstance(timeout, tuple):
                  try:
                      connect, read = timeout
                      timeout = TimeoutSauce(connect=connect, read=read)
                  except ValueError:
                      raise ValueError(
                          f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                          f"or a single float to set both timeouts to the same value."
                      )
              elif isinstance(timeout, TimeoutSauce):
                  pass
              else:
                  timeout = TimeoutSauce(connect=timeout, read=timeout)
      
              try:
      >           resp = conn.urlopen(
                      method=request.method,
                      url=url,
                      body=request.body,
                      headers=request.headers,
                      redirect=False,
                      assert_same_host=False,
                      preload_content=False,
                      decode_content=False,
                      retries=self.max_retries,
                      timeout=timeout,
                      chunked=chunked,
                  )
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:667: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:843: in urlopen
          retries = retries.increment(
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      self = Retry(total=0, connect=None, read=False, redirect=None, status=None)
      method = 'POST', url = '/demo/', response = None
      error = NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09830f40>: Failed to establish a new connection: [Errno 111] Connection refused')
      _pool = <urllib3.connectionpool.HTTPConnectionPool object at 0x7feb09830bb0>
      _stacktrace = <traceback object at 0x7feb09590040>
      
          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: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/ (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09830f40>: Failed to establish a new connection: [Errno 111] Connection refused'))
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/retry.py:519: MaxRetryError
      
      During handling of the above exception, another exception occurred:
      
      self = <elog.logbook.Logbook object at 0x7feb05e26fd0>
      message = 'This is a message2', msg_id = None, reply = False
      attributes = {'Author': 'robot', 'When': 1756376002, 'cmd': 'Submit', 'exp': 'demo', ...}
      attachments = [], suppress_email_notification = False, encoding = None
      timeout = None, kwargs = {'Author': 'robot'}
      new_attachment_list = [('Text', ('', b'This is a message2'))]
      objects_to_close = []
      attributes_to_edit = {'Author': b'robot', 'When': 1756376002, 'cmd': b'Submit', 'exp': b'demo', ...}
      
          def post(self, message, msg_id=None, reply=False, attributes=None, attachments=None,
                   suppress_email_notification=False, encoding=None, timeout=None, **kwargs):
              """
              Posts message to the logbook. If msg_id is not specified new message will be created, otherwise existing
              message will be edited, or a reply (if reply=True) to it will be created. This method returns the msg_id
              of the newly created message.
      
              :param message: string with message text
              :param msg_id: ID number of message to edit or reply. If not specified new message is created.
              :param reply: If 'True' reply to existing message is created instead of editing it
              :param attributes: Dictionary of attributes. Following attributes are used internally by the elog and will be
                                 ignored: Text, Date, Encoding, Reply to, In reply to, Locked by, Attachment
              :param attachments: list of:
                                        - file like objects which read() will return bytes (if file_like_object.name is not
                                          defined, default name "attachment<i>" will be used.
                                        - paths to the files
                                  All items will be appended as attachment to the elog entry. In case of unknown
                                  attachment an exception LogbookInvalidAttachment will be raised.
              :param suppress_email_notification: If set to True or 1, E-Mail notification will be suppressed, defaults to False.
              :param encoding: Defines encoding of the message. Can be: 'plain' -> plain text, 'html'->html-text,
                               'ELCode' --> elog formatting syntax
              :param timeout: Define the timeout to be used by the post request. Its value is directly passed to the requests
                              post. Use None to disable the request timeout.
              :param kwargs: Anything in the kwargs will be interpreted as attribute. e.g.: logbook.post('Test text',
                             Author='Rok Vintar), "Author" will be sent as an attribute. If named same as one of the
                             attributes defined in "attributes", kwargs will have priority.
      
              :return: msg_id
              """
      
              attributes = attributes or {}
              attributes = {**attributes, **kwargs}  # kwargs as attributes with higher priority
      
              attachments = attachments or []
      
              if encoding is not None:
                  if encoding not in ['plain', 'HTML', 'ELCode']:
                      raise LogbookMessageRejected('Invalid message encoding. Valid options: plain, HTML, ELCode.')
                  attributes['Encoding'] = encoding
      
              if suppress_email_notification:
                  attributes["suppress"] = 1
      
              # THE ATTACHMENT STRATEGY WHEN DEALING WITH POST MODIFICATION
              #
              # 1. Does the message on the server have already attachments?
              #    1.1 - We read the message getting the existing attachment list.
              #    1.2 - Add to the attributes dictionary one line for each attachment like this:
              #       attributes['attachmentN'] = timestamped_filename_name
              #
              # 2. Do we have new attachments?
              #    2.1 - Those are in the new_attachment_list. This is a list of this type:
              #       [ ('attfileN', ('filename', fileobject)) ]
              #    2.2 - We need to loop over all the new attachments:
              #       2.2.1 - Does a file already on the server with the same name exist?
              #         2.2.1.1 - No: OK. Then we go ahead with the next attachment.
              #         2.2.1.2 - Yes:
              #           2.2.1.2.1 - Are the two files identical?
              #               2.2.1.2.1.1 - Yes: then we remove this current entry from the new_attachment_list and we leave the one
              #                      already on server.
              #               2.2.1.2.1.2 - No:
              #                  2.2.1.2.1.2.1 - Then the file has been update.
              #                  2.2.1.2.1.2.2 - We need to remove the file on server first (using special post)
              #                  2.2.1.2.1.2.3 - We have to remove the old attachment from the attributes dictionary.
              #
      
              if attachments:
                  # here we accomplish point 2.1.
                  # new_attachment_list is something like [ ('attfileN', ('filename', fileobject)) ]
                  new_attachment_list, objects_to_close = self._prepare_attachments(attachments)
              else:
                  objects_to_close = list()
                  new_attachment_list = list()
      
              attributes_to_edit = dict()
              if msg_id:
                  # Message exists, we can continue
                  if reply:
                      # Verify that there is a message on the server, otherwise do not reply to it!
                      self._check_if_message_on_server(msg_id)  # raises exception in case of none existing message
                      attributes['reply_to'] = str(msg_id)
                  else:  # Edit existing
                      attributes['edit_id'] = str(msg_id)
                      attributes['skiplock'] = '1'
      
                      # here we accomplish point 1.1.
                      # existing_attachments_list is something like:
                      # [ 'https://elog.url.com/logbook/timestamped_filename' ]
                      msg_to_edit, attributes_to_edit, existing_attachments_list = self.read(msg_id)
      
                      for attribute, data in attributes.items():
                          new_data = attributes.get(attribute)
                          if new_data is not None:
                              attributes_to_edit[attribute] = new_data
      
                      i = 0
                      existing_attachments_filename_list = list()
                      for attachment in existing_attachments_list:
                          # here we accomplish point 1.2. We strip the timestamped_filename from the whole URL.
                          attributes_to_edit[f'attachment{i}'] = os.path.basename(attachment)
                          existing_attachments_filename_list.append(os.path.basename(attachment)[14:])
                          i += 1
      
                      # let's accomplish 2.2. Loop over all new attachment
                      duplicate_attachment_list = list()
                      for new_attachment in new_attachment_list:
                          # the new_attachment_list is something like:
                          # [ ('attfileN', ('filename', fileobject)) ]
                          new_attachment_filename = new_attachment[1][0]
                          if new_attachment_filename in existing_attachments_filename_list:
                              # a file with the same name existing already on the server.
                              # we need to check if the two files are the same.
                              # read the content of the new file
                              new_attachment_content = new_attachment[1][1].read()
                              # don't forget to reset the fileobj to the beginning of the file
                              new_attachment[1][1].seek(0)
                              # get the existing attachment content
                              attachment_index = existing_attachments_filename_list.index(new_attachment_filename)
                              existing_attachment_content = self.download_attachment(
                                  url=existing_attachments_list[attachment_index],
                                  timeout=timeout
                              )
                              # check if the two contents are the same
                              if new_attachment_content == existing_attachment_content:
                                  # yes. then we don't upload a second copy. we remove the current entry from the list
                                  duplicate_attachment_list.append(new_attachment)
                              else:
                                  # no. they are not the same file. we will replace the existing file with the new one
                                  # first: we need to remove the attachment from the server using the dedicated method
                                  self.delete_attachment(msg_id, attributes=attributes_to_edit,
                                                         attachment_id=attachment_index,
                                                         timeout=timeout, text=msg_to_edit)
                                  # now we can remove this attachment from the auxiliary lists.
                                  existing_attachments_filename_list.pop(attachment_index)
                                  existing_attachments_list.pop(attachment_index)
                                  # now we need to rebuild the attributes dictionary for the part concerning the attachments.
                                  # we remove all of them first
                                  keys_to_be_removed = list()
                                  for key in attributes_to_edit.keys():
                                      if key.startswith('attachment'):
                                          keys_to_be_removed.append(key)
                                      if key.startswith('delatt'):
                                          keys_to_be_removed.append(key)
                                  for key in keys_to_be_removed:
                                      del attributes_to_edit[key]
      
                                  # now we rebuild it
                                  for i, attachment in enumerate(existing_attachments_list):
                                      attributes_to_edit[f'attachment{i}'] = os.path.basename(attachment)
      
                      # remove all duplicate attachments from the new_attachment_list
                      for attach in duplicate_attachment_list:
                          new_attachment_list.remove(attach)
      
              else:
                  # As we create a new message, specify creation time if not already specified in attributes
                  if 'When' not in attributes:
                      attributes['When'] = int(datetime.now().timestamp())
      
              if not attributes_to_edit:
                  attributes_to_edit = attributes
      
              # Remove any attributes that should not be sent
              _remove_reserved_attributes(attributes_to_edit)
      
              # Make requests module think that Text is a "file". This is the only way to force requests to send data as
              # multipart/form-data even if there are no attachments. Elog understands only multipart/form-data
              new_attachment_list.append(('Text', ('', message.encode('iso-8859-1'))))
      
              # Base attributes are common to all messages
              self._add_base_msg_attributes(attributes_to_edit)
      
              # Keys in attributes cannot have certain characters like whitespaces or dashes for the http request
              attributes_to_edit = _replace_special_characters_in_attribute_keys(attributes_to_edit)
      
              # All string values in the attributes must be encoded in latin1
              attributes_to_edit = _encode_values(attributes_to_edit)
      
              try:
      >           response = requests.post(self._url, data=attributes_to_edit, files=new_attachment_list,
                                           allow_redirects=False, verify=False, timeout=timeout)
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:288: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:115: in post
          return request("post", url, data=data, json=json, **kwargs)
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:59: in request
          return session.request(method=method, url=url, **kwargs)
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:589: in request
          resp = self.send(prep, **send_kwargs)
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:703: in send
          r = adapter.send(request, **kwargs)
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      self = <requests.adapters.HTTPAdapter object at 0x7feb0522b790>
      request = <PreparedRequest [POST]>, stream = False
      timeout = Timeout(connect=None, read=None, total=None), verify = False
      cert = None, proxies = OrderedDict()
      
          def send(
              self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
          ):
              """Sends PreparedRequest object. Returns Response object.
      
              :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
              :param stream: (optional) Whether to stream the request content.
              :param timeout: (optional) How long to wait for the server to send
                  data before giving up, as a float, or a :ref:`(connect timeout,
                  read timeout) <timeouts>` tuple.
              :type timeout: float or tuple or urllib3 Timeout object
              :param verify: (optional) Either a boolean, in which case it controls whether
                  we verify the server's TLS certificate, or a string, in which case it
                  must be a path to a CA bundle to use
              :param cert: (optional) Any user-provided SSL certificate to be trusted.
              :param proxies: (optional) The proxies dictionary to apply to the request.
              :rtype: requests.Response
              """
      
              try:
                  conn = self.get_connection_with_tls_context(
                      request, verify, proxies=proxies, cert=cert
                  )
              except LocationValueError as e:
                  raise InvalidURL(e, request=request)
      
              self.cert_verify(conn, request.url, verify, cert)
              url = self.request_url(request, proxies)
              self.add_headers(
                  request,
                  stream=stream,
                  timeout=timeout,
                  verify=verify,
                  cert=cert,
                  proxies=proxies,
              )
      
              chunked = not (request.body is None or "Content-Length" in request.headers)
      
              if isinstance(timeout, tuple):
                  try:
                      connect, read = timeout
                      timeout = TimeoutSauce(connect=connect, read=read)
                  except ValueError:
                      raise ValueError(
                          f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                          f"or a single float to set both timeouts to the same value."
                      )
              elif isinstance(timeout, TimeoutSauce):
                  pass
              else:
                  timeout = TimeoutSauce(connect=timeout, read=timeout)
      
              try:
                  resp = conn.urlopen(
                      method=request.method,
                      url=url,
                      body=request.body,
                      headers=request.headers,
                      redirect=False,
                      assert_same_host=False,
                      preload_content=False,
                      decode_content=False,
                      retries=self.max_retries,
                      timeout=timeout,
                      chunked=chunked,
                  )
      
              except (ProtocolError, OSError) as err:
                  raise ConnectionError(err, request=request)
      
              except MaxRetryError as e:
                  if isinstance(e.reason, ConnectTimeoutError):
                      # TODO: Remove this in 3.0.0: see #2811
                      if not isinstance(e.reason, NewConnectionError):
                          raise ConnectTimeout(e, request=request)
      
                  if isinstance(e.reason, ResponseError):
                      raise RetryError(e, request=request)
      
                  if isinstance(e.reason, _ProxyError):
                      raise ProxyError(e, request=request)
      
                  if isinstance(e.reason, _SSLError):
                      # This branch is for urllib3 v1.22 and later.
                      raise SSLError(e, request=request)
      
      >           raise ConnectionError(e, request=request)
      E           requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/ (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09830f40>: Failed to establish a new connection: [Errno 111] Connection refused'))
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:700: ConnectionError
      
      During handling of the above exception, another exception occurred:
      
      self = <urllib3.connection.HTTPConnection object at 0x7feb098025b0>
      
          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,
                  )
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:199: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/connection.py:85: in create_connection
          raise err
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      address = ('localhost', 8080), 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 111] Connection refused
      
      /root/mambaforge/envs/ci-env/lib/python3.8/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 0x7feb09830640>
      method = 'GET', url = '/demo/None', body = None
      headers = {'User-Agent': 'python-requests/2.32.4', 'Accept-Encoding': 'gzip, deflate, br, zstd', 'Accept': '*/*', 'Connection': 'keep-alive', 'Cookie': 'unm=robot;upwd=me1T.2jUUqQNa1wNuey9zNBOmOa4eILOaPb.ZSZjpn4;'}
      retries = Retry(total=0, connect=None, read=False, redirect=None, status=None)
      redirect = False, assert_same_host = False
      timeout = Timeout(connect=None, read=None, total=None), pool_timeout = None
      release_conn = False, chunked = False, body_pos = None, preload_content = False
      decode_content = False, response_kw = {}
      parsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/demo/None', 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,
                  )
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:789: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:495: in _make_request
          conn.request(
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:441: in request
          self.endheaders()
      /root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1251: in endheaders
          self._send_output(message_body, encode_chunked=encode_chunked)
      /root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1011: in _send_output
          self.send(msg)
      /root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:951: in send
          self.connect()
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:279: in connect
          self.sock = self._new_conn()
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      self = <urllib3.connection.HTTPConnection object at 0x7feb098025b0>
      
          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 0x7feb098025b0>: Failed to establish a new connection: [Errno 111] Connection refused
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:214: NewConnectionError
      
      The above exception was the direct cause of the following exception:
      
      self = <requests.adapters.HTTPAdapter object at 0x7feb098307f0>
      request = <PreparedRequest [GET]>, stream = False
      timeout = Timeout(connect=None, read=None, total=None), verify = False
      cert = None, proxies = OrderedDict()
      
          def send(
              self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
          ):
              """Sends PreparedRequest object. Returns Response object.
      
              :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
              :param stream: (optional) Whether to stream the request content.
              :param timeout: (optional) How long to wait for the server to send
                  data before giving up, as a float, or a :ref:`(connect timeout,
                  read timeout) <timeouts>` tuple.
              :type timeout: float or tuple or urllib3 Timeout object
              :param verify: (optional) Either a boolean, in which case it controls whether
                  we verify the server's TLS certificate, or a string, in which case it
                  must be a path to a CA bundle to use
              :param cert: (optional) Any user-provided SSL certificate to be trusted.
              :param proxies: (optional) The proxies dictionary to apply to the request.
              :rtype: requests.Response
              """
      
              try:
                  conn = self.get_connection_with_tls_context(
                      request, verify, proxies=proxies, cert=cert
                  )
              except LocationValueError as e:
                  raise InvalidURL(e, request=request)
      
              self.cert_verify(conn, request.url, verify, cert)
              url = self.request_url(request, proxies)
              self.add_headers(
                  request,
                  stream=stream,
                  timeout=timeout,
                  verify=verify,
                  cert=cert,
                  proxies=proxies,
              )
      
              chunked = not (request.body is None or "Content-Length" in request.headers)
      
              if isinstance(timeout, tuple):
                  try:
                      connect, read = timeout
                      timeout = TimeoutSauce(connect=connect, read=read)
                  except ValueError:
                      raise ValueError(
                          f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                          f"or a single float to set both timeouts to the same value."
                      )
              elif isinstance(timeout, TimeoutSauce):
                  pass
              else:
                  timeout = TimeoutSauce(connect=timeout, read=timeout)
      
              try:
      >           resp = conn.urlopen(
                      method=request.method,
                      url=url,
                      body=request.body,
                      headers=request.headers,
                      redirect=False,
                      assert_same_host=False,
                      preload_content=False,
                      decode_content=False,
                      retries=self.max_retries,
                      timeout=timeout,
                      chunked=chunked,
                  )
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:667: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:843: in urlopen
          retries = retries.increment(
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      self = Retry(total=0, connect=None, read=False, redirect=None, status=None)
      method = 'GET', url = '/demo/None', response = None
      error = NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb098025b0>: Failed to establish a new connection: [Errno 111] Connection refused')
      _pool = <urllib3.connectionpool.HTTPConnectionPool object at 0x7feb09830640>
      _stacktrace = <traceback object at 0x7feb09803440>
      
          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: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb098025b0>: Failed to establish a new connection: [Errno 111] Connection refused'))
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/retry.py:519: MaxRetryError
      
      During handling of the above exception, another exception occurred:
      
      self = <elog.logbook.Logbook object at 0x7feb05e26fd0>, msg_id = None
      timeout = None
      
          def _check_if_message_on_server(self, msg_id, timeout=None):
              """Try to load page for specific message. If there is a html tag like <td class="errormsg"> then there is no
              such message.
      
              :param msg_id: ID of message to be checked
              :params timeout: The value of timeout to be passed to the get request
              :return:
              """
      
              request_headers = dict()
              if self._user or self._password:
                  request_headers['Cookie'] = self._make_user_and_pswd_cookie()
              try:
      >           response = requests.get(self._url + str(msg_id), headers=request_headers, allow_redirects=False,
                                          verify=False, timeout=timeout)
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:581: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:73: in get
          return request("get", url, params=params, **kwargs)
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:59: in request
          return session.request(method=method, url=url, **kwargs)
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:589: in request
          resp = self.send(prep, **send_kwargs)
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:703: in send
          r = adapter.send(request, **kwargs)
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      self = <requests.adapters.HTTPAdapter object at 0x7feb098307f0>
      request = <PreparedRequest [GET]>, stream = False
      timeout = Timeout(connect=None, read=None, total=None), verify = False
      cert = None, proxies = OrderedDict()
      
          def send(
              self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
          ):
              """Sends PreparedRequest object. Returns Response object.
      
              :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
              :param stream: (optional) Whether to stream the request content.
              :param timeout: (optional) How long to wait for the server to send
                  data before giving up, as a float, or a :ref:`(connect timeout,
                  read timeout) <timeouts>` tuple.
              :type timeout: float or tuple or urllib3 Timeout object
              :param verify: (optional) Either a boolean, in which case it controls whether
                  we verify the server's TLS certificate, or a string, in which case it
                  must be a path to a CA bundle to use
              :param cert: (optional) Any user-provided SSL certificate to be trusted.
              :param proxies: (optional) The proxies dictionary to apply to the request.
              :rtype: requests.Response
              """
      
              try:
                  conn = self.get_connection_with_tls_context(
                      request, verify, proxies=proxies, cert=cert
                  )
              except LocationValueError as e:
                  raise InvalidURL(e, request=request)
      
              self.cert_verify(conn, request.url, verify, cert)
              url = self.request_url(request, proxies)
              self.add_headers(
                  request,
                  stream=stream,
                  timeout=timeout,
                  verify=verify,
                  cert=cert,
                  proxies=proxies,
              )
      
              chunked = not (request.body is None or "Content-Length" in request.headers)
      
              if isinstance(timeout, tuple):
                  try:
                      connect, read = timeout
                      timeout = TimeoutSauce(connect=connect, read=read)
                  except ValueError:
                      raise ValueError(
                          f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                          f"or a single float to set both timeouts to the same value."
                      )
              elif isinstance(timeout, TimeoutSauce):
                  pass
              else:
                  timeout = TimeoutSauce(connect=timeout, read=timeout)
      
              try:
                  resp = conn.urlopen(
                      method=request.method,
                      url=url,
                      body=request.body,
                      headers=request.headers,
                      redirect=False,
                      assert_same_host=False,
                      preload_content=False,
                      decode_content=False,
                      retries=self.max_retries,
                      timeout=timeout,
                      chunked=chunked,
                  )
      
              except (ProtocolError, OSError) as err:
                  raise ConnectionError(err, request=request)
      
              except MaxRetryError as e:
                  if isinstance(e.reason, ConnectTimeoutError):
                      # TODO: Remove this in 3.0.0: see #2811
                      if not isinstance(e.reason, NewConnectionError):
                          raise ConnectTimeout(e, request=request)
      
                  if isinstance(e.reason, ResponseError):
                      raise RetryError(e, request=request)
      
                  if isinstance(e.reason, _ProxyError):
                      raise ProxyError(e, request=request)
      
                  if isinstance(e.reason, _SSLError):
                      # This branch is for urllib3 v1.22 and later.
                      raise SSLError(e, request=request)
      
      >           raise ConnectionError(e, request=request)
      E           requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb098025b0>: Failed to establish a new connection: [Errno 111] Connection refused'))
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:700: ConnectionError
      
      During handling of the above exception, another exception occurred:
      
      mock_home = <MagicMock name='home' id='140647452478240'>
      mock_getpass = <MagicMock name='getpass' id='140647452477088'>
      
          @patch("slic.utils.elog.getpass")
          @patch("slic.utils.elog.Path.home")
          def test_get_default_elog_instance_asks_password_and_opens(mock_home, mock_getpass):
              mock_home.return_value = Path("/does/not/exist")  # Fausse home → lecture échoue
              mock_getpass.return_value = "testpassword"
              user = "robot"
              text = "This is a message2"
              url = "http://localhost:8080/demo"
      
              elog = Elog("http://localhost:8080/demo", user=user)
      
              try:
      >           msd_id = elog.post(text)
      
      tests/test_utils_elog.py:55: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      slic/utils/elog.py:16: in post
          return self._log.post(*args, **kwargs)
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:307: in post
          self._check_if_message_on_server(msg_id)  # raises exceptions if no message or no response from server
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      self = <elog.logbook.Logbook object at 0x7feb05e26fd0>, msg_id = None
      timeout = None
      
          def _check_if_message_on_server(self, msg_id, timeout=None):
              """Try to load page for specific message. If there is a html tag like <td class="errormsg"> then there is no
              such message.
      
              :param msg_id: ID of message to be checked
              :params timeout: The value of timeout to be passed to the get request
              :return:
              """
      
              request_headers = dict()
              if self._user or self._password:
                  request_headers['Cookie'] = self._make_user_and_pswd_cookie()
              try:
                  response = requests.get(self._url + str(msg_id), headers=request_headers, allow_redirects=False,
                                          verify=False, timeout=timeout)
      
                  # If there is no message code 200 will be returned (OK) and _validate_response will not recognise it
                  # but there will be some error in the html code.
                  resp_message, resp_headers, resp_msg_id = _validate_response(response)
                  # If there is no message, code 200 will be returned (OK) but there will be some error indication in
                  # the html code.
                  if re.findall('<td.*?class="errormsg".*?>.*?</td>',
                                resp_message.decode('utf-8', 'ignore'),
                                flags=re.DOTALL):
                      raise LogbookInvalidMessageID('Message with ID: ' + str(msg_id) + ' does not exist on logbook.')
      
              except requests.Timeout as e:
                  # Catch here a timeout o the post request.
                  # Raise the logbook exception and let the user handle it
                  raise LogbookServerTimeout('{0} method cannot be completed because of a network timeout:\n' +
                                             '{1}'.format(sys._getframe().f_code.co_name, e))
      
              except requests.RequestException as e:
      >           raise LogbookServerProblem('No response from the logbook server.\nDetails: ' + '{0}'.format(e))
      E           elog.logbook_exceptions.LogbookServerProblem: No response from the logbook server.
      E           Details: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb098025b0>: Failed to establish a new connection: [Errno 111] Connection refused'))
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:601: LogbookServerProblem
      
      During handling of the above exception, another exception occurred:
      
      mock_home = <MagicMock name='home' id='140647452478240'>
      mock_getpass = <MagicMock name='getpass' id='140647452477088'>
      
          @patch("slic.utils.elog.getpass")
          @patch("slic.utils.elog.Path.home")
          def test_get_default_elog_instance_asks_password_and_opens(mock_home, mock_getpass):
              mock_home.return_value = Path("/does/not/exist")  # Fausse home → lecture échoue
              mock_getpass.return_value = "testpassword"
              user = "robot"
              text = "This is a message2"
              url = "http://localhost:8080/demo"
      
              elog = Elog("http://localhost:8080/demo", user=user)
      
              try:
                  msd_id = elog.post(text)
              except Exception as e:
      >           pytest.fail(f"elog.post() raised an unexpected exception: {e}")
      E           Failed: elog.post() raised an unexpected exception: No response from the logbook server.
      E           Details: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb098025b0>: Failed to establish a new connection: [Errno 111] Connection refused'))
      
      tests/test_utils_elog.py:57: Failed
      

      📌 Teardown phase

      duration:

      0.0003665182739496231
      

      outcome:

      passed
      

    Function: test_get_default_elog_with_path_home

    • Test 180

      📌 Setup phase

      duration:

      0.00018758885562419891
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.009295018389821053
      

      outcome:

      failed
      

      crash:

      path: /workspace/tligui_y/slic/tests/test_utils_elog.py
      lineno: 92
      message: Failed: elog.post() raised an unexpected exception: No response from the logbook server.
      Details: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb098b2bb0>: Failed to establish a new connection: [Errno 111] Connection refused'))
      

      traceback:

      -   path: tests/test_utils_elog.py
        lineno: 92
        message: Failed
      

      longrepr:

      self = <urllib3.connection.HTTPConnection object at 0x7feb09937130>
      
          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,
                  )
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:199: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/connection.py:85: in create_connection
          raise err
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      address = ('localhost', 8080), 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 111] Connection refused
      
      /root/mambaforge/envs/ci-env/lib/python3.8/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 0x7feb09937670>
      method = 'POST', url = '/demo/'
      body = b'--e76de29c11540daf53cb0ad4febce9b6\r\nContent-Disposition: form-data; name="Author"\r\n\r\nrobot\r\n--e76de29c11540d...Disposition: form-data; name="Text"; filename=""\r\n\r\nThis is a message3\r\n--e76de29c11540daf53cb0ad4febce9b6--\r\n'
      headers = {'User-Agent': 'python-requests/2.32.4', 'Accept-Encoding': 'gzip, deflate, br, zstd', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '736', 'Content-Type': 'multipart/form-data; boundary=e76de29c11540daf53cb0ad4febce9b6'}
      retries = Retry(total=0, connect=None, read=False, redirect=None, status=None)
      redirect = False, assert_same_host = False
      timeout = Timeout(connect=None, read=None, total=None), pool_timeout = None
      release_conn = False, chunked = False, body_pos = None, preload_content = False
      decode_content = False, response_kw = {}
      parsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/demo/', 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,
                  )
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:789: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:495: in _make_request
          conn.request(
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:441: in request
          self.endheaders()
      /root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1251: in endheaders
          self._send_output(message_body, encode_chunked=encode_chunked)
      /root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1011: in _send_output
          self.send(msg)
      /root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:951: in send
          self.connect()
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:279: in connect
          self.sock = self._new_conn()
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      self = <urllib3.connection.HTTPConnection object at 0x7feb09937130>
      
          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 0x7feb09937130>: Failed to establish a new connection: [Errno 111] Connection refused
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:214: NewConnectionError
      
      The above exception was the direct cause of the following exception:
      
      self = <requests.adapters.HTTPAdapter object at 0x7feb09937850>
      request = <PreparedRequest [POST]>, stream = False
      timeout = Timeout(connect=None, read=None, total=None), verify = False
      cert = None, proxies = OrderedDict()
      
          def send(
              self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
          ):
              """Sends PreparedRequest object. Returns Response object.
      
              :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
              :param stream: (optional) Whether to stream the request content.
              :param timeout: (optional) How long to wait for the server to send
                  data before giving up, as a float, or a :ref:`(connect timeout,
                  read timeout) <timeouts>` tuple.
              :type timeout: float or tuple or urllib3 Timeout object
              :param verify: (optional) Either a boolean, in which case it controls whether
                  we verify the server's TLS certificate, or a string, in which case it
                  must be a path to a CA bundle to use
              :param cert: (optional) Any user-provided SSL certificate to be trusted.
              :param proxies: (optional) The proxies dictionary to apply to the request.
              :rtype: requests.Response
              """
      
              try:
                  conn = self.get_connection_with_tls_context(
                      request, verify, proxies=proxies, cert=cert
                  )
              except LocationValueError as e:
                  raise InvalidURL(e, request=request)
      
              self.cert_verify(conn, request.url, verify, cert)
              url = self.request_url(request, proxies)
              self.add_headers(
                  request,
                  stream=stream,
                  timeout=timeout,
                  verify=verify,
                  cert=cert,
                  proxies=proxies,
              )
      
              chunked = not (request.body is None or "Content-Length" in request.headers)
      
              if isinstance(timeout, tuple):
                  try:
                      connect, read = timeout
                      timeout = TimeoutSauce(connect=connect, read=read)
                  except ValueError:
                      raise ValueError(
                          f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                          f"or a single float to set both timeouts to the same value."
                      )
              elif isinstance(timeout, TimeoutSauce):
                  pass
              else:
                  timeout = TimeoutSauce(connect=timeout, read=timeout)
      
              try:
      >           resp = conn.urlopen(
                      method=request.method,
                      url=url,
                      body=request.body,
                      headers=request.headers,
                      redirect=False,
                      assert_same_host=False,
                      preload_content=False,
                      decode_content=False,
                      retries=self.max_retries,
                      timeout=timeout,
                      chunked=chunked,
                  )
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:667: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:843: in urlopen
          retries = retries.increment(
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      self = Retry(total=0, connect=None, read=False, redirect=None, status=None)
      method = 'POST', url = '/demo/', response = None
      error = NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09937130>: Failed to establish a new connection: [Errno 111] Connection refused')
      _pool = <urllib3.connectionpool.HTTPConnectionPool object at 0x7feb09937670>
      _stacktrace = <traceback object at 0x7feb0965e740>
      
          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: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/ (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09937130>: Failed to establish a new connection: [Errno 111] Connection refused'))
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/retry.py:519: MaxRetryError
      
      During handling of the above exception, another exception occurred:
      
      self = <elog.logbook.Logbook object at 0x7feb09937280>
      message = 'This is a message3', msg_id = None, reply = False
      attributes = {'Author': 'robot', 'When': 1756376002, 'cmd': 'Submit', 'exp': 'demo', ...}
      attachments = [], suppress_email_notification = False, encoding = None
      timeout = None, kwargs = {'Author': 'robot'}
      new_attachment_list = [('Text', ('', b'This is a message3'))]
      objects_to_close = []
      attributes_to_edit = {'Author': b'robot', 'When': 1756376002, 'cmd': b'Submit', 'exp': b'demo', ...}
      
          def post(self, message, msg_id=None, reply=False, attributes=None, attachments=None,
                   suppress_email_notification=False, encoding=None, timeout=None, **kwargs):
              """
              Posts message to the logbook. If msg_id is not specified new message will be created, otherwise existing
              message will be edited, or a reply (if reply=True) to it will be created. This method returns the msg_id
              of the newly created message.
      
              :param message: string with message text
              :param msg_id: ID number of message to edit or reply. If not specified new message is created.
              :param reply: If 'True' reply to existing message is created instead of editing it
              :param attributes: Dictionary of attributes. Following attributes are used internally by the elog and will be
                                 ignored: Text, Date, Encoding, Reply to, In reply to, Locked by, Attachment
              :param attachments: list of:
                                        - file like objects which read() will return bytes (if file_like_object.name is not
                                          defined, default name "attachment<i>" will be used.
                                        - paths to the files
                                  All items will be appended as attachment to the elog entry. In case of unknown
                                  attachment an exception LogbookInvalidAttachment will be raised.
              :param suppress_email_notification: If set to True or 1, E-Mail notification will be suppressed, defaults to False.
              :param encoding: Defines encoding of the message. Can be: 'plain' -> plain text, 'html'->html-text,
                               'ELCode' --> elog formatting syntax
              :param timeout: Define the timeout to be used by the post request. Its value is directly passed to the requests
                              post. Use None to disable the request timeout.
              :param kwargs: Anything in the kwargs will be interpreted as attribute. e.g.: logbook.post('Test text',
                             Author='Rok Vintar), "Author" will be sent as an attribute. If named same as one of the
                             attributes defined in "attributes", kwargs will have priority.
      
              :return: msg_id
              """
      
              attributes = attributes or {}
              attributes = {**attributes, **kwargs}  # kwargs as attributes with higher priority
      
              attachments = attachments or []
      
              if encoding is not None:
                  if encoding not in ['plain', 'HTML', 'ELCode']:
                      raise LogbookMessageRejected('Invalid message encoding. Valid options: plain, HTML, ELCode.')
                  attributes['Encoding'] = encoding
      
              if suppress_email_notification:
                  attributes["suppress"] = 1
      
              # THE ATTACHMENT STRATEGY WHEN DEALING WITH POST MODIFICATION
              #
              # 1. Does the message on the server have already attachments?
              #    1.1 - We read the message getting the existing attachment list.
              #    1.2 - Add to the attributes dictionary one line for each attachment like this:
              #       attributes['attachmentN'] = timestamped_filename_name
              #
              # 2. Do we have new attachments?
              #    2.1 - Those are in the new_attachment_list. This is a list of this type:
              #       [ ('attfileN', ('filename', fileobject)) ]
              #    2.2 - We need to loop over all the new attachments:
              #       2.2.1 - Does a file already on the server with the same name exist?
              #         2.2.1.1 - No: OK. Then we go ahead with the next attachment.
              #         2.2.1.2 - Yes:
              #           2.2.1.2.1 - Are the two files identical?
              #               2.2.1.2.1.1 - Yes: then we remove this current entry from the new_attachment_list and we leave the one
              #                      already on server.
              #               2.2.1.2.1.2 - No:
              #                  2.2.1.2.1.2.1 - Then the file has been update.
              #                  2.2.1.2.1.2.2 - We need to remove the file on server first (using special post)
              #                  2.2.1.2.1.2.3 - We have to remove the old attachment from the attributes dictionary.
              #
      
              if attachments:
                  # here we accomplish point 2.1.
                  # new_attachment_list is something like [ ('attfileN', ('filename', fileobject)) ]
                  new_attachment_list, objects_to_close = self._prepare_attachments(attachments)
              else:
                  objects_to_close = list()
                  new_attachment_list = list()
      
              attributes_to_edit = dict()
              if msg_id:
                  # Message exists, we can continue
                  if reply:
                      # Verify that there is a message on the server, otherwise do not reply to it!
                      self._check_if_message_on_server(msg_id)  # raises exception in case of none existing message
                      attributes['reply_to'] = str(msg_id)
                  else:  # Edit existing
                      attributes['edit_id'] = str(msg_id)
                      attributes['skiplock'] = '1'
      
                      # here we accomplish point 1.1.
                      # existing_attachments_list is something like:
                      # [ 'https://elog.url.com/logbook/timestamped_filename' ]
                      msg_to_edit, attributes_to_edit, existing_attachments_list = self.read(msg_id)
      
                      for attribute, data in attributes.items():
                          new_data = attributes.get(attribute)
                          if new_data is not None:
                              attributes_to_edit[attribute] = new_data
      
                      i = 0
                      existing_attachments_filename_list = list()
                      for attachment in existing_attachments_list:
                          # here we accomplish point 1.2. We strip the timestamped_filename from the whole URL.
                          attributes_to_edit[f'attachment{i}'] = os.path.basename(attachment)
                          existing_attachments_filename_list.append(os.path.basename(attachment)[14:])
                          i += 1
      
                      # let's accomplish 2.2. Loop over all new attachment
                      duplicate_attachment_list = list()
                      for new_attachment in new_attachment_list:
                          # the new_attachment_list is something like:
                          # [ ('attfileN', ('filename', fileobject)) ]
                          new_attachment_filename = new_attachment[1][0]
                          if new_attachment_filename in existing_attachments_filename_list:
                              # a file with the same name existing already on the server.
                              # we need to check if the two files are the same.
                              # read the content of the new file
                              new_attachment_content = new_attachment[1][1].read()
                              # don't forget to reset the fileobj to the beginning of the file
                              new_attachment[1][1].seek(0)
                              # get the existing attachment content
                              attachment_index = existing_attachments_filename_list.index(new_attachment_filename)
                              existing_attachment_content = self.download_attachment(
                                  url=existing_attachments_list[attachment_index],
                                  timeout=timeout
                              )
                              # check if the two contents are the same
                              if new_attachment_content == existing_attachment_content:
                                  # yes. then we don't upload a second copy. we remove the current entry from the list
                                  duplicate_attachment_list.append(new_attachment)
                              else:
                                  # no. they are not the same file. we will replace the existing file with the new one
                                  # first: we need to remove the attachment from the server using the dedicated method
                                  self.delete_attachment(msg_id, attributes=attributes_to_edit,
                                                         attachment_id=attachment_index,
                                                         timeout=timeout, text=msg_to_edit)
                                  # now we can remove this attachment from the auxiliary lists.
                                  existing_attachments_filename_list.pop(attachment_index)
                                  existing_attachments_list.pop(attachment_index)
                                  # now we need to rebuild the attributes dictionary for the part concerning the attachments.
                                  # we remove all of them first
                                  keys_to_be_removed = list()
                                  for key in attributes_to_edit.keys():
                                      if key.startswith('attachment'):
                                          keys_to_be_removed.append(key)
                                      if key.startswith('delatt'):
                                          keys_to_be_removed.append(key)
                                  for key in keys_to_be_removed:
                                      del attributes_to_edit[key]
      
                                  # now we rebuild it
                                  for i, attachment in enumerate(existing_attachments_list):
                                      attributes_to_edit[f'attachment{i}'] = os.path.basename(attachment)
      
                      # remove all duplicate attachments from the new_attachment_list
                      for attach in duplicate_attachment_list:
                          new_attachment_list.remove(attach)
      
              else:
                  # As we create a new message, specify creation time if not already specified in attributes
                  if 'When' not in attributes:
                      attributes['When'] = int(datetime.now().timestamp())
      
              if not attributes_to_edit:
                  attributes_to_edit = attributes
      
              # Remove any attributes that should not be sent
              _remove_reserved_attributes(attributes_to_edit)
      
              # Make requests module think that Text is a "file". This is the only way to force requests to send data as
              # multipart/form-data even if there are no attachments. Elog understands only multipart/form-data
              new_attachment_list.append(('Text', ('', message.encode('iso-8859-1'))))
      
              # Base attributes are common to all messages
              self._add_base_msg_attributes(attributes_to_edit)
      
              # Keys in attributes cannot have certain characters like whitespaces or dashes for the http request
              attributes_to_edit = _replace_special_characters_in_attribute_keys(attributes_to_edit)
      
              # All string values in the attributes must be encoded in latin1
              attributes_to_edit = _encode_values(attributes_to_edit)
      
              try:
      >           response = requests.post(self._url, data=attributes_to_edit, files=new_attachment_list,
                                           allow_redirects=False, verify=False, timeout=timeout)
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:288: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:115: in post
          return request("post", url, data=data, json=json, **kwargs)
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:59: in request
          return session.request(method=method, url=url, **kwargs)
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:589: in request
          resp = self.send(prep, **send_kwargs)
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:703: in send
          r = adapter.send(request, **kwargs)
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      self = <requests.adapters.HTTPAdapter object at 0x7feb09937850>
      request = <PreparedRequest [POST]>, stream = False
      timeout = Timeout(connect=None, read=None, total=None), verify = False
      cert = None, proxies = OrderedDict()
      
          def send(
              self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
          ):
              """Sends PreparedRequest object. Returns Response object.
      
              :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
              :param stream: (optional) Whether to stream the request content.
              :param timeout: (optional) How long to wait for the server to send
                  data before giving up, as a float, or a :ref:`(connect timeout,
                  read timeout) <timeouts>` tuple.
              :type timeout: float or tuple or urllib3 Timeout object
              :param verify: (optional) Either a boolean, in which case it controls whether
                  we verify the server's TLS certificate, or a string, in which case it
                  must be a path to a CA bundle to use
              :param cert: (optional) Any user-provided SSL certificate to be trusted.
              :param proxies: (optional) The proxies dictionary to apply to the request.
              :rtype: requests.Response
              """
      
              try:
                  conn = self.get_connection_with_tls_context(
                      request, verify, proxies=proxies, cert=cert
                  )
              except LocationValueError as e:
                  raise InvalidURL(e, request=request)
      
              self.cert_verify(conn, request.url, verify, cert)
              url = self.request_url(request, proxies)
              self.add_headers(
                  request,
                  stream=stream,
                  timeout=timeout,
                  verify=verify,
                  cert=cert,
                  proxies=proxies,
              )
      
              chunked = not (request.body is None or "Content-Length" in request.headers)
      
              if isinstance(timeout, tuple):
                  try:
                      connect, read = timeout
                      timeout = TimeoutSauce(connect=connect, read=read)
                  except ValueError:
                      raise ValueError(
                          f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                          f"or a single float to set both timeouts to the same value."
                      )
              elif isinstance(timeout, TimeoutSauce):
                  pass
              else:
                  timeout = TimeoutSauce(connect=timeout, read=timeout)
      
              try:
                  resp = conn.urlopen(
                      method=request.method,
                      url=url,
                      body=request.body,
                      headers=request.headers,
                      redirect=False,
                      assert_same_host=False,
                      preload_content=False,
                      decode_content=False,
                      retries=self.max_retries,
                      timeout=timeout,
                      chunked=chunked,
                  )
      
              except (ProtocolError, OSError) as err:
                  raise ConnectionError(err, request=request)
      
              except MaxRetryError as e:
                  if isinstance(e.reason, ConnectTimeoutError):
                      # TODO: Remove this in 3.0.0: see #2811
                      if not isinstance(e.reason, NewConnectionError):
                          raise ConnectTimeout(e, request=request)
      
                  if isinstance(e.reason, ResponseError):
                      raise RetryError(e, request=request)
      
                  if isinstance(e.reason, _ProxyError):
                      raise ProxyError(e, request=request)
      
                  if isinstance(e.reason, _SSLError):
                      # This branch is for urllib3 v1.22 and later.
                      raise SSLError(e, request=request)
      
      >           raise ConnectionError(e, request=request)
      E           requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/ (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09937130>: Failed to establish a new connection: [Errno 111] Connection refused'))
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:700: ConnectionError
      
      During handling of the above exception, another exception occurred:
      
      self = <urllib3.connection.HTTPConnection object at 0x7feb098b2bb0>
      
          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,
                  )
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:199: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/connection.py:85: in create_connection
          raise err
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      address = ('localhost', 8080), 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 111] Connection refused
      
      /root/mambaforge/envs/ci-env/lib/python3.8/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 0x7feb098b2730>
      method = 'GET', url = '/demo/None', body = None
      headers = {'User-Agent': 'python-requests/2.32.4', 'Accept-Encoding': 'gzip, deflate, br, zstd', 'Accept': '*/*', 'Connection': 'keep-alive', 'Cookie': 'unm=robot;upwd=me1T.2jUUqQNa1wNuey9zNBOmOa4eILOaPb.ZSZjpn4;'}
      retries = Retry(total=0, connect=None, read=False, redirect=None, status=None)
      redirect = False, assert_same_host = False
      timeout = Timeout(connect=None, read=None, total=None), pool_timeout = None
      release_conn = False, chunked = False, body_pos = None, preload_content = False
      decode_content = False, response_kw = {}
      parsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/demo/None', 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,
                  )
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:789: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:495: in _make_request
          conn.request(
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:441: in request
          self.endheaders()
      /root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1251: in endheaders
          self._send_output(message_body, encode_chunked=encode_chunked)
      /root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1011: in _send_output
          self.send(msg)
      /root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:951: in send
          self.connect()
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:279: in connect
          self.sock = self._new_conn()
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      self = <urllib3.connection.HTTPConnection object at 0x7feb098b2bb0>
      
          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 0x7feb098b2bb0>: Failed to establish a new connection: [Errno 111] Connection refused
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:214: NewConnectionError
      
      The above exception was the direct cause of the following exception:
      
      self = <requests.adapters.HTTPAdapter object at 0x7feb098b25b0>
      request = <PreparedRequest [GET]>, stream = False
      timeout = Timeout(connect=None, read=None, total=None), verify = False
      cert = None, proxies = OrderedDict()
      
          def send(
              self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
          ):
              """Sends PreparedRequest object. Returns Response object.
      
              :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
              :param stream: (optional) Whether to stream the request content.
              :param timeout: (optional) How long to wait for the server to send
                  data before giving up, as a float, or a :ref:`(connect timeout,
                  read timeout) <timeouts>` tuple.
              :type timeout: float or tuple or urllib3 Timeout object
              :param verify: (optional) Either a boolean, in which case it controls whether
                  we verify the server's TLS certificate, or a string, in which case it
                  must be a path to a CA bundle to use
              :param cert: (optional) Any user-provided SSL certificate to be trusted.
              :param proxies: (optional) The proxies dictionary to apply to the request.
              :rtype: requests.Response
              """
      
              try:
                  conn = self.get_connection_with_tls_context(
                      request, verify, proxies=proxies, cert=cert
                  )
              except LocationValueError as e:
                  raise InvalidURL(e, request=request)
      
              self.cert_verify(conn, request.url, verify, cert)
              url = self.request_url(request, proxies)
              self.add_headers(
                  request,
                  stream=stream,
                  timeout=timeout,
                  verify=verify,
                  cert=cert,
                  proxies=proxies,
              )
      
              chunked = not (request.body is None or "Content-Length" in request.headers)
      
              if isinstance(timeout, tuple):
                  try:
                      connect, read = timeout
                      timeout = TimeoutSauce(connect=connect, read=read)
                  except ValueError:
                      raise ValueError(
                          f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                          f"or a single float to set both timeouts to the same value."
                      )
              elif isinstance(timeout, TimeoutSauce):
                  pass
              else:
                  timeout = TimeoutSauce(connect=timeout, read=timeout)
      
              try:
      >           resp = conn.urlopen(
                      method=request.method,
                      url=url,
                      body=request.body,
                      headers=request.headers,
                      redirect=False,
                      assert_same_host=False,
                      preload_content=False,
                      decode_content=False,
                      retries=self.max_retries,
                      timeout=timeout,
                      chunked=chunked,
                  )
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:667: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:843: in urlopen
          retries = retries.increment(
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      self = Retry(total=0, connect=None, read=False, redirect=None, status=None)
      method = 'GET', url = '/demo/None', response = None
      error = NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb098b2bb0>: Failed to establish a new connection: [Errno 111] Connection refused')
      _pool = <urllib3.connectionpool.HTTPConnectionPool object at 0x7feb098b2730>
      _stacktrace = <traceback object at 0x7feb097c29c0>
      
          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: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb098b2bb0>: Failed to establish a new connection: [Errno 111] Connection refused'))
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/retry.py:519: MaxRetryError
      
      During handling of the above exception, another exception occurred:
      
      self = <elog.logbook.Logbook object at 0x7feb09937280>, msg_id = None
      timeout = None
      
          def _check_if_message_on_server(self, msg_id, timeout=None):
              """Try to load page for specific message. If there is a html tag like <td class="errormsg"> then there is no
              such message.
      
              :param msg_id: ID of message to be checked
              :params timeout: The value of timeout to be passed to the get request
              :return:
              """
      
              request_headers = dict()
              if self._user or self._password:
                  request_headers['Cookie'] = self._make_user_and_pswd_cookie()
              try:
      >           response = requests.get(self._url + str(msg_id), headers=request_headers, allow_redirects=False,
                                          verify=False, timeout=timeout)
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:581: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:73: in get
          return request("get", url, params=params, **kwargs)
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:59: in request
          return session.request(method=method, url=url, **kwargs)
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:589: in request
          resp = self.send(prep, **send_kwargs)
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:703: in send
          r = adapter.send(request, **kwargs)
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      self = <requests.adapters.HTTPAdapter object at 0x7feb098b25b0>
      request = <PreparedRequest [GET]>, stream = False
      timeout = Timeout(connect=None, read=None, total=None), verify = False
      cert = None, proxies = OrderedDict()
      
          def send(
              self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
          ):
              """Sends PreparedRequest object. Returns Response object.
      
              :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
              :param stream: (optional) Whether to stream the request content.
              :param timeout: (optional) How long to wait for the server to send
                  data before giving up, as a float, or a :ref:`(connect timeout,
                  read timeout) <timeouts>` tuple.
              :type timeout: float or tuple or urllib3 Timeout object
              :param verify: (optional) Either a boolean, in which case it controls whether
                  we verify the server's TLS certificate, or a string, in which case it
                  must be a path to a CA bundle to use
              :param cert: (optional) Any user-provided SSL certificate to be trusted.
              :param proxies: (optional) The proxies dictionary to apply to the request.
              :rtype: requests.Response
              """
      
              try:
                  conn = self.get_connection_with_tls_context(
                      request, verify, proxies=proxies, cert=cert
                  )
              except LocationValueError as e:
                  raise InvalidURL(e, request=request)
      
              self.cert_verify(conn, request.url, verify, cert)
              url = self.request_url(request, proxies)
              self.add_headers(
                  request,
                  stream=stream,
                  timeout=timeout,
                  verify=verify,
                  cert=cert,
                  proxies=proxies,
              )
      
              chunked = not (request.body is None or "Content-Length" in request.headers)
      
              if isinstance(timeout, tuple):
                  try:
                      connect, read = timeout
                      timeout = TimeoutSauce(connect=connect, read=read)
                  except ValueError:
                      raise ValueError(
                          f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                          f"or a single float to set both timeouts to the same value."
                      )
              elif isinstance(timeout, TimeoutSauce):
                  pass
              else:
                  timeout = TimeoutSauce(connect=timeout, read=timeout)
      
              try:
                  resp = conn.urlopen(
                      method=request.method,
                      url=url,
                      body=request.body,
                      headers=request.headers,
                      redirect=False,
                      assert_same_host=False,
                      preload_content=False,
                      decode_content=False,
                      retries=self.max_retries,
                      timeout=timeout,
                      chunked=chunked,
                  )
      
              except (ProtocolError, OSError) as err:
                  raise ConnectionError(err, request=request)
      
              except MaxRetryError as e:
                  if isinstance(e.reason, ConnectTimeoutError):
                      # TODO: Remove this in 3.0.0: see #2811
                      if not isinstance(e.reason, NewConnectionError):
                          raise ConnectTimeout(e, request=request)
      
                  if isinstance(e.reason, ResponseError):
                      raise RetryError(e, request=request)
      
                  if isinstance(e.reason, _ProxyError):
                      raise ProxyError(e, request=request)
      
                  if isinstance(e.reason, _SSLError):
                      # This branch is for urllib3 v1.22 and later.
                      raise SSLError(e, request=request)
      
      >           raise ConnectionError(e, request=request)
      E           requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb098b2bb0>: Failed to establish a new connection: [Errno 111] Connection refused'))
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:700: ConnectionError
      
      During handling of the above exception, another exception occurred:
      
      mock_home = <MagicMock name='home' id='140647451303744'>
      mock_getuser = <MagicMock name='getuser' id='140647451733824'>
      mock_getpass = <MagicMock name='getpass' id='140647453841488'>
      
          @patch("slic.utils.elog.getpass")
          @patch("slic.utils.elog.getuser")
          @patch("slic.utils.elog.Path.home")
          def test_get_default_elog_with_path_home(mock_home, mock_getuser, mock_getpass):
              fake_user = "robot"
              fake_pw = "testpassword"
              mock_getuser.return_value = fake_user
              mock_getpass.return_value = fake_pw  # fallback safety
              text = "This is a message3"
              url = "http://localhost:8080/demo"
      
              tmp_home = Path("/tmp/fake_home_for_robot")
              tmp_home.mkdir(parents=True, exist_ok=True)
              pw_file = tmp_home / ".elog_psi"
              pw_file.write_text(fake_pw)
              mock_home.return_value = tmp_home
      
              try:
                  elog = Elog("http://localhost:8080/demo")
                  try:
      >               msg_id = elog.post(text)
      
      tests/test_utils_elog.py:90: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      slic/utils/elog.py:16: in post
          return self._log.post(*args, **kwargs)
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:307: in post
          self._check_if_message_on_server(msg_id)  # raises exceptions if no message or no response from server
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      self = <elog.logbook.Logbook object at 0x7feb09937280>, msg_id = None
      timeout = None
      
          def _check_if_message_on_server(self, msg_id, timeout=None):
              """Try to load page for specific message. If there is a html tag like <td class="errormsg"> then there is no
              such message.
      
              :param msg_id: ID of message to be checked
              :params timeout: The value of timeout to be passed to the get request
              :return:
              """
      
              request_headers = dict()
              if self._user or self._password:
                  request_headers['Cookie'] = self._make_user_and_pswd_cookie()
              try:
                  response = requests.get(self._url + str(msg_id), headers=request_headers, allow_redirects=False,
                                          verify=False, timeout=timeout)
      
                  # If there is no message code 200 will be returned (OK) and _validate_response will not recognise it
                  # but there will be some error in the html code.
                  resp_message, resp_headers, resp_msg_id = _validate_response(response)
                  # If there is no message, code 200 will be returned (OK) but there will be some error indication in
                  # the html code.
                  if re.findall('<td.*?class="errormsg".*?>.*?</td>',
                                resp_message.decode('utf-8', 'ignore'),
                                flags=re.DOTALL):
                      raise LogbookInvalidMessageID('Message with ID: ' + str(msg_id) + ' does not exist on logbook.')
      
              except requests.Timeout as e:
                  # Catch here a timeout o the post request.
                  # Raise the logbook exception and let the user handle it
                  raise LogbookServerTimeout('{0} method cannot be completed because of a network timeout:\n' +
                                             '{1}'.format(sys._getframe().f_code.co_name, e))
      
              except requests.RequestException as e:
      >           raise LogbookServerProblem('No response from the logbook server.\nDetails: ' + '{0}'.format(e))
      E           elog.logbook_exceptions.LogbookServerProblem: No response from the logbook server.
      E           Details: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb098b2bb0>: Failed to establish a new connection: [Errno 111] Connection refused'))
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:601: LogbookServerProblem
      
      During handling of the above exception, another exception occurred:
      
      mock_home = <MagicMock name='home' id='140647451303744'>
      mock_getuser = <MagicMock name='getuser' id='140647451733824'>
      mock_getpass = <MagicMock name='getpass' id='140647453841488'>
      
          @patch("slic.utils.elog.getpass")
          @patch("slic.utils.elog.getuser")
          @patch("slic.utils.elog.Path.home")
          def test_get_default_elog_with_path_home(mock_home, mock_getuser, mock_getpass):
              fake_user = "robot"
              fake_pw = "testpassword"
              mock_getuser.return_value = fake_user
              mock_getpass.return_value = fake_pw  # fallback safety
              text = "This is a message3"
              url = "http://localhost:8080/demo"
      
              tmp_home = Path("/tmp/fake_home_for_robot")
              tmp_home.mkdir(parents=True, exist_ok=True)
              pw_file = tmp_home / ".elog_psi"
              pw_file.write_text(fake_pw)
              mock_home.return_value = tmp_home
      
              try:
                  elog = Elog("http://localhost:8080/demo")
                  try:
                      msg_id = elog.post(text)
                  except Exception as e:
      >               pytest.fail(f"elog.post() raised an unexpected exception: {e}")
      E               Failed: elog.post() raised an unexpected exception: No response from the logbook server.
      E               Details: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb098b2bb0>: Failed to establish a new connection: [Errno 111] Connection refused'))
      
      tests/test_utils_elog.py:92: Failed
      

      📌 Teardown phase

      duration:

      0.00034400075674057007
      

      outcome:

      passed
      

    Function: test_screenshot

    • Test 181

      📌 Setup phase

      duration:

      0.00019518006592988968
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.010428791865706444
      

      outcome:

      failed
      

      crash:

      path: /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py
      lineno: 601
      message: elog.logbook_exceptions.LogbookServerProblem: No response from the logbook server.
      Details: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09b7ea60>: Failed to establish a new connection: [Errno 111] Connection refused'))
      

      traceback:

      -   path: tests/test_utils_elog.py
        lineno: 116
        message: []
      -   path: slic/utils/elog.py
        lineno: 21
        message: in screenshot
      -   path: slic/utils/elog.py
        lineno: 16
        message: in post
      -   path: /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py
        lineno: 307
        message: in post
      -   path: /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py
        lineno: 601
        message: LogbookServerProblem
      

      longrepr:

      self = <urllib3.connection.HTTPConnection object at 0x7feb0958cb20>
      
          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,
                  )
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:199: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/connection.py:85: in create_connection
          raise err
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      address = ('localhost', 8080), 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 111] Connection refused
      
      /root/mambaforge/envs/ci-env/lib/python3.8/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 0x7feb0977c0a0>
      method = 'POST', url = '/demo/'
      body = b'--1194c6bfc5b78a946fff64f5d06636c0\r\nContent-Disposition: form-data; name="Author"\r\n\r\nrobot\r\n--1194c6bfc5b78a...-data; name="Text"; filename=""\r\n\r\nSCREENSHOT_INTEGRATION_TEST_MSG_456\r\n--1194c6bfc5b78a946fff64f5d06636c0--\r\n'
      headers = {'User-Agent': 'python-requests/2.32.4', 'Accept-Encoding': 'gzip, deflate, br, zstd', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '889', 'Content-Type': 'multipart/form-data; boundary=1194c6bfc5b78a946fff64f5d06636c0'}
      retries = Retry(total=0, connect=None, read=False, redirect=None, status=None)
      redirect = False, assert_same_host = False
      timeout = Timeout(connect=None, read=None, total=None), pool_timeout = None
      release_conn = False, chunked = False, body_pos = None, preload_content = False
      decode_content = False, response_kw = {}
      parsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/demo/', 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,
                  )
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:789: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:495: in _make_request
          conn.request(
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:441: in request
          self.endheaders()
      /root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1251: in endheaders
          self._send_output(message_body, encode_chunked=encode_chunked)
      /root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1011: in _send_output
          self.send(msg)
      /root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:951: in send
          self.connect()
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:279: in connect
          self.sock = self._new_conn()
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      self = <urllib3.connection.HTTPConnection object at 0x7feb0958cb20>
      
          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 0x7feb0958cb20>: Failed to establish a new connection: [Errno 111] Connection refused
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:214: NewConnectionError
      
      The above exception was the direct cause of the following exception:
      
      self = <requests.adapters.HTTPAdapter object at 0x7feb0958c490>
      request = <PreparedRequest [POST]>, stream = False
      timeout = Timeout(connect=None, read=None, total=None), verify = False
      cert = None, proxies = OrderedDict()
      
          def send(
              self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
          ):
              """Sends PreparedRequest object. Returns Response object.
      
              :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
              :param stream: (optional) Whether to stream the request content.
              :param timeout: (optional) How long to wait for the server to send
                  data before giving up, as a float, or a :ref:`(connect timeout,
                  read timeout) <timeouts>` tuple.
              :type timeout: float or tuple or urllib3 Timeout object
              :param verify: (optional) Either a boolean, in which case it controls whether
                  we verify the server's TLS certificate, or a string, in which case it
                  must be a path to a CA bundle to use
              :param cert: (optional) Any user-provided SSL certificate to be trusted.
              :param proxies: (optional) The proxies dictionary to apply to the request.
              :rtype: requests.Response
              """
      
              try:
                  conn = self.get_connection_with_tls_context(
                      request, verify, proxies=proxies, cert=cert
                  )
              except LocationValueError as e:
                  raise InvalidURL(e, request=request)
      
              self.cert_verify(conn, request.url, verify, cert)
              url = self.request_url(request, proxies)
              self.add_headers(
                  request,
                  stream=stream,
                  timeout=timeout,
                  verify=verify,
                  cert=cert,
                  proxies=proxies,
              )
      
              chunked = not (request.body is None or "Content-Length" in request.headers)
      
              if isinstance(timeout, tuple):
                  try:
                      connect, read = timeout
                      timeout = TimeoutSauce(connect=connect, read=read)
                  except ValueError:
                      raise ValueError(
                          f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                          f"or a single float to set both timeouts to the same value."
                      )
              elif isinstance(timeout, TimeoutSauce):
                  pass
              else:
                  timeout = TimeoutSauce(connect=timeout, read=timeout)
      
              try:
      >           resp = conn.urlopen(
                      method=request.method,
                      url=url,
                      body=request.body,
                      headers=request.headers,
                      redirect=False,
                      assert_same_host=False,
                      preload_content=False,
                      decode_content=False,
                      retries=self.max_retries,
                      timeout=timeout,
                      chunked=chunked,
                  )
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:667: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:843: in urlopen
          retries = retries.increment(
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      self = Retry(total=0, connect=None, read=False, redirect=None, status=None)
      method = 'POST', url = '/demo/', response = None
      error = NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb0958cb20>: Failed to establish a new connection: [Errno 111] Connection refused')
      _pool = <urllib3.connectionpool.HTTPConnectionPool object at 0x7feb0977c0a0>
      _stacktrace = <traceback object at 0x7feb09808600>
      
          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: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/ (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb0958cb20>: Failed to establish a new connection: [Errno 111] Connection refused'))
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/retry.py:519: MaxRetryError
      
      During handling of the above exception, another exception occurred:
      
      self = <elog.logbook.Logbook object at 0x7feb0977c5b0>
      message = 'SCREENSHOT_INTEGRATION_TEST_MSG_456', msg_id = None, reply = False
      attributes = {'Author': 'robot', 'When': 1756376002, 'cmd': 'Submit', 'exp': 'demo', ...}
      attachments = ['/tmp/fake_screenshot.png'], suppress_email_notification = False
      encoding = None, timeout = None, kwargs = {'Author': 'robot'}
      new_attachment_list = [('attfile0', ('fake_screenshot.png', <_io.BufferedReader name='/tmp/fake_screenshot.png'>)), ('Text', ('', b'SCREENSHOT_INTEGRATION_TEST_MSG_456'))]
      objects_to_close = [<_io.BufferedReader name='/tmp/fake_screenshot.png'>]
      attributes_to_edit = {'Author': b'robot', 'When': 1756376002, 'cmd': b'Submit', 'exp': b'demo', ...}
      
          def post(self, message, msg_id=None, reply=False, attributes=None, attachments=None,
                   suppress_email_notification=False, encoding=None, timeout=None, **kwargs):
              """
              Posts message to the logbook. If msg_id is not specified new message will be created, otherwise existing
              message will be edited, or a reply (if reply=True) to it will be created. This method returns the msg_id
              of the newly created message.
      
              :param message: string with message text
              :param msg_id: ID number of message to edit or reply. If not specified new message is created.
              :param reply: If 'True' reply to existing message is created instead of editing it
              :param attributes: Dictionary of attributes. Following attributes are used internally by the elog and will be
                                 ignored: Text, Date, Encoding, Reply to, In reply to, Locked by, Attachment
              :param attachments: list of:
                                        - file like objects which read() will return bytes (if file_like_object.name is not
                                          defined, default name "attachment<i>" will be used.
                                        - paths to the files
                                  All items will be appended as attachment to the elog entry. In case of unknown
                                  attachment an exception LogbookInvalidAttachment will be raised.
              :param suppress_email_notification: If set to True or 1, E-Mail notification will be suppressed, defaults to False.
              :param encoding: Defines encoding of the message. Can be: 'plain' -> plain text, 'html'->html-text,
                               'ELCode' --> elog formatting syntax
              :param timeout: Define the timeout to be used by the post request. Its value is directly passed to the requests
                              post. Use None to disable the request timeout.
              :param kwargs: Anything in the kwargs will be interpreted as attribute. e.g.: logbook.post('Test text',
                             Author='Rok Vintar), "Author" will be sent as an attribute. If named same as one of the
                             attributes defined in "attributes", kwargs will have priority.
      
              :return: msg_id
              """
      
              attributes = attributes or {}
              attributes = {**attributes, **kwargs}  # kwargs as attributes with higher priority
      
              attachments = attachments or []
      
              if encoding is not None:
                  if encoding not in ['plain', 'HTML', 'ELCode']:
                      raise LogbookMessageRejected('Invalid message encoding. Valid options: plain, HTML, ELCode.')
                  attributes['Encoding'] = encoding
      
              if suppress_email_notification:
                  attributes["suppress"] = 1
      
              # THE ATTACHMENT STRATEGY WHEN DEALING WITH POST MODIFICATION
              #
              # 1. Does the message on the server have already attachments?
              #    1.1 - We read the message getting the existing attachment list.
              #    1.2 - Add to the attributes dictionary one line for each attachment like this:
              #       attributes['attachmentN'] = timestamped_filename_name
              #
              # 2. Do we have new attachments?
              #    2.1 - Those are in the new_attachment_list. This is a list of this type:
              #       [ ('attfileN', ('filename', fileobject)) ]
              #    2.2 - We need to loop over all the new attachments:
              #       2.2.1 - Does a file already on the server with the same name exist?
              #         2.2.1.1 - No: OK. Then we go ahead with the next attachment.
              #         2.2.1.2 - Yes:
              #           2.2.1.2.1 - Are the two files identical?
              #               2.2.1.2.1.1 - Yes: then we remove this current entry from the new_attachment_list and we leave the one
              #                      already on server.
              #               2.2.1.2.1.2 - No:
              #                  2.2.1.2.1.2.1 - Then the file has been update.
              #                  2.2.1.2.1.2.2 - We need to remove the file on server first (using special post)
              #                  2.2.1.2.1.2.3 - We have to remove the old attachment from the attributes dictionary.
              #
      
              if attachments:
                  # here we accomplish point 2.1.
                  # new_attachment_list is something like [ ('attfileN', ('filename', fileobject)) ]
                  new_attachment_list, objects_to_close = self._prepare_attachments(attachments)
              else:
                  objects_to_close = list()
                  new_attachment_list = list()
      
              attributes_to_edit = dict()
              if msg_id:
                  # Message exists, we can continue
                  if reply:
                      # Verify that there is a message on the server, otherwise do not reply to it!
                      self._check_if_message_on_server(msg_id)  # raises exception in case of none existing message
                      attributes['reply_to'] = str(msg_id)
                  else:  # Edit existing
                      attributes['edit_id'] = str(msg_id)
                      attributes['skiplock'] = '1'
      
                      # here we accomplish point 1.1.
                      # existing_attachments_list is something like:
                      # [ 'https://elog.url.com/logbook/timestamped_filename' ]
                      msg_to_edit, attributes_to_edit, existing_attachments_list = self.read(msg_id)
      
                      for attribute, data in attributes.items():
                          new_data = attributes.get(attribute)
                          if new_data is not None:
                              attributes_to_edit[attribute] = new_data
      
                      i = 0
                      existing_attachments_filename_list = list()
                      for attachment in existing_attachments_list:
                          # here we accomplish point 1.2. We strip the timestamped_filename from the whole URL.
                          attributes_to_edit[f'attachment{i}'] = os.path.basename(attachment)
                          existing_attachments_filename_list.append(os.path.basename(attachment)[14:])
                          i += 1
      
                      # let's accomplish 2.2. Loop over all new attachment
                      duplicate_attachment_list = list()
                      for new_attachment in new_attachment_list:
                          # the new_attachment_list is something like:
                          # [ ('attfileN', ('filename', fileobject)) ]
                          new_attachment_filename = new_attachment[1][0]
                          if new_attachment_filename in existing_attachments_filename_list:
                              # a file with the same name existing already on the server.
                              # we need to check if the two files are the same.
                              # read the content of the new file
                              new_attachment_content = new_attachment[1][1].read()
                              # don't forget to reset the fileobj to the beginning of the file
                              new_attachment[1][1].seek(0)
                              # get the existing attachment content
                              attachment_index = existing_attachments_filename_list.index(new_attachment_filename)
                              existing_attachment_content = self.download_attachment(
                                  url=existing_attachments_list[attachment_index],
                                  timeout=timeout
                              )
                              # check if the two contents are the same
                              if new_attachment_content == existing_attachment_content:
                                  # yes. then we don't upload a second copy. we remove the current entry from the list
                                  duplicate_attachment_list.append(new_attachment)
                              else:
                                  # no. they are not the same file. we will replace the existing file with the new one
                                  # first: we need to remove the attachment from the server using the dedicated method
                                  self.delete_attachment(msg_id, attributes=attributes_to_edit,
                                                         attachment_id=attachment_index,
                                                         timeout=timeout, text=msg_to_edit)
                                  # now we can remove this attachment from the auxiliary lists.
                                  existing_attachments_filename_list.pop(attachment_index)
                                  existing_attachments_list.pop(attachment_index)
                                  # now we need to rebuild the attributes dictionary for the part concerning the attachments.
                                  # we remove all of them first
                                  keys_to_be_removed = list()
                                  for key in attributes_to_edit.keys():
                                      if key.startswith('attachment'):
                                          keys_to_be_removed.append(key)
                                      if key.startswith('delatt'):
                                          keys_to_be_removed.append(key)
                                  for key in keys_to_be_removed:
                                      del attributes_to_edit[key]
      
                                  # now we rebuild it
                                  for i, attachment in enumerate(existing_attachments_list):
                                      attributes_to_edit[f'attachment{i}'] = os.path.basename(attachment)
      
                      # remove all duplicate attachments from the new_attachment_list
                      for attach in duplicate_attachment_list:
                          new_attachment_list.remove(attach)
      
              else:
                  # As we create a new message, specify creation time if not already specified in attributes
                  if 'When' not in attributes:
                      attributes['When'] = int(datetime.now().timestamp())
      
              if not attributes_to_edit:
                  attributes_to_edit = attributes
      
              # Remove any attributes that should not be sent
              _remove_reserved_attributes(attributes_to_edit)
      
              # Make requests module think that Text is a "file". This is the only way to force requests to send data as
              # multipart/form-data even if there are no attachments. Elog understands only multipart/form-data
              new_attachment_list.append(('Text', ('', message.encode('iso-8859-1'))))
      
              # Base attributes are common to all messages
              self._add_base_msg_attributes(attributes_to_edit)
      
              # Keys in attributes cannot have certain characters like whitespaces or dashes for the http request
              attributes_to_edit = _replace_special_characters_in_attribute_keys(attributes_to_edit)
      
              # All string values in the attributes must be encoded in latin1
              attributes_to_edit = _encode_values(attributes_to_edit)
      
              try:
      >           response = requests.post(self._url, data=attributes_to_edit, files=new_attachment_list,
                                           allow_redirects=False, verify=False, timeout=timeout)
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:288: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:115: in post
          return request("post", url, data=data, json=json, **kwargs)
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:59: in request
          return session.request(method=method, url=url, **kwargs)
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:589: in request
          resp = self.send(prep, **send_kwargs)
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:703: in send
          r = adapter.send(request, **kwargs)
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      self = <requests.adapters.HTTPAdapter object at 0x7feb0958c490>
      request = <PreparedRequest [POST]>, stream = False
      timeout = Timeout(connect=None, read=None, total=None), verify = False
      cert = None, proxies = OrderedDict()
      
          def send(
              self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
          ):
              """Sends PreparedRequest object. Returns Response object.
      
              :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
              :param stream: (optional) Whether to stream the request content.
              :param timeout: (optional) How long to wait for the server to send
                  data before giving up, as a float, or a :ref:`(connect timeout,
                  read timeout) <timeouts>` tuple.
              :type timeout: float or tuple or urllib3 Timeout object
              :param verify: (optional) Either a boolean, in which case it controls whether
                  we verify the server's TLS certificate, or a string, in which case it
                  must be a path to a CA bundle to use
              :param cert: (optional) Any user-provided SSL certificate to be trusted.
              :param proxies: (optional) The proxies dictionary to apply to the request.
              :rtype: requests.Response
              """
      
              try:
                  conn = self.get_connection_with_tls_context(
                      request, verify, proxies=proxies, cert=cert
                  )
              except LocationValueError as e:
                  raise InvalidURL(e, request=request)
      
              self.cert_verify(conn, request.url, verify, cert)
              url = self.request_url(request, proxies)
              self.add_headers(
                  request,
                  stream=stream,
                  timeout=timeout,
                  verify=verify,
                  cert=cert,
                  proxies=proxies,
              )
      
              chunked = not (request.body is None or "Content-Length" in request.headers)
      
              if isinstance(timeout, tuple):
                  try:
                      connect, read = timeout
                      timeout = TimeoutSauce(connect=connect, read=read)
                  except ValueError:
                      raise ValueError(
                          f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                          f"or a single float to set both timeouts to the same value."
                      )
              elif isinstance(timeout, TimeoutSauce):
                  pass
              else:
                  timeout = TimeoutSauce(connect=timeout, read=timeout)
      
              try:
                  resp = conn.urlopen(
                      method=request.method,
                      url=url,
                      body=request.body,
                      headers=request.headers,
                      redirect=False,
                      assert_same_host=False,
                      preload_content=False,
                      decode_content=False,
                      retries=self.max_retries,
                      timeout=timeout,
                      chunked=chunked,
                  )
      
              except (ProtocolError, OSError) as err:
                  raise ConnectionError(err, request=request)
      
              except MaxRetryError as e:
                  if isinstance(e.reason, ConnectTimeoutError):
                      # TODO: Remove this in 3.0.0: see #2811
                      if not isinstance(e.reason, NewConnectionError):
                          raise ConnectTimeout(e, request=request)
      
                  if isinstance(e.reason, ResponseError):
                      raise RetryError(e, request=request)
      
                  if isinstance(e.reason, _ProxyError):
                      raise ProxyError(e, request=request)
      
                  if isinstance(e.reason, _SSLError):
                      # This branch is for urllib3 v1.22 and later.
                      raise SSLError(e, request=request)
      
      >           raise ConnectionError(e, request=request)
      E           requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/ (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb0958cb20>: Failed to establish a new connection: [Errno 111] Connection refused'))
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:700: ConnectionError
      
      During handling of the above exception, another exception occurred:
      
      self = <urllib3.connection.HTTPConnection object at 0x7feb09b7ea60>
      
          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,
                  )
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:199: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/connection.py:85: in create_connection
          raise err
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      address = ('localhost', 8080), 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 111] Connection refused
      
      /root/mambaforge/envs/ci-env/lib/python3.8/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 0x7feb09b7e640>
      method = 'GET', url = '/demo/None', body = None
      headers = {'User-Agent': 'python-requests/2.32.4', 'Accept-Encoding': 'gzip, deflate, br, zstd', 'Accept': '*/*', 'Connection': 'keep-alive', 'Cookie': 'unm=robot;upwd=me1T.2jUUqQNa1wNuey9zNBOmOa4eILOaPb.ZSZjpn4;'}
      retries = Retry(total=0, connect=None, read=False, redirect=None, status=None)
      redirect = False, assert_same_host = False
      timeout = Timeout(connect=None, read=None, total=None), pool_timeout = None
      release_conn = False, chunked = False, body_pos = None, preload_content = False
      decode_content = False, response_kw = {}
      parsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/demo/None', 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,
                  )
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:789: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:495: in _make_request
          conn.request(
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:441: in request
          self.endheaders()
      /root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1251: in endheaders
          self._send_output(message_body, encode_chunked=encode_chunked)
      /root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:1011: in _send_output
          self.send(msg)
      /root/mambaforge/envs/ci-env/lib/python3.8/http/client.py:951: in send
          self.connect()
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:279: in connect
          self.sock = self._new_conn()
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      self = <urllib3.connection.HTTPConnection object at 0x7feb09b7ea60>
      
          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 0x7feb09b7ea60>: Failed to establish a new connection: [Errno 111] Connection refused
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connection.py:214: NewConnectionError
      
      The above exception was the direct cause of the following exception:
      
      self = <requests.adapters.HTTPAdapter object at 0x7feb09b7eaf0>
      request = <PreparedRequest [GET]>, stream = False
      timeout = Timeout(connect=None, read=None, total=None), verify = False
      cert = None, proxies = OrderedDict()
      
          def send(
              self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
          ):
              """Sends PreparedRequest object. Returns Response object.
      
              :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
              :param stream: (optional) Whether to stream the request content.
              :param timeout: (optional) How long to wait for the server to send
                  data before giving up, as a float, or a :ref:`(connect timeout,
                  read timeout) <timeouts>` tuple.
              :type timeout: float or tuple or urllib3 Timeout object
              :param verify: (optional) Either a boolean, in which case it controls whether
                  we verify the server's TLS certificate, or a string, in which case it
                  must be a path to a CA bundle to use
              :param cert: (optional) Any user-provided SSL certificate to be trusted.
              :param proxies: (optional) The proxies dictionary to apply to the request.
              :rtype: requests.Response
              """
      
              try:
                  conn = self.get_connection_with_tls_context(
                      request, verify, proxies=proxies, cert=cert
                  )
              except LocationValueError as e:
                  raise InvalidURL(e, request=request)
      
              self.cert_verify(conn, request.url, verify, cert)
              url = self.request_url(request, proxies)
              self.add_headers(
                  request,
                  stream=stream,
                  timeout=timeout,
                  verify=verify,
                  cert=cert,
                  proxies=proxies,
              )
      
              chunked = not (request.body is None or "Content-Length" in request.headers)
      
              if isinstance(timeout, tuple):
                  try:
                      connect, read = timeout
                      timeout = TimeoutSauce(connect=connect, read=read)
                  except ValueError:
                      raise ValueError(
                          f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                          f"or a single float to set both timeouts to the same value."
                      )
              elif isinstance(timeout, TimeoutSauce):
                  pass
              else:
                  timeout = TimeoutSauce(connect=timeout, read=timeout)
      
              try:
      >           resp = conn.urlopen(
                      method=request.method,
                      url=url,
                      body=request.body,
                      headers=request.headers,
                      redirect=False,
                      assert_same_host=False,
                      preload_content=False,
                      decode_content=False,
                      retries=self.max_retries,
                      timeout=timeout,
                      chunked=chunked,
                  )
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:667: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/connectionpool.py:843: in urlopen
          retries = retries.increment(
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      self = Retry(total=0, connect=None, read=False, redirect=None, status=None)
      method = 'GET', url = '/demo/None', response = None
      error = NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09b7ea60>: Failed to establish a new connection: [Errno 111] Connection refused')
      _pool = <urllib3.connectionpool.HTTPConnectionPool object at 0x7feb09b7e640>
      _stacktrace = <traceback object at 0x7feb09906780>
      
          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: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09b7ea60>: Failed to establish a new connection: [Errno 111] Connection refused'))
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/urllib3/util/retry.py:519: MaxRetryError
      
      During handling of the above exception, another exception occurred:
      
      self = <elog.logbook.Logbook object at 0x7feb0977c5b0>, msg_id = None
      timeout = None
      
          def _check_if_message_on_server(self, msg_id, timeout=None):
              """Try to load page for specific message. If there is a html tag like <td class="errormsg"> then there is no
              such message.
      
              :param msg_id: ID of message to be checked
              :params timeout: The value of timeout to be passed to the get request
              :return:
              """
      
              request_headers = dict()
              if self._user or self._password:
                  request_headers['Cookie'] = self._make_user_and_pswd_cookie()
              try:
      >           response = requests.get(self._url + str(msg_id), headers=request_headers, allow_redirects=False,
                                          verify=False, timeout=timeout)
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:581: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:73: in get
          return request("get", url, params=params, **kwargs)
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/api.py:59: in request
          return session.request(method=method, url=url, **kwargs)
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:589: in request
          resp = self.send(prep, **send_kwargs)
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/sessions.py:703: in send
          r = adapter.send(request, **kwargs)
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      self = <requests.adapters.HTTPAdapter object at 0x7feb09b7eaf0>
      request = <PreparedRequest [GET]>, stream = False
      timeout = Timeout(connect=None, read=None, total=None), verify = False
      cert = None, proxies = OrderedDict()
      
          def send(
              self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
          ):
              """Sends PreparedRequest object. Returns Response object.
      
              :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
              :param stream: (optional) Whether to stream the request content.
              :param timeout: (optional) How long to wait for the server to send
                  data before giving up, as a float, or a :ref:`(connect timeout,
                  read timeout) <timeouts>` tuple.
              :type timeout: float or tuple or urllib3 Timeout object
              :param verify: (optional) Either a boolean, in which case it controls whether
                  we verify the server's TLS certificate, or a string, in which case it
                  must be a path to a CA bundle to use
              :param cert: (optional) Any user-provided SSL certificate to be trusted.
              :param proxies: (optional) The proxies dictionary to apply to the request.
              :rtype: requests.Response
              """
      
              try:
                  conn = self.get_connection_with_tls_context(
                      request, verify, proxies=proxies, cert=cert
                  )
              except LocationValueError as e:
                  raise InvalidURL(e, request=request)
      
              self.cert_verify(conn, request.url, verify, cert)
              url = self.request_url(request, proxies)
              self.add_headers(
                  request,
                  stream=stream,
                  timeout=timeout,
                  verify=verify,
                  cert=cert,
                  proxies=proxies,
              )
      
              chunked = not (request.body is None or "Content-Length" in request.headers)
      
              if isinstance(timeout, tuple):
                  try:
                      connect, read = timeout
                      timeout = TimeoutSauce(connect=connect, read=read)
                  except ValueError:
                      raise ValueError(
                          f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                          f"or a single float to set both timeouts to the same value."
                      )
              elif isinstance(timeout, TimeoutSauce):
                  pass
              else:
                  timeout = TimeoutSauce(connect=timeout, read=timeout)
      
              try:
                  resp = conn.urlopen(
                      method=request.method,
                      url=url,
                      body=request.body,
                      headers=request.headers,
                      redirect=False,
                      assert_same_host=False,
                      preload_content=False,
                      decode_content=False,
                      retries=self.max_retries,
                      timeout=timeout,
                      chunked=chunked,
                  )
      
              except (ProtocolError, OSError) as err:
                  raise ConnectionError(err, request=request)
      
              except MaxRetryError as e:
                  if isinstance(e.reason, ConnectTimeoutError):
                      # TODO: Remove this in 3.0.0: see #2811
                      if not isinstance(e.reason, NewConnectionError):
                          raise ConnectTimeout(e, request=request)
      
                  if isinstance(e.reason, ResponseError):
                      raise RetryError(e, request=request)
      
                  if isinstance(e.reason, _ProxyError):
                      raise ProxyError(e, request=request)
      
                  if isinstance(e.reason, _SSLError):
                      # This branch is for urllib3 v1.22 and later.
                      raise SSLError(e, request=request)
      
      >           raise ConnectionError(e, request=request)
      E           requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09b7ea60>: Failed to establish a new connection: [Errno 111] Connection refused'))
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/requests/adapters.py:700: ConnectionError
      
      During handling of the above exception, another exception occurred:
      
      mock_screenshot_class = <MagicMock name='Screenshot' id='140647452388896'>
      
          @patch("slic.utils.elog.Screenshot")
          def test_screenshot(mock_screenshot_class):
              fake_path = "/tmp/fake_screenshot.png"
              with open(fake_path, "wb") as f:
                  f.write(b"fake image data")
      
              mock_instance = mock_screenshot_class.return_value
              mock_instance.shoot.return_value = [fake_path]
      
              elog = Elog("http://localhost:8080/demo", user="robot", password="testpassword")
      
              test_msg = "SCREENSHOT_INTEGRATION_TEST_MSG_456"
      >       msg_id = elog.screenshot(message=test_msg)
      
      tests/test_utils_elog.py:116: 
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      slic/utils/elog.py:21: in screenshot
          return self.post(message, **kwargs)
      slic/utils/elog.py:16: in post
          return self._log.post(*args, **kwargs)
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:307: in post
          self._check_if_message_on_server(msg_id)  # raises exceptions if no message or no response from server
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
      
      self = <elog.logbook.Logbook object at 0x7feb0977c5b0>, msg_id = None
      timeout = None
      
          def _check_if_message_on_server(self, msg_id, timeout=None):
              """Try to load page for specific message. If there is a html tag like <td class="errormsg"> then there is no
              such message.
      
              :param msg_id: ID of message to be checked
              :params timeout: The value of timeout to be passed to the get request
              :return:
              """
      
              request_headers = dict()
              if self._user or self._password:
                  request_headers['Cookie'] = self._make_user_and_pswd_cookie()
              try:
                  response = requests.get(self._url + str(msg_id), headers=request_headers, allow_redirects=False,
                                          verify=False, timeout=timeout)
      
                  # If there is no message code 200 will be returned (OK) and _validate_response will not recognise it
                  # but there will be some error in the html code.
                  resp_message, resp_headers, resp_msg_id = _validate_response(response)
                  # If there is no message, code 200 will be returned (OK) but there will be some error indication in
                  # the html code.
                  if re.findall('<td.*?class="errormsg".*?>.*?</td>',
                                resp_message.decode('utf-8', 'ignore'),
                                flags=re.DOTALL):
                      raise LogbookInvalidMessageID('Message with ID: ' + str(msg_id) + ' does not exist on logbook.')
      
              except requests.Timeout as e:
                  # Catch here a timeout o the post request.
                  # Raise the logbook exception and let the user handle it
                  raise LogbookServerTimeout('{0} method cannot be completed because of a network timeout:\n' +
                                             '{1}'.format(sys._getframe().f_code.co_name, e))
      
              except requests.RequestException as e:
      >           raise LogbookServerProblem('No response from the logbook server.\nDetails: ' + '{0}'.format(e))
      E           elog.logbook_exceptions.LogbookServerProblem: No response from the logbook server.
      E           Details: HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /demo/None (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7feb09b7ea60>: Failed to establish a new connection: [Errno 111] Connection refused'))
      
      /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/elog/logbook.py:601: LogbookServerProblem
      

      📌 Teardown phase

      duration:

      0.00040868669748306274
      

      outcome:

      passed
      
  • 📄 test_utils_get_adj.py

    Function: test_get_adjs_filter

    • Test 233

      📌 Setup phase

      duration:

      0.0001723961904644966
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0013879667967557907
      

      outcome:

      failed
      

      crash:

      path: /workspace/tligui_y/slic/tests/test_utils_get_adj.py
      lineno: 42
      message: AssertionError: assert {'contrast', ...mid_contrast'} == {'brightness'...mid_contrast'}
      
        Extra items in the right set:
        'brightness'
      
        Full diff:
          {
        -     'brightness',
              'contrast',
              'mid_brightness',
              'mid_contrast',
          }
      

      traceback:

      -   path: tests/test_utils_get_adj.py
        lineno: 42
        message: AssertionError
      

      longrepr:

      def test_get_adjs_filter():
              a4 = SubAdjustable("mid_brightness",         units="%", limit_low=0,   limit_high=100)
              a5 = SubAdjustable("debug_internal",   internal=True)
              public = get_adjs()
      >       assert set(public) == {'brightness', 'contrast', 'mid_contrast', 'mid_brightness'}
      E       AssertionError: assert {'contrast', ...mid_contrast'} == {'brightness'...mid_contrast'}
      E         
      E         Extra items in the right set:
      E         'brightness'
      E         
      E         Full diff:
      E           {
      E         -     'brightness',
      E               'contrast',
      E               'mid_brightness',
      E               'mid_contrast',
      E           }
      
      tests/test_utils_get_adj.py:42: AssertionError
      

      📌 Teardown phase

      duration:

      0.00019770953804254532
      

      outcome:

      passed
      
  • 📄 test_utils_logcfg.py

    Function: test_import_logging_once_per_module

    • Test 246

      📌 Setup phase

      duration:

      0.00018928758800029755
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      1.7560598272830248
      

      outcome:

      failed
      

      crash:

      path: /workspace/tligui_y/slic/tests/test_utils_logcfg.py
      lineno: 78
      message: AssertionError: Expected 1 import log for 'math', found 0
      assert 0 == 1
      

      traceback:

      -   path: tests/test_utils_logcfg.py
        lineno: 78
        message: AssertionError
      

      stdout:

      [E 250828 10:15:55 tools:40] cannot assign endstation to IP 172.18.0.3 (038eaf845eac)
      
      
      

      longrepr:

      def test_import_logging_once_per_module():
              code = textwrap.dedent("""
                  from slic.utils.logcfg import *
                  import math
                  import io
                  import random
              """)
      
              with tempfile.NamedTemporaryFile("w", suffix=".py", delete=False) as tmp:
                  tmp.write(code)
                  tmp_path = tmp.name
      
              env = os.environ.copy()
              root_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
              env["PYTHONPATH"] = root_path + os.pathsep + env.get("PYTHONPATH", "")
      
              result = subprocess.run([sys.executable, tmp_path], capture_output=True, text=True, env=env)
              os.remove(tmp_path)
      
              assert result.returncode == 0, f"Script failed:\n{result.stderr}"
      
              stderr = result.stderr
              print(stderr)
              lines = stderr.splitlines()
              for mod in ["math", "io", "random"]:
                  count = sum(1 for line in lines if f"importing: {mod}" in line)
      >           assert count == 1, f"Expected 1 import log for '{mod}', found {count}"
      E           AssertionError: Expected 1 import log for 'math', found 0
      E           assert 0 == 1
      
      tests/test_utils_logcfg.py:78: AssertionError
      

      📌 Teardown phase

      duration:

      0.0004467582330107689
      

      outcome:

      passed
      
  • 📄 test_utils_shortcut.py

    Function: TestShortcutsSingleton

    • Test 454

      📌 Setup phase

      duration:

      0.0002901945263147354
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0007099341601133347
      

      outcome:

      failed
      

      crash:

      path: /workspace/tligui_y/slic/tests/test_utils_shortcut.py
      lineno: 138
      message: assert 3 == 2
       +  where 3 = len({'<lambda>': Shortcut "<lambda>", 'FuncA': Shortcut "FuncA", 'FuncB': Shortcut "FuncB"})
       +    where {'<lambda>': Shortcut "<lambda>", 'FuncA': Shortcut "FuncA", 'FuncB': Shortcut "FuncB"} = _get()
       +      where _get = <lambda>: Shortcut "<lambda>"\nFuncA:    Shortcut "FuncA"\nFuncB:    Shortcut "FuncB"\n._get
      

      traceback:

      -   path: tests/test_utils_shortcut.py
        lineno: 138
        message: AssertionError
      

      longrepr:

      self = <test_utils_shortcut.TestShortcutsSingleton object at 0x7feb09bdfee0>
      
          def test_registration(self):
              # Test automatic registration
              @as_shortcut(name="FuncA")
              def func_a():
                  pass
      
              @as_shortcut(name="FuncB")
              def func_b():
                  pass
      
      >       assert len(shortcuts._get()) == 2
      E       assert 3 == 2
      E        +  where 3 = len({'<lambda>': Shortcut "<lambda>", 'FuncA': Shortcut "FuncA", 'FuncB': Shortcut "FuncB"})
      E        +    where {'<lambda>': Shortcut "<lambda>", 'FuncA': Shortcut "FuncA", 'FuncB': Shortcut "FuncB"} = _get()
      E        +      where _get = <lambda>: Shortcut "<lambda>"\nFuncA:    Shortcut "FuncA"\nFuncB:    Shortcut "FuncB"\n._get
      
      tests/test_utils_shortcut.py:138: AssertionError
      

      📌 Teardown phase

      duration:

      0.0002776775509119034
      

      outcome:

      passed
      

    Function: TestFullIntegration

    • Test 459

      📌 Setup phase

      duration:

      0.00031516142189502716
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0006153751164674759
      

      outcome:

      failed
      

      crash:

      path: /workspace/tligui_y/slic/tests/test_utils_shortcut.py
      lineno: 203
      message: assert 5 == 2
       +  where 5 = len({'<lambda>': Shortcut "<lambda>", 'First': Shortcut "First", 'FuncA': Shortcut "FuncA", 'FuncB': Shortcut "FuncB", ...})
       +    where {'<lambda>': Shortcut "<lambda>", 'First': Shortcut "First", 'FuncA': Shortcut "FuncA", 'FuncB': Shortcut "FuncB", ...} = _get()
       +      where _get = <lambda>: Shortcut "<lambda>"\nFirst:    Shortcut "First"\nFuncA:    Shortcut "FuncA"\nFuncB:    Shortcut "FuncB"\nSecond:   Shortcut "Second"\n._get
      

      traceback:

      -   path: tests/test_utils_shortcut.py
        lineno: 203
        message: AssertionError
      

      longrepr:

      self = <test_utils_shortcut.TestFullIntegration object at 0x7feb09cdfcd0>
      
          def test_multiple_shortcuts(self):
              # Test multiple shortcuts coexistence
              @as_shortcut(name="First")
              def first():
                  return 1
      
              @as_shortcut(name="Second")
              def second():
                  return 2
      
              assert shortcuts["First"].func() == 1
              assert shortcuts["Second"].func() == 2
      >       assert len(shortcuts._get()) == 2
      E       assert 5 == 2
      E        +  where 5 = len({'<lambda>': Shortcut "<lambda>", 'First': Shortcut "First", 'FuncA': Shortcut "FuncA", 'FuncB': Shortcut "FuncB", ...})
      E        +    where {'<lambda>': Shortcut "<lambda>", 'First': Shortcut "First", 'FuncA': Shortcut "FuncA", 'FuncB': Shortcut "FuncB", ...} = _get()
      E        +      where _get = <lambda>: Shortcut "<lambda>"\nFirst:    Shortcut "First"\nFuncA:    Shortcut "FuncA"\nFuncB:    Shortcut "FuncB"\nSecond:   Shortcut "Second"\n._get
      
      tests/test_utils_shortcut.py:203: AssertionError
      

      📌 Teardown phase

      duration:

      0.00031558703631162643
      

      outcome:

      passed
      
  • 📄 test_utils_tqdm_mod.py

    Function: test_float_alignment_in_bar

    • Test 473

      📌 Setup phase

      duration:

      0.00017123576253652573
      

      outcome:

      passed
      

      📌 Call phase

      duration:

      0.0033523766323924065
      

      outcome:

      failed
      

      crash:

      path: /workspace/tligui_y/slic/tests/test_utils_tqdm_mod.py
      lineno: 130
      message: assert 3 == 1
       +  where 3 = len({50, 64, 65})
       +    where {50, 64, 65} = set([50, 64, 64, 65, 65])
      

      traceback:

      -   path: tests/test_utils_tqdm_mod.py
        lineno: 130
        message: AssertionError
      

      stdout:

      
      
      AlignBar:   0%|          | 0/100.1 [00:00<?, ? Hz]
      AlignBar:   1%|1         |   1.3/100.1 [00:00<00:00, 57652.2 Hz]
      AlignBar:  12%|#2        |  12.5/100.1 [00:00<00:00, 81738.0 Hz]
      AlignBar: 100%|#########9|  99.9/100.1 [00:00<00:00, 420734.0 Hz]
      AlignBar: 100%|##########| 100.1/100.1 [00:00<00:00, 217807.9 Hz]
      
      

      longrepr:

      def test_float_alignment_in_bar():
              # Capture the tqdm output into a string buffer
              f = io.StringIO()
              with redirect_stdout(f):
                  bar = tqdm_mod(total=100.12, desc="AlignBar", file=f, miniters=1, mininterval=0)
                  bar.set(1.3333)
                  bar.set(12.5)
                  bar.set(99.89)
                  bar.set(100.12)
                  bar.close()
      
              # Extract lines containing the label
              lines = extract_lines(f.getvalue(), "AlignBar")
      
              # Expected formatted values using format_sizeof
              expected_values = [
                  "1.3/100.1",
                  "12.5/100.1",
                  "99.9/100.1",
                  "100.1/100.1",
              ]
      
              # Extract the actual padded float/total strings from the full lines
              values = []
              for line in lines:
                  match = re.search(r"(\d{1,3}\.\d)/100\.1", line)
                  if match:
                      values.append(match.group(0))
      
              # Ensure raw 100.12 never appears : format_sizeof must have truncated it
              assert all("100.12" not in line for line in lines), "Unrounded value '100.12' found in output!"
      
              # Check all expected values appear rounded as expected by format_sizeof
              for expected in expected_values:
                  assert expected in values, f"Missing expected value: {expected}"
      
              # Check that all values are visually aligned, output with same length, to ensure that format_sizeof add the good number avec spaces
              print("\n")
              bar_segments = []
              for line in lines:
                  match = re.search(r".*?\]", line)
                  if match:
                      bar_segments.append(match.group(0))
                      print(match.group(0))
      
              lengths = [len(seg) for seg in bar_segments]
      >       assert len(set(lengths)) == 1
      E       assert 3 == 1
      E        +  where 3 = len({50, 64, 65})
      E        +    where {50, 64, 65} = set([50, 64, 64, 65, 65])
      
      tests/test_utils_tqdm_mod.py:130: AssertionError
      

      📌 Teardown phase

      duration:

      0.00024230685085058212
      

      outcome:

      passed
      

📚 Collected files

(1 tests)
    • Outcome: passed
    • result:
    -   nodeid: .
      type: Dir
    
ci-reports (13 tests)
  • ci-reports
    • Outcome: passed
    • result:
    -   nodeid: ci-reports/allure
      type: Dir
    -   nodeid: ci-reports/junit
      type: Dir
    -   nodeid: ci-reports/markdown
      type: Dir
    
    • ci-reports/allure
      • Outcome: passed
      • result:
      -   nodeid: ci-reports/allure/data
        type: Dir
      -   nodeid: ci-reports/allure/export
        type: Dir
      -   nodeid: ci-reports/allure/history
        type: Dir
      -   nodeid: ci-reports/allure/plugin
        type: Dir
      -   nodeid: ci-reports/allure/widgets
        type: Dir
      
    • ci-reports/allure/data
      • Outcome: passed
      • result:
      -   nodeid: ci-reports/allure/data/test-cases
        type: Dir
      
    • ci-reports/allure/data/test-cases
      • Outcome: passed
      • result:
      []
      
    • ci-reports/allure/export
      • Outcome: passed
      • result:
      []
      
    • ci-reports/allure/history
      • Outcome: passed
      • result:
      []
      
    • ci-reports/allure/plugin
      • Outcome: passed
      • result:
      -   nodeid: ci-reports/allure/plugin/behaviors
        type: Dir
      -   nodeid: ci-reports/allure/plugin/packages
        type: Dir
      -   nodeid: ci-reports/allure/plugin/screen-diff
        type: Dir
      
    • ci-reports/allure/plugin/behaviors
      • Outcome: passed
      • result:
      []
      
    • ci-reports/allure/plugin/packages
      • Outcome: passed
      • result:
      []
      
    • ci-reports/allure/plugin/screen-diff
      • Outcome: passed
      • result:
      []
      
    • ci-reports/allure/widgets
      • Outcome: passed
      • result:
      []
      
    • ci-reports/junit
      • Outcome: passed
      • result:
      []
      
    • ci-reports/markdown
      • Outcome: passed
      • result:
      []
      
markdown (1 tests)
  • markdown
    • Outcome: passed
    • result:
    []
    
morbidissimo (6 tests)
  • morbidissimo
    • Outcome: passed
    • result:
    -   nodeid: morbidissimo/morbidissimo
      type: Package
    
    • morbidissimo/morbidissimo
      • Outcome: passed
      • result:
      -   nodeid: morbidissimo/morbidissimo/modman
        type: Package
      -   nodeid: morbidissimo/morbidissimo/morioc
        type: Package
      
    • morbidissimo/morbidissimo/modman
      • Outcome: passed
      • result:
      -   nodeid: morbidissimo/morbidissimo/modman/scripts
        type: Dir
      
    • morbidissimo/morbidissimo/modman/scripts
      • Outcome: passed
      • result:
      []
      
    • morbidissimo/morbidissimo/morioc
      • Outcome: passed
      • result:
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py
        type: Module
      
    • morbidissimo/morbidissimo/morioc/test_infer_type.py
      • Outcome: passed
      • result:
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_it_type_str
        type: Function
        lineno: 14
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_it_type_float
        type: Function
        lineno: 17
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_it_type_int
        type: Function
        lineno: 20
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_it_value_str
        type: Function
        lineno: 24
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_it_value_long_str
        type: Function
        lineno: 27
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_it_value_float
        type: Function
        lineno: 32
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_it_value_int
        type: Function
        lineno: 35
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_it_empty_value_str
        type: Function
        lineno: 39
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_it_empty_value_float
        type: Function
        lineno: 42
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_it_empty_value_int
        type: Function
        lineno: 45
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_pstrue_str
        type: Function
        lineno: 49
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_pstrue_float
        type: Function
        lineno: 52
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_pstrue_int
        type: Function
        lineno: 55
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_psfalse_str
        type: Function
        lineno: 59
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_psfalse_float
        type: Function
        lineno: 62
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_psfalse_int
        type: Function
        lineno: 65
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_it_None
        type: Function
        lineno: 69
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_it_True
        type: Function
        lineno: 72
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_it_False
        type: Function
        lineno: 75
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_it_nan
        type: Function
        lineno: 78
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_it_np_nan
        type: Function
        lineno: 81
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_it_np1D_int
        type: Function
        lineno: 85
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_it_np2D_int
        type: Function
        lineno: 91
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_it_np1D_float
        type: Function
        lineno: 99
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_it_np2D_float
        type: Function
        lineno: 105
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_it_np1D_bool
        type: Function
        lineno: 114
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_it_np1D_object
        type: Function
        lineno: 119
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_it_np_scalar_int
        type: Function
        lineno: 126
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_it_np_scalar_float
        type: Function
        lineno: 131
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_it_np_scalar_bool
        type: Function
        lineno: 136
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_it_list
        type: Function
        lineno: 145
      -   nodeid: morbidissimo/morbidissimo/morioc/test_infer_type.py::test_it_tuple
        type: Function
        lineno: 150
      
outputs (1 tests)
  • outputs
    • Outcome: passed
    • result:
    []
    
slic (30 tests)
  • slic
    • Outcome: passed
    • result:
    -   nodeid: slic/core
      type: Package
    -   nodeid: slic/devices
      type: Package
    -   nodeid: slic/gui
      type: Package
    -   nodeid: slic/utils
      type: Package
    
    • slic/core
      • Outcome: passed
      • result:
      -   nodeid: slic/core/acquisition
        type: Package
      -   nodeid: slic/core/adjustable
        type: Package
      -   nodeid: slic/core/condition
        type: Package
      -   nodeid: slic/core/device
        type: Package
      -   nodeid: slic/core/scanner
        type: Package
      -   nodeid: slic/core/sensor
        type: Package
      -   nodeid: slic/core/task
        type: Package
      
    • slic/core/acquisition
      • Outcome: passed
      • result:
      -   nodeid: slic/core/acquisition/broker
        type: Package
      
    • slic/core/acquisition/broker
      • Outcome: passed
      • result:
      []
      
    • slic/core/adjustable
      • Outcome: passed
      • result:
      []
      
    • slic/core/condition
      • Outcome: passed
      • result:
      []
      
    • slic/core/device
      • Outcome: passed
      • result:
      []
      
    • slic/core/scanner
      • Outcome: passed
      • result:
      []
      
    • slic/core/sensor
      • Outcome: passed
      • result:
      []
      
    • slic/core/task
      • Outcome: passed
      • result:
      []
      
    • slic/devices
      • Outcome: passed
      • result:
      -   nodeid: slic/devices/cameras
        type: Package
      -   nodeid: slic/devices/endstations
        type: Package
      -   nodeid: slic/devices/general
        type: Package
      -   nodeid: slic/devices/loptics
        type: Package
      -   nodeid: slic/devices/timing
        type: Package
      -   nodeid: slic/devices/xdiagnostics
        type: Package
      -   nodeid: slic/devices/xoptics
        type: Package
      
    • slic/devices/cameras
      • Outcome: passed
      • result:
      []
      
    • slic/devices/endstations
      • Outcome: passed
      • result:
      []
      
    • slic/devices/general
      • Outcome: passed
      • result:
      -   nodeid: slic/devices/general/detectors
        type: Package
      -   nodeid: slic/devices/general/unused
        type: Dir
      
    • slic/devices/general/detectors
      • Outcome: passed
      • result:
      []
      
    • slic/devices/general/unused
      • Outcome: passed
      • result:
      []
      
    • slic/devices/loptics
      • Outcome: passed
      • result:
      []
      
    • slic/devices/timing
      • Outcome: passed
      • result:
      -   nodeid: slic/devices/timing/events
        type: Package
      
    • slic/devices/timing/events
      • Outcome: passed
      • result:
      []
      
    • slic/devices/xdiagnostics
      • Outcome: passed
      • result:
      []
      
    • slic/devices/xoptics
      • Outcome: passed
      • result:
      -   nodeid: slic/devices/xoptics/slits
        type: Package
      -   nodeid: slic/devices/xoptics/unused
        type: Dir
      
    • slic/devices/xoptics/slits
      • Outcome: passed
      • result:
      []
      
    • slic/devices/xoptics/unused
      • Outcome: passed
      • result:
      []
      
    • slic/gui
      • Outcome: passed
      • result:
      -   nodeid: slic/gui/daqpanels
        type: Package
      -   nodeid: slic/gui/widgets
        type: Package
      
    • slic/gui/daqpanels
      • Outcome: passed
      • result:
      []
      
    • slic/gui/widgets
      • Outcome: passed
      • result:
      []
      
    • slic/utils
      • Outcome: passed
      • result:
      -   nodeid: slic/utils/ioc
        type: Package
      -   nodeid: slic/utils/unused
        type: Dir
      
    • slic/utils/ioc
      • Outcome: passed
      • result:
      []
      
    • slic/utils/unused
      • Outcome: passed
      • result:
      -   nodeid: slic/utils/unused/xsim
        type: Package
      
    • slic/utils/unused/xsim
      • Outcome: passed
      • result:
      []
      
temp-ci (1 tests)
  • temp-ci
    • Outcome: passed
    • result:
    []
    
test-ci (1 tests)
  • test-ci
    • Outcome: passed
    • result:
    []
    
tests (54 tests)
  • tests
    • Outcome: passed
    • result:
    -   nodeid: tests/test_utils_argfwd.py
      type: Module
    -   nodeid: tests/test_utils_ask_yes_no.py
      type: Module
    -   nodeid: tests/test_utils_channels.py
      type: Module
    -   nodeid: tests/test_utils_config.py
      type: Module
    -   nodeid: tests/test_utils_cpint.py
      type: Module
    -   nodeid: tests/test_utils_dbusnotify.py
      type: Module
    -   nodeid: tests/test_utils_debug.py
      type: Module
    -   nodeid: tests/test_utils_dictext.py
      type: Module
    -   nodeid: tests/test_utils_dotdir.py
      type: Module
    -   nodeid: tests/test_utils_duo.py
      type: Module
    -   nodeid: tests/test_utils_elog.py
      type: Module
    -   nodeid: tests/test_utils_eval.py
      type: Module
    -   nodeid: tests/test_utils_exceptions.py
      type: Module
    -   nodeid: tests/test_utils_get_adj.py
      type: Module
    -   nodeid: tests/test_utils_hastepics.py
      type: Module
    -   nodeid: tests/test_utils_ipy.py
      type: Module
    -   nodeid: tests/test_utils_jsonext.py
      type: Module
    -   nodeid: tests/test_utils_lazypv.py
      type: Module
    -   nodeid: tests/test_utils_logcfg.py
      type: Module
    -   nodeid: tests/test_utils_logign.py
      type: Module
    -   nodeid: tests/test_utils_marker.py
      type: Module
    -   nodeid: tests/test_utils_metaclasses.py
      type: Module
    -   nodeid: tests/test_utils_namespace.py
      type: Module
    -   nodeid: tests/test_utils_npy.py
      type: Module
    -   nodeid: tests/test_utils_opmsg.py
      type: Module
    -   nodeid: tests/test_utils_path.py
      type: Module
    -   nodeid: tests/test_utils_picklio.py
      type: Module
    -   nodeid: tests/test_utils_printing.py
      type: Module
    -   nodeid: tests/test_utils_pv.py
      type: Module
    -   nodeid: tests/test_utils_pvpreload.py
      type: Module
    -   nodeid: tests/test_utils_pyepics.py
      type: Module
    -   nodeid: tests/test_utils_rangebar.py
      type: Module
    -   nodeid: tests/test_utils_readable.py
      type: Module
    -   nodeid: tests/test_utils_registry.py
      type: Module
    -   nodeid: tests/test_utils_reprate.py
      type: Module
    -   nodeid: tests/test_utils_richcfg.py
      type: Module
    -   nodeid: tests/test_utils_run_later.py
      type: Module
    -   nodeid: tests/test_utils_sendmail.py
      type: Module
    -   nodeid: tests/test_utils_sendsms.py
      type: Module
    -   nodeid: tests/test_utils_shortcut.py
      type: Module
    -   nodeid: tests/test_utils_snapshot.py
      type: Module
    -   nodeid: tests/test_utils_termtitle.py
      type: Module
    -   nodeid: tests/test_utils_tqdm_mod.py
      type: Module
    -   nodeid: tests/test_utils_trinary.py
      type: Module
    -   nodeid: tests/test_utils_typecast.py
      type: Module
    -   nodeid: tests/test_utils_utils.py
      type: Module
    -   nodeid: tests/test_utils_xrange.py
      type: Module
    
    • tests/test_utils_argfwd.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_argfwd.py::test_split_at[lst0-2-expected0]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_argfwd.py::test_split_at[lst1-1-expected1]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_argfwd.py::test_split_at[lst2-0-expected2]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_argfwd.py::test_merge_lists_unique[a0-b0-expected0]
        type: Function
        lineno: 16
      -   nodeid: tests/test_utils_argfwd.py::test_merge_lists_unique[a1-b1-expected1]
        type: Function
        lineno: 16
      -   nodeid: tests/test_utils_argfwd.py::test_merge_lists_unique[a2-b2-expected2]
        type: Function
        lineno: 16
      -   nodeid: tests/test_utils_argfwd.py::test_merge_dicts_unique[a0-b0-expected0]
        type: Function
        lineno: 25
      -   nodeid: tests/test_utils_argfwd.py::test_merge_dicts_unique[a1-b1-expected1]
        type: Function
        lineno: 25
      -   nodeid: tests/test_utils_argfwd.py::test_merge_dicts_unique[a2-b2-expected2]
        type: Function
        lineno: 25
      -   nodeid: tests/test_utils_argfwd.py::test_make_params_pos_basic[pos0-expected_names0]
        type: Function
        lineno: 34
      -   nodeid: tests/test_utils_argfwd.py::test_make_params_pos_basic[pos1-expected_names1]
        type: Function
        lineno: 34
      -   nodeid: tests/test_utils_argfwd.py::test_make_params_pos_basic[pos2-expected_names2]
        type: Function
        lineno: 34
      -   nodeid: tests/test_utils_argfwd.py::test_make_params_kw_basic[kw0-expected_keys0-expected_defaults0]
        type: Function
        lineno: 47
      -   nodeid: tests/test_utils_argfwd.py::test_make_params_kw_basic[kw1-expected_keys1-expected_defaults1]
        type: Function
        lineno: 47
      -   nodeid: tests/test_utils_argfwd.py::test_make_params_kw_basic[kw2-expected_keys2-expected_defaults2]
        type: Function
        lineno: 47
      -   nodeid: tests/test_utils_argfwd.py::test_make_signature_parametrized[pos0-kw0-(x, y, z=3)]
        type: Function
        lineno: 59
      -   nodeid: tests/test_utils_argfwd.py::test_make_signature_parametrized[pos1-kw1-(a, b=1, c=2)]
        type: Function
        lineno: 59
      -   nodeid: tests/test_utils_argfwd.py::test_make_signature_parametrized[pos2-kw2-(flag=False)]
        type: Function
        lineno: 59
      -   nodeid: tests/test_utils_argfwd.py::test_get_args_parametrized[<lambda>-expected_pos0-expected_kw0]
        type: Function
        lineno: 70
      -   nodeid: tests/test_utils_argfwd.py::test_get_args_parametrized[<lambda>-expected_pos1-expected_kw1]
        type: Function
        lineno: 70
      -   nodeid: tests/test_utils_argfwd.py::test_get_args_parametrized[<lambda>-expected_pos2-expected_kw2]
        type: Function
        lineno: 70
      -   nodeid: tests/test_utils_argfwd.py::test_signature_visible[wrap_all-(a, b, d=30, c=10)]
        type: Function
        lineno: 103
      -   nodeid: tests/test_utils_argfwd.py::test_signature_visible[wrap_skip-(a, b, c=10, d=20)]
        type: Function
        lineno: 103
      -   nodeid: tests/test_utils_argfwd.py::test_signature_visible[wrap_ignore_all-(x, y, c=10, d=20)]
        type: Function
        lineno: 103
      -   nodeid: tests/test_utils_argfwd.py::test_wrapper_behavior[wrap_all-args0-kwargs0-36]
        type: Function
        lineno: 111
      -   nodeid: tests/test_utils_argfwd.py::test_wrapper_behavior[wrap_all-args1-kwargs1-11]
        type: Function
        lineno: 111
      -   nodeid: tests/test_utils_argfwd.py::test_wrapper_behavior[wrap_skip-args2-kwargs2-10]
        type: Function
        lineno: 111
      -   nodeid: tests/test_utils_argfwd.py::test_wrapper_behavior[wrap_ignore_all-args3-kwargs3-10]
        type: Function
        lineno: 111
      
    • tests/test_utils_ask_yes_no.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no[None-y-True-Question? [y/n] ]
        type: Function
        lineno: 8
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no[None-yes-True-Question? [y/n] ]
        type: Function
        lineno: 8
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no[None-n-False-Question? [y/n] ]
        type: Function
        lineno: 8
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no[None-no-False-Question? [y/n] ]
        type: Function
        lineno: 8
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no[None-user_input4-True-Question? [y/n] ]
        type: Function
        lineno: 8
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no[None-user_input5-False-Question? [y/n] ]
        type: Function
        lineno: 8
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no[None-user_input6-True-Question? [y/n] ]
        type: Function
        lineno: 8
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no[y-y-True-Question? [Y/n] ]
        type: Function
        lineno: 8
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no[y-n-False-Question? [Y/n] ]
        type: Function
        lineno: 8
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no[y--True-Question? [Y/n] ]
        type: Function
        lineno: 8
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no[n-y-True-Question? [y/N] ]
        type: Function
        lineno: 8
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no[n-n-False-Question? [y/N] ]
        type: Function
        lineno: 8
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no[n--False-Question? [y/N] ]
        type: Function
        lineno: 8
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no_ctrl_c[None-KeyboardInterrupt-False-n]
        type: Function
        lineno: 46
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no_ctrl_c[None-KeyboardInterrupt-True-y]
        type: Function
        lineno: 46
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no_ctrl_c[y-KeyboardInterrupt-False-n]
        type: Function
        lineno: 46
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no_ctrl_c[y-KeyboardInterrupt-True-y]
        type: Function
        lineno: 46
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no_ctrl_c[n-KeyboardInterrupt-False-n]
        type: Function
        lineno: 46
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no_ctrl_c[None-user_input5-False-n]
        type: Function
        lineno: 46
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no_ctrl_c[None-user_input6-True-y]
        type: Function
        lineno: 46
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no_ctrl_c[None-user_input7-False-None]
        type: Function
        lineno: 46
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no_ctrl_c[n-user_input8-False-None]
        type: Function
        lineno: 46
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no_ctrl_c[n-user_input9-False-Invalid]
        type: Function
        lineno: 46
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no_ctrl_d[None-EOFError-False-n]
        type: Function
        lineno: 79
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no_ctrl_d[None-EOFError-True-y]
        type: Function
        lineno: 79
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no_ctrl_d[y-EOFError-True-y]
        type: Function
        lineno: 79
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no_ctrl_d[n-EOFError-True-y]
        type: Function
        lineno: 79
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no_ctrl_d[n-EOFError-False-n]
        type: Function
        lineno: 79
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no_ctrl_d[None-user_input5-True-y]
        type: Function
        lineno: 79
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no_ctrl_d[None-user_input6-False-n]
        type: Function
        lineno: 79
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no_ctrl_d[y-EOFError-True-None]
        type: Function
        lineno: 79
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no_ctrl_d[n-EOFError-False-None]
        type: Function
        lineno: 79
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no_ctrl_d[None-user_input9-True-None]
        type: Function
        lineno: 79
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no_ctrl_d[n-user_input10-False-None]
        type: Function
        lineno: 79
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no_ctrl_d[None-user_input11-True-None]
        type: Function
        lineno: 79
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no_ctrl_d[None-user_input12-False-n]
        type: Function
        lineno: 79
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no_ctrl_d[None-user_input13-True-y]
        type: Function
        lineno: 79
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no_mixed_sequences[None-invalid-None-user_input0-False]
        type: Function
        lineno: 117
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no_mixed_sequences[None-None-notananswer-user_input1-True]
        type: Function
        lineno: 117
      -   nodeid: tests/test_utils_ask_yes_no.py::test_ask_yes_no_mixed_sequences[None-n-nop-user_input2-False]
        type: Function
        lineno: 117
      
    • tests/test_utils_channels.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_channels.py::test_load_channels_and_channels_class_with_professional_names
        type: Function
        lineno: 42
      
    • tests/test_utils_config.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_config.py::test_config_with_nested_and_list_data
        type: Function
        lineno: 15
      -   nodeid: tests/test_utils_config.py::test_config_with_strange_and_edge_keys
        type: Function
        lineno: 73
      
    • tests/test_utils_cpint.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_cpint.py::test_load_color_variants_all_keys_and_types[red]
        type: Function
        lineno: 9
      -   nodeid: tests/test_utils_cpint.py::test_load_color_variants_all_keys_and_types[blue]
        type: Function
        lineno: 9
      -   nodeid: tests/test_utils_cpint.py::test_load_color_variants_all_keys_and_types[yellow]
        type: Function
        lineno: 9
      -   nodeid: tests/test_utils_cpint.py::test_load_color_variants_all_keys_and_types[green]
        type: Function
        lineno: 9
      -   nodeid: tests/test_utils_cpint.py::test_load_color_variants_all_keys_and_types[cyan]
        type: Function
        lineno: 9
      -   nodeid: tests/test_utils_cpint.py::test_load_color_variants_all_keys_and_types[magenta]
        type: Function
        lineno: 9
      -   nodeid: tests/test_utils_cpint.py::test_load_color_variants_all_keys_and_types[white]
        type: Function
        lineno: 9
      -   nodeid: tests/test_utils_cpint.py::test_load_color_variants_all_keys_and_types[black]
        type: Function
        lineno: 9
      -   nodeid: tests/test_utils_cpint.py::test_cprint_all_cases_fancy[objects0-color_spec0- | -['Fancy', 'list'] | {'a': 7} | None-None]
        type: Function
        lineno: 24
      -   nodeid: tests/test_utils_cpint.py::test_cprint_all_cases_fancy[objects1-color_spec1- - -{'k': [1, 2]} - 99 - ['X', ['Y']]-None]
        type: Function
        lineno: 24
      -   nodeid: tests/test_utils_cpint.py::test_cprint_all_cases_fancy[objects2-color_spec2- / -[] / {} / End-None]
        type: Function
        lineno: 24
      -   nodeid: tests/test_utils_cpint.py::test_cprint_all_cases_fancy[objects3-color_spec3-;-['', [3, 4]];done;0-None]
        type: Function
        lineno: 24
      -   nodeid: tests/test_utils_cpint.py::test_cprint_all_cases_fancy[objects4-color_spec4-::-['alpha', None]::['beta', {}]::stop-None]
        type: Function
        lineno: 24
      -   nodeid: tests/test_utils_cpint.py::test_cprint_all_cases_fancy[objects5-color_spec5- ... -['deep', ['deeper', ['deepest']]] ... X-None]
        type: Function
        lineno: 24
      -   nodeid: tests/test_utils_cpint.py::test_cprint_all_cases_fancy[objects6-color_spec6- // -{'dict': {'nested': [4, 5]}} // [True, False] // 6.28-None]
        type: Function
        lineno: 24
      -   nodeid: tests/test_utils_cpint.py::test_cprint_all_cases_fancy[objects7-color_spec7-==-['A', ['B']]==string==C-None]
        type: Function
        lineno: 24
      -   nodeid: tests/test_utils_cpint.py::test_cprint_all_cases_fancy[objects8-color_spec8- ++ -['Test', None, []] ++ {'v': 0}-None]
        type: Function
        lineno: 24
      -   nodeid: tests/test_utils_cpint.py::test_cprint_all_cases_fancy[objects9-None-;-['no', 'color'];plain-None]
        type: Function
        lineno: 24
      -   nodeid: tests/test_utils_cpint.py::test_cprint_all_cases_fancy[objects10-None- | -['simple'] |  | 12-None]
        type: Function
        lineno: 24
      -   nodeid: tests/test_utils_cpint.py::test_cprint_all_cases_fancy[objects11-None- : -[['very', 'deep']] : {'ok': True}-None]
        type: Function
        lineno: 24
      -   nodeid: tests/test_utils_cpint.py::test_cprint_all_cases_fancy[objects12-color_spec12-|-['fail', 'color']|123-ValueError]
        type: Function
        lineno: 24
      -   nodeid: tests/test_utils_cpint.py::test_cprint_all_cases_fancy[objects13-color_spec13- * -['error'] * {}-ValueError]
        type: Function
        lineno: 24
      -   nodeid: tests/test_utils_cpint.py::test_cprint_all_cases_fancy[objects14-color_spec14-//-['nope']//['bad']-ValueError]
        type: Function
        lineno: 24
      -   nodeid: tests/test_utils_cpint.py::test_cprint_all_cases_fancy[objects15-color_spec15----wrong--base-ValueError]
        type: Function
        lineno: 24
      
    • tests/test_utils_dbusnotify.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_dbusnotify.py::DBusTestCase
        type: UnitTestCase
      -   nodeid: tests/test_utils_dbusnotify.py::test_notify_create
        type: Function
        lineno: 26
      -   nodeid: tests/test_utils_dbusnotify.py::test_notify_update
        type: Function
        lineno: 37
      -   nodeid: tests/test_utils_dbusnotify.py::test_get_server_info
        type: Function
        lineno: 46
      -   nodeid: tests/test_utils_dbusnotify.py::test_get_capabilities
        type: Function
        lineno: 57
      -   nodeid: tests/test_utils_dbusnotify.py::test_notify_and_close
        type: Function
        lineno: 72
      -   nodeid: tests/test_utils_dbusnotify.py::test_notify_invalid_value
        type: Function
        lineno: 82
      -   nodeid: tests/test_utils_dbusnotify.py::test_convert_dbus_strings
        type: Function
        lineno: 88
      
    • tests/test_utils_dbusnotify.py::DBusTestCase
      • Outcome: passed
      • result:
      []
      
    • tests/test_utils_debug.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_debug.py::test_traceable[A-entry0-creating: A(10, 20)]
        type: Function
        lineno: 21
      -   nodeid: tests/test_utils_debug.py::test_traceable[A-entry1-creating: A(10, 20, e=100)]
        type: Function
        lineno: 21
      -   nodeid: tests/test_utils_debug.py::test_traceable[A-entry2-creating: A('foo', [1, 2, 3], flag=True, data={'x': 9})]
        type: Function
        lineno: 21
      -   nodeid: tests/test_utils_debug.py::test_traceable[A-entry3-creating: A(CustomObj(big), [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], name='test', meta='yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy...)]
        type: Function
        lineno: 21
      -   nodeid: tests/test_utils_debug.py::test_traceable[A-entry4-creating: A('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA..., [0, 0, 0, 0, 0])]
        type: Function
        lineno: 21
      -   nodeid: tests/test_utils_debug.py::test_short_repr[abc-10-'abc']
        type: Function
        lineno: 52
      -   nodeid: tests/test_utils_debug.py::test_short_repr[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-10-'aaaaaaaaaa...]
        type: Function
        lineno: 52
      -   nodeid: tests/test_utils_debug.py::test_short_repr[12345-10-12345]
        type: Function
        lineno: 52
      -   nodeid: tests/test_utils_debug.py::test_short_repr[value3-15-[0, 0, 0, 0, 0,...]
        type: Function
        lineno: 52
      -   nodeid: tests/test_utils_debug.py::test_short_repr[None-10-None]
        type: Function
        lineno: 52
      -   nodeid: tests/test_utils_debug.py::test_short_repr[value5-20-Obj(xxxxxxxxxxxxxxxxx...]
        type: Function
        lineno: 52
      
    • tests/test_utils_dictext.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_dictext.py::test_attrdict_getattr[data0-x-1]
        type: Function
        lineno: 12
      -   nodeid: tests/test_utils_dictext.py::test_attrdict_getattr[data1-world-ok]
        type: Function
        lineno: 12
      -   nodeid: tests/test_utils_dictext.py::test_attrdict_getattr[data2-outer-expected2]
        type: Function
        lineno: 12
      -   nodeid: tests/test_utils_dictext.py::test_attrdict_setattr[initial0-nouveau-123]
        type: Function
        lineno: 26
      -   nodeid: tests/test_utils_dictext.py::test_attrdict_setattr[initial1-b-valeur]
        type: Function
        lineno: 26
      -   nodeid: tests/test_utils_dictext.py::test_attrdict_delattr[initial0-a-expected_keys0]
        type: Function
        lineno: 40
      -   nodeid: tests/test_utils_dictext.py::test_attrdict_delattr[initial1-k-expected_keys1]
        type: Function
        lineno: 40
      -   nodeid: tests/test_utils_dictext.py::test_attrdict_dir[data0-expected_keys0]
        type: Function
        lineno: 55
      -   nodeid: tests/test_utils_dictext.py::test_attrdict_dir[data1-expected_keys1]
        type: Function
        lineno: 55
      -   nodeid: tests/test_utils_dictext.py::test_attrdict_getattr_and_missing[data0-x-1-None]
        type: Function
        lineno: 69
      -   nodeid: tests/test_utils_dictext.py::test_attrdict_getattr_and_missing[data1-missing-None-'MyDict' object has no attribute 'missing']
        type: Function
        lineno: 69
      -   nodeid: tests/test_utils_dictext.py::test_dictupdatemixin_init_and_update[init_kwargs0-None-kwargs0-expected0]
        type: Function
        lineno: 90
      -   nodeid: tests/test_utils_dictext.py::test_dictupdatemixin_init_and_update[init_kwargs1-other1-kwargs1-expected1]
        type: Function
        lineno: 90
      -   nodeid: tests/test_utils_dictext.py::test_dictupdatemixin_init_and_update[init_kwargs2-other2-kwargs2-expected2]
        type: Function
        lineno: 90
      -   nodeid: tests/test_utils_dictext.py::test_dictupdatemixin_init_and_update[init_kwargs3-None-kwargs3-expected3]
        type: Function
        lineno: 90
      -   nodeid: tests/test_utils_dictext.py::test_dictupdatemixin_init_and_update[init_kwargs4-other4-kwargs4-expected4]
        type: Function
        lineno: 90
      -   nodeid: tests/test_utils_dictext.py::test_dictupdatemixin_init_and_update[init_kwargs5-other5-kwargs5-expected5]
        type: Function
        lineno: 90
      
    • tests/test_utils_dotdir.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_dotdir.py::test_dotdir_creation_and_base_exists
        type: Function
        lineno: 14
      -   nodeid: tests/test_utils_dotdir.py::test_dotdir_repr_returns_path_str
        type: Function
        lineno: 28
      -   nodeid: tests/test_utils_dotdir.py::test_dotdir_call
        type: Function
        lineno: 35
      
    • tests/test_utils_duo.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_duo.py::TestPickledDictReal
        type: Class
      -   nodeid: tests/test_utils_duo.py::TestSecrets
        type: Class
      -   nodeid: tests/test_utils_duo.py::test_get_pgroup_raises_if_no_key
        type: Function
        lineno: 142
      -   nodeid: tests/test_utils_duo.py::test_get_pgroup_info_with_props_same_name_and_pi
        type: Function
        lineno: 148
      -   nodeid: tests/test_utils_duo.py::test_get_pgroup_info_with_props_different_pi
        type: Function
        lineno: 175
      -   nodeid: tests/test_utils_duo.py::test_get_pgroup_info_without_props_with_owner
        type: Function
        lineno: 202
      -   nodeid: tests/test_utils_duo.py::test_get_pgroup_info_without_props_no_owner
        type: Function
        lineno: 222
      -   nodeid: tests/test_utils_duo.py::test_get_pgroup_info_mock
        type: Function
        lineno: 240
      
    • tests/test_utils_duo.py::TestPickledDictReal
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_duo.py::TestPickledDictReal::test_set_get
        type: Function
        lineno: 15
      -   nodeid: tests/test_utils_duo.py::TestPickledDictReal::test_load
        type: Function
        lineno: 49
      
    • tests/test_utils_duo.py::TestSecrets
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_duo.py::TestSecrets::test_secret_workflow
        type: Function
        lineno: 93
      -   nodeid: tests/test_utils_duo.py::TestSecrets::test_multiple_secrets
        type: Function
        lineno: 110
      -   nodeid: tests/test_utils_duo.py::TestSecrets::test_keyboard_interrupt
        type: Function
        lineno: 122
      
    • tests/test_utils_elog.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_elog.py::test_get_default_elog_instance_with_direct_password_and_real_check
        type: Function
        lineno: 12
      -   nodeid: tests/test_utils_elog.py::test_get_default_elog_instance_with_wrong_password_and_real_check
        type: Function
        lineno: 31
      -   nodeid: tests/test_utils_elog.py::test_get_default_elog_instance_asks_password_and_opens
        type: Function
        lineno: 42
      -   nodeid: tests/test_utils_elog.py::test_get_default_elog_with_path_home
        type: Function
        lineno: 69
      -   nodeid: tests/test_utils_elog.py::test_screenshot
        type: Function
        lineno: 103
      
    • tests/test_utils_eval.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_valid[1 + 2-3]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_valid[4 - 2-2]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_valid[3 * 5-15]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_valid[10 / 2-5.0]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_valid[10 % 3-1]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_valid[-5--5]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_valid[+7-7]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_valid[1 + 2 * 3-7]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_valid[(1 + 2) * 3-9]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_valid[-(-3)-3]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_valid[-2 + 4 * 2-6]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_valid[(4 + 5) * (6 - 1)-45]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_valid[(((3)))-3]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_valid[-(-(-2))--2]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_valid[3 + +4-7]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_valid[3 + -4--1]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_valid[True + 1-2]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_valid['string'-string]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_valid[1e1000 * 1e1000-inf]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_valid['a' + 'b'-ab]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_raises_with_message[2 ** 3-Unsupported BinOp Pow]
        type: Function
        lineno: 33
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_raises_with_message[3 << 1-Unsupported BinOp LShift]
        type: Function
        lineno: 33
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_raises_with_message[1 < 2-Unsupported node type Compare]
        type: Function
        lineno: 33
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_raises_with_message[abs(3)-Unsupported node type Call]
        type: Function
        lineno: 33
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_raises_with_message[a + 2-Unsupported node type Name]
        type: Function
        lineno: 33
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_raises_with_message[string-Unsupported node type Name]
        type: Function
        lineno: 33
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_raises_with_message[[1, 2] + [3]-Unsupported node type List]
        type: Function
        lineno: 33
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_raises_with_message[{1: 2}-Unsupported node type Dict]
        type: Function
        lineno: 33
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_runtime_errors[1 / 0-ZeroDivisionError]
        type: Function
        lineno: 52
      -   nodeid: tests/test_utils_eval.py::test_arithmetic_eval_runtime_errors[10 % 0-ZeroDivisionError]
        type: Function
        lineno: 52
      -   nodeid: tests/test_utils_eval.py::test_forgiving_eval[1 + 2-3]
        type: Function
        lineno: 61
      -   nodeid: tests/test_utils_eval.py::test_forgiving_eval[bad + 2-bad + 2]
        type: Function
        lineno: 61
      -   nodeid: tests/test_utils_eval.py::test_forgiving_eval[1 / 0-1 / 0]
        type: Function
        lineno: 61
      -   nodeid: tests/test_utils_eval.py::test_forgiving_eval[2 ** 10-2 ** 10]
        type: Function
        lineno: 61
      -   nodeid: tests/test_utils_eval.py::test_defaulting_eval[3 * 4-0-12]
        type: Function
        lineno: 71
      -   nodeid: tests/test_utils_eval.py::test_defaulting_eval[invalid + 1-99-99]
        type: Function
        lineno: 71
      -   nodeid: tests/test_utils_eval.py::test_defaulting_eval[1 / 0--1--1]
        type: Function
        lineno: 71
      -   nodeid: tests/test_utils_eval.py::test_defaulting_eval[2 ** 10-42-42]
        type: Function
        lineno: 71
      
    • tests/test_utils_exceptions.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_exceptions.py::test_chained_exception_various[cause_key_error-High-level task failed\ncaused by KeyError: 'missing']
        type: Function
        lineno: 28
      -   nodeid: tests/test_utils_exceptions.py::test_chained_exception_various[cause_index_error-High-level task failed\ncaused by IndexError: list index out of range]
        type: Function
        lineno: 28
      -   nodeid: tests/test_utils_exceptions.py::test_chained_exception_various[cause_zero_division-High-level task failed\ncaused by ZeroDivisionError: division by zero]
        type: Function
        lineno: 28
      -   nodeid: tests/test_utils_exceptions.py::test_chained_exception_various[cause_value_error-High-level task failed\ncaused by ValueError: invalid literal for int() with base 10: 'not_a_number']
        type: Function
        lineno: 28
      -   nodeid: tests/test_utils_exceptions.py::test_chained_exception_various[cause_type_error-High-level task failed\ncaused by TypeError: can only concatenate str (not "int") to str]
        type: Function
        lineno: 28
      -   nodeid: tests/test_utils_exceptions.py::test_printed_exception[cause_key_error-KeyError: 'missing']
        type: Function
        lineno: 60
      -   nodeid: tests/test_utils_exceptions.py::test_printed_exception[cause_index_error-IndexError: list index out of range]
        type: Function
        lineno: 60
      -   nodeid: tests/test_utils_exceptions.py::test_printed_exception[cause_zero_division-ZeroDivisionError: division by zero]
        type: Function
        lineno: 60
      -   nodeid: tests/test_utils_exceptions.py::test_printed_exception[cause_value_error-ValueError: invalid literal for int() with base 10: 'not_a_number']
        type: Function
        lineno: 60
      -   nodeid: tests/test_utils_exceptions.py::test_printed_exception[cause_type_error-TypeError: can only concatenate str (not "int") to str]
        type: Function
        lineno: 60
      
    • tests/test_utils_get_adj.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_get_adj.py::test_get_adj_success
        type: Function
        lineno: 23
      -   nodeid: tests/test_utils_get_adj.py::test_get_adj_not_found
        type: Function
        lineno: 27
      -   nodeid: tests/test_utils_get_adj.py::test_ensure_adjs_mixed
        type: Function
        lineno: 31
      -   nodeid: tests/test_utils_get_adj.py::test_get_adjs_filter
        type: Function
        lineno: 37
      
    • tests/test_utils_hastepics.py
      • Outcome: passed
      • result:
      []
      
    • tests/test_utils_ipy.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_ipy.py::test_devices_repr_fallback_and_ignore
        type: Function
        lineno: 19
      
    • tests/test_utils_jsonext.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_jsonext.py::test_json_validate_save_load[input_obj0-expected0]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_jsonext.py::test_json_validate_save_load[input_obj1-42]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_jsonext.py::test_json_validate_save_load[(1-1j)-expected2]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_jsonext.py::test_json_validate_save_load[input_obj3-/tmp/file.txt]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_jsonext.py::test_json_validate_save_load[input_obj4-expected4]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_jsonext.py::test_json_validate_save_load[input_obj5-expected5]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_jsonext.py::test_json_validate_save_load[input_obj6-expected6]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_jsonext.py::test_json_validate_save_load[input_obj7-expected7]
        type: Function
        lineno: 7
      
    • tests/test_utils_lazypv.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_lazypv.py::test_getattr
        type: Function
        lineno: 7
      
    • tests/test_utils_logcfg.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_logcfg.py::test_custom_log_outputs[LONG-<lambda>-This is a LONG message]
        type: Function
        lineno: 21
      -   nodeid: tests/test_utils_logcfg.py::test_custom_log_outputs[ENLARGE-<lambda>-Please ENLARGE this!]
        type: Function
        lineno: 21
      -   nodeid: tests/test_utils_logcfg.py::test_import_logging_once_per_module
        type: Function
        lineno: 51
      
    • tests/test_utils_logign.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_logign.py::test_ignore_log_msg_behavior[WARNING-This should be ignored-This should appear]
        type: Function
        lineno: 9
      -   nodeid: tests/test_utils_logign.py::test_ignore_log_msg_behavior[ENLARGE-ENLARGE this-Keep this ENLARGE]
        type: Function
        lineno: 9
      -   nodeid: tests/test_utils_logign.py::test_ignore_only_by_level
        type: Function
        lineno: 42
      -   nodeid: tests/test_utils_logign.py::test_ignore_only_by_msg
        type: Function
        lineno: 64
      -   nodeid: tests/test_utils_logign.py::test_filter_removed_after_context
        type: Function
        lineno: 86
      
    • tests/test_utils_marker.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_marker.py::test_format_value_with_units
        type: Function
        lineno: 30
      -   nodeid: tests/test_utils_marker.py::test_format_value_without_units
        type: Function
        lineno: 33
      -   nodeid: tests/test_utils_marker.py::test_marker_name_default
        type: Function
        lineno: 39
      -   nodeid: tests/test_utils_marker.py::test_marker_name_custom
        type: Function
        lineno: 44
      -   nodeid: tests/test_utils_marker.py::test_marker_repr_format
        type: Function
        lineno: 49
      -   nodeid: tests/test_utils_marker.py::test_marker_update_changes_value
        type: Function
        lineno: 56
      -   nodeid: tests/test_utils_marker.py::test_marker_update_with_explicit_value
        type: Function
        lineno: 63
      -   nodeid: tests/test_utils_marker.py::test_marker_goto_sets_value_and_returns_result
        type: Function
        lineno: 69
      -   nodeid: tests/test_utils_marker.py::test_marker_call_is_alias_of_goto
        type: Function
        lineno: 77
      -   nodeid: tests/test_utils_marker.py::test_markers_register_and_access
        type: Function
        lineno: 87
      -   nodeid: tests/test_utils_marker.py::test_markers_repr_contains_all
        type: Function
        lineno: 103
      -   nodeid: tests/test_utils_marker.py::test_marker_registry_dict_is_printable_dict
        type: Function
        lineno: 114
      -   nodeid: tests/test_utils_marker.py::test_markers_getitem_invalid_key_raises
        type: Function
        lineno: 122
      
    • tests/test_utils_metaclasses.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_metaclasses.py::test_combine_classes_combines_methods
        type: Function
        lineno: 14
      -   nodeid: tests/test_utils_metaclasses.py::test_registryabc_combines_registrymeta_and_abcmeta
        type: Function
        lineno: 25
      
    • tests/test_utils_namespace.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_namespace.py::test_namespace_pretty_repr_mixed_and_nested
        type: Function
        lineno: 4
      
    • tests/test_utils_npy.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_npy.py::test_nice_arange[0-5-1-expected0]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_npy.py::test_nice_arange[5-0--1-expected1]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_npy.py::test_nice_arange[1-2-0.3-expected2]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_npy.py::test_nice_arange[-2-2-1.5-expected3]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_npy.py::test_nice_arange[2.5-0.5--0.4-expected4]
        type: Function
        lineno: 7
      -   nodeid: tests/test_utils_npy.py::test_nice_linspace[0-10-4-expected0]
        type: Function
        lineno: 18
      -   nodeid: tests/test_utils_npy.py::test_nice_linspace[5-15-2-expected1]
        type: Function
        lineno: 18
      -   nodeid: tests/test_utils_npy.py::test_nice_linspace[-5-5-4-expected2]
        type: Function
        lineno: 18
      -   nodeid: tests/test_utils_npy.py::test_nice_linspace[0-1-3-expected3]
        type: Function
        lineno: 18
      -   nodeid: tests/test_utils_npy.py::test_nice_linspace[2-2-3-expected4]
        type: Function
        lineno: 18
      -   nodeid: tests/test_utils_npy.py::test_nice_linspace[3-0-3-expected5]
        type: Function
        lineno: 18
      -   nodeid: tests/test_utils_npy.py::test_nice_linspace[0-1-0-expected6]
        type: Function
        lineno: 18
      -   nodeid: tests/test_utils_npy.py::test_nice_linspace[-2-2-3-expected7]
        type: Function
        lineno: 18
      -   nodeid: tests/test_utils_npy.py::test_nice_steps_centered[-2-2-2-True-expected0]
        type: Function
        lineno: 33
      -   nodeid: tests/test_utils_npy.py::test_nice_steps_centered[0-5-2-True-expected1]
        type: Function
        lineno: 33
      -   nodeid: tests/test_utils_npy.py::test_nice_steps_centered[0-5-2-False-expected2]
        type: Function
        lineno: 33
      -   nodeid: tests/test_utils_npy.py::test_nice_steps_centered[-1-2-1.5-True-expected3]
        type: Function
        lineno: 33
      -   nodeid: tests/test_utils_npy.py::test_nice_steps_centered[-1-2--1.5-True-expected4]
        type: Function
        lineno: 33
      -   nodeid: tests/test_utils_npy.py::test_nice_steps_centered[5-0--2-True-expected5]
        type: Function
        lineno: 33
      -   nodeid: tests/test_utils_npy.py::test_nice_steps_left_aligned[0-5-2-True-expected0]
        type: Function
        lineno: 46
      -   nodeid: tests/test_utils_npy.py::test_nice_steps_left_aligned[0-5-2-False-expected1]
        type: Function
        lineno: 46
      -   nodeid: tests/test_utils_npy.py::test_nice_steps_left_aligned[-1-2-1.5-True-expected2]
        type: Function
        lineno: 46
      -   nodeid: tests/test_utils_npy.py::test_nice_steps_left_aligned[-1-2-1.5-False-expected3]
        type: Function
        lineno: 46
      -   nodeid: tests/test_utils_npy.py::test_nice_steps_left_aligned[-2-1-1.2-True-expected4]
        type: Function
        lineno: 46
      -   nodeid: tests/test_utils_npy.py::test_nice_steps_left_aligned[5-0--2-True-expected5]
        type: Function
        lineno: 46
      -   nodeid: tests/test_utils_npy.py::test_nice_steps_left_aligned[5-0--2-False-expected6]
        type: Function
        lineno: 46
      -   nodeid: tests/test_utils_npy.py::test_nice_steps_right_aligned[0-5-2-True-expected0]
        type: Function
        lineno: 60
      -   nodeid: tests/test_utils_npy.py::test_nice_steps_right_aligned[0-5-2-False-expected1]
        type: Function
        lineno: 60
      -   nodeid: tests/test_utils_npy.py::test_nice_steps_right_aligned[-1-2-1.5-True-expected2]
        type: Function
        lineno: 60
      -   nodeid: tests/test_utils_npy.py::test_nice_steps_right_aligned[-1-2-1.5-False-expected3]
        type: Function
        lineno: 60
      -   nodeid: tests/test_utils_npy.py::test_nice_steps_right_aligned[5-0--2-True-expected4]
        type: Function
        lineno: 60
      -   nodeid: tests/test_utils_npy.py::test_nice_steps_right_aligned[5-0--2-False-expected5]
        type: Function
        lineno: 60
      -   nodeid: tests/test_utils_npy.py::test_nice_steps_right_aligned[-3-3-2-True-expected6]
        type: Function
        lineno: 60
      -   nodeid: tests/test_utils_npy.py::test_within_scalar[5-0-10-True]
        type: Function
        lineno: 74
      -   nodeid: tests/test_utils_npy.py::test_within_scalar[5-6-10-False]
        type: Function
        lineno: 74
      -   nodeid: tests/test_utils_npy.py::test_within_scalar[5-None-10-True]
        type: Function
        lineno: 74
      -   nodeid: tests/test_utils_npy.py::test_within_scalar[5-0-None-True]
        type: Function
        lineno: 74
      -   nodeid: tests/test_utils_npy.py::test_within_scalar[5-None-None-True]
        type: Function
        lineno: 74
      -   nodeid: tests/test_utils_npy.py::test_within_fraction[data0-2-5-0.6]
        type: Function
        lineno: 85
      -   nodeid: tests/test_utils_npy.py::test_within_fraction[data1-5-25-0.6666666666666666]
        type: Function
        lineno: 85
      -   nodeid: tests/test_utils_npy.py::test_within_fraction[data2-None-2-0.3333333333333333]
        type: Function
        lineno: 85
      -   nodeid: tests/test_utils_npy.py::test_within_fraction[data3-0-1-0]
        type: Function
        lineno: 85
      -   nodeid: tests/test_utils_npy.py::test_fraction_to_percentage[0.456-1-45.6]
        type: Function
        lineno: 96
      -   nodeid: tests/test_utils_npy.py::test_fraction_to_percentage[0.12345-2-12.35]
        type: Function
        lineno: 96
      -   nodeid: tests/test_utils_npy.py::test_fraction_to_percentage[0.9999-0-100.0]
        type: Function
        lineno: 96
      -   nodeid: tests/test_utils_npy.py::test_get_dtype[val0-ndarray]
        type: Function
        lineno: 105
      -   nodeid: tests/test_utils_npy.py::test_get_dtype[val1-list]
        type: Function
        lineno: 105
      -   nodeid: tests/test_utils_npy.py::test_get_dtype[3.14-float]
        type: Function
        lineno: 105
      -   nodeid: tests/test_utils_npy.py::test_get_shape[val0-expected0]
        type: Function
        lineno: 118
      -   nodeid: tests/test_utils_npy.py::test_get_shape[val1-expected1]
        type: Function
        lineno: 118
      -   nodeid: tests/test_utils_npy.py::test_get_shape[42-expected2]
        type: Function
        lineno: 118
      -   nodeid: tests/test_utils_npy.py::test_is_array[val0-True]
        type: Function
        lineno: 127
      -   nodeid: tests/test_utils_npy.py::test_is_array[val1-False]
        type: Function
        lineno: 127
      -   nodeid: tests/test_utils_npy.py::test_is_array[42-False]
        type: Function
        lineno: 127
      
    • tests/test_utils_opmsg.py
      • Outcome: passed
      • result:
      []
      
    • tests/test_utils_path.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_path.py::test_can_create_all_files_user_says_yes
        type: Function
        lineno: 10
      -   nodeid: tests/test_utils_path.py::test_can_create_all_files_user_says_no
        type: Function
        lineno: 36
      -   nodeid: tests/test_utils_path.py::test_make_missing_dir_creates_folder
        type: Function
        lineno: 54
      -   nodeid: tests/test_utils_path.py::test_glob_files_returns_matching_files_only
        type: Function
        lineno: 66
      -   nodeid: tests/test_utils_path.py::test_filter_files_excludes_directories
        type: Function
        lineno: 83
      
    • tests/test_utils_picklio.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_picklio.py::test_pickle_and_unpickle[test_obj0]
        type: Function
        lineno: 6
      -   nodeid: tests/test_utils_picklio.py::test_pickle_and_unpickle[test_obj1]
        type: Function
        lineno: 6
      -   nodeid: tests/test_utils_picklio.py::test_pickle_and_unpickle[simple string]
        type: Function
        lineno: 6
      -   nodeid: tests/test_utils_picklio.py::test_pickle_and_unpickle[42]
        type: Function
        lineno: 6
      -   nodeid: tests/test_utils_picklio.py::test_pickle_and_unpickle[3.14159]
        type: Function
        lineno: 6
      -   nodeid: tests/test_utils_picklio.py::test_pickle_and_unpickle[test_obj5]
        type: Function
        lineno: 6
      -   nodeid: tests/test_utils_picklio.py::test_pickle_and_unpickle[test_obj6]
        type: Function
        lineno: 6
      
    • tests/test_utils_printing.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_printing.py::test_maxlen_valid[seq0-3]
        type: Function
        lineno: 8
      -   nodeid: tests/test_utils_printing.py::test_maxlen_valid[seq1-0]
        type: Function
        lineno: 8
      -   nodeid: tests/test_utils_printing.py::test_maxlen_valid[seq2-3]
        type: Function
        lineno: 8
      -   nodeid: tests/test_utils_printing.py::test_maxlen_valid[seq3-2]
        type: Function
        lineno: 8
      -   nodeid: tests/test_utils_printing.py::test_strlen[42-2]
        type: Function
        lineno: 17
      -   nodeid: tests/test_utils_printing.py::test_strlen[hello-5]
        type: Function
        lineno: 17
      -   nodeid: tests/test_utils_printing.py::test_strlen[False-5]
        type: Function
        lineno: 17
      -   nodeid: tests/test_utils_printing.py::test_strlen[None-4]
        type: Function
        lineno: 17
      -   nodeid: tests/test_utils_printing.py::test_strlen[value4-9]
        type: Function
        lineno: 17
      -   nodeid: tests/test_utils_printing.py::test_strlen[value5-8]
        type: Function
        lineno: 17
      -   nodeid: tests/test_utils_printing.py::test_strlen[value6-6]
        type: Function
        lineno: 17
      -   nodeid: tests/test_utils_printing.py::test_strlen[-0]
        type: Function
        lineno: 17
      -   nodeid: tests/test_utils_printing.py::test_strlen[this is a phrase-16]
        type: Function
        lineno: 17
      -   nodeid: tests/test_utils_printing.py::test_maxstrlen[seq0-6]
        type: Function
        lineno: 31
      -   nodeid: tests/test_utils_printing.py::test_maxstrlen[seq1-3]
        type: Function
        lineno: 31
      -   nodeid: tests/test_utils_printing.py::test_maxstrlen[seq2-9]
        type: Function
        lineno: 31
      -   nodeid: tests/test_utils_printing.py::test_maxstrlen[seq3-16]
        type: Function
        lineno: 31
      -   nodeid: tests/test_utils_printing.py::test_maxstrlen[seq4-5]
        type: Function
        lineno: 31
      -   nodeid: tests/test_utils_printing.py::test_transpose_matrix[data0-expected0]
        type: Function
        lineno: 41
      -   nodeid: tests/test_utils_printing.py::test_transpose_matrix[data1-expected1]
        type: Function
        lineno: 41
      -   nodeid: tests/test_utils_printing.py::test_transpose_matrix[data2-expected2]
        type: Function
        lineno: 41
      -   nodeid: tests/test_utils_printing.py::test_prepend[initial0-1-expected0]
        type: Function
        lineno: 50
      -   nodeid: tests/test_utils_printing.py::test_prepend[initial1-a-expected1]
        type: Function
        lineno: 50
      -   nodeid: tests/test_utils_printing.py::test_prepend[initial2-prepend2-expected2]
        type: Function
        lineno: 50
      -   nodeid: tests/test_utils_printing.py::test_prepend[initial3-prepend3-expected3]
        type: Function
        lineno: 50
      -   nodeid: tests/test_utils_printing.py::test_fmt_table_line[entries0-widths0-  a   bbb]
        type: Function
        lineno: 61
      -   nodeid: tests/test_utils_printing.py::test_fmt_table_line[entries1-widths1- 1  2]
        type: Function
        lineno: 61
      -   nodeid: tests/test_utils_printing.py::test_fmt_table_line[entries2-widths2-  long  val]
        type: Function
        lineno: 61
      -   nodeid: tests/test_utils_printing.py::test_fmt_table_line[entries3-widths3- True  False]
        type: Function
        lineno: 61
      -   nodeid: tests/test_utils_printing.py::test_fmt_table_line[entries4-widths4-  123  4567]
        type: Function
        lineno: 61
      -   nodeid: tests/test_utils_printing.py::test_fmt_table_line[entries5-widths5- text with space   end]
        type: Function
        lineno: 61
      -   nodeid: tests/test_utils_printing.py::test_fmt_table_line[entries6-widths6-  {'a': 1}   {'b': 2}]
        type: Function
        lineno: 61
      -   nodeid: tests/test_utils_printing.py::test_fmt_table_line[entries7-widths7-    [1, 2]     [3, 4]]
        type: Function
        lineno: 61
      -   nodeid: tests/test_utils_printing.py::test_fmt_label_sep[widths0------ ----]
        type: Function
        lineno: 74
      -   nodeid: tests/test_utils_printing.py::test_fmt_label_sep[widths1-=-== ===]
        type: Function
        lineno: 74
      -   nodeid: tests/test_utils_printing.py::test_fmt_label_sep[widths2-*-***** **]
        type: Function
        lineno: 74
      -   nodeid: tests/test_utils_printing.py::test_printable_dict_with_header[d0-HeaderTest-expected_lines0]
        type: Function
        lineno: 82
      -   nodeid: tests/test_utils_printing.py::test_printable_dict_of_dicts
        type: Function
        lineno: 101
      -   nodeid: tests/test_utils_printing.py::test_printable_table[data0-labels0-A: ID\nB: \u2713 Success?\nC: SuperPrecisionValue\nD: Result Metadata\n\n#             A     B          C                            D\n- ------------- ----- ---------- ----------------------------\n0            X1  True     0.1234               {'meta': 'ok'}\n1 AnotherSample False 98765.4321          {'meta': [1, 2, 3]}\n2             Z  None        0.0 {'meta': {'nested_key': 42}}]
        type: Function
        lineno: 128
      
    • tests/test_utils_pv.py
      • Outcome: passed
      • result:
      []
      
    • tests/test_utils_pvpreload.py
      • Outcome: passed
      • result:
      []
      
    • tests/test_utils_pyepics.py
      • Outcome: passed
      • result:
      []
      
    • tests/test_utils_rangebar.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_rangebar.py::test_full_progress_bar
        type: Function
        lineno: 10
      -   nodeid: tests/test_utils_rangebar.py::test_half_progress_bar
        type: Function
        lineno: 24
      -   nodeid: tests/test_utils_rangebar.py::test_zero_progress_bar
        type: Function
        lineno: 39
      -   nodeid: tests/test_utils_rangebar.py::test_overflow_bar
        type: Function
        lineno: 54
      -   nodeid: tests/test_utils_rangebar.py::test_underflow_bar
        type: Function
        lineno: 68
      -   nodeid: tests/test_utils_rangebar.py::test_repr
        type: Function
        lineno: 82
      -   nodeid: tests/test_utils_rangebar.py::test_each_value_separately[0-          ]
        type: Function
        lineno: 88
      -   nodeid: tests/test_utils_rangebar.py::test_each_value_separately[10-\u2588         ]
        type: Function
        lineno: 88
      -   nodeid: tests/test_utils_rangebar.py::test_each_value_separately[25-\u2588\u2588\u258c       ]
        type: Function
        lineno: 88
      -   nodeid: tests/test_utils_rangebar.py::test_each_value_separately[27-\u2588\u2588\u258a       ]
        type: Function
        lineno: 88
      -   nodeid: tests/test_utils_rangebar.py::test_each_value_separately[49-\u2588\u2588\u2588\u2588\u2589     ]
        type: Function
        lineno: 88
      -   nodeid: tests/test_utils_rangebar.py::test_each_value_separately[50-\u2588\u2588\u2588\u2588\u2588     ]
        type: Function
        lineno: 88
      -   nodeid: tests/test_utils_rangebar.py::test_each_value_separately[51-\u2588\u2588\u2588\u2588\u2588\u258f    ]
        type: Function
        lineno: 88
      -   nodeid: tests/test_utils_rangebar.py::test_each_value_separately[73-\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u258e  ]
        type: Function
        lineno: 88
      -   nodeid: tests/test_utils_rangebar.py::test_each_value_separately[75-\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u258c  ]
        type: Function
        lineno: 88
      -   nodeid: tests/test_utils_rangebar.py::test_each_value_separately[90-\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 ]
        type: Function
        lineno: 88
      -   nodeid: tests/test_utils_rangebar.py::test_each_value_separately[100-\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588]
        type: Function
        lineno: 88
      
    • tests/test_utils_readable.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_readable.py::test_readable_seconds[59.4-59 seconds]
        type: Function
        lineno: 3
      -   nodeid: tests/test_utils_readable.py::test_readable_seconds[59.9-60 seconds]
        type: Function
        lineno: 3
      -   nodeid: tests/test_utils_readable.py::test_readable_seconds[119.9-120 seconds]
        type: Function
        lineno: 3
      -   nodeid: tests/test_utils_readable.py::test_readable_seconds[120.1-2 minutes]
        type: Function
        lineno: 3
      -   nodeid: tests/test_utils_readable.py::test_readable_seconds[3599.9-60 minutes]
        type: Function
        lineno: 3
      -   nodeid: tests/test_utils_readable.py::test_readable_seconds[3600.1-60 minutes]
        type: Function
        lineno: 3
      -   nodeid: tests/test_utils_readable.py::test_readable_seconds[7199.9-120 minutes]
        type: Function
        lineno: 3
      -   nodeid: tests/test_utils_readable.py::test_readable_seconds[7200.1-2 hours]
        type: Function
        lineno: 3
      -   nodeid: tests/test_utils_readable.py::test_readable_seconds[90.4-90 seconds]
        type: Function
        lineno: 3
      -   nodeid: tests/test_utils_readable.py::test_readable_seconds[90.6-91 seconds]
        type: Function
        lineno: 3
      -   nodeid: tests/test_utils_readable.py::test_readable_seconds[121.9-2 minutes]
        type: Function
        lineno: 3
      -   nodeid: tests/test_utils_readable.py::test_readable_seconds[1296000.0-2 weeks]
        type: Function
        lineno: 3
      -   nodeid: tests/test_utils_readable.py::test_readable_seconds[2592000.0-4 weeks]
        type: Function
        lineno: 3
      -   nodeid: tests/test_utils_readable.py::test_readable_seconds[2800000.0-5 weeks]
        type: Function
        lineno: 3
      -   nodeid: tests/test_utils_readable.py::test_readable_seconds[3888000.0-6 weeks]
        type: Function
        lineno: 3
      -   nodeid: tests/test_utils_readable.py::test_readable_seconds[5097600.0-8 weeks]
        type: Function
        lineno: 3
      -   nodeid: tests/test_utils_readable.py::test_readable_seconds[5184000.0-9 weeks]
        type: Function
        lineno: 3
      -   nodeid: tests/test_utils_readable.py::test_readable_seconds[5270400.0-2 months]
        type: Function
        lineno: 3
      -   nodeid: tests/test_utils_readable.py::test_readable_seconds[23328000.0-9 months]
        type: Function
        lineno: 3
      -   nodeid: tests/test_utils_readable.py::test_readable_seconds[31104000.0-12 months]
        type: Function
        lineno: 3
      -   nodeid: tests/test_utils_readable.py::test_readable_seconds[33696000.0-13 months]
        type: Function
        lineno: 3
      -   nodeid: tests/test_utils_readable.py::test_readable_seconds[59616000.0-23 months]
        type: Function
        lineno: 3
      -   nodeid: tests/test_utils_readable.py::test_readable_seconds[62208000.0-24 months]
        type: Function
        lineno: 3
      -   nodeid: tests/test_utils_readable.py::test_readable_seconds[64208000.0-2 years]
        type: Function
        lineno: 3
      
    • tests/test_utils_registry.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_registry.py::test_metaclass_creates_weakset
        type: Function
        lineno: 13
      -   nodeid: tests/test_utils_registry.py::test_metaclass_tracks_instances
        type: Function
        lineno: 22
      -   nodeid: tests/test_utils_registry.py::test_registry_inheritance
        type: Function
        lineno: 32
      -   nodeid: tests/test_utils_registry.py::test_instance_tracking
        type: Function
        lineno: 39
      -   nodeid: tests/test_utils_registry.py::test_collect_instances_recursive
        type: Function
        lineno: 53
      -   nodeid: tests/test_utils_registry.py::test_instances_function
        type: Function
        lineno: 69
      -   nodeid: tests/test_utils_registry.py::test_non_registry_class_error
        type: Function
        lineno: 93
      -   nodeid: tests/test_utils_registry.py::test_signature_preservation
        type: Function
        lineno: 102
      
    • tests/test_utils_reprate.py
      • Outcome: passed
      • result:
      []
      
    • tests/test_utils_richcfg.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_richcfg.py::test_rich_inspector_outputs_more_than_builtin
        type: Function
        lineno: 45
      
    • tests/test_utils_run_later.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_run_later.py::test_init_and_repr
        type: Function
        lineno: 17
      -   nodeid: tests/test_utils_run_later.py::test_call
        type: Function
        lineno: 22
      -   nodeid: tests/test_utils_run_later.py::test_matmul_with_string
        type: Function
        lineno: 27
      -   nodeid: tests/test_utils_run_later.py::test_matmul_with_list
        type: Function
        lineno: 32
      -   nodeid: tests/test_utils_run_later.py::test_matmul_with_single_int
        type: Function
        lineno: 37
      -   nodeid: tests/test_utils_run_later.py::test_run_at_future_triggered_and_logs
        type: Function
        lineno: 49
      -   nodeid: tests/test_utils_run_later.py::test_run_at_already_past
        type: Function
        lineno: 61
      -   nodeid: tests/test_utils_run_later.py::test_run_in_future_triggered_and_logs
        type: Function
        lineno: 72
      -   nodeid: tests/test_utils_run_later.py::test_run_in_past
        type: Function
        lineno: 83
      -   nodeid: tests/test_utils_run_later.py::test_run_later_with_seconds
        type: Function
        lineno: 95
      -   nodeid: tests/test_utils_run_later.py::test_run_later_with_past_datetime
        type: Function
        lineno: 105
      -   nodeid: tests/test_utils_run_later.py::test_run_at_tqdm_multiple_updates
        type: Function
        lineno: 115
      -   nodeid: tests/test_utils_run_later.py::test_today_basic
        type: Function
        lineno: 137
      -   nodeid: tests/test_utils_run_later.py::test_tomorrow_basic
        type: Function
        lineno: 143
      -   nodeid: tests/test_utils_run_later.py::test_yesterday_basic
        type: Function
        lineno: 149
      -   nodeid: tests/test_utils_run_later.py::test_today_matmul_string
        type: Function
        lineno: 155
      -   nodeid: tests/test_utils_run_later.py::test_tomorrow_matmul_list
        type: Function
        lineno: 161
      -   nodeid: tests/test_utils_run_later.py::test_yesterday_matmul_single
        type: Function
        lineno: 167
      
    • tests/test_utils_sendmail.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_sendmail.py::test_sendmail_local_delivery
        type: Function
        lineno: 13
      -   nodeid: tests/test_utils_sendmail.py::test_sendmail_raises_on_sendmail_failure
        type: Function
        lineno: 60
      
    • tests/test_utils_sendsms.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_sendsms.py::test_sendsms_local_delivery
        type: Function
        lineno: 6
      
    • tests/test_utils_shortcut.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_shortcut.py::TestShortcutInitialization
        type: Class
      -   nodeid: tests/test_utils_shortcut.py::test_run_method
        type: Function
        lineno: 31
      -   nodeid: tests/test_utils_shortcut.py::test_repr_output
        type: Function
        lineno: 54
      -   nodeid: tests/test_utils_shortcut.py::test_source_with_regular_function
        type: Function
        lineno: 62
      -   nodeid: tests/test_utils_shortcut.py::test_source_error_handling
        type: Function
        lineno: 76
      -   nodeid: tests/test_utils_shortcut.py::test_as_shortcut_basic
        type: Function
        lineno: 86
      -   nodeid: tests/test_utils_shortcut.py::test_as_shortcut_with_name
        type: Function
        lineno: 96
      -   nodeid: tests/test_utils_shortcut.py::test_as_shortcut_factory_pattern
        type: Function
        lineno: 104
      -   nodeid: tests/test_utils_shortcut.py::TestShortcutsSingleton
        type: Class
      -   nodeid: tests/test_utils_shortcut.py::TestFullIntegration
        type: Class
      -   nodeid: tests/test_utils_shortcut.py::test_registry_inheritance
        type: Function
        lineno: 204
      
    • tests/test_utils_shortcut.py::TestFullIntegration
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_shortcut.py::TestFullIntegration::test_workflow
        type: Function
        lineno: 170
      -   nodeid: tests/test_utils_shortcut.py::TestFullIntegration::test_multiple_shortcuts
        type: Function
        lineno: 190
      
    • tests/test_utils_shortcut.py::TestShortcutInitialization
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_shortcut.py::TestShortcutInitialization::test_init_with_custom_name
        type: Function
        lineno: 16
      -   nodeid: tests/test_utils_shortcut.py::TestShortcutInitialization::test_init_without_name
        type: Function
        lineno: 23
      
    • tests/test_utils_shortcut.py::TestShortcutsSingleton
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_shortcut.py::TestShortcutsSingleton::test_singleton_behavior
        type: Function
        lineno: 121
      -   nodeid: tests/test_utils_shortcut.py::TestShortcutsSingleton::test_registration
        type: Function
        lineno: 127
      -   nodeid: tests/test_utils_shortcut.py::TestShortcutsSingleton::test_getitem_access
        type: Function
        lineno: 141
      -   nodeid: tests/test_utils_shortcut.py::TestShortcutsSingleton::test_missing_key
        type: Function
        lineno: 149
      -   nodeid: tests/test_utils_shortcut.py::TestShortcutsSingleton::test_repr_output
        type: Function
        lineno: 154
      
    • tests/test_utils_snapshot.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_snapshot.py::test_snapshot[exclude_internals]
        type: Function
        lineno: 83
      -   nodeid: tests/test_utils_snapshot.py::test_snapshot[include_internals]
        type: Function
        lineno: 83
      -   nodeid: tests/test_utils_snapshot.py::test_snapshot[empty_case]
        type: Function
        lineno: 83
      -   nodeid: tests/test_utils_snapshot.py::test_snapshot[sort_str]
        type: Function
        lineno: 83
      -   nodeid: tests/test_utils_snapshot.py::test_snapshot[sort_id]
        type: Function
        lineno: 83
      -   nodeid: tests/test_utils_snapshot.py::test_snapshot[sort_case_insensitive]
        type: Function
        lineno: 83
      -   nodeid: tests/test_utils_snapshot.py::test_snapshot[sort_length]
        type: Function
        lineno: 83
      -   nodeid: tests/test_utils_snapshot.py::test_snapshot[sort_reverse]
        type: Function
        lineno: 83
      
    • tests/test_utils_termtitle.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_termtitle.py::test_terminal_title_with_tmux
        type: Function
        lineno: 9
      
    • tests/test_utils_tqdm_mod.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_tqdm_mod.py::test_complete_progress_bar
        type: Function
        lineno: 25
      -   nodeid: tests/test_utils_tqdm_mod.py::test_set_progress_multiple_points
        type: Function
        lineno: 42
      -   nodeid: tests/test_utils_tqdm_mod.py::test_format_sizeof_alignment
        type: Function
        lineno: 65
      -   nodeid: tests/test_utils_tqdm_mod.py::test_float_alignment_in_bar
        type: Function
        lineno: 83
      -   nodeid: tests/test_utils_tqdm_mod.py::test_custom_unit
        type: Function
        lineno: 132
      -   nodeid: tests/test_utils_tqdm_mod.py::test_clamp_above_total
        type: Function
        lineno: 146
      -   nodeid: tests/test_utils_tqdm_mod.py::test_clamp_below_zero
        type: Function
        lineno: 163
      
    • tests/test_utils_trinary.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_trinary.py::test_check_trinary_valid_values
        type: Function
        lineno: 6
      -   nodeid: tests/test_utils_trinary.py::test_check_trinary_invalid_value
        type: Function
        lineno: 14
      -   nodeid: tests/test_utils_trinary.py::test_check_trinary_with_custom_allowed_values
        type: Function
        lineno: 22
      
    • tests/test_utils_typecast.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_typecast.py::test_downcast_success
        type: Function
        lineno: 24
      -   nodeid: tests/test_utils_typecast.py::test_upcast_success
        type: Function
        lineno: 30
      -   nodeid: tests/test_utils_typecast.py::test_downcast_invalid
        type: Function
        lineno: 41
      -   nodeid: tests/test_utils_typecast.py::test_upcast_invalid
        type: Function
        lineno: 48
      -   nodeid: tests/test_utils_typecast.py::test_object_identity_preserved
        type: Function
        lineno: 53
      -   nodeid: tests/test_utils_typecast.py::test_ensure_subclass_valid
        type: Function
        lineno: 64
      -   nodeid: tests/test_utils_typecast.py::test_ensure_subclass_invalid
        type: Function
        lineno: 67
      -   nodeid: tests/test_utils_typecast.py::test_cast_changes_class
        type: Function
        lineno: 79
      -   nodeid: tests/test_utils_typecast.py::test_cast_preserves_identity
        type: Function
        lineno: 86
      
    • tests/test_utils_utils.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_utils.py::test_singleton_instance
        type: Function
        lineno: 17
      -   nodeid: tests/test_utils_utils.py::test_singleton_identity
        type: Function
        lineno: 25
      -   nodeid: tests/test_utils_utils.py::test_typename[None-NoneType]
        type: Function
        lineno: 44
      -   nodeid: tests/test_utils_utils.py::test_typename[True-bool]
        type: Function
        lineno: 44
      -   nodeid: tests/test_utils_utils.py::test_typename[42-int]
        type: Function
        lineno: 44
      -   nodeid: tests/test_utils_utils.py::test_typename[3.14-float]
        type: Function
        lineno: 44
      -   nodeid: tests/test_utils_utils.py::test_typename[text-str]
        type: Function
        lineno: 44
      -   nodeid: tests/test_utils_utils.py::test_typename[obj5-set]
        type: Function
        lineno: 44
      -   nodeid: tests/test_utils_utils.py::test_typename[obj6-list]
        type: Function
        lineno: 44
      -   nodeid: tests/test_utils_utils.py::test_typename[obj7-list]
        type: Function
        lineno: 44
      -   nodeid: tests/test_utils_utils.py::test_typename[obj8-dict]
        type: Function
        lineno: 44
      -   nodeid: tests/test_utils_utils.py::test_typename[<lambda>-function]
        type: Function
        lineno: 44
      -   nodeid: tests/test_utils_utils.py::test_typename[sample_function-function]
        type: Function
        lineno: 44
      -   nodeid: tests/test_utils_utils.py::test_typename[nested-function]
        type: Function
        lineno: 44
      -   nodeid: tests/test_utils_utils.py::test_typename[len-builtin_function_or_method]
        type: Function
        lineno: 44
      -   nodeid: tests/test_utils_utils.py::test_typename[sum-builtin_function_or_method]
        type: Function
        lineno: 44
      -   nodeid: tests/test_utils_utils.py::test_typename[math-module]
        type: Function
        lineno: 44
      -   nodeid: tests/test_utils_utils.py::test_typename[sys-module]
        type: Function
        lineno: 44
      -   nodeid: tests/test_utils_utils.py::test_typename[function-type]
        type: Function
        lineno: 44
      -   nodeid: tests/test_utils_utils.py::test_typename[<genexpr>-generator]
        type: Function
        lineno: 44
      -   nodeid: tests/test_utils_utils.py::test_typename[obj18-list_iterator]
        type: Function
        lineno: 44
      -   nodeid: tests/test_utils_utils.py::test_next_int[nums0-4]
        type: Function
        lineno: 77
      -   nodeid: tests/test_utils_utils.py::test_next_int[nums1-21]
        type: Function
        lineno: 77
      -   nodeid: tests/test_utils_utils.py::test_next_int[nums2-0]
        type: Function
        lineno: 77
      -   nodeid: tests/test_utils_utils.py::test_zero_pad[7-3-007]
        type: Function
        lineno: 87
      -   nodeid: tests/test_utils_utils.py::test_zero_pad[123-5-00123]
        type: Function
        lineno: 87
      -   nodeid: tests/test_utils_utils.py::test_zero_pad[0-2-00]
        type: Function
        lineno: 87
      -   nodeid: tests/test_utils_utils.py::test_iround[3.6-4]
        type: Function
        lineno: 97
      -   nodeid: tests/test_utils_utils.py::test_iround[2.1-2]
        type: Function
        lineno: 97
      -   nodeid: tests/test_utils_utils.py::test_iround[-1.5--2]
        type: Function
        lineno: 97
      -   nodeid: tests/test_utils_utils.py::test_iround[-1.4--1]
        type: Function
        lineno: 97
      -   nodeid: tests/test_utils_utils.py::test_sorted_naturally[items0-expected0]
        type: Function
        lineno: 108
      -   nodeid: tests/test_utils_utils.py::test_sorted_naturally[items1-expected1]
        type: Function
        lineno: 108
      -   nodeid: tests/test_utils_utils.py::test_sorted_naturally_reverse[items0-expected0]
        type: Function
        lineno: 115
      
    • tests/test_utils_xrange.py
      • Outcome: passed
      • result:
      -   nodeid: tests/test_utils_xrange.py::test_xrange_finite[args0-kwargs0-expected0]
        type: Function
        lineno: 11
      -   nodeid: tests/test_utils_xrange.py::test_xrange_finite[args1-kwargs1-expected1]
        type: Function
        lineno: 11
      -   nodeid: tests/test_utils_xrange.py::test_xrange_finite[args2-kwargs2-expected2]
        type: Function
        lineno: 11
      -   nodeid: tests/test_utils_xrange.py::test_xrange_finite[args3-kwargs3-expected3]
        type: Function
        lineno: 11
      -   nodeid: tests/test_utils_xrange.py::test_xrange_infinite[args0-kwargs0-count(0)]
        type: Function
        lineno: 20
      -   nodeid: tests/test_utils_xrange.py::test_xrange_infinite[args1-kwargs1-count(0, 2)]
        type: Function
        lineno: 20
      -   nodeid: tests/test_utils_xrange.py::test_xrange_too_many_args[args0]
        type: Function
        lineno: 31
      
. (1 tests)
  • .
    • Outcome: passed
    • result:
    -   nodeid: ci-reports
      type: Dir
    -   nodeid: markdown
      type: Dir
    -   nodeid: morbidissimo
      type: Dir
    -   nodeid: outputs
      type: Dir
    -   nodeid: slic
      type: Package
    -   nodeid: temp-ci
      type: Dir
    -   nodeid: test-ci
      type: Dir
    -   nodeid: tests
      type: Dir
    

⚠️ Warnings

Warnings nº1
message: The module numpy.dual is deprecated.  Instead of using dual, use the functions directly from numpy or scipy.
category: DeprecationWarning
when: collect
filename: /root/mambaforge/envs/ci-env/lib/python3.8/site-packages/scipy/fft/__init__.py
lineno: 97
Warnings nº2
message: invalid escape sequence \[
category: DeprecationWarning
when: collect
filename: /workspace/tligui_y/slic/tests/test_utils_pv.py
lineno: 12