From e2bbf721f3efb63ab7a9652ce03af04ce0e457fa Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Mon, 17 Feb 2025 08:47:52 -0600 Subject: [PATCH 01/13] Doc / typos fixes (#569) * docs: Fix grammatical error in about.md ('ran' to 'run') * docs: Fix repeated word 'and' in developing.md * docs: Remove redundant 'doctest.' in pytest-plugin/index.md * docs: Fix grammatical error in pytest-plugin/index.md ('These are fixtures are' -> 'These fixtures are') * docs: Complete session identifier example in about.md * docs: Improve punctuation in make commands documentation * docs: Improve clarity of test stability description in pytest-plugin/index.md * docs: Fix incorrect verb usage ('custom' -> 'customize') in pytest-plugin/index.md * docs: Fix incorrect apostrophe usage in plural 'IDs' * docs: Fix incorrect apostrophe usage in plural 'APIs' * docs: Fix inconsistent pluralization in list of tmux objects * docs: Make entr(1) references consistent in formatting * docs: Fix inconsistent capitalization of tmux object names * docs: Remove extra space before parenthesis * docs: Make command formatting consistent in developing.md * docs: Remove unnecessary explanation of $ symbol * docs: Make helper command formatting consistent * docs: Make watch_test command formatting consistent * docs: Make documentation build commands formatting consistent * docs: Standardize key combination format (Ctrl-a -> Ctrl+a) * docs: Replace # symbol with 'number' for clarity * docs: Make start_docs and start commands formatting consistent * docs: Make version number formatting consistent (0.10 -> v0.10) * docs: Remove extra blank lines in tmux session creation command block * docs: Fix grammar in sessions/windows lookup description * docs: Add missing ptpython link definition * docs: Make method reference format consistent in pytest plugin docs * docs: Add missing uv link definition * docs: Make code block formatting consistent in version update example * docs: Make code block formatting consistent in CHANGES example * docs: Make server fixture reference consistent * docs: Make helper commands formatting consistent with console code blocks * docs: Make tmux(1) reference formatting consistent * docs: Make entr(1) references consistent * docs: Make make(1) reference formatting consistent --- docs/about.md | 18 +++---- docs/developing.md | 98 +++++++++++++++++++++++++++---------- docs/pytest-plugin/index.md | 12 ++--- docs/quickstart.md | 5 +- 4 files changed, 90 insertions(+), 43 deletions(-) diff --git a/docs/about.md b/docs/about.md index 0f5557c81..3a5c91bba 100644 --- a/docs/about.md +++ b/docs/about.md @@ -17,7 +17,7 @@ libtmux is a [typed](https://docs.python.org/3/library/typing.html) [abstraction layer] for tmux. It builds upon the concept of targets `-t`, to direct commands against -individual session, windows and panes and `FORMATS`, template variables +individual sessions, windows and panes and `FORMATS`, template variables exposed by tmux to describe their properties. Think of `-t` analogously to [scope]. @@ -32,18 +32,18 @@ relations of {class}`Server`, {class}`Session`, {class}`Window` and | {class}`Window` | {class}`Pane` | {class}`Session` | | {class}`Pane` | None | {class}`Window` | -Internally, tmux allows multiple servers to be ran on a system. Each one +Internally, tmux allows multiple servers to be run on a system. Each one uses a socket. The server-client architecture is executed so cleanly, many users don't think about it. tmux automatically connects to a default socket name and location for you if none (`-L`, `-S`) is specified. A server will be created automatically upon starting if none exists. -A server can have multiple sessions. `Ctrl-a s` can be used to switch +A server can have multiple sessions. `Ctrl+a s` can be used to switch between sessions running on the server. -Sessions, Windows and Panes all have their own unique identifier for +Sessions, windows and panes all have their own unique identifier for internal purposes. {class}`common.TmuxMappingObject` will make use of the -unique identifiers (`session_id`, `window_id`, `pane_id` ) to look +unique identifiers (`session_id`, `window_id`, `pane_id`) to look up the data stored in the {class}`Server` object. | Object | Prefix | Example | @@ -56,7 +56,7 @@ up the data stored in the {class}`Server` object. ## Similarities to tmux and Pythonics libtmux was built in the spirit of understanding how tmux operates -and how python objects and tools can abstract the API's in a pleasant way. +and how python objects and tools can abstract the APIs in a pleasant way. libtmux uses `FORMATTERS` in tmux to give identity attributes to {class}`Session`, {class}`Window` and {class}`Pane` objects. See @@ -66,13 +66,13 @@ libtmux uses `FORMATTERS` in tmux to give identity attributes to How is libtmux able to keep references to panes, windows and sessions? -> Tmux has unique ID's for sessions, windows and panes. +> Tmux has unique IDs for sessions, windows and panes. > > panes use `%`, such as `%1234` > > windows use `@`, such as `@2345` > -> sessions use `$`, for money, such as `$` +> sessions use `$`, such as `$13` > > How is libtmux able to handle windows with no names? @@ -82,7 +82,7 @@ How is libtmux able to keep references to panes, windows and sessions? > Pane index refers to the order of a pane on the screen. > -> Window index refers to the # of the window in the session. +> Window index refers to the number of the window in the session. > > To assert pane, window and session data, libtmux will use > {meth}`Server.sessions()`, {meth}`Session.windows()`, diff --git a/docs/developing.md b/docs/developing.md index 149f5df19..dcafc1f16 100644 --- a/docs/developing.md +++ b/docs/developing.md @@ -1,6 +1,6 @@ # Development -Install and [git] and [uv] +Install [git] and [uv] Clone: @@ -20,15 +20,29 @@ $ uv sync --all-extras --dev [installation documentation]: https://docs.astral.sh/uv/getting-started/installation/ [git]: https://git-scm.com/ +[uv]: https://github.com/astral-sh/uv Makefile commands prefixed with `watch_` will watch files and rerun. ## Tests -`uv run py.test` +```console +$ uv run py.test +``` -Helpers: `make test` -Rerun tests on file change: `make watch_test` (requires [entr(1)]) +### Helpers + +```console +$ make test +``` + +Rerun tests on file change: + +```console +$ make watch_test +``` + +(requires [entr(1)]) ### Pytest plugin @@ -44,19 +58,50 @@ Default preview server: http://localhost:8023 [sphinx-autobuild] will automatically build the docs, watch for file changes and launch a server. -From home directory: `make start_docs` From inside `docs/`: `make start` +From home directory: +```console +$ make start_docs +``` + +From inside `docs/`: +```console +$ make start +``` [sphinx-autobuild]: https://github.com/executablebooks/sphinx-autobuild ### Manual documentation (the hard way) -`cd docs/` and `make html` to build. `make serve` to start http server. +```console +$ cd docs/ +$ make html +``` + +to build. + +```console +$ make serve +``` + +to start http server. -Helpers: `make build_docs`, `make serve_docs` +Helpers: +```console +$ make build_docs +$ make serve_docs +``` -Rebuild docs on file change: `make watch_docs` (requires [entr(1)]) +Rebuild docs on file change: +```console +$ make watch_docs +``` +(requires [entr(1)]) -Rebuild docs and run server via one terminal: `make dev_docs` (requires above, and a `make(1)` with +Rebuild docs and run server via one terminal: +```console +$ make dev_docs +``` +(requires above, and {command}`make(1)` with `-J` support, e.g. GNU Make) ## Linting @@ -95,7 +140,7 @@ $ make ruff $ make watch_ruff ``` -requires [`entr(1)`]. +requires [entr(1)]. ```` @@ -177,7 +222,7 @@ $ make mypy $ make watch_mypy ``` -requires [`entr(1)`]. +requires [entr(1)]. ```` ## Releasing @@ -197,15 +242,17 @@ Let's assume we pick 0.9.1 `CHANGES`: Assure any PRs merged since last release are mentioned. Give a thank you to the contributor. Set the header with the new version and the date. Leave the "current" header and _Insert changes/features/fixes for next release here_ at -the top:: +the top: - current - ------- - - *Insert changes/features/fixes for next release here* +``` +current +------- +- *Insert changes/features/fixes for next release here* - libtmux 0.9.1 (2020-10-12) - -------------------------- - - :issue:`1`: Fix bug +libtmux 0.9.1 (2020-10-12) +-------------------------- +- :issue:`1`: Fix bug +``` `libtmux/__init__.py` and `__about__.py` - Set version @@ -225,20 +272,21 @@ to PyPI. This isn't used yet since package maintainers may want setup.py in the source. See https://github.com/tmux-python/tmuxp/issues/625. -As of 0.10, [uv] handles virtualenv creation, package requirements, versioning, +As of v0.10, [uv] handles virtualenv creation, package requirements, versioning, building, and publishing. Therefore there is no setup.py or requirements files. -Update `__version__` in `__about__.py` and `pyproject.toml`:: +Update `__version__` in `__about__.py` and `pyproject.toml`: - git commit -m 'build(libtmux): Tag v0.1.1' - git tag v0.1.1 - git push - git push --tags +```console +git commit -m 'build(libtmux): Tag v0.1.1' +git tag v0.1.1 +git push +git push --tags +``` [twine]: https://twine.readthedocs.io/ [uv]: https://github.com/astral-sh/uv [entr(1)]: http://eradman.com/entrproject/ -[`entr(1)`]: http://eradman.com/entrproject/ [ruff format]: https://docs.astral.sh/ruff/formatter/ [ruff]: https://ruff.rs [mypy]: http://mypy-lang.org/ diff --git a/docs/pytest-plugin/index.md b/docs/pytest-plugin/index.md index 7c3eed133..cdcdf5a82 100644 --- a/docs/pytest-plugin/index.md +++ b/docs/pytest-plugin/index.md @@ -33,7 +33,7 @@ The pytest plugin will be automatically detected via pytest, and the fixtures wi View libtmux's own [tests/](https://github.com/tmux-python/libtmux/tree/master/tests) as well as tmuxp's [tests/](https://github.com/tmux-python/tmuxp/tree/master/tests). -libtmux's tests `autouse` the {ref}`recommended-fixtures` above to ensure stable, assertions and +libtmux's tests `autouse` the {ref}`recommended-fixtures` above to ensure stable test execution, assertions and object lookups in the test grid. ## pytest-tmux @@ -41,14 +41,14 @@ object lookups in the test grid. `pytest-tmux` works through providing {ref}`pytest fixtures ` - so read up on those! -The plugin's fixtures guarantee a fresh, headless `tmux(1)` server, session, window, or pane is +The plugin's fixtures guarantee a fresh, headless {command}`tmux(1)` server, session, window, or pane is passed into your test. (recommended-fixtures)= ## Recommended fixtures -These are fixtures are automatically used when the plugin is enabled and `pytest` is run. +These fixtures are automatically used when the plugin is enabled and `pytest` is run. - Creating temporary, test directories for: - `/home/` ({func}`home_path`) @@ -67,14 +67,14 @@ options: - Pass a `config_file` into {class}`~libtmux.Server` - Set the `HOME` directory to a local or temporary pytest path with a configuration file -You could also read the code and override {func}`server fixtures `'s in your own doctest. doctest. +You could also read the code and override {func}`server fixture ` in your own doctest. (custom_session_params)= ### Custom session parameters -You can override `session_params` to custom the `session` fixture. The -dictionary will directly pass into :meth:`Server.new_session` keyword arguments. +You can override `session_params` to customize the `session` fixture. The +dictionary will directly pass into {meth}`Server.new_session` keyword arguments. ```python import pytest diff --git a/docs/quickstart.md b/docs/quickstart.md index 1c17fa87c..bb94c5c70 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -50,15 +50,14 @@ via trunk (can break easily): ``` [pip]: https://pip.pypa.io/en/stable/ +[ptpython]: https://github.com/prompt-toolkit/ptpython ## Start a tmux session Now, let's open a tmux session. ```console - $ tmux new-session -n bar -s foo - ``` This tutorial will be using the session and window name in the example. @@ -177,7 +176,7 @@ Session($1 ...) However, this isn't guaranteed, libtmux works against current tmux information, the session's name could be changed, or another tmux session may be created, -so {meth}`Server.sessions` and {meth}`Server.windows` exists as a lookup. +so {meth}`Server.sessions` and {meth}`Server.windows` exist as a lookup. ## Get session by ID From cfbf8ded434d13aedb368a16a2682daca3f9c15b Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Mon, 17 Feb 2025 08:54:27 -0600 Subject: [PATCH 02/13] test(version): Convert parametrize tests to use NamedTuple fixtures --- tests/test_version.py | 119 +++++++++++++++++++++++++++++++++--------- 1 file changed, 95 insertions(+), 24 deletions(-) diff --git a/tests/test_version.py b/tests/test_version.py index f702a2c81..58df075a6 100644 --- a/tests/test_version.py +++ b/tests/test_version.py @@ -27,20 +27,31 @@ ] +class VersionTestFixture(t.NamedTuple): + """Test fixture for version string validation.""" + + test_id: str + version: str + + +VERSION_TEST_FIXTURES: list[VersionTestFixture] = [ + VersionTestFixture(test_id="simple_version", version="1"), + VersionTestFixture(test_id="minor_version", version="1.0"), + VersionTestFixture(test_id="patch_version", version="1.0.0"), + VersionTestFixture(test_id="beta_version", version="1.0.0b"), + VersionTestFixture(test_id="beta_with_number", version="1.0.0b1"), + VersionTestFixture(test_id="beta_with_os", version="1.0.0b-openbsd"), + VersionTestFixture(test_id="next_version", version="1.0.0-next"), + VersionTestFixture(test_id="next_with_number", version="1.0.0-next.1"), +] + + @pytest.mark.parametrize( - "version", - [ - "1", - "1.0", - "1.0.0", - "1.0.0b", - "1.0.0b1", - "1.0.0b-openbsd", - "1.0.0-next", - "1.0.0-next.1", - ], + list(VersionTestFixture._fields), + VERSION_TEST_FIXTURES, + ids=[test.test_id for test in VERSION_TEST_FIXTURES], ) -def test_version(version: str) -> None: +def test_version(test_id: str, version: str) -> None: """Assert LooseVersion constructor against various version strings.""" assert LooseVersion(version) @@ -48,27 +59,87 @@ def test_version(version: str) -> None: class VersionCompareFixture(t.NamedTuple): """Test fixture for version comparison.""" + test_id: str a: object op: VersionCompareOp b: object raises: type[Exception] | bool +VERSION_COMPARE_FIXTURES: list[VersionCompareFixture] = [ + VersionCompareFixture( + test_id="equal_simple", + a="1", + op=operator.eq, + b="1", + raises=False, + ), + VersionCompareFixture( + test_id="equal_with_minor", + a="1", + op=operator.eq, + b="1.0", + raises=False, + ), + VersionCompareFixture( + test_id="equal_with_patch", + a="1", + op=operator.eq, + b="1.0.0", + raises=False, + ), + VersionCompareFixture( + test_id="greater_than_alpha", + a="1", + op=operator.gt, + b="1.0.0a", + raises=False, + ), + VersionCompareFixture( + test_id="greater_than_beta", + a="1", + op=operator.gt, + b="1.0.0b", + raises=False, + ), + VersionCompareFixture( + test_id="less_than_patch", + a="1", + op=operator.lt, + b="1.0.0p1", + raises=False, + ), + VersionCompareFixture( + test_id="less_than_openbsd", + a="1", + op=operator.lt, + b="1.0.0-openbsd", + raises=False, + ), + VersionCompareFixture( + test_id="less_than_equal_raises", + a="1", + op=operator.lt, + b="1", + raises=AssertionError, + ), + VersionCompareFixture( + test_id="beta_to_rc_compare", + a="1.0.0c", + op=operator.gt, + b="1.0.0b", + raises=False, + ), +] + + @pytest.mark.parametrize( - VersionCompareFixture._fields, - [ - VersionCompareFixture(a="1", op=operator.eq, b="1", raises=False), - VersionCompareFixture(a="1", op=operator.eq, b="1.0", raises=False), - VersionCompareFixture(a="1", op=operator.eq, b="1.0.0", raises=False), - VersionCompareFixture(a="1", op=operator.gt, b="1.0.0a", raises=False), - VersionCompareFixture(a="1", op=operator.gt, b="1.0.0b", raises=False), - VersionCompareFixture(a="1", op=operator.lt, b="1.0.0p1", raises=False), - VersionCompareFixture(a="1", op=operator.lt, b="1.0.0-openbsd", raises=False), - VersionCompareFixture(a="1", op=operator.lt, b="1", raises=AssertionError), - VersionCompareFixture(a="1.0.0c", op=operator.gt, b="1.0.0b", raises=False), - ], + list(VersionCompareFixture._fields), + VERSION_COMPARE_FIXTURES, + ids=[test.test_id for test in VERSION_COMPARE_FIXTURES], ) def test_version_compare( + test_id: str, a: str, op: VersionCompareOp, b: str, From 43fde27ac929a9d0fdcb48bce3af7d50634b3650 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Mon, 17 Feb 2025 08:56:48 -0600 Subject: [PATCH 03/13] test(window): Convert parametrize tests, fix `test_window_rename` --- tests/test_window.py | 72 +++++++++++++++++++++++++++++++++----------- 1 file changed, 55 insertions(+), 17 deletions(-) diff --git a/tests/test_window.py b/tests/test_window.py index b08ad2d14..0be62613e 100644 --- a/tests/test_window.py +++ b/tests/test_window.py @@ -211,33 +211,53 @@ def test_split_size(session: Session) -> None: assert pane.pane_width == str(int(window_width_before * 0.1)) +class WindowRenameFixture(t.NamedTuple): + """Test fixture for window rename functionality.""" + + test_id: str + window_name_before: str + window_name_input: str + window_name_after: str + + +WINDOW_RENAME_FIXTURES: list[WindowRenameFixture] = [ + WindowRenameFixture( + test_id="rename_with_spaces", + window_name_before="test", + window_name_input="ha ha ha fjewlkjflwef", + window_name_after="ha ha ha fjewlkjflwef", + ), + WindowRenameFixture( + test_id="rename_with_escapes", + window_name_before=r"hello \ wazzup 0", + window_name_input=r"hello \ wazzup 0", + window_name_after=r"hello \\ wazzup 0", + ), +] + + @pytest.mark.parametrize( - ("window_name_before", "window_name_after"), - [("test", "ha ha ha fjewlkjflwef"), ("test", "hello \\ wazzup 0")], + list(WindowRenameFixture._fields), + WINDOW_RENAME_FIXTURES, + ids=[test.test_id for test in WINDOW_RENAME_FIXTURES], ) def test_window_rename( session: Session, + test_id: str, window_name_before: str, + window_name_input: str, window_name_after: str, ) -> None: """Test Window.rename_window().""" - window_name_before = "test" - window_name_after = "ha ha ha fjewlkjflwef" - session.set_option("automatic-rename", "off") window = session.new_window(window_name=window_name_before, attach=True) assert window == session.active_window assert window.window_name == window_name_before - window.rename_window(window_name_after) - - window = session.active_window - - assert window.window_name == window_name_after + window.rename_window(window_name_input) window = session.active_window - assert window.window_name == window_name_after @@ -385,24 +405,42 @@ def test_empty_window_name(session: Session) -> None: assert "''" in cmd.stdout +class WindowSplitEnvironmentFixture(t.NamedTuple): + """Test fixture for window split with environment variables.""" + + test_id: str + environment: dict[str, str] + + +WINDOW_SPLIT_ENV_FIXTURES: list[WindowSplitEnvironmentFixture] = [ + WindowSplitEnvironmentFixture( + test_id="single_env_var", + environment={"ENV_VAR": "pane"}, + ), + WindowSplitEnvironmentFixture( + test_id="multiple_env_vars", + environment={"ENV_VAR_1": "pane_1", "ENV_VAR_2": "pane_2"}, + ), +] + + @pytest.mark.skipif( has_lt_version("3.0"), reason="needs -e flag for split-window which was introduced in 3.0", ) @pytest.mark.parametrize( - "environment", - [ - {"ENV_VAR": "pane"}, - {"ENV_VAR_1": "pane_1", "ENV_VAR_2": "pane_2"}, - ], + list(WindowSplitEnvironmentFixture._fields), + WINDOW_SPLIT_ENV_FIXTURES, + ids=[test.test_id for test in WINDOW_SPLIT_ENV_FIXTURES], ) def test_split_with_environment( session: Session, + test_id: str, environment: dict[str, str], ) -> None: """Verify splitting window with environment variables.""" env = shutil.which("env") - assert env is not None, "Cannot find usable `env` in Path." + assert env is not None, "Cannot find usable `env` in PATH." window = session.new_window(window_name="split_with_environment") pane = window.split( From 25b6423958f3a76a5888c56ee859c3f2e8bba08e Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Mon, 17 Feb 2025 09:13:06 -0600 Subject: [PATCH 04/13] test(session): Convert new_window_with_environment test to use NamedTuple fixture --- tests/test_session.py | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/tests/test_session.py b/tests/test_session.py index 25c90f701..2e43ef123 100644 --- a/tests/test_session.py +++ b/tests/test_session.py @@ -275,19 +275,37 @@ def test_cmd_inserts_session_id(session: Session) -> None: assert cmd.cmd[-1] == last_arg +class SessionWindowEnvironmentFixture(t.NamedTuple): + """Test fixture for window environment variables in sessions.""" + + test_id: str + environment: dict[str, str] + + +SESSION_WINDOW_ENV_FIXTURES: list[SessionWindowEnvironmentFixture] = [ + SessionWindowEnvironmentFixture( + test_id="single_env_var", + environment={"ENV_VAR": "window"}, + ), + SessionWindowEnvironmentFixture( + test_id="multiple_env_vars", + environment={"ENV_VAR_1": "window_1", "ENV_VAR_2": "window_2"}, + ), +] + + @pytest.mark.skipif( has_lt_version("3.0"), reason="needs -e flag for new-window which was introduced in 3.0", ) @pytest.mark.parametrize( - "environment", - [ - {"ENV_VAR": "window"}, - {"ENV_VAR_1": "window_1", "ENV_VAR_2": "window_2"}, - ], + list(SessionWindowEnvironmentFixture._fields), + SESSION_WINDOW_ENV_FIXTURES, + ids=[test.test_id for test in SESSION_WINDOW_ENV_FIXTURES], ) def test_new_window_with_environment( session: Session, + test_id: str, environment: dict[str, str], ) -> None: """Verify new window with environment vars.""" From 7af5551b039d281569fb972a0fb3482c6438b2b0 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Mon, 17 Feb 2025 09:15:34 -0600 Subject: [PATCH 05/13] test(session): Improve PeriodRaisesBadSessionName test with test_id and constant list --- tests/test_session.py | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/tests/test_session.py b/tests/test_session.py index 2e43ef123..33b82dd72 100644 --- a/tests/test_session.py +++ b/tests/test_session.py @@ -221,21 +221,39 @@ def test_unset_environment(session: Session) -> None: class PeriodRaisesBadSessionName(t.NamedTuple): """Test fixture for bad session name names.""" + test_id: str session_name: str raises: bool +PERIOD_RAISES_BAD_SESSION_NAME_FIXTURES: list[PeriodRaisesBadSessionName] = [ + PeriodRaisesBadSessionName( + test_id="period_in_name", + session_name="hey.period", + raises=True, + ), + PeriodRaisesBadSessionName( + test_id="colon_in_name", + session_name="hey:its a colon", + raises=True, + ), + PeriodRaisesBadSessionName( + test_id="valid_name", + session_name="hey moo", + raises=False, + ), +] + + @pytest.mark.parametrize( - PeriodRaisesBadSessionName._fields, - [ - PeriodRaisesBadSessionName("hey.period", True), - PeriodRaisesBadSessionName("hey:its a colon", True), - PeriodRaisesBadSessionName("hey moo", False), - ], + list(PeriodRaisesBadSessionName._fields), + PERIOD_RAISES_BAD_SESSION_NAME_FIXTURES, + ids=[test.test_id for test in PERIOD_RAISES_BAD_SESSION_NAME_FIXTURES], ) def test_periods_raise_bad_session_name( server: Server, session: Session, + test_id: str, session_name: str, raises: bool, ) -> None: From 79b7501d745ec09cba8f81d3e6d25b35458d731a Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Mon, 17 Feb 2025 09:17:15 -0600 Subject: [PATCH 06/13] test(common): Improve SessionCheckName test with test_id and constant list --- tests/test_common.py | 54 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/tests/test_common.py b/tests/test_common.py index fb32427e0..e6dc30ce9 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -203,23 +203,59 @@ def test_tmux_cmd_unicode(session: Session) -> None: class SessionCheckName(t.NamedTuple): """Test fixture for test_session_check_name().""" + test_id: str session_name: str | None raises: bool exc_msg_regex: str | None +SESSION_CHECK_NAME_FIXTURES: list[SessionCheckName] = [ + SessionCheckName( + test_id="empty_string", + session_name="", + raises=True, + exc_msg_regex="empty", + ), + SessionCheckName( + test_id="none_value", + session_name=None, + raises=True, + exc_msg_regex="empty", + ), + SessionCheckName( + test_id="contains_period", + session_name="my great session.", + raises=True, + exc_msg_regex="contains periods", + ), + SessionCheckName( + test_id="contains_colon", + session_name="name: great session", + raises=True, + exc_msg_regex="contains colons", + ), + SessionCheckName( + test_id="valid_name", + session_name="new great session", + raises=False, + exc_msg_regex=None, + ), + SessionCheckName( + test_id="valid_with_special_chars", + session_name="ajf8a3fa83fads,,,a", + raises=False, + exc_msg_regex=None, + ), +] + + @pytest.mark.parametrize( - SessionCheckName._fields, - [ - SessionCheckName("", True, "empty"), - SessionCheckName(None, True, "empty"), - SessionCheckName("my great session.", True, "contains periods"), - SessionCheckName("name: great session", True, "contains colons"), - SessionCheckName("new great session", False, None), - SessionCheckName("ajf8a3fa83fads,,,a", False, None), - ], + list(SessionCheckName._fields), + SESSION_CHECK_NAME_FIXTURES, + ids=[test.test_id for test in SESSION_CHECK_NAME_FIXTURES], ) def test_session_check_name( + test_id: str, session_name: str | None, raises: bool, exc_msg_regex: str | None, From 33f6533260a9d6381da9b05b58a351dffac0d7b7 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Mon, 17 Feb 2025 09:21:05 -0600 Subject: [PATCH 07/13] test(common): Convert version comparison tests to use NamedTuple fixture --- tests/test_common.py | 184 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 146 insertions(+), 38 deletions(-) diff --git a/tests/test_common.py b/tests/test_common.py index e6dc30ce9..889b89be7 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -150,44 +150,6 @@ def test_has_version() -> None: assert has_version(str(get_version())) -def test_has_gt_version() -> None: - """Test has_gt_version().""" - assert has_gt_version("1.6") - assert has_gt_version("1.6b") - - assert not has_gt_version("4.0") - assert not has_gt_version("4.0b") - - -def test_has_gte_version() -> None: - """Test has_gte_version().""" - assert has_gte_version("1.6") - assert has_gte_version("1.6b") - assert has_gte_version(str(get_version())) - - assert not has_gte_version("4.0") - assert not has_gte_version("4.0b") - - -def test_has_lt_version() -> None: - """Test has_lt_version().""" - assert has_lt_version("4.0a") - assert has_lt_version("4.0") - - assert not has_lt_version("1.7") - assert not has_lt_version(str(get_version())) - - -def test_has_lte_version() -> None: - """Test has_lti_version().""" - assert has_lte_version("4.0a") - assert has_lte_version("4.0") - assert has_lte_version(str(get_version())) - - assert not has_lte_version("1.7") - assert not has_lte_version("1.7b") - - def test_tmux_cmd_raises_on_not_found(monkeypatch: pytest.MonkeyPatch) -> None: """Verify raises if tmux command not found.""" monkeypatch.setenv("PATH", "") @@ -277,3 +239,149 @@ def test_get_libtmux_version() -> None: version = get_libtmux_version() assert isinstance(version, LooseVersion) assert LooseVersion(__version__) == version + + +class VersionComparisonFixture(t.NamedTuple): + """Test fixture for version comparison functions.""" + + test_id: str + version: str + comparison_type: t.Literal["gt", "gte", "lt", "lte"] + expected: bool + + +VERSION_COMPARISON_FIXTURES: list[VersionComparisonFixture] = [ + # Greater than tests + VersionComparisonFixture( + test_id="gt_older_version", + version="1.6", + comparison_type="gt", + expected=True, + ), + VersionComparisonFixture( + test_id="gt_older_version_with_letter", + version="1.6b", + comparison_type="gt", + expected=True, + ), + VersionComparisonFixture( + test_id="gt_newer_version", + version="4.0", + comparison_type="gt", + expected=False, + ), + VersionComparisonFixture( + test_id="gt_newer_version_with_letter", + version="4.0b", + comparison_type="gt", + expected=False, + ), + # Greater than or equal tests + VersionComparisonFixture( + test_id="gte_older_version", + version="1.6", + comparison_type="gte", + expected=True, + ), + VersionComparisonFixture( + test_id="gte_older_version_with_letter", + version="1.6b", + comparison_type="gte", + expected=True, + ), + VersionComparisonFixture( + test_id="gte_current_version", + version=str(get_version()), + comparison_type="gte", + expected=True, + ), + VersionComparisonFixture( + test_id="gte_newer_version", + version="4.0", + comparison_type="gte", + expected=False, + ), + VersionComparisonFixture( + test_id="gte_newer_version_with_letter", + version="4.0b", + comparison_type="gte", + expected=False, + ), + # Less than tests + VersionComparisonFixture( + test_id="lt_newer_version_with_letter", + version="4.0a", + comparison_type="lt", + expected=True, + ), + VersionComparisonFixture( + test_id="lt_newer_version", + version="4.0", + comparison_type="lt", + expected=True, + ), + VersionComparisonFixture( + test_id="lt_older_version", + version="1.7", + comparison_type="lt", + expected=False, + ), + VersionComparisonFixture( + test_id="lt_current_version", + version=str(get_version()), + comparison_type="lt", + expected=False, + ), + # Less than or equal tests + VersionComparisonFixture( + test_id="lte_newer_version_with_letter", + version="4.0a", + comparison_type="lte", + expected=True, + ), + VersionComparisonFixture( + test_id="lte_newer_version", + version="4.0", + comparison_type="lte", + expected=True, + ), + VersionComparisonFixture( + test_id="lte_current_version", + version=str(get_version()), + comparison_type="lte", + expected=True, + ), + VersionComparisonFixture( + test_id="lte_older_version", + version="1.7", + comparison_type="lte", + expected=False, + ), + VersionComparisonFixture( + test_id="lte_older_version_with_letter", + version="1.7b", + comparison_type="lte", + expected=False, + ), +] + + +@pytest.mark.parametrize( + list(VersionComparisonFixture._fields), + VERSION_COMPARISON_FIXTURES, + ids=[test.test_id for test in VERSION_COMPARISON_FIXTURES], +) +def test_version_comparison( + test_id: str, + version: str, + comparison_type: t.Literal["gt", "gte", "lt", "lte"], + expected: bool, +) -> None: + """Test version comparison functions.""" + comparison_funcs = { + "gt": has_gt_version, + "gte": has_gte_version, + "lt": has_lt_version, + "lte": has_lte_version, + } + assert comparison_funcs[comparison_type](version) == expected From d2e3aea55b9fdb2fa17e93e1ad3eb58752b41afd Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Mon, 17 Feb 2025 09:23:25 -0600 Subject: [PATCH 08/13] test(common): Convert version parsing tests to use NamedTuple fixture --- tests/test_common.py | 165 ++++++++++++++++++++++++------------------- 1 file changed, 92 insertions(+), 73 deletions(-) diff --git a/tests/test_common.py b/tests/test_common.py index 889b89be7..f09687aa8 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -32,79 +32,6 @@ version_regex = re.compile(r"([0-9]\.[0-9])|(master)") -def test_allows_master_version(monkeypatch: pytest.MonkeyPatch) -> None: - """Assert get_version() works with builds from git trunk.""" - - class Hi: - stdout: t.ClassVar = ["tmux master"] - stderr = None - - def mock_tmux_cmd(*args: t.Any, **kwargs: t.Any) -> Hi: - return Hi() - - monkeypatch.setattr(libtmux.common, "tmux_cmd", mock_tmux_cmd) - - assert has_minimum_version() - assert has_gte_version(TMUX_MIN_VERSION) - assert has_gt_version(TMUX_MAX_VERSION), "Greater than the max-supported version" - assert get_version() == f"{TMUX_MAX_VERSION}-master", ( - "Is the latest supported version with -master appended" - ) - - -def test_allows_next_version(monkeypatch: pytest.MonkeyPatch) -> None: - """Assert get_version() supports next version.""" - TMUX_NEXT_VERSION = str(float(TMUX_MAX_VERSION) + 0.1) - - class Hi: - stdout: t.ClassVar = [f"tmux next-{TMUX_NEXT_VERSION}"] - stderr = None - - def mock_tmux_cmd(*args: t.Any, **kwargs: t.Any) -> Hi: - return Hi() - - monkeypatch.setattr(libtmux.common, "tmux_cmd", mock_tmux_cmd) - - assert has_minimum_version() - assert has_gte_version(TMUX_MIN_VERSION) - assert has_gt_version(TMUX_MAX_VERSION), "Greater than the max-supported version" - assert get_version() == TMUX_NEXT_VERSION - - -def test_get_version_openbsd(monkeypatch: pytest.MonkeyPatch) -> None: - """Assert get_version() with OpenBSD versions.""" - - class Hi: - stderr: t.ClassVar = ["tmux: unknown option -- V"] - - def mock_tmux_cmd(*args: t.Any, **kwargs: t.Any) -> Hi: - return Hi() - - monkeypatch.setattr(libtmux.common, "tmux_cmd", mock_tmux_cmd) - monkeypatch.setattr(sys, "platform", "openbsd 5.2") - assert has_minimum_version() - assert has_gte_version(TMUX_MIN_VERSION) - assert has_gt_version(TMUX_MAX_VERSION), "Greater than the max-supported version" - assert get_version() == f"{TMUX_MAX_VERSION}-openbsd", ( - "Is the latest supported version with -openbsd appended" - ) - - -def test_get_version_too_low(monkeypatch: pytest.MonkeyPatch) -> None: - """Assert get_version() raises if tmux version too low.""" - - class Hi: - stderr: t.ClassVar = ["tmux: unknown option -- V"] - - def mock_tmux_cmd(*args: t.Any, **kwargs: t.Any) -> Hi: - return Hi() - - monkeypatch.setattr(libtmux.common, "tmux_cmd", mock_tmux_cmd) - with pytest.raises(LibTmuxException) as exc_info: - get_version() - exc_info.match("is running tmux 1.3 or earlier") - - def test_ignores_letter_versions(monkeypatch: pytest.MonkeyPatch) -> None: """Tests version utilities ignores letters such as 1.8b. @@ -385,3 +312,95 @@ def test_version_comparison( "lte": has_lte_version, } assert comparison_funcs[comparison_type](version) == expected + + +class VersionParsingFixture(t.NamedTuple): + """Test fixture for version parsing and validation.""" + + test_id: str + mock_stdout: list[str] | None + mock_stderr: list[str] | None + mock_platform: str | None + expected_version: str | None + raises: bool + exc_msg_regex: str | None + + +VERSION_PARSING_FIXTURES: list[VersionParsingFixture] = [ + VersionParsingFixture( + test_id="master_version", + mock_stdout=["tmux master"], + mock_stderr=None, + mock_platform=None, + expected_version=f"{TMUX_MAX_VERSION}-master", + raises=False, + exc_msg_regex=None, + ), + VersionParsingFixture( + test_id="next_version", + mock_stdout=[f"tmux next-{float(TMUX_MAX_VERSION) + 0.1!s}"], + mock_stderr=None, + mock_platform=None, + expected_version=str(float(TMUX_MAX_VERSION) + 0.1), + raises=False, + exc_msg_regex=None, + ), + VersionParsingFixture( + test_id="openbsd_version", + mock_stdout=None, + mock_stderr=["tmux: unknown option -- V"], + mock_platform="openbsd 5.2", + expected_version=f"{TMUX_MAX_VERSION}-openbsd", + raises=False, + exc_msg_regex=None, + ), + VersionParsingFixture( + test_id="too_low_version", + mock_stdout=None, + mock_stderr=["tmux: unknown option -- V"], + mock_platform=None, + expected_version=None, + raises=True, + exc_msg_regex="is running tmux 1.3 or earlier", + ), +] + + +@pytest.mark.parametrize( + list(VersionParsingFixture._fields), + VERSION_PARSING_FIXTURES, + ids=[test.test_id for test in VERSION_PARSING_FIXTURES], +) +def test_version_parsing( + monkeypatch: pytest.MonkeyPatch, + test_id: str, + mock_stdout: list[str] | None, + mock_stderr: list[str] | None, + mock_platform: str | None, + expected_version: str | None, + raises: bool, + exc_msg_regex: str | None, +) -> None: + """Test version parsing and validation.""" + + class MockTmuxOutput: + stdout = mock_stdout + stderr = mock_stderr + + def mock_tmux_cmd(*args: t.Any, **kwargs: t.Any) -> MockTmuxOutput: + return MockTmuxOutput() + + monkeypatch.setattr(libtmux.common, "tmux_cmd", mock_tmux_cmd) + if mock_platform is not None: + monkeypatch.setattr(sys, "platform", mock_platform) + + if raises: + with pytest.raises(LibTmuxException) as exc_info: + get_version() + if exc_msg_regex is not None: + exc_info.match(exc_msg_regex) + else: + assert get_version() == expected_version + assert has_minimum_version() + assert has_gte_version(TMUX_MIN_VERSION) + assert has_gt_version(TMUX_MAX_VERSION) From 135f9ab1f21cb2000a97412cd86f86b510fc9c86 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Mon, 17 Feb 2025 09:27:55 -0600 Subject: [PATCH 09/13] test(common): Convert version validation tests to use NamedTuple fixture --- tests/test_common.py | 184 +++++++++++++++++++++++++++++++++---------- 1 file changed, 144 insertions(+), 40 deletions(-) diff --git a/tests/test_common.py b/tests/test_common.py index f09687aa8..3d67182c1 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -32,46 +32,6 @@ version_regex = re.compile(r"([0-9]\.[0-9])|(master)") -def test_ignores_letter_versions(monkeypatch: pytest.MonkeyPatch) -> None: - """Tests version utilities ignores letters such as 1.8b. - - See ticket https://github.com/tmux-python/tmuxp/issues/55. - - In version 0.1.7 this is adjusted to use LooseVersion, in order to - allow letters. - - """ - monkeypatch.setattr(libtmux.common, "TMUX_MIN_VERSION", "1.9a") - result = has_minimum_version() - assert result - - monkeypatch.setattr(libtmux.common, "TMUX_MIN_VERSION", "1.8a") - result = has_minimum_version() - assert result - - # Should not throw - assert isinstance(has_version("1.8"), bool) - assert isinstance(has_version("1.8a"), bool) - assert isinstance(has_version("1.9a"), bool) - - -def test_error_version_less_1_7(monkeypatch: pytest.MonkeyPatch) -> None: - """Test raises if tmux version less than 1.7.""" - - def mock_get_version() -> LooseVersion: - return LooseVersion("1.7") - - monkeypatch.setattr(libtmux.common, "get_version", mock_get_version) - with pytest.raises(LibTmuxException) as excinfo: - has_minimum_version() - excinfo.match(r"libtmux only supports") - - with pytest.raises(LibTmuxException) as excinfo: - has_minimum_version() - - excinfo.match(r"libtmux only supports") - - def test_has_version() -> None: """Test has_version().""" assert has_version(str(get_version())) @@ -404,3 +364,147 @@ def mock_tmux_cmd(*args: t.Any, **kwargs: t.Any) -> MockTmuxOutput: assert has_minimum_version() assert has_gte_version(TMUX_MIN_VERSION) assert has_gt_version(TMUX_MAX_VERSION) + + +class VersionValidationFixture(t.NamedTuple): + """Test fixture for version validation tests.""" + + test_id: str + mock_min_version: str | None + mock_version: str | None + check_type: t.Literal["min_version", "has_version", "type_check"] + raises: bool + exc_msg_regex: str | None + + +VERSION_VALIDATION_FIXTURES: list[VersionValidationFixture] = [ + # Letter version tests + VersionValidationFixture( + test_id="accepts_letter_in_min_version_1_9a", + mock_min_version="1.9a", + mock_version=None, + check_type="min_version", + raises=False, + exc_msg_regex=None, + ), + VersionValidationFixture( + test_id="accepts_letter_in_min_version_1_8a", + mock_min_version="1.8a", + mock_version=None, + check_type="min_version", + raises=False, + exc_msg_regex=None, + ), + VersionValidationFixture( + test_id="accepts_version_1_8", + mock_min_version=None, + mock_version="1.8", + check_type="type_check", + raises=False, + exc_msg_regex=None, + ), + VersionValidationFixture( + test_id="accepts_version_1_8a", + mock_min_version=None, + mock_version="1.8a", + check_type="type_check", + raises=False, + exc_msg_regex=None, + ), + VersionValidationFixture( + test_id="accepts_version_1_9a", + mock_min_version=None, + mock_version="1.9a", + check_type="type_check", + raises=False, + exc_msg_regex=None, + ), + # Version too low tests + VersionValidationFixture( + test_id="rejects_version_1_7", + mock_min_version=None, + mock_version="1.7", + check_type="min_version", + raises=True, + exc_msg_regex=r"libtmux only supports", + ), + # Additional test cases for version validation + VersionValidationFixture( + test_id="accepts_master_version", + mock_min_version=None, + mock_version="master", + check_type="type_check", + raises=False, + exc_msg_regex=None, + ), + VersionValidationFixture( + test_id="accepts_next_version", + mock_min_version=None, + mock_version="next-3.4", + check_type="type_check", + raises=False, + exc_msg_regex=None, + ), + VersionValidationFixture( + test_id="accepts_openbsd_version", + mock_min_version=None, + mock_version="3.3-openbsd", + check_type="type_check", + raises=False, + exc_msg_regex=None, + ), + VersionValidationFixture( + test_id="accepts_dev_version", + mock_min_version=None, + mock_version="3.3-dev", + check_type="type_check", + raises=False, + exc_msg_regex=None, + ), + VersionValidationFixture( + test_id="accepts_rc_version", + mock_min_version=None, + mock_version="3.3-rc2", + check_type="type_check", + raises=False, + exc_msg_regex=None, + ), +] + + +@pytest.mark.parametrize( + list(VersionValidationFixture._fields), + VERSION_VALIDATION_FIXTURES, + ids=[test.test_id for test in VERSION_VALIDATION_FIXTURES], +) +def test_version_validation( + monkeypatch: pytest.MonkeyPatch, + test_id: str, + mock_min_version: str | None, + mock_version: str | None, + check_type: t.Literal["min_version", "has_version", "type_check"], + raises: bool, + exc_msg_regex: str | None, +) -> None: + """Test version validation.""" + if mock_min_version is not None: + monkeypatch.setattr(libtmux.common, "TMUX_MIN_VERSION", mock_min_version) + + if mock_version is not None: + + def mock_get_version() -> LooseVersion: + return LooseVersion(mock_version) + + monkeypatch.setattr(libtmux.common, "get_version", mock_get_version) + + if check_type == "min_version": + if raises: + with pytest.raises(LibTmuxException) as exc_info: + has_minimum_version() + if exc_msg_regex is not None: + exc_info.match(exc_msg_regex) + else: + assert has_minimum_version() + elif check_type == "type_check": + assert mock_version is not None # For type checker + assert isinstance(has_version(mock_version), bool) From 0c047a527499a2cebe0992c826fd48707729cc5a Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Mon, 17 Feb 2025 09:35:38 -0600 Subject: [PATCH 10/13] docs(CHANGES) Note testsuite overhaul --- CHANGES | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGES b/CHANGES index e0015f54c..fecc9a6c2 100644 --- a/CHANGES +++ b/CHANGES @@ -15,6 +15,15 @@ $ pip install --user --upgrade --pre libtmux - _Future release notes will be placed here_ +### Development + +- Improved test organization and coverage in `test_common.py` (#570): + - Consolidated version-related tests into parametrized fixtures using NamedTuples + - Added comprehensive test cases for various version formats (master, next, OpenBSD, dev, rc) + - Improved test readability with clear test IDs and logical grouping + - Consistent use of pytest parametrize convention across test suite +- Fix broken test for `test_window_rename` (#570) + ## libtmux 0.44.1 (2025-02-17) ### Packaging From cc4e888a8e6240615fc2cfc15c0ae953946464ba Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Mon, 17 Feb 2025 10:29:47 -0600 Subject: [PATCH 11/13] fix(typings) Move typing-extensions into `TypeGuard` Missed this in #564. --- src/libtmux/pane.py | 7 +++++-- src/libtmux/server.py | 6 ++---- src/libtmux/session.py | 8 ++++++-- src/libtmux/window.py | 9 +++++++-- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/libtmux/pane.py b/src/libtmux/pane.py index 895d83f89..a60bb36f6 100644 --- a/src/libtmux/pane.py +++ b/src/libtmux/pane.py @@ -13,8 +13,6 @@ import typing as t import warnings -from typing_extensions import Self - from libtmux.common import has_gte_version, has_lt_version, tmux_cmd from libtmux.constants import ( PANE_DIRECTION_FLAG_MAP, @@ -28,12 +26,17 @@ from . import exc if t.TYPE_CHECKING: + import sys import types from .server import Server from .session import Session from .window import Window + if sys.version_info >= (3, 11): + from typing import Self + else: + from typing_extensions import Self logger = logging.getLogger(__name__) diff --git a/src/libtmux/server.py b/src/libtmux/server.py index e022965ab..1eaf82f66 100644 --- a/src/libtmux/server.py +++ b/src/libtmux/server.py @@ -15,8 +15,6 @@ import typing as t import warnings -from typing_extensions import Self - from libtmux._internal.query_list import QueryList from libtmux.common import tmux_cmd from libtmux.neo import fetch_objs @@ -39,9 +37,9 @@ import types if sys.version_info >= (3, 10): - from typing import TypeAlias + from typing import Self, TypeAlias else: - from typing_extensions import TypeAlias + from typing_extensions import Self, TypeAlias DashLiteral: TypeAlias = t.Literal["-"] diff --git a/src/libtmux/session.py b/src/libtmux/session.py index fd5bb36da..d1433e014 100644 --- a/src/libtmux/session.py +++ b/src/libtmux/session.py @@ -13,8 +13,6 @@ import typing as t import warnings -from typing_extensions import Self - from libtmux._internal.query_list import QueryList from libtmux.constants import WINDOW_DIRECTION_FLAG_MAP, WindowDirection from libtmux.formats import FORMAT_SEPARATOR @@ -33,10 +31,16 @@ ) if t.TYPE_CHECKING: + import sys import types from libtmux.common import tmux_cmd + if sys.version_info >= (3, 11): + from typing import Self + else: + from typing_extensions import Self + from .server import Server diff --git a/src/libtmux/window.py b/src/libtmux/window.py index bf7495650..121c7ea03 100644 --- a/src/libtmux/window.py +++ b/src/libtmux/window.py @@ -13,8 +13,6 @@ import typing as t import warnings -from typing_extensions import Self - from libtmux._internal.query_list import QueryList from libtmux.common import has_gte_version, tmux_cmd from libtmux.constants import ( @@ -30,11 +28,18 @@ from .common import PaneDict, WindowOptionDict, handle_option_error if t.TYPE_CHECKING: + import sys import types from .server import Server from .session import Session + if sys.version_info >= (3, 11): + from typing import Self + else: + from typing_extensions import Self + + logger = logging.getLogger(__name__) From 024259a7c44e3fcb1c4ee9d83366ce758425345e Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Mon, 17 Feb 2025 10:31:31 -0600 Subject: [PATCH 12/13] docs(CHANGES) Note `typing_extensions` fix --- CHANGES | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES b/CHANGES index fecc9a6c2..2813d4e02 100644 --- a/CHANGES +++ b/CHANGES @@ -15,6 +15,10 @@ $ pip install --user --upgrade --pre libtmux - _Future release notes will be placed here_ +### Bug fix + +- Fix `typing_extensions` issue by wrapping it in `TYPE_CHECKING`, continuation of #564, via #572. + ### Development - Improved test organization and coverage in `test_common.py` (#570): From efdc59c8d1eab97c46139d4d2b2a38eed603eeea Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Mon, 17 Feb 2025 10:34:54 -0600 Subject: [PATCH 13/13] Tag v0.44.2 (`typing-extensions` import fix, part 2) --- CHANGES | 2 ++ pyproject.toml | 2 +- src/libtmux/__about__.py | 2 +- uv.lock | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 2813d4e02..320670151 100644 --- a/CHANGES +++ b/CHANGES @@ -15,6 +15,8 @@ $ pip install --user --upgrade --pre libtmux - _Future release notes will be placed here_ +## libtmux 0.44.2 (2025-02-17) + ### Bug fix - Fix `typing_extensions` issue by wrapping it in `TYPE_CHECKING`, continuation of #564, via #572. diff --git a/pyproject.toml b/pyproject.toml index b9f1d21a7..a1752d1c2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "libtmux" -version = "0.44.1" +version = "0.44.2" description = "Typed library that provides an ORM wrapper for tmux, a terminal multiplexer." requires-python = ">=3.9,<4.0" authors = [ diff --git a/src/libtmux/__about__.py b/src/libtmux/__about__.py index 61aa08170..9f27b720e 100644 --- a/src/libtmux/__about__.py +++ b/src/libtmux/__about__.py @@ -4,7 +4,7 @@ __title__ = "libtmux" __package_name__ = "libtmux" -__version__ = "0.44.1" +__version__ = "0.44.2" __description__ = "Typed scripting library / ORM / API wrapper for tmux" __email__ = "tony@git-pull.com" __author__ = "Tony Narlock" diff --git a/uv.lock b/uv.lock index decf874e9..10fc21123 100644 --- a/uv.lock +++ b/uv.lock @@ -378,7 +378,7 @@ wheels = [ [[package]] name = "libtmux" -version = "0.44.1" +version = "0.44.2" source = { editable = "." } [package.dev-dependencies]