refactor: reorganize repository to src/ layout
Move 6 packages (core, config, data_processing, analysis, visualization, cli) into src/ to reduce root clutter. Merge tools/data.py into data_processing/transforms.py. Move docs to docs/. Path resolution via .pth file (setup_dev.py), pytest pythonpath config, and sys.path bootstrap in rxconfig.py and CLI entry points. Clean up pyproject.toml deps (remove stale pins, add snowflake-connector-python). Fix tomllib import for Python 3.10 compatibility. All 113 tests pass.
This commit is contained in:
-140
@@ -1,140 +0,0 @@
|
||||
"""
|
||||
Data models for NHS High-Cost Drug Patient Pathway Analysis Tool.
|
||||
|
||||
Contains dataclasses for encapsulating application state and filter parameters.
|
||||
"""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import date
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
|
||||
@dataclass
|
||||
class AnalysisFilters:
|
||||
"""
|
||||
Encapsulates all filter state for the analysis pipeline.
|
||||
|
||||
Replaces the individual parameters currently passed to generate_graph()
|
||||
and the global state managed in the GUI. This provides:
|
||||
- Type safety for filter values
|
||||
- Validation of filter combinations
|
||||
- Easy serialization for caching/persistence
|
||||
- Clear interface between GUI and analysis engine
|
||||
|
||||
Attributes:
|
||||
start_date: Patient initiated start date (treatment pathway start)
|
||||
end_date: Patient initiated end date (treatment pathway start cutoff)
|
||||
last_seen_date: Minimum last seen date (filters out patients not seen recently)
|
||||
trusts: List of NHS Trust names to include (empty = all)
|
||||
drugs: List of drug names to include (empty = all)
|
||||
directories: List of medical directories/specialties to include (empty = all)
|
||||
custom_title: Optional custom title for the graph (blank = auto-generated)
|
||||
minimum_patients: Minimum number of patients for a pathway to be included
|
||||
output_dir: Directory where output files should be saved
|
||||
"""
|
||||
|
||||
start_date: date
|
||||
end_date: date
|
||||
last_seen_date: date
|
||||
trusts: list[str] = field(default_factory=list)
|
||||
drugs: list[str] = field(default_factory=list)
|
||||
directories: list[str] = field(default_factory=list)
|
||||
custom_title: str = ""
|
||||
minimum_patients: int = 0
|
||||
output_dir: Optional[Path] = None
|
||||
|
||||
def validate(self) -> list[str]:
|
||||
"""
|
||||
Validate filter configuration for logical consistency.
|
||||
|
||||
Returns:
|
||||
List of error messages. Empty list means all validations passed.
|
||||
"""
|
||||
errors = []
|
||||
|
||||
# Date range validation
|
||||
if self.end_date < self.start_date:
|
||||
errors.append(
|
||||
f"End date ({self.end_date}) cannot be before start date ({self.start_date})"
|
||||
)
|
||||
|
||||
if self.last_seen_date > self.end_date:
|
||||
errors.append(
|
||||
f"Last seen date ({self.last_seen_date}) is after end date ({self.end_date}), "
|
||||
"which would exclude all patients"
|
||||
)
|
||||
|
||||
# Minimum patients validation
|
||||
if self.minimum_patients < 0:
|
||||
errors.append(
|
||||
f"Minimum patients ({self.minimum_patients}) cannot be negative"
|
||||
)
|
||||
|
||||
# Output directory validation
|
||||
if self.output_dir is not None and not self.output_dir.exists():
|
||||
errors.append(f"Output directory does not exist: {self.output_dir}")
|
||||
|
||||
# Filter list validation (warn if empty but don't error)
|
||||
# Empty lists are valid and mean "include all"
|
||||
|
||||
return errors
|
||||
|
||||
@property
|
||||
def has_trust_filter(self) -> bool:
|
||||
"""Check if any trust filter is applied."""
|
||||
return len(self.trusts) > 0
|
||||
|
||||
@property
|
||||
def has_drug_filter(self) -> bool:
|
||||
"""Check if any drug filter is applied."""
|
||||
return len(self.drugs) > 0
|
||||
|
||||
@property
|
||||
def has_directory_filter(self) -> bool:
|
||||
"""Check if any directory filter is applied."""
|
||||
return len(self.directories) > 0
|
||||
|
||||
@property
|
||||
def title(self) -> str:
|
||||
"""
|
||||
Return the display title for the graph.
|
||||
|
||||
If custom_title is set, use it. Otherwise, generate a default title
|
||||
based on the date range.
|
||||
"""
|
||||
if self.custom_title:
|
||||
return self.custom_title
|
||||
return f"Patients initiated from {self.start_date} to {self.end_date}"
|
||||
|
||||
def summary(self) -> str:
|
||||
"""
|
||||
Return a human-readable summary of the filter configuration.
|
||||
|
||||
Useful for logging and display in the GUI.
|
||||
"""
|
||||
lines = [
|
||||
f"Date range: {self.start_date} to {self.end_date}",
|
||||
f"Last seen after: {self.last_seen_date}",
|
||||
f"Minimum patients: {self.minimum_patients}",
|
||||
]
|
||||
|
||||
if self.trusts:
|
||||
lines.append(f"Trusts: {len(self.trusts)} selected")
|
||||
else:
|
||||
lines.append("Trusts: All")
|
||||
|
||||
if self.drugs:
|
||||
lines.append(f"Drugs: {len(self.drugs)} selected")
|
||||
else:
|
||||
lines.append("Drugs: All")
|
||||
|
||||
if self.directories:
|
||||
lines.append(f"Directories: {len(self.directories)} selected")
|
||||
else:
|
||||
lines.append("Directories: All")
|
||||
|
||||
if self.custom_title:
|
||||
lines.append(f"Custom title: {self.custom_title}")
|
||||
|
||||
return "\n".join(lines)
|
||||
Reference in New Issue
Block a user