conson-xp 1.0.1__py3-none-any.whl → 1.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {conson_xp-1.0.1.dist-info → conson_xp-1.2.0.dist-info}/METADATA +1 -1
- conson_xp-1.2.0.dist-info/RECORD +181 -0
- xp/__init__.py +4 -3
- xp/api/main.py +18 -3
- xp/api/models/api.py +13 -2
- xp/api/models/discover.py +12 -2
- xp/api/routers/conbus_blink.py +18 -6
- xp/api/routers/conbus_custom.py +11 -3
- xp/api/routers/conbus_datapoint.py +10 -3
- xp/api/routers/conbus_output.py +29 -9
- xp/api/routers/errors.py +6 -5
- xp/cli/__init__.py +1 -1
- xp/cli/commands/__init__.py +1 -0
- xp/cli/commands/api.py +1 -5
- xp/cli/commands/api_start_commands.py +14 -8
- xp/cli/commands/conbus/conbus.py +9 -37
- xp/cli/commands/conbus/conbus_actiontable_commands.py +21 -1
- xp/cli/commands/conbus/conbus_autoreport_commands.py +21 -11
- xp/cli/commands/conbus/conbus_blink_commands.py +53 -21
- xp/cli/commands/conbus/conbus_config_commands.py +7 -4
- xp/cli/commands/conbus/conbus_custom_commands.py +13 -4
- xp/cli/commands/conbus/conbus_datapoint_commands.py +28 -8
- xp/cli/commands/conbus/conbus_discover_commands.py +15 -4
- xp/cli/commands/conbus/conbus_lightlevel_commands.py +50 -11
- xp/cli/commands/conbus/conbus_linknumber_commands.py +21 -11
- xp/cli/commands/conbus/conbus_msactiontable_commands.py +25 -1
- xp/cli/commands/conbus/conbus_output_commands.py +46 -12
- xp/cli/commands/conbus/conbus_raw_commands.py +17 -6
- xp/cli/commands/conbus/conbus_receive_commands.py +15 -7
- xp/cli/commands/conbus/conbus_scan_commands.py +35 -102
- xp/cli/commands/file_commands.py +26 -15
- xp/cli/commands/homekit/homekit.py +14 -8
- xp/cli/commands/homekit/homekit_start_commands.py +5 -5
- xp/cli/commands/module_commands.py +26 -19
- xp/cli/commands/reverse_proxy_commands.py +24 -18
- xp/cli/commands/server/server_commands.py +18 -18
- xp/cli/commands/telegram/telegram.py +4 -12
- xp/cli/commands/telegram/telegram_blink_commands.py +10 -8
- xp/cli/commands/telegram/telegram_checksum_commands.py +19 -8
- xp/cli/commands/telegram/telegram_discover_commands.py +2 -4
- xp/cli/commands/telegram/telegram_linknumber_commands.py +11 -8
- xp/cli/commands/telegram/telegram_parse_commands.py +10 -9
- xp/cli/commands/telegram/telegram_version_commands.py +8 -4
- xp/cli/main.py +5 -1
- xp/cli/utils/click_tree.py +23 -3
- xp/cli/utils/datapoint_type_choice.py +20 -0
- xp/cli/utils/decorators.py +165 -14
- xp/cli/utils/error_handlers.py +49 -18
- xp/cli/utils/formatters.py +95 -10
- xp/cli/utils/serial_number_type.py +18 -0
- xp/cli/utils/system_function_choice.py +20 -0
- xp/cli/utils/xp_module_type.py +20 -0
- xp/connection/__init__.py +1 -1
- xp/connection/exceptions.py +5 -5
- xp/models/__init__.py +1 -1
- xp/models/actiontable/__init__.py +1 -0
- xp/models/actiontable/actiontable.py +17 -1
- xp/models/actiontable/msactiontable_xp20.py +10 -0
- xp/models/actiontable/msactiontable_xp24.py +20 -3
- xp/models/actiontable/msactiontable_xp33.py +27 -4
- xp/models/conbus/__init__.py +1 -0
- xp/models/conbus/conbus.py +34 -4
- xp/models/conbus/conbus_autoreport.py +20 -2
- xp/models/conbus/conbus_blink.py +22 -2
- xp/models/conbus/conbus_client_config.py +22 -1
- xp/models/conbus/conbus_connection_status.py +16 -2
- xp/models/conbus/conbus_custom.py +21 -2
- xp/models/conbus/conbus_datapoint.py +22 -2
- xp/models/conbus/conbus_discover.py +18 -2
- xp/models/conbus/conbus_lightlevel.py +20 -2
- xp/models/conbus/conbus_linknumber.py +20 -2
- xp/models/conbus/conbus_output.py +22 -2
- xp/models/conbus/conbus_raw.py +17 -2
- xp/models/conbus/conbus_receive.py +16 -2
- xp/models/homekit/__init__.py +1 -0
- xp/models/homekit/homekit_accessory.py +15 -1
- xp/models/homekit/homekit_config.py +52 -0
- xp/models/homekit/homekit_conson_config.py +32 -0
- xp/models/log_entry.py +49 -9
- xp/models/protocol/__init__.py +1 -0
- xp/models/protocol/conbus_protocol.py +130 -21
- xp/models/telegram/__init__.py +1 -0
- xp/models/telegram/action_type.py +16 -2
- xp/models/telegram/datapoint_type.py +36 -2
- xp/models/telegram/event_telegram.py +46 -10
- xp/models/telegram/event_type.py +8 -1
- xp/models/telegram/input_action_type.py +34 -2
- xp/models/telegram/input_type.py +9 -1
- xp/models/telegram/module_type.py +69 -19
- xp/models/telegram/module_type_code.py +43 -1
- xp/models/telegram/output_telegram.py +30 -6
- xp/models/telegram/reply_telegram.py +56 -11
- xp/models/telegram/system_function.py +35 -3
- xp/models/telegram/system_telegram.py +18 -4
- xp/models/telegram/telegram.py +12 -3
- xp/models/telegram/telegram_type.py +8 -1
- xp/models/telegram/timeparam_type.py +27 -0
- xp/models/write_config_type.py +17 -2
- xp/services/__init__.py +1 -1
- xp/services/conbus/__init__.py +1 -0
- xp/services/conbus/actiontable/__init__.py +1 -0
- xp/services/conbus/actiontable/actiontable_service.py +33 -2
- xp/services/conbus/actiontable/msactiontable_service.py +40 -3
- xp/services/conbus/actiontable/msactiontable_xp24_serializer.py +36 -4
- xp/services/conbus/actiontable/msactiontable_xp33_serializer.py +45 -5
- xp/services/conbus/conbus_autoreport_get_service.py +17 -8
- xp/services/conbus/conbus_autoreport_set_service.py +29 -16
- xp/services/conbus/conbus_blink_all_service.py +40 -21
- xp/services/conbus/conbus_blink_service.py +37 -13
- xp/services/conbus/conbus_custom_service.py +29 -13
- xp/services/conbus/conbus_datapoint_queryall_service.py +40 -16
- xp/services/conbus/conbus_datapoint_service.py +33 -12
- xp/services/conbus/conbus_discover_service.py +43 -7
- xp/services/conbus/conbus_lightlevel_get_service.py +22 -14
- xp/services/conbus/conbus_lightlevel_set_service.py +40 -20
- xp/services/conbus/conbus_linknumber_get_service.py +18 -10
- xp/services/conbus/conbus_linknumber_set_service.py +34 -8
- xp/services/conbus/conbus_output_service.py +33 -13
- xp/services/conbus/conbus_raw_service.py +36 -16
- xp/services/conbus/conbus_receive_service.py +38 -6
- xp/services/conbus/conbus_scan_service.py +45 -19
- xp/services/homekit/__init__.py +1 -0
- xp/services/homekit/homekit_cache_service.py +31 -6
- xp/services/homekit/homekit_conbus_service.py +33 -2
- xp/services/homekit/homekit_config_validator.py +97 -15
- xp/services/homekit/homekit_conson_validator.py +51 -7
- xp/services/homekit/homekit_dimminglight.py +47 -1
- xp/services/homekit/homekit_dimminglight_service.py +35 -1
- xp/services/homekit/homekit_hap_service.py +71 -18
- xp/services/homekit/homekit_lightbulb.py +35 -1
- xp/services/homekit/homekit_lightbulb_service.py +30 -2
- xp/services/homekit/homekit_module_service.py +23 -1
- xp/services/homekit/homekit_outlet.py +47 -1
- xp/services/homekit/homekit_outlet_service.py +44 -2
- xp/services/homekit/homekit_service.py +113 -19
- xp/services/log_file_service.py +37 -41
- xp/services/module_type_service.py +26 -5
- xp/services/protocol/__init__.py +1 -1
- xp/services/protocol/conbus_protocol.py +115 -20
- xp/services/protocol/protocol_factory.py +40 -0
- xp/services/protocol/telegram_protocol.py +38 -7
- xp/services/reverse_proxy_service.py +79 -14
- xp/services/server/__init__.py +1 -0
- xp/services/server/base_server_service.py +102 -14
- xp/services/server/cp20_server_service.py +12 -4
- xp/services/server/server_service.py +26 -11
- xp/services/server/xp130_server_service.py +11 -3
- xp/services/server/xp20_server_service.py +11 -3
- xp/services/server/xp230_server_service.py +11 -3
- xp/services/server/xp24_server_service.py +33 -6
- xp/services/server/xp33_server_service.py +41 -8
- xp/services/telegram/__init__.py +1 -0
- xp/services/telegram/telegram_blink_service.py +19 -31
- xp/services/telegram/telegram_checksum_service.py +10 -10
- xp/services/telegram/telegram_discover_service.py +58 -29
- xp/services/telegram/telegram_link_number_service.py +27 -40
- xp/services/telegram/telegram_output_service.py +46 -49
- xp/services/telegram/telegram_service.py +41 -41
- xp/services/telegram/telegram_version_service.py +4 -2
- xp/utils/__init__.py +1 -1
- xp/utils/dependencies.py +0 -1
- xp/utils/serialization.py +6 -0
- xp/utils/time_utils.py +6 -11
- conson_xp-1.0.1.dist-info/RECORD +0 -181
- {conson_xp-1.0.1.dist-info → conson_xp-1.2.0.dist-info}/WHEEL +0 -0
- {conson_xp-1.0.1.dist-info → conson_xp-1.2.0.dist-info}/entry_points.txt +0 -0
- {conson_xp-1.0.1.dist-info → conson_xp-1.2.0.dist-info}/licenses/LICENSE +0 -0
xp/cli/utils/decorators.py
CHANGED
|
@@ -11,15 +11,39 @@ from xp.cli.utils.formatters import OutputFormatter
|
|
|
11
11
|
def handle_service_errors(
|
|
12
12
|
*service_exceptions: Type[Exception],
|
|
13
13
|
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
14
|
-
"""
|
|
14
|
+
"""Handle common service exceptions with consistent JSON error formatting.
|
|
15
15
|
|
|
16
16
|
Args:
|
|
17
|
-
service_exceptions: Tuple of exception types to catch and handle
|
|
17
|
+
service_exceptions: Tuple of exception types to catch and handle.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
Decorator function that wraps commands with error handling.
|
|
18
21
|
"""
|
|
19
22
|
|
|
20
23
|
def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
|
|
24
|
+
"""Apply error handling to the decorated function.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
func: The function to decorate.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
Wrapped function with error handling.
|
|
31
|
+
"""
|
|
32
|
+
|
|
21
33
|
@functools.wraps(func)
|
|
22
34
|
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
35
|
+
"""Execute function with error handling.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
args: Positional arguments passed to the decorated function.
|
|
39
|
+
kwargs: Keyword arguments passed to the decorated function.
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
Result from the decorated function.
|
|
43
|
+
|
|
44
|
+
Raises:
|
|
45
|
+
SystemExit: When a service exception or unexpected error occurs.
|
|
46
|
+
"""
|
|
23
47
|
formatter = OutputFormatter(True)
|
|
24
48
|
|
|
25
49
|
try:
|
|
@@ -40,20 +64,38 @@ def handle_service_errors(
|
|
|
40
64
|
|
|
41
65
|
|
|
42
66
|
def common_options(func: Callable[..., Any]) -> Callable[..., Any]:
|
|
43
|
-
"""
|
|
67
|
+
"""Add validation option to command.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
func: The function to decorate.
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
Decorated function with common options.
|
|
74
|
+
"""
|
|
44
75
|
return func
|
|
45
76
|
|
|
46
77
|
|
|
47
78
|
def telegram_parser_command(
|
|
48
79
|
service_exceptions: Tuple[Type[Exception], ...] = (),
|
|
49
80
|
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
50
|
-
"""
|
|
81
|
+
"""Apply telegram parsing commands with standard error handling.
|
|
51
82
|
|
|
52
83
|
Args:
|
|
53
|
-
service_exceptions: Additional service exceptions to handle
|
|
84
|
+
service_exceptions: Additional service exceptions to handle.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
Decorator function for telegram parsing commands.
|
|
54
88
|
"""
|
|
55
89
|
|
|
56
90
|
def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
|
|
91
|
+
"""Apply telegram parser decorators.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
func: The function to decorate.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
Decorated function with telegram parsing support.
|
|
98
|
+
"""
|
|
57
99
|
# Apply common options
|
|
58
100
|
func = common_options(func)
|
|
59
101
|
|
|
@@ -71,13 +113,24 @@ def telegram_parser_command(
|
|
|
71
113
|
def service_command(
|
|
72
114
|
*service_exceptions: Type[Exception],
|
|
73
115
|
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
74
|
-
"""
|
|
116
|
+
"""Apply service-based commands with error handling and JSON output.
|
|
75
117
|
|
|
76
118
|
Args:
|
|
77
|
-
service_exceptions: Service exception types to handle
|
|
119
|
+
service_exceptions: Service exception types to handle.
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
Decorator function for service commands.
|
|
78
123
|
"""
|
|
79
124
|
|
|
80
125
|
def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
|
|
126
|
+
"""Apply service command decorators.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
func: The function to decorate.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
Decorated function with service error handling.
|
|
133
|
+
"""
|
|
81
134
|
func = handle_service_errors(*service_exceptions)(func)
|
|
82
135
|
return func
|
|
83
136
|
|
|
@@ -87,9 +140,24 @@ def service_command(
|
|
|
87
140
|
def list_command(
|
|
88
141
|
*service_exceptions: Type[Exception],
|
|
89
142
|
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
90
|
-
"""
|
|
143
|
+
"""Apply list/search commands with common options.
|
|
144
|
+
|
|
145
|
+
Args:
|
|
146
|
+
service_exceptions: Service exception types to handle.
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
Decorator function for list commands.
|
|
150
|
+
"""
|
|
91
151
|
|
|
92
152
|
def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
|
|
153
|
+
"""Apply list command decorators.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
func: The function to decorate.
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
Decorated function with list error handling.
|
|
160
|
+
"""
|
|
93
161
|
func = handle_service_errors(*service_exceptions)(func)
|
|
94
162
|
return func
|
|
95
163
|
|
|
@@ -97,9 +165,21 @@ def list_command(
|
|
|
97
165
|
|
|
98
166
|
|
|
99
167
|
def file_operation_command() -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
100
|
-
"""
|
|
168
|
+
"""Apply file operation commands with common filters.
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
Decorator function for file operation commands.
|
|
172
|
+
"""
|
|
101
173
|
|
|
102
174
|
def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
|
|
175
|
+
"""Apply file operation decorators.
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
func: The function to decorate.
|
|
179
|
+
|
|
180
|
+
Returns:
|
|
181
|
+
Decorated function with filter options.
|
|
182
|
+
"""
|
|
103
183
|
func = click.option(
|
|
104
184
|
"--time-range", help="Filter by time range (HH:MM:SS,mmm-HH:MM:SS,mmm)"
|
|
105
185
|
)(func)
|
|
@@ -121,15 +201,36 @@ def file_operation_command() -> Callable[[Callable[..., Any]], Callable[..., Any
|
|
|
121
201
|
def with_formatter(
|
|
122
202
|
formatter_class: Any = None,
|
|
123
203
|
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
124
|
-
"""
|
|
204
|
+
"""Inject a formatter instance into the command.
|
|
125
205
|
|
|
126
206
|
Args:
|
|
127
|
-
formatter_class: Custom formatter class to use
|
|
207
|
+
formatter_class: Custom formatter class to use.
|
|
208
|
+
|
|
209
|
+
Returns:
|
|
210
|
+
Decorator function that injects a formatter.
|
|
128
211
|
"""
|
|
129
212
|
|
|
130
213
|
def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
|
|
214
|
+
"""Apply formatter injection.
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
func: The function to decorate.
|
|
218
|
+
|
|
219
|
+
Returns:
|
|
220
|
+
Wrapped function with formatter injection.
|
|
221
|
+
"""
|
|
222
|
+
|
|
131
223
|
@functools.wraps(func)
|
|
132
224
|
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
225
|
+
"""Execute function with injected formatter.
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
args: Positional arguments passed to the decorated function.
|
|
229
|
+
kwargs: Keyword arguments passed to the decorated function.
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
Result from the decorated function.
|
|
233
|
+
"""
|
|
133
234
|
formatter_cls = formatter_class or OutputFormatter
|
|
134
235
|
formatter = formatter_cls(True)
|
|
135
236
|
kwargs["formatter"] = formatter
|
|
@@ -143,15 +244,39 @@ def with_formatter(
|
|
|
143
244
|
def require_arguments(
|
|
144
245
|
*required_args: str,
|
|
145
246
|
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
146
|
-
"""
|
|
247
|
+
"""Validate required arguments are present.
|
|
147
248
|
|
|
148
249
|
Args:
|
|
149
|
-
required_args: Names of required arguments
|
|
250
|
+
required_args: Names of required arguments.
|
|
251
|
+
|
|
252
|
+
Returns:
|
|
253
|
+
Decorator function that validates required arguments.
|
|
150
254
|
"""
|
|
151
255
|
|
|
152
256
|
def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
|
|
257
|
+
"""Apply argument validation.
|
|
258
|
+
|
|
259
|
+
Args:
|
|
260
|
+
func: The function to decorate.
|
|
261
|
+
|
|
262
|
+
Returns:
|
|
263
|
+
Wrapped function with argument validation.
|
|
264
|
+
"""
|
|
265
|
+
|
|
153
266
|
@functools.wraps(func)
|
|
154
267
|
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
268
|
+
"""Execute function with argument validation.
|
|
269
|
+
|
|
270
|
+
Args:
|
|
271
|
+
args: Positional arguments passed to the decorated function.
|
|
272
|
+
kwargs: Keyword arguments passed to the decorated function.
|
|
273
|
+
|
|
274
|
+
Returns:
|
|
275
|
+
Result from the decorated function.
|
|
276
|
+
|
|
277
|
+
Raises:
|
|
278
|
+
SystemExit: When required arguments are missing.
|
|
279
|
+
"""
|
|
155
280
|
formatter = OutputFormatter(True)
|
|
156
281
|
|
|
157
282
|
# Check for missing required arguments
|
|
@@ -175,11 +300,37 @@ def require_arguments(
|
|
|
175
300
|
|
|
176
301
|
|
|
177
302
|
def connection_command() -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
178
|
-
"""
|
|
303
|
+
"""Apply commands that connect to remote services.
|
|
304
|
+
|
|
305
|
+
Returns:
|
|
306
|
+
Decorator function for connection commands.
|
|
307
|
+
"""
|
|
179
308
|
|
|
180
309
|
def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
|
|
310
|
+
"""Apply connection command decorators.
|
|
311
|
+
|
|
312
|
+
Args:
|
|
313
|
+
func: The function to decorate.
|
|
314
|
+
|
|
315
|
+
Returns:
|
|
316
|
+
Wrapped function with connection error handling.
|
|
317
|
+
"""
|
|
318
|
+
|
|
181
319
|
@functools.wraps(func)
|
|
182
320
|
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
321
|
+
"""Execute function with connection error handling.
|
|
322
|
+
|
|
323
|
+
Args:
|
|
324
|
+
args: Positional arguments passed to the decorated function.
|
|
325
|
+
kwargs: Keyword arguments passed to the decorated function.
|
|
326
|
+
|
|
327
|
+
Returns:
|
|
328
|
+
Result from the decorated function.
|
|
329
|
+
|
|
330
|
+
Raises:
|
|
331
|
+
SystemExit: When a connection timeout occurs.
|
|
332
|
+
Exception: Re-raises other exceptions for handling by other decorators.
|
|
333
|
+
"""
|
|
183
334
|
formatter = OutputFormatter(True)
|
|
184
335
|
|
|
185
336
|
try:
|
xp/cli/utils/error_handlers.py
CHANGED
|
@@ -19,9 +19,12 @@ class CLIErrorHandler:
|
|
|
19
19
|
"""Handle telegram parsing errors with JSON formatting.
|
|
20
20
|
|
|
21
21
|
Args:
|
|
22
|
-
error: The parsing error that occurred
|
|
23
|
-
raw_input: The raw input that failed to parse
|
|
24
|
-
context: Additional context information
|
|
22
|
+
error: The parsing error that occurred.
|
|
23
|
+
raw_input: The raw input that failed to parse.
|
|
24
|
+
context: Additional context information.
|
|
25
|
+
|
|
26
|
+
Raises:
|
|
27
|
+
SystemExit: Always exits with code 1 after displaying error.
|
|
25
28
|
"""
|
|
26
29
|
formatter = OutputFormatter(True)
|
|
27
30
|
error_data = {"raw_input": raw_input}
|
|
@@ -40,8 +43,11 @@ class CLIErrorHandler:
|
|
|
40
43
|
"""Handle connection/network errors with JSON formatting.
|
|
41
44
|
|
|
42
45
|
Args:
|
|
43
|
-
error: The connection error that occurred
|
|
44
|
-
config: Configuration information (IP, port, timeout)
|
|
46
|
+
error: The connection error that occurred.
|
|
47
|
+
config: Configuration information (IP, port, timeout).
|
|
48
|
+
|
|
49
|
+
Raises:
|
|
50
|
+
SystemExit: Always exits with code 1 after displaying error.
|
|
45
51
|
"""
|
|
46
52
|
formatter = OutputFormatter(True)
|
|
47
53
|
|
|
@@ -73,9 +79,12 @@ class CLIErrorHandler:
|
|
|
73
79
|
"""Handle general service errors with JSON formatting.
|
|
74
80
|
|
|
75
81
|
Args:
|
|
76
|
-
error: The service error that occurred
|
|
77
|
-
operation: Description of the operation that failed
|
|
78
|
-
context: Additional context information
|
|
82
|
+
error: The service error that occurred.
|
|
83
|
+
operation: Description of the operation that failed.
|
|
84
|
+
context: Additional context information.
|
|
85
|
+
|
|
86
|
+
Raises:
|
|
87
|
+
SystemExit: Always exits with code 1 after displaying error.
|
|
79
88
|
"""
|
|
80
89
|
formatter = OutputFormatter(True)
|
|
81
90
|
error_data = {"operation": operation}
|
|
@@ -92,8 +101,11 @@ class CLIErrorHandler:
|
|
|
92
101
|
"""Handle validation errors with JSON formatting.
|
|
93
102
|
|
|
94
103
|
Args:
|
|
95
|
-
error: The validation error that occurred
|
|
96
|
-
input_data: The input that failed validation
|
|
104
|
+
error: The validation error that occurred.
|
|
105
|
+
input_data: The input that failed validation.
|
|
106
|
+
|
|
107
|
+
Raises:
|
|
108
|
+
SystemExit: Always exits with code 1 after displaying error.
|
|
97
109
|
"""
|
|
98
110
|
formatter = OutputFormatter(True)
|
|
99
111
|
error_data = {"valid_format": False, "raw_input": input_data}
|
|
@@ -111,9 +123,12 @@ class CLIErrorHandler:
|
|
|
111
123
|
"""Handle file operation errors with JSON formatting.
|
|
112
124
|
|
|
113
125
|
Args:
|
|
114
|
-
error: The file error that occurred
|
|
115
|
-
file_path: Path to the file that caused the error
|
|
116
|
-
operation: Type of file operation (parsing, reading, etc.)
|
|
126
|
+
error: The file error that occurred.
|
|
127
|
+
file_path: Path to the file that caused the error.
|
|
128
|
+
operation: Type of file operation (parsing, reading, etc.).
|
|
129
|
+
|
|
130
|
+
Raises:
|
|
131
|
+
SystemExit: Always exits with code 1 after displaying error.
|
|
117
132
|
"""
|
|
118
133
|
formatter = OutputFormatter(True)
|
|
119
134
|
error_data = {"file_path": file_path, "operation": operation}
|
|
@@ -129,9 +144,12 @@ class CLIErrorHandler:
|
|
|
129
144
|
"""Handle 'not found' errors with JSON formatting.
|
|
130
145
|
|
|
131
146
|
Args:
|
|
132
|
-
error: The not found error that occurred
|
|
133
|
-
item_type: Type of item that was not found
|
|
134
|
-
identifier: Identifier used to search for the item
|
|
147
|
+
error: The not found error that occurred.
|
|
148
|
+
item_type: Type of item that was not found.
|
|
149
|
+
identifier: Identifier used to search for the item.
|
|
150
|
+
|
|
151
|
+
Raises:
|
|
152
|
+
SystemExit: Always exits with code 1 after displaying error.
|
|
135
153
|
"""
|
|
136
154
|
formatter = OutputFormatter(True)
|
|
137
155
|
error_data = {"item_type": item_type, "identifier": identifier}
|
|
@@ -148,7 +166,16 @@ class ServerErrorHandler(CLIErrorHandler):
|
|
|
148
166
|
def handle_server_startup_error(
|
|
149
167
|
error: Exception, port: int, config_path: str
|
|
150
168
|
) -> None:
|
|
151
|
-
"""Handle server startup errors with JSON formatting.
|
|
169
|
+
"""Handle server startup errors with JSON formatting.
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
error: The server startup error that occurred.
|
|
173
|
+
port: Port number the server attempted to use.
|
|
174
|
+
config_path: Path to the configuration file.
|
|
175
|
+
|
|
176
|
+
Raises:
|
|
177
|
+
SystemExit: Always exits with code 1 after displaying error.
|
|
178
|
+
"""
|
|
152
179
|
formatter = OutputFormatter(True)
|
|
153
180
|
error_data = {
|
|
154
181
|
"port": port,
|
|
@@ -162,7 +189,11 @@ class ServerErrorHandler(CLIErrorHandler):
|
|
|
162
189
|
|
|
163
190
|
@staticmethod
|
|
164
191
|
def handle_server_not_running_error() -> None:
|
|
165
|
-
"""Handle errors when server is not running with JSON formatting.
|
|
192
|
+
"""Handle errors when server is not running with JSON formatting.
|
|
193
|
+
|
|
194
|
+
Raises:
|
|
195
|
+
SystemExit: Always exits with code 1 after displaying error.
|
|
196
|
+
"""
|
|
166
197
|
error_response = OutputFormatter(True).error_response(
|
|
167
198
|
"No server is currently running"
|
|
168
199
|
)
|
xp/cli/utils/formatters.py
CHANGED
|
@@ -8,10 +8,22 @@ class OutputFormatter:
|
|
|
8
8
|
"""Handles standardized output formatting for CLI commands."""
|
|
9
9
|
|
|
10
10
|
def __init__(self, json_output: bool = False):
|
|
11
|
+
"""Initialize the output formatter.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
json_output: Whether to format output as JSON (default: False).
|
|
15
|
+
"""
|
|
11
16
|
self.json_output = json_output
|
|
12
17
|
|
|
13
18
|
def success_response(self, data: Dict[str, Any]) -> str:
|
|
14
|
-
"""Format a successful response.
|
|
19
|
+
"""Format a successful response.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
data: Response data to format.
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
Formatted success response as string.
|
|
26
|
+
"""
|
|
15
27
|
if self.json_output:
|
|
16
28
|
return json.dumps(data, indent=2)
|
|
17
29
|
return self._format_text_response(data)
|
|
@@ -19,7 +31,15 @@ class OutputFormatter:
|
|
|
19
31
|
def error_response(
|
|
20
32
|
self, error: str, extra_data: Optional[Dict[str, Any]] = None
|
|
21
33
|
) -> str:
|
|
22
|
-
"""Format an error response.
|
|
34
|
+
"""Format an error response.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
error: Error message.
|
|
38
|
+
extra_data: Additional error data to include.
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
Formatted error response as string.
|
|
42
|
+
"""
|
|
23
43
|
error_data = {"success": False, "error": error}
|
|
24
44
|
if extra_data:
|
|
25
45
|
error_data.update(extra_data)
|
|
@@ -29,7 +49,15 @@ class OutputFormatter:
|
|
|
29
49
|
return f"Error: {error}"
|
|
30
50
|
|
|
31
51
|
def validation_response(self, is_valid: bool, data: Dict[str, Any]) -> str:
|
|
32
|
-
"""Format a validation response.
|
|
52
|
+
"""Format a validation response.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
is_valid: Whether validation passed.
|
|
56
|
+
data: Validation data to include.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
Formatted validation response as string.
|
|
60
|
+
"""
|
|
33
61
|
if self.json_output:
|
|
34
62
|
response_data = {"valid": is_valid} | data
|
|
35
63
|
return json.dumps(response_data, indent=2)
|
|
@@ -38,7 +66,14 @@ class OutputFormatter:
|
|
|
38
66
|
return f"Status: {status}"
|
|
39
67
|
|
|
40
68
|
def checksum_status(self, is_valid: bool) -> str:
|
|
41
|
-
"""Format checksum validation status.
|
|
69
|
+
"""Format checksum validation status.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
is_valid: Whether checksum is valid.
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
Formatted checksum status as string.
|
|
76
|
+
"""
|
|
42
77
|
if self.json_output:
|
|
43
78
|
return json.dumps({"checksum_valid": is_valid}, indent=2)
|
|
44
79
|
|
|
@@ -46,7 +81,14 @@ class OutputFormatter:
|
|
|
46
81
|
|
|
47
82
|
@staticmethod
|
|
48
83
|
def _format_text_response(data: Dict[str, Any]) -> str:
|
|
49
|
-
"""Format data for human-readable text output.
|
|
84
|
+
"""Format data for human-readable text output.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
data: Data dictionary to format.
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
Formatted text output as string.
|
|
91
|
+
"""
|
|
50
92
|
lines = []
|
|
51
93
|
|
|
52
94
|
# Handle common data patterns
|
|
@@ -77,7 +119,15 @@ class TelegramFormatter(OutputFormatter):
|
|
|
77
119
|
def format_telegram_summary(
|
|
78
120
|
self, telegram_data: Dict[str, Any], service_formatter_method: Any = None
|
|
79
121
|
) -> str:
|
|
80
|
-
"""Format telegram summary using service method when available.
|
|
122
|
+
"""Format telegram summary using service method when available.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
telegram_data: Telegram data to format.
|
|
126
|
+
service_formatter_method: Optional service formatter method.
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
Formatted telegram summary as string.
|
|
130
|
+
"""
|
|
81
131
|
if self.json_output:
|
|
82
132
|
return json.dumps(telegram_data, indent=2)
|
|
83
133
|
|
|
@@ -98,7 +148,16 @@ class TelegramFormatter(OutputFormatter):
|
|
|
98
148
|
def format_validation_result(
|
|
99
149
|
self, parsed_telegram: Any, checksum_valid: Optional[bool], service_summary: str
|
|
100
150
|
) -> str:
|
|
101
|
-
"""Format telegram validation results.
|
|
151
|
+
"""Format telegram validation results.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
parsed_telegram: Parsed telegram object.
|
|
155
|
+
checksum_valid: Whether checksum is valid.
|
|
156
|
+
service_summary: Summary from service.
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
Formatted validation result as string.
|
|
160
|
+
"""
|
|
102
161
|
if self.json_output:
|
|
103
162
|
output = parsed_telegram.to_dict()
|
|
104
163
|
output["checksum_valid"] = checksum_valid
|
|
@@ -118,7 +177,16 @@ class ListFormatter(OutputFormatter):
|
|
|
118
177
|
def format_list_response(
|
|
119
178
|
self, items: list, title: str, item_formatter: Any = None
|
|
120
179
|
) -> str:
|
|
121
|
-
"""Format a list of items with optional custom formatter.
|
|
180
|
+
"""Format a list of items with optional custom formatter.
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
items: List of items to format.
|
|
184
|
+
title: Title for the list.
|
|
185
|
+
item_formatter: Optional custom formatter function.
|
|
186
|
+
|
|
187
|
+
Returns:
|
|
188
|
+
Formatted list as string.
|
|
189
|
+
"""
|
|
122
190
|
if self.json_output:
|
|
123
191
|
return json.dumps(
|
|
124
192
|
{
|
|
@@ -144,7 +212,15 @@ class ListFormatter(OutputFormatter):
|
|
|
144
212
|
return "\n".join(lines)
|
|
145
213
|
|
|
146
214
|
def format_search_results(self, matches: list, query: str) -> str:
|
|
147
|
-
"""Format search results.
|
|
215
|
+
"""Format search results.
|
|
216
|
+
|
|
217
|
+
Args:
|
|
218
|
+
matches: List of matching items.
|
|
219
|
+
query: Search query string.
|
|
220
|
+
|
|
221
|
+
Returns:
|
|
222
|
+
Formatted search results as string.
|
|
223
|
+
"""
|
|
148
224
|
if self.json_output:
|
|
149
225
|
return json.dumps(
|
|
150
226
|
{
|
|
@@ -181,7 +257,16 @@ class StatisticsFormatter(OutputFormatter):
|
|
|
181
257
|
def format_file_statistics(
|
|
182
258
|
self, file_path: str, stats: Dict[str, Any], entry_count: int
|
|
183
259
|
) -> str:
|
|
184
|
-
"""Format file analysis statistics.
|
|
260
|
+
"""Format file analysis statistics.
|
|
261
|
+
|
|
262
|
+
Args:
|
|
263
|
+
file_path: Path to the analyzed file.
|
|
264
|
+
stats: Statistics dictionary.
|
|
265
|
+
entry_count: Total number of entries.
|
|
266
|
+
|
|
267
|
+
Returns:
|
|
268
|
+
Formatted statistics as string.
|
|
269
|
+
"""
|
|
185
270
|
if self.json_output:
|
|
186
271
|
return json.dumps(
|
|
187
272
|
{
|
|
@@ -1,14 +1,32 @@
|
|
|
1
|
+
"""Click parameter type for serial number validation."""
|
|
2
|
+
|
|
1
3
|
from typing import Any, Optional
|
|
2
4
|
|
|
3
5
|
import click
|
|
4
6
|
|
|
5
7
|
|
|
6
8
|
class SerialNumberParamType(click.ParamType):
|
|
9
|
+
"""Click parameter type for validating and formatting serial numbers.
|
|
10
|
+
|
|
11
|
+
Attributes:
|
|
12
|
+
name: The parameter type name.
|
|
13
|
+
"""
|
|
14
|
+
|
|
7
15
|
name = "serial_number"
|
|
8
16
|
|
|
9
17
|
def convert(
|
|
10
18
|
self, value: Any, param: Optional[click.Parameter], ctx: Optional[click.Context]
|
|
11
19
|
) -> Optional[str]:
|
|
20
|
+
"""Convert and validate serial number input.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
value: The input value to convert.
|
|
24
|
+
param: The Click parameter.
|
|
25
|
+
ctx: The Click context.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
10-character zero-padded serial number string, or None if input is None.
|
|
29
|
+
"""
|
|
12
30
|
if value is None:
|
|
13
31
|
return None
|
|
14
32
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"""Click parameter type for SystemFunction enum validation."""
|
|
2
|
+
|
|
1
3
|
from typing import Any, Optional
|
|
2
4
|
|
|
3
5
|
import click
|
|
@@ -7,14 +9,32 @@ from xp.models.telegram.system_function import SystemFunction
|
|
|
7
9
|
|
|
8
10
|
# noinspection DuplicatedCode
|
|
9
11
|
class SystemFunctionChoice(click.ParamType):
|
|
12
|
+
"""Click parameter type for validating SystemFunction enum values.
|
|
13
|
+
|
|
14
|
+
Attributes:
|
|
15
|
+
name: The parameter type name.
|
|
16
|
+
choices: List of valid choice strings.
|
|
17
|
+
"""
|
|
18
|
+
|
|
10
19
|
name = "system_function"
|
|
11
20
|
|
|
12
21
|
def __init__(self) -> None:
|
|
22
|
+
"""Initialize the SystemFunctionChoice parameter type."""
|
|
13
23
|
self.choices = [key.lower() for key in SystemFunction.__members__.keys()]
|
|
14
24
|
|
|
15
25
|
def convert(
|
|
16
26
|
self, value: Any, param: Optional[click.Parameter], ctx: Optional[click.Context]
|
|
17
27
|
) -> Any:
|
|
28
|
+
"""Convert and validate input to SystemFunction enum.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
value: The input value to convert.
|
|
32
|
+
param: The Click parameter.
|
|
33
|
+
ctx: The Click context.
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
SystemFunction enum member if valid, None if input is None.
|
|
37
|
+
"""
|
|
18
38
|
if value is None:
|
|
19
39
|
return value
|
|
20
40
|
|
xp/cli/utils/xp_module_type.py
CHANGED
|
@@ -1,17 +1,37 @@
|
|
|
1
|
+
"""Click parameter type for XP module type validation."""
|
|
2
|
+
|
|
1
3
|
from typing import Any, Optional
|
|
2
4
|
|
|
3
5
|
import click
|
|
4
6
|
|
|
5
7
|
|
|
6
8
|
class XpModuleTypeChoice(click.ParamType):
|
|
9
|
+
"""Click parameter type for validating XP module types.
|
|
10
|
+
|
|
11
|
+
Attributes:
|
|
12
|
+
name: The parameter type name.
|
|
13
|
+
choices: List of valid module type strings.
|
|
14
|
+
"""
|
|
15
|
+
|
|
7
16
|
name = "xpmoduletype"
|
|
8
17
|
|
|
9
18
|
def __init__(self) -> None:
|
|
19
|
+
"""Initialize the XpModuleTypeChoice parameter type."""
|
|
10
20
|
self.choices = ["xp20", "xp24", "xp31", "xp33"]
|
|
11
21
|
|
|
12
22
|
def convert(
|
|
13
23
|
self, value: Any, param: Optional[click.Parameter], ctx: Optional[click.Context]
|
|
14
24
|
) -> Any:
|
|
25
|
+
"""Convert and validate XP module type input.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
value: The input value to convert.
|
|
29
|
+
param: The Click parameter.
|
|
30
|
+
ctx: The Click context.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
Lowercase module type string if valid, None if input is None.
|
|
34
|
+
"""
|
|
15
35
|
if value is None:
|
|
16
36
|
return value
|
|
17
37
|
|
xp/connection/__init__.py
CHANGED