-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathposition_history_manager.py
More file actions
242 lines (200 loc) · 7.69 KB
/
position_history_manager.py
File metadata and controls
242 lines (200 loc) · 7.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
"""
Position History Manager Module
Handles position history export and management
This module provides:
- Position history export to CSV
- History clearing with confirmation
- Default filename generation
- Export result handling
"""
import logging
from datetime import datetime
from typing import Callable, Optional
from dataclasses import dataclass
from enum import Enum, auto
logger = logging.getLogger(__name__)
class ExportResult(Enum):
"""Result of export operation"""
SUCCESS = auto()
NO_DATA = auto()
CANCELLED = auto()
FAILED = auto()
@dataclass
class ExportInfo:
"""Information about an export operation"""
result: ExportResult
filename: str = ""
snapshot_count: int = 0
error_message: str = ""
class PositionHistoryManager:
"""
Manages position history export and clearing operations.
This class separates business logic from GUI concerns,
using callbacks for file dialogs and messages.
"""
# Default CSV filename format
FILENAME_FORMAT = "position_history_{timestamp}.csv"
TIMESTAMP_FORMAT = "%Y%m%d_%H%M%S"
def __init__(
self,
position_history=None,
# Callbacks for GUI interactions
get_save_filename: Optional[Callable[[str], Optional[str]]] = None,
show_warning: Optional[Callable[[str, str], None]] = None,
show_info: Optional[Callable[[str, str], None]] = None,
show_error: Optional[Callable[[str, str], None]] = None,
confirm_action: Optional[Callable[[str, str], bool]] = None,
):
"""
Initialize position history manager.
Args:
position_history: Position history object to manage
get_save_filename: Callback(default_name) -> filename or None
show_warning: Callback(message, title) for warning dialogs
show_info: Callback(message, title) for info dialogs
show_error: Callback(message, title) for error dialogs
confirm_action: Callback(message, title) -> bool for confirmation
"""
self.position_history = position_history
self.get_save_filename = get_save_filename
self.show_warning = show_warning
self.show_info = show_info
self.show_error = show_error
self.confirm_action = confirm_action
@property
def history_count(self) -> int:
"""Get number of snapshots in history"""
if self.position_history is None:
return 0
return len(self.position_history)
@property
def has_data(self) -> bool:
"""Check if there is any history data"""
return self.history_count > 0
def generate_default_filename(self) -> str:
"""
Generate default filename for export.
Returns:
Filename with timestamp, e.g., 'position_history_20240115_143022.csv'
"""
timestamp = datetime.now().strftime(self.TIMESTAMP_FORMAT)
return self.FILENAME_FORMAT.format(timestamp=timestamp)
def export_to_csv(self, filename: Optional[str] = None) -> ExportInfo:
"""
Export position history to CSV file.
Args:
filename: Target filename, or None to prompt for filename
Returns:
ExportInfo with result details
"""
# Check if there's data to export
if not self.has_data:
logger.warning("No position history to export")
if self.show_warning:
self.show_warning("No position history to export.", "No Data")
return ExportInfo(result=ExportResult.NO_DATA)
# Get filename if not provided
if filename is None:
if self.get_save_filename:
default_name = self.generate_default_filename()
filename = self.get_save_filename(default_name)
# Check if user cancelled
if not filename:
logger.debug("Export cancelled by user")
return ExportInfo(result=ExportResult.CANCELLED)
# Perform export
try:
success = self.position_history.export_to_csv(filename)
if success:
count = self.history_count
logger.info(f"Position history exported to {filename} ({count} snapshots)")
if self.show_info:
self.show_info(
f"Position history exported successfully to:\n{filename}\n\n{count} snapshots saved.",
"Export Successful"
)
return ExportInfo(
result=ExportResult.SUCCESS,
filename=filename,
snapshot_count=count
)
else:
logger.error(f"Failed to export position history to {filename}")
if self.show_error:
self.show_error("Failed to export position history.", "Export Failed")
return ExportInfo(
result=ExportResult.FAILED,
filename=filename,
error_message="Export returned False"
)
except Exception as e:
logger.error(f"Exception during export: {e}")
if self.show_error:
self.show_error(f"Failed to export: {e}", "Export Failed")
return ExportInfo(
result=ExportResult.FAILED,
filename=filename or "",
error_message=str(e)
)
def clear_history(self, skip_confirmation: bool = False) -> bool:
"""
Clear all position history.
Args:
skip_confirmation: If True, skip confirmation dialog
Returns:
True if history was cleared, False if cancelled
"""
if not self.has_data:
logger.debug("No history to clear")
return False
# Confirm with user unless skipped
if not skip_confirmation and self.confirm_action:
message = f"Clear all position history?\n\nThis will delete {self.history_count} recorded snapshots."
if not self.confirm_action(message, "Clear History"):
logger.debug("Clear history cancelled by user")
return False
# Clear history
self.position_history.clear()
logger.info("Position history cleared by user")
if self.show_info:
self.show_info("Position history cleared.", "Cleared")
return True
def get_export_info(self) -> dict:
"""
Get information about current history for display.
Returns:
Dictionary with history information
"""
return {
'count': self.history_count,
'has_data': self.has_data,
'default_filename': self.generate_default_filename()
}
def create_position_history_manager(
position_history=None,
get_save_filename: Callable = None,
show_warning: Callable = None,
show_info: Callable = None,
show_error: Callable = None,
confirm_action: Callable = None
) -> PositionHistoryManager:
"""
Create a PositionHistoryManager with callbacks.
Args:
position_history: Position history object
get_save_filename: Callback(default_name) -> filename
show_warning: Callback(message, title) for warnings
show_info: Callback(message, title) for info
show_error: Callback(message, title) for errors
confirm_action: Callback(message, title) -> bool
Returns:
Configured PositionHistoryManager instance
"""
return PositionHistoryManager(
position_history=position_history,
get_save_filename=get_save_filename,
show_warning=show_warning,
show_info=show_info,
show_error=show_error,
confirm_action=confirm_action
)