8000 snapshot(refactor[typing]): Improve type overrides with generics by tony · Pull Request #590 · tmux-python/libtmux · GitHub
[go: up one dir, main page]

Skip to content

snapshot(refactor[typing]): Improve type overrides with generics #590

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 44 commits into
base: snapshots
Choose a base branch
from
Draft
Changes from 1 commit
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
ea5b0c4
.tool-versions(uv,python) uv 0.6.12 -> 0.6.14, python 3.13.2 -> 3.13.3
tony Apr 12, 2025
88e62d8
py(deps[dev]) Bump dev packages
tony Apr 12, 2025
4c49754
py(deps[dev]) Bump dev packages
tony Apr 19, 2025
93f2e75
py(deps[dev]) Bump dev packages
8000 tony Apr 26, 2025
b9a5cb7
pyproject(mypy) Add mypy override for frozen_dataclass method-assign
tony Feb 28, 2025
477e24b
pyproject(ruff) Ignore B010 set-attr-with-constant rule for frozen_da…
tony Feb 28, 2025
19a331c
pyproject(mypy) Add mypy override for `frozen_dataclass_sealable` `me…
tony Feb 28, 2025
e5be3f4
pyproject.toml(chore[mypy]): Exclude frozen_dataclass_sealable test f…
tony Mar 1, 2025
a929424
pyproject.toml(chore[lint,types]): Exclude frozen_dataclass_sealable …
tony Mar 1, 2025
7046533
frozen_dataclass(feat): Add `frozen_dataclass`
tony Feb 28, 2025
112709f
frozen_dataclass_sealable(feat): Add `frozen_dataclass_sealable`
tony Feb 28, 2025
b6d41dc
docs(frozen_dataclass) Add to `internals`
tony Feb 28, 2025
c244be5
docs(frozen_dataclass_sealable) Add to `internals`
tony Feb 28, 2025
50be574
WIP: Snapshot
tony Feb 28, 2025
7e75203
test(Snapshot): Replace MagicMock with pytest fixtures
tony Mar 1, 2025
d9a6d8a
docs(ServerSnapshot): Fix doctest examples in snapshot.py
tony Mar 1, 2025
df905f6
docs(Pane): Fix send_keys method doctest example
tony Mar 1, 2025
239d401
src/libtmux/snapshot.py uv run ruff check --select ALL src/libtmux/sn…
tony Mar 1, 2025
82deff8
test/test_snapshot.py: uv run ruff check --select ALL src/libtmux/sna…
tony Mar 1, 2025
9a940df
chore[mypy]: Add snapshot module override
tony Mar 1, 2025
e806d88
refactor(snapshot): Add explicit type ignores for seal methods
tony Mar 1, 2025
c8b202d
test(snapshot): Add type annotation to mock_filter function
tony Mar 1, 2025
f52f617
Revert "chore[mypy]: Add snapshot module override"
tony Mar 1, 2025
8997ba1
snapshot(refactor[Snapshot]): Fix dataclass field order and enhance s…
tony Mar 1, 2025
b42672b
mypy(config[snapshot]): Add override for property/field conflicts
tony Mar 1, 2025
13f7624
test(fix[PaneSnapshot]): Specify capture_content flag in tests
tony Mar 1, 2025
1eb0307
snapshot.py(style[exceptions]): Fix linting issues identified by ruff
tony Mar 1, 2025
b4f2db5
snapshot.py(refactor[performance]): Extract helper function for sessi…
tony Mar 1, 2025
00151d7
notes(2025-03-02) Add architecture notes
tony Mar 2, 2025
d6421c8
frozen_dataclass_sealable fix imports from `typing`
tony Mar 2, 2025
47aaec8
pyproject(mypy) Add mypy override for frozen_dataclass method-assign
tony Feb 28, 2025
83088eb
snapshot(refactor[typing]): Improve type overrides with generics
tony Mar 2, 2025
314a89e
docs: proposal for snapshot.py refactoring into package structure
tony Mar 2, 2025
a30f674
snapshot: New architecture, part 0: Remove old snapshot.py
tony Mar 2, 2025
0a6b46d
snapshot: New architecture, part 1: Add new architecture
tony Mar 2, 2025
2d12f0e
mypy(config[snapshot]): Update module pattern to include submodules
tony Mar 2, 2025
5237944
notes(2025-03-02) Updates to architecture notes
tony Mar 2, 2025
91b57f7
notes(2025-03-02[architecture-plan]) Update with typing ideas
tony Mar 2, 2025
ec6db9b
snapshot(factory): Implement type-safe factory and fluent API
tony Mar 2, 2025
729430d
notes(2025-03-02[architecture-plan]) Update for latest changes
tony Mar 2, 2025
2077a36
docs(snapshot[README]) Add README
tony Mar 2, 2025
fe23292
docs(snapshot[README]): add comprehensive doctest-based README for sn…
tony Mar 2, 2025
f6fde52
docs(snapshot/README): Comprehensive overhaul with doctest integration
tony Mar 2, 2025
ac85da4
docs(snapshot/README): Add Capabilities and Limitations table
tony Mar 2, 2025
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
test/test_snapshot.py: uv run ruff check --select ALL src/libtmux/sna…
…pshot.py tests/test_snapshot.py --fix --unsafe-fixes --preview --show-fixes; uv run ruff format .
  • Loading branch information
tony committed Apr 26, 2025
commit 82deff8c425ef7578563455c472f630a8a4b3aa4
51 changes: 28 additions & 23 deletions tests/test_snapshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@

from __future__ import annotations

from typing import TYPE_CHECKING
from unittest.mock import MagicMock, patch

import pytest

from libtmux._internal.frozen_dataclass_sealable import is_sealable
from libtmux.server import Server
from libtmux.session import Session
from libtmux.snapshot import (
PaneSnapshot,
ServerSnapshot,
Expand All @@ -19,15 +18,19 @@
snapshot_to_dict,
)

if TYPE_CHECKING:
from libtmux.server import Server
from libtmux.session import Session


class TestPaneSnapshot:
"""Test the PaneSnapshot class."""

def test_pane_snapshot_is_sealable(self):
def test_pane_snapshot_is_sealable(self) -> None:
"""Test that PaneSnapshot is sealable."""
assert is_sealable(PaneSnapshot)

def test_pane_snapshot_creation(self, session: Session):
def test_pane_snapshot_creation(self, session: Session) -> None:
"""Test creating a PaneSnapshot."""
# Get a real pane from the session fixture
pane = session.active_window.active_pane
Expand All @@ -52,7 +55,7 @@ def test_pane_snapshot_creation(self, session: Session):
assert len(snapshot.pane_content) > 0
assert any("test content" in line for line in snapshot.pane_content)

def test_pane_snapshot_no_content(self, session: Session):
def test_pane_snapshot_no_content(self, session: Session) -> None:
"""Test creating a PaneSnapshot without capturing content."""
# Get a real pane from the session fixture
pane = session.active_window.active_pane
Expand All @@ -68,7 +71,7 @@ def test_pane_snapshot_no_content(self, session: Session):
# Test that capture_pane method returns empty list
assert snapshot.capture_pane() == []

def test_pane_snapshot_cmd_not_implemented(self, session: Session):
def test_pane_snapshot_cmd_not_implemented(self, session: Session) -> None:
"""Test that cmd method raises NotImplementedError."""
# Get a real pane from the session fixture
pane = session.active_window.active_pane
Expand All @@ -86,11 +89,11 @@ def test_pane_snapshot_cmd_not_implemented(self, session: Session):
class TestWindowSnapshot:
"""Test the WindowSnapshot class."""

def test_window_snapshot_is_sealable(self):
def test_window_snapshot_is_sealable(self) -> None:
"""Test that WindowSnapshot is sealable."""
assert is_sealable(WindowSnapshot)

def test_window_snapshot_creation(self, session: Session):
def test_window_snapshot_creation(self, session: Session) -> None:
"""Test creating a WindowSnapshot."""
# Get a real window from the session fixture
window = session.active_window
Expand All @@ -115,7 +118,7 @@ def test_window_snapshot_creation(self, session: Session):
# Check active_pane property
assert snapshot.active_pane is not None

def test_window_snapshot_no_content(self, session: Session):
def test_window_snapshot_no_content(self, session: Session) -> None:
"""Test creating a WindowSnapshot without capturing content."""
# Get a real window from the session fixture
window = session.active_window
Expand All @@ -137,7 +140,7 @@ def test_window_snapshot_no_content(self, session: Session):
for pane_snap in snapshot.panes_snapshot:
assert pane_snap.pane_content is None

def test_window_snapshot_cmd_not_implemented(self, session: Session):
def test_window_snapshot_cmd_not_implemented(self, session: Session) -> None:
"""Test that cmd method raises NotImplementedError."""
# Get a real window from the session fixture
window = session.active_window
Expand All @@ -157,11 +160,11 @@ def test_window_snapshot_cmd_not_implemented(self, session: Session):
class TestSessionSnapshot:
"""Test the SessionSnapshot class."""

def test_session_snapshot_is_sealable(self):
def test_session_snapshot_is_sealable(self) -> None:
"""Test that SessionSnapshot is sealable."""
assert is_sealable(SessionSnapshot)

def test_session_snapshot_creation(self, session: Session):
def test_session_snapshot_creation(self, session: Session) -> None:
"""Test creating a SessionSnapshot."""
# Create a mock return value instead of trying to modify a real SessionSnapshot
mock_snapshot = MagicMock(spec=SessionSnapshot)
Expand All @@ -170,15 +173,16 @@ def test_session_snapshot_creation(self, session: Session):

# Patch the from_session method to return our mock
with patch(
"libtmux.snapshot.SessionSnapshot.from_session", return_value=mock_snapshot
"libtmux.snapshot.SessionSnapshot.from_session",
return_value=mock_snapshot,
):
snapshot = SessionSnapshot.from_session(session)

# Check that the snapshot has the correct attributes
assert snapshot.id == session.id
assert snapshot.name == session.name

def test_session_snapshot_cmd_not_implemented(self):
def test_session_snapshot_cmd_not_implemented(self) -> None:
"""Test that cmd method raises NotImplementedError."""
# Create a minimal SessionSnapshot instance without using from_session
snapshot = SessionSnapshot.__new__(SessionSnapshot)
Expand All @@ -191,11 +195,11 @@ def test_session_snapshot_cmd_not_implemented(self):
class TestServerSnapshot:
"""Test the ServerSnapshot class."""

def test_server_snapshot_is_sealable(self):
def test_server_snapshot_is_sealable(self) -> None:
"""Test that ServerSnapshot is sealable."""
assert is_sealable(ServerSnapshot)

def test_server_snapshot_creation(self, server: Server, session: Session):
def test_server_snapshot_creation(self, server: Server, session: Session) -> None:
"""Test creating a ServerSnapshot."""
# Create a mock with the properties we want to test
mock_session_snapshot = MagicMock(spec=SessionSnapshot)
Expand All @@ -208,7 +212,8 @@ def test_server_snapshot_creation(self, server: Server, session: Session):

# Patch the from_server method to return our mock
with patch(
"libtmux.snapshot.ServerSnapshot.from_server", return_value=mock_snapshot
"libtmux.snapshot.ServerSnapshot.from_server",
return_value=mock_snapshot,
):
snapshot = ServerSnapshot.from_server(server)

Expand All @@ -218,7 +223,7 @@ def test_server_snapshot_creation(self, server: Server, session: Session):
# Check that sessions were added
assert len(snapshot.sessions) == 1

def test_server_snapshot_cmd_not_implemented(self):
def test_server_snapshot_cmd_not_implemented(self) -> None:
"""Test that cmd method raises NotImplementedError."""
# Create a minimal ServerSnapshot instance
snapshot = ServerSnapshot.__new__(ServerSnapshot)
Expand All @@ -227,15 +232,15 @@ def test_server_snapshot_cmd_not_implemented(self):
with pytest.raises(NotImplementedError):
snapshot.cmd("test-command")

def test_server_snapshot_is_alive(self):
def test_server_snapshot_is_alive(self) -> None:
"""Test that is_alive method returns False."""
# Create a minimal ServerSnapshot instance
snapshot = ServerSnapshot.__new__(ServerSnapshot)

# Test that is_alive method returns False
assert snapshot.is_alive() is False

def test_server_snapshot_raise_if_dead(self):
def test_server_snapshot_raise_if_dead(self) -> None:
"""Test that raise_if_dead method raises ConnectionError."""
# Create a minimal ServerSnapshot instance
snapshot = ServerSnapshot.__new__(ServerSnapshot)
Expand All @@ -245,7 +250,7 @@ def test_server_snapshot_raise_if_dead(self):
snapshot.raise_if_dead()


def test_snapshot_to_dict(session: Session):
def test_snapshot_to_dict(session: Session) -> None:
"""Test the snapshot_to_dict function."""
# Create a mock pane snapshot with the attributes we need
mock_snapshot = MagicMock(spec=PaneSnapshot)
Expand All @@ -263,7 +268,7 @@ def test_snapshot_to_dict(session: Session):
assert mock_snapshot.pane_index in str(snapshot_dict.values())


def test_snapshot_active_only():
def test_snapshot_active_only() -> None:
"""Test the snapshot_active_only function."""
# Create a minimal server snapshot with a session, window and pane
mock_server_snap = MagicMock(spec=ServerSnapshot)
Expand All @@ -282,7 +287,7 @@ def test_snapshot_active_only():
mock_server_snap.sessions_snapshot = [mock_session_snap]

# Create mock filter function that passes everything through
def mock_filter(snapshot):
def mock_filter(snapshot) -> bool:
return True

# Apply the filter with a patch to avoid actual implementation
Expand Down
0