Skip to content

Commit 3a3cd0f

Browse files
committed
docs: proposal for snapshot.py refactoring into package structure
This commit adds a detailed proposal for refactoring the current monolithic snapshot.py module into a structured package to improve maintainability, testability, and extensibility. Key improvements proposed: - Split into smaller, focused modules with clear responsibilities - Separate base classes, concrete implementations, and utility functions - Establish clear type boundaries with a dedicated types.py - Maintain backward compatibility via public API re-exports The proposal includes a four-phase implementation plan with timeline estimates, benefits and tradeoffs analysis, backward compatibility strategy, and success metrics for evaluating the refactoring.
1 parent fc05e89 commit 3a3cd0f

File tree

1 file changed

+244
-0
lines changed

1 file changed

+244
-0
lines changed
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
# Snapshot Module Redesign Proposal
2+
3+
**Date**: March 2, 2025
4+
**Author**: Development Team
5+
**Status**: Draft Proposal
6+
7+
## Executive Summary
8+
9+
This document proposes refactoring the current monolithic `snapshot.py` module (approximately 650 lines) into a structured package to improve maintainability, testability, and extensibility. The primary goal is to separate concerns, reduce file size, and establish a clear API boundary while maintaining backward compatibility.
10+
11+
## Current State Analysis
12+
13+
### Structure
14+
15+
The current `snapshot.py` module contains:
16+
17+
- 4 base classes with sealable mixin functionality
18+
- 4 concrete snapshot classes (Server, Session, Window, Pane)
19+
- Several utility functions for filtering and transformations
20+
- Type definitions and aliases
21+
- Complex inter-dependencies between classes
22+
23+
### Pain Points
24+
25+
1. **Size**: The file is large (~650 lines) and challenging to navigate
26+
2. **Tight coupling**: Classes reference each other directly, creating complex dependencies
27+
3. **Mixed concerns**: Type definitions, base classes, implementations, and utilities are intermingled
28+
4. **Testing complexity**: Testing specific components requires loading the entire module
29+
5. **Future maintenance**: Adding new features or making changes affects the entire module
30+
31+
## Proposed Structure
32+
33+
We propose refactoring into a dedicated package with this structure:
34+
35+
```
36+
src/libtmux/snapshot/
37+
├── __init__.py # Module documentation only, no exports
38+
├── base.py # Base classes with Sealable mixins
39+
├── types.py # Type definitions, exports, and annotations
40+
├── models/
41+
│ ├── __init__.py # Package documentation only, no exports
42+
│ ├── pane.py # PaneSnapshot implementation
43+
│ ├── window.py # WindowSnapshot implementation
44+
│ ├── session.py # SessionSnapshot implementation
45+
│ └── server.py # ServerSnapshot implementation
46+
└── utils.py # Utility functions (filter_snapshot, snapshot_to_dict, etc.)
47+
```
48+
49+
### Key Components
50+
51+
1. **`__init__.py`**: Document the module purpose and structure, but without exporting classes
52+
```python
53+
"""Hierarchical snapshots of tmux objects.
54+
55+
libtmux.snapshot
56+
~~~~~~~~~~~~~~
57+
58+
This module provides hierarchical snapshots of tmux objects (Server, Session,
59+
Window, Pane) that are immutable and maintain the relationships between objects.
60+
"""
61+
```
62+
63+
2. **`types.py`**: Centralizes all type definitions
64+
```python
65+
from __future__ import annotations
66+
67+
import typing as t
68+
69+
from libtmux.pane import Pane
70+
from libtmux.server import Server
71+
from libtmux.session import Session
72+
from libtmux.window import Window
73+
74+
# Type variables for generic typing
75+
PaneT = t.TypeVar("PaneT", bound=Pane, covariant=True)
76+
WindowT = t.TypeVar("WindowT", bound=Window, covariant=True)
77+
SessionT = t.TypeVar("SessionT", bound=Session, covariant=True)
78+
ServerT = t.TypeVar("ServerT", bound=Server, covariant=True)
79+
80+
# Forward references for snapshot classes
81+
if t.TYPE_CHECKING:
82+
from libtmux.snapshot.models.pane import PaneSnapshot
83+
from libtmux.snapshot.models.window import WindowSnapshot
84+
from libtmux.snapshot.models.session import SessionSnapshot
85+
from libtmux.snapshot.models.server import ServerSnapshot
86+
87+
# Union type for snapshot classes
88+
SnapshotType = t.Union[ServerSnapshot, SessionSnapshot, WindowSnapshot, PaneSnapshot]
89+
else:
90+
# Runtime placeholder - will be properly defined after imports
91+
SnapshotType = t.Any
92+
```
93+
94+
3. **`base.py`**: Base classes that implement sealable behavior
95+
```python
96+
from __future__ import annotations
97+
98+
import typing as t
99+
100+
from libtmux._internal.frozen_dataclass_sealable import Sealable
101+
from libtmux._internal.query_list import QueryList
102+
from libtmux.pane import Pane
103+
from libtmux.server import Server
104+
from libtmux.session import Session
105+
from libtmux.window import Window
106+
107+
from libtmux.snapshot.types import PaneT, WindowT, SessionT, PaneT
108+
109+
class SealablePaneBase(Pane, Sealable):
110+
"""Base class for sealable pane classes."""
111+
112+
class SealableWindowBase(Window, Sealable, t.Generic[PaneT]):
113+
"""Base class for sealable window classes with generic pane type."""
114+
115+
# Implementation of properties with proper typing
116+
117+
class SealableSessionBase(Session, Sealable, t.Generic[WindowT, PaneT]):
118+
"""Base class for sealable session classes with generic window and pane types."""
119+
120+
# Implementation of properties with proper typing
121+
122+
class SealableServerBase(Server, Sealable, t.Generic[SessionT, WindowT, PaneT]):
123+
"""Generic base for sealable server with typed session, window, and pane."""
124+
125+
# Implementation of properties with proper typing
126+
```
127+
128+
4. **Model classes**: Individual implementations in separate files
129+
- Each file contains a single snapshot class with focused responsibility
130+
- Clear imports and dependencies between modules
131+
- Proper type annotations
132+
133+
5. **`utils.py`**: Utility functions separated from model implementations
134+
```python
135+
from __future__ import annotations
136+
137+
import copy
138+
import datetime
139+
import typing as t
140+
141+
from libtmux.snapshot.types import SnapshotType
142+
from libtmux.snapshot.models.server import ServerSnapshot
143+
from libtmux.snapshot.models.session import SessionSnapshot
144+
from libtmux.snapshot.models.window import WindowSnapshot
145+
from libtmux.snapshot.models.pane import PaneSnapshot
146+
147+
def filter_snapshot(
148+
snapshot: SnapshotType,
149+
filter_func: t.Callable[[SnapshotType], bool],
150+
) -> SnapshotType | None:
151+
"""Filter a snapshot hierarchy based on a filter function."""
152+
# Implementation...
153+
154+
def snapshot_to_dict(
155+
snapshot: SnapshotType | t.Any,
156+
) -> dict[str, t.Any]:
157+
"""Convert a snapshot to a dictionary, avoiding circular references."""
158+
# Implementation...
159+
160+
def snapshot_active_only(
161+
full_snapshot: ServerSnapshot,
162+
) -> ServerSnapshot:
163+
"""Return a filtered snapshot containing only active sessions, windows, and panes."""
164+
# Implementation...
165+
```
166+
167+
## Implementation Plan
168+
169+
We propose a phased approach with the following steps:
170+
171+
### Phase 1: Setup Package Structure (Week 1)
172+
173+
1. Create the package directory structure
174+
2. Set up module files with appropriate documentation
175+
3. Create the types.py module with all type definitions
176+
4. Draft the base.py module with base classes
177+
178+
### Phase 2: Migrate Models (Week 2-3)
179+
180+
1. Move PaneSnapshot to its own module
181+
2. Move WindowSnapshot to its own module
182+
3. Move SessionSnapshot to its own module
183+
4. Move ServerSnapshot to its own module
184+
5. Update imports and references between modules
185+
186+
### Phase 3: Extract Utilities (Week 3)
187+
188+
1. Move utility functions to utils.py
189+
2. Update imports and references
190+
191+
### Phase 4: Testing and Finalization (Week 4)
192+
193+
1. Add/update tests to verify all functionality works correctly
194+
2. Update documentation
195+
3. Final code review
196+
4. Merge to main branch
197+
198+
## Benefits and Tradeoffs
199+
200+
### Benefits
201+
202+
1. **Improved maintainability**: Smaller, focused files with clear responsibilities
203+
2. **Better organization**: Separation of concerns between different components
204+
3. **Simplified testing**: Ability to test components in isolation
205+
4. **Enhanced discoverability**: Easier for new developers to understand the codebase
206+
5. **Clearer API boundary**: Direct imports encourage explicit dependencies
207+
6. **Future extensibility**: Easier to add new snapshot types or modify existing ones
208+
209+
### Tradeoffs
210+
211+
1. **Initial effort**: Significant upfront work to refactor and test
212+
2. **Complexity**: More files to navigate and understand
213+
3. **Risk**: Potential for regressions during refactoring
214+
4. **Import overhead**: Slightly more verbose import statements
215+
5. **Learning curve**: Team needs to adapt to the new structure
216+
217+
## Backward Compatibility
218+
219+
The proposed changes maintain backward compatibility through:
220+
221+
1. **Direct imports**: Users will need to update imports to reference specific modules
222+
2. **Same behavior**: No functional changes to how snapshots work
223+
3. **Same type definitions**: Type hints remain compatible with existing code
224+
225+
## Success Metrics
226+
227+
The success of this refactoring will be measured by:
228+
229+
1. **Code coverage**: Maintain or improve current test coverage
230+
2. **File sizes**: No file should exceed 200 lines
231+
3. **Import clarity**: Clear and direct imports between modules
232+
4. **Maintainability**: Reduction in complexity metrics
233+
5. **Developer feedback**: Team survey on code navigability
234+
235+
## Conclusion
236+
237+
This redesign addresses the current maintainability issues with the snapshot module while preserving all functionality and backward compatibility. The modular approach will make future maintenance easier and allow for more focused testing. We recommend proceeding with this refactoring as outlined in the implementation plan.
238+
239+
## Next Steps
240+
241+
1. Review and finalize this proposal
242+
2. Create implementation tickets in the issue tracker
243+
3. Assign resources for implementation
244+
4. Schedule code reviews at each phase completion

0 commit comments

Comments
 (0)