tmux-python / libtmux

⚙️ Python API / wrapper for tmux
https://libtmux.git-pull.com
MIT License
1.01k stars 104 forks source link

`retry_until()`: Improve pytest error message via rewriting #376

Open tony opened 2 years ago

tony commented 2 years ago

372 added retry_until()

pytest assertion rewriting provides pytest_assertrepr_compare().

Now

________________________________________________ test_automatic_rename_option ________________________________________________

session = Session($1 libtmux_yn08bma4)

    def test_automatic_rename_option(session):
        """With option automatic-rename: on."""
        yaml_config = test_utils.read_config_file(
            "workspacebuilder/window_automatic_rename.yaml"
        )
        s = session
        sconfig = kaptan.Kaptan(handler="yaml")                                                                                                                                                                                                     [56/238]        sconfig = sconfig.import_config(yaml_config).get()

        # This should be a command guaranteed to be terminal name across systems
        portable_command = sconfig["windows"][0]["panes"][0]["shell_command"][0]["cmd"]
        # If a command is like "man ls", get the command base name, "ls"
        if " " in portable_command:
            portable_command = portable_command.split(" ")[0]

        builder = WorkspaceBuilder(sconf=sconfig)

        window_count = len(session._windows)  # current window count
        assert len(s._windows) == window_count
        for w, wconf in builder.iter_create_windows(s):

            for p in builder.iter_create_panes(w, wconf):
                w.select_layout("tiled")  # fix glitch with pane size
                p = p
                assert len(s._windows), window_count
            assert isinstance(w, Window)
            assert w.show_window_option("automatic-rename") == "on"

            assert len(s._windows) == window_count

            window_count += 1
            w.select_layout(wconf["layout"])

        assert s.name != "tmuxp"
        w = s.windows[0]

        def check_window_name_mismatch() -> bool:
            session.server._update_windows()
            return w.name != portable_command

        assert retry_until(check_window_name_mismatch, 2, interval=0.25)

        pane_base_index = w.show_window_option("pane-base-index", g=True)
        w.select_pane(pane_base_index)

        def check_window_name_match() -> bool:
            session.server._update_windows()
            return w.name == portable_command

>       assert retry_until(check_window_name_match, 2, interval=0.25)
                                                                                                                                                                                                                                                            tests/test_workspacebuilder.py:402:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

fun = <function test_automatic_rename_option.<locals>.check_window_name_match at 0x7f484aee43a0>, seconds = 2

    def retry_until(
        fun: Callable,
        seconds: float = RETRY_TIMEOUT_SECONDS,
        *,
        interval: Optional[float] = RETRY_INTERVAL_SECONDS,
        raises: Optional[bool] = True,
    ) -> bool:                                                                                                                                                                                                                                       [0/238]        """
        Retry a function until a condition meets or the specified time passes.

        Parameters
        ----------
        fun : callable
            A function that will be called repeatedly until it returns ``True``  or
            the specified time passes.
        seconds : float
            Seconds to retry. Defaults to ``8``, which is configurable via
            ``RETRY_TIMEOUT_SECONDS`` environment variables.
        interval : float
            Time in seconds to wait between calls. Defaults to ``0.05`` and is
            configurable via ``RETRY_INTERVAL_SECONDS`` environment variable.
        raises : bool
            Wether or not to raise an exception on timeout. Defaults to ``True``.

        Examples
        --------

        >>> def f():
        ...     p = w.attached_pane
        ...     p.server._update_panes()
        ...     return p.current_path == pane_path
        ...
        ... retry(f)

        In pytest:

        >>> assert retry(f, raises=False)
        """
        ini = time.time()

        while not fun():
            end = time.time()
            if end - ini >= seconds:
                if raises:
>                   raise WaitTimeout()
E                   libtmux.exc.WaitTimeout

.venv/lib/python3.10/site-packages/libtmux/test.py:103: WaitTimeout
FAILED tests/test_workspacebuilder.py::test_automatic_rename_option - libtmux.exc.WaitTimeout

What we want

We want the higher level frame in the stack:

        def check_window_name_match() -> bool:
            session.server._update_windows()
            return w.name == portable_command

>       assert retry_until(check_window_name_match, 2, interval=0.25)

.venv/lib/python3.10/site-packages/libtmux/test.py:103: WaitTimeout

FAILED tests/test_workspacebuilder.py::test_automatic_rename_option - libtmux.exc.WaitTimeout in check_window_name_match()
rockandska commented 1 year ago

Are you aware of __tracebackhide__ = True ? If not, try to add __tracebackhide__ = True to retry_until and check_window_name_match methods I think it will do what you want

tony commented 1 year ago

@rockandska I did not see that message, thank you!

Taking note of: