Skip to content

Commit 5b5de78

Browse files
Dayan GrahamDayan Graham
authored andcommitted
chore: Add more tasks and delete unused fules.
1 parent 141de73 commit 5b5de78

76 files changed

Lines changed: 3119 additions & 136 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.cursor/rules/python.mdc

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
---
2-
description:
3-
globs:
4-
alwaysApply: true
5-
---
61
# Python Style Guide (Stream Viz Backend)
72

83
## Design Philosophy
@@ -21,7 +16,7 @@ alwaysApply: true
2116
- API request/response validation (FastAPI integration).
2217
- WebSocket message validation.
2318
- Complex internal data structures for clarity and validation.
24-
- **Validation:** Check pyright regularly to ensure types are correct.
19+
- **Validation:** Run `mypy` regularly to check type consistency (`mypy src/`).
2520

2621
## Asynchronous Programming (Asyncio)
2722
- **Default:** Use `async def` for all I/O-bound operations (network calls, database access, etc.).
@@ -61,11 +56,6 @@ alwaysApply: true
6156
- Implement structured logging (e.g., using `structlog` or Python's JSON formatter).
6257
- Include relevant context in log messages (e.g., `query_id`, client address).
6358

64-
## Code Style
65-
- Do not put whitespace on blank lines
66-
- Generally follow Ruff rules
67-
- Be SUPER obsessive about not leaving unused variables, params or imports
68-
6959
## Testing
7060
- **Framework:** Use `pytest`.
7161
- **Async Testing:** Use `httpx` for testing FastAPI endpoints asynchronously.
@@ -84,3 +74,8 @@ alwaysApply: true
8474
- **Run Scripts:** `uv run path/to/script.py` (add `--with <package>` for temporary dependencies).
8575
- **Format/Lint:** `ruff format .` and `ruff check . --fix`.
8676
- **Type Check:** `mypy src/` (or relevant paths).
77+
78+
### Common Patterns
79+
80+
- **Dependency Injection:** Use dependency injection to decouple components and improve testability rather than app.state
81+

IMPROVEMENTS.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Stream Viz Backend Code Review & Improvement Suggestions
2+
3+
This document outlines findings and suggestions for improving the `stream-viz` backend codebase based on a review focusing on SOLID principles, clarity, and best practices.
4+
5+
## Overall Structure & Design
6+
7+
* **Good Separation:** The project follows a reasonable structure separating concerns into `api`, `core`, `utils`, and `main.py`. This promotes modularity.
8+
* **Dependency Injection:** Good use of FastAPI's dependency injection (`Depends`) for `TimeplusQueryManager` and `PerspectiveManager` in the WebSocket endpoint (`api/websocket/endpoint.py`). This improves testability and decoupling.
9+
* **Manager Classes:** The use of `TimeplusQueryManager` and `PerspectiveManager` centralizes logic for interacting with these external services, which is good. They act as facades and manage resource lifecycles (like queries and tables) using reference counting.
10+
* **Configuration:** Using Pydantic's `BaseSettings` (`config.py`) for configuration management is a standard and effective practice.
11+
* **Asyncio Usage:** The codebase heavily relies on `asyncio`, which is appropriate for I/O-bound tasks like handling WebSockets and interacting with external streaming services.
12+
13+
## SOLID Principles & Clean Code Analysis
14+
15+
1. **Single Responsibility Principle (SRP):**
16+
* **Mostly Good:** Classes like `WebSocketConnectionManager`, `TimeplusQueryManager`, and `PerspectiveManager` generally adhere well to SRP.
17+
* **`WebSocketMessageHandler`:** (`api/websocket/message_handler.py`) The `handle_start_query` method is quite long and complex. Consider breaking it down into smaller helper methods.
18+
* **`TimeplusQueryManager._run_query`:** This method is very long (~100 lines) and handles many tasks within the stream processing loop. Refactor into smaller, focused async methods (e.g., `_process_schema`, `_process_data_chunk`).
19+
* **`websocket_endpoint`:** (`api/websocket/endpoint.py`) The main `try...except` block is large. Some error/cleanup logic could potentially move to `WebSocketConnectionManager` or `WebSocketMessageHandler`.
20+
21+
2. **Open/Closed Principle (OCP):**
22+
* **Message Handling:** Dispatching messages via `isinstance` is acceptable for now but consider a more scalable pattern (e.g., command pattern or dictionary mapping) if more message types are added.
23+
24+
3. **Liskov Substitution Principle (LSP):**
25+
* **Opportunity:** If supporting alternative streaming sources or visualization backends becomes necessary, define abstract base classes/interfaces for managers (`QueryManager`, `VizManager`) to enable substitution.
26+
27+
4. **Interface Segregation Principle (ISP):**
28+
* **Mostly Good:** Manager interfaces are generally focused.
29+
* **`TimeplusQueryManager` Callbacks:** The specific set of callbacks required by `start_or_join_query` tightly couples it to `WebSocketMessageHandler`. Consider alternatives if other consumers need different interaction patterns.
30+
31+
5. **Dependency Inversion Principle (DIP):**
32+
* **Good (FastAPI):** FastAPI's `Depends` inverts control effectively.
33+
* **Managers & Clients:** Managers (`TimeplusQueryManager`, `PerspectiveManager`) create their underlying clients (`proton_driver`, `perspective`) directly. Injecting these clients (or interfaces) would improve testability and flexibility.
34+
35+
## Clarity, Messiness & Specific Issues
36+
37+
* **Error Handling:**
38+
* Extensive but complex, especially in WebSocket endpoint and message handler cleanup logic. Centralize where possible.
39+
* Unclear error propagation strategy from Timeplus callbacks in `WebSocketMessageHandler`. Decide whether errors should stop the upstream query.
40+
* **Async/Sync Mix:**
41+
* Verify potentially blocking calls (e.g., `PerspectiveManager.update_table`) and use `asyncio.to_thread` if needed.
42+
* Simplify unnecessary async wrappers around non-blocking calls in `WebSocketMessageHandler`.
43+
* **Missing Tests:** The `src/stream_viz/tests` directory is empty. This is a critical gap.
44+
* **Empty Files:** `src/stream_viz/utils/hashing.py` is empty. Implement or remove.
45+
* **Magic Strings:** Replace string literals for WebSocket message types (e.g., "table_ready") with Enums or constants for robustness.
46+
* **Resource Cleanup:** Double-check cleanup logic (`cleanup_query_resources`, `shutdown`) for edge cases and completeness.
47+
* **Perspective Client Loop:** Ensure the event loop handling in `PerspectiveManager` is robust for deployment scenarios.
48+
49+
## High-Priority Improvement Actions
50+
51+
1. **Implement Comprehensive Tests:** Add unit tests (mocking external deps) and integration tests. Start with managers and critical WebSocket logic.
52+
2. **Refactor Large Methods:** Break down `handle_start_query` (in `WebSocketMessageHandler`), `_run_query` (in `TimeplusQueryManager`), and `websocket_endpoint`.
53+
3. **Clarify & Standardize Error Handling:** Define clear error propagation rules (especially for callbacks) and simplify cleanup logic.
54+
4. **Address Async/Sync:** Use `asyncio.to_thread` for confirmed blocking calls. Remove unnecessary wrappers.
55+
5. **Inject Dependencies:** Inject `proton_driver` and `perspective` clients into their respective managers.
56+
6. **Populate/Remove Empty Files:** Add tests to `tests/`. Implement or remove `utils/hashing.py`.

TODO.md

Lines changed: 0 additions & 125 deletions
This file was deleted.

src/stream_viz/utils/hashing.py

Whitespace-only changes.

typings/proton_driver/__init__.pyi

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
"""
2+
This type stub file was generated by pyright.
3+
"""
4+
5+
from .client import Client
6+
from .dbapi import connect
7+
8+
VERSION = ...
9+
__version__ = ...
10+
__all__ = ['Client', 'connect']

typings/proton_driver/block.pyi

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
"""
2+
This type stub file was generated by pyright.
3+
"""
4+
5+
class BlockInfo:
6+
is_overflows = ...
7+
bucket_num = ...
8+
def write(self, buf): # -> None:
9+
...
10+
11+
def read(self, buf): # -> None:
12+
...
13+
14+
15+
16+
class BaseBlock:
17+
def __init__(self, columns_with_types=..., data=..., info=..., types_check=...) -> None:
18+
...
19+
20+
def normalize(self, data):
21+
...
22+
23+
@property
24+
def num_columns(self):
25+
...
26+
27+
@property
28+
def num_rows(self):
29+
...
30+
31+
def get_columns(self):
32+
...
33+
34+
def get_rows(self):
35+
...
36+
37+
def get_column_by_index(self, index):
38+
...
39+
40+
def transposed(self): # -> list[tuple[Any, ...]]:
41+
...
42+
43+
44+
45+
class ColumnOrientedBlock(BaseBlock):
46+
def normalize(self, data): # -> list[Any]:
47+
...
48+
49+
@property
50+
def num_columns(self): # -> int:
51+
...
52+
53+
@property
54+
def num_rows(self): # -> int:
55+
...
56+
57+
def get_columns(self): # -> list[Any]:
58+
...
59+
60+
def get_rows(self): # -> list[tuple[Any, ...]]:
61+
...
62+
63+
def get_column_by_index(self, index):
64+
...
65+
66+
67+
68+
class RowOrientedBlock(BaseBlock):
69+
dict_row_types = ...
70+
tuple_row_types = ...
71+
supported_row_types = ...
72+
def normalize(self, data): # -> list[Any]:
73+
...
74+
75+
@property
76+
def num_columns(self): # -> int:
77+
...
78+
79+
@property
80+
def num_rows(self): # -> int:
81+
...
82+
83+
def get_columns(self): # -> list[tuple[Any, ...]]:
84+
...
85+
86+
def get_rows(self): # -> list[Any]:
87+
...
88+
89+
def get_column_by_index(self, index): # -> list[Any]:
90+
...
91+
92+
93+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
"""
2+
This type stub file was generated by pyright.
3+
"""
4+
5+
class BlockStreamProfileInfo:
6+
def __init__(self) -> None:
7+
...
8+
9+
def read(self, fin): # -> None:
10+
...
11+
12+
13+

0 commit comments

Comments
 (0)