speedy-utils 1.1.43__py3-none-any.whl → 1.1.44__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.
@@ -115,32 +115,39 @@ class ErrorStats:
115
115
  func_name: str,
116
116
  ) -> str:
117
117
  """Write error details to a log file."""
118
+ from io import StringIO
119
+ from rich.console import Console
120
+
118
121
  log_path = self._error_log_dir / f'{idx}.log'
119
122
 
123
+ output = StringIO()
124
+ console = Console(file=output, width=120, no_color=False)
125
+
120
126
  # Format traceback
121
127
  tb_lines = self._format_traceback(error)
122
128
 
123
- content = []
124
- content.append(f'{"=" * 60}')
125
- content.append(f'Error at index: {idx}')
126
- content.append(f'Function: {func_name}')
127
- content.append(f'Error Type: {type(error).__name__}')
128
- content.append(f'Error Message: {error}')
129
- content.append(f'{"=" * 60}')
130
- content.append('')
131
- content.append('Input:')
132
- content.append('-' * 40)
129
+ console.print(f'{"=" * 60}')
130
+ console.print(f'Error at index: {idx}')
131
+ console.print(f'Function: {func_name}')
132
+ console.print(f'Error Type: {type(error).__name__}')
133
+ console.print(f'Error Message: {error}')
134
+ console.print(f'{"=" * 60}')
135
+ console.print('')
136
+ console.print('Input:')
137
+ console.print('-' * 40)
133
138
  try:
134
- content.append(repr(input_value))
139
+ import json
140
+ console.print(json.dumps(input_value, indent=2))
135
141
  except Exception:
136
- content.append('<unable to repr input>')
137
- content.append('')
138
- content.append('Traceback:')
139
- content.append('-' * 40)
140
- content.extend(tb_lines)
142
+ console.print(repr(input_value))
143
+ console.print('')
144
+ console.print('Traceback:')
145
+ console.print('-' * 40)
146
+ for line in tb_lines:
147
+ console.print(line)
141
148
 
142
149
  with open(log_path, 'w') as f:
143
- f.write('\n'.join(content))
150
+ f.write(output.getvalue())
144
151
 
145
152
  return str(log_path)
146
153
 
@@ -824,7 +831,7 @@ def multi_process(
824
831
  log_worker: Literal['zero', 'first', 'all'] = 'first',
825
832
  total_items: int | None = None,
826
833
  poll_interval: float = 0.3,
827
- error_handler: ErrorHandlerType = 'raise',
834
+ error_handler: ErrorHandlerType = 'log',
828
835
  max_error_files: int = 100,
829
836
  **func_kwargs: Any,
830
837
  ) -> list[Any]:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: speedy-utils
3
- Version: 1.1.43
3
+ Version: 1.1.44
4
4
  Summary: Fast and easy-to-use package for data science
5
5
  Project-URL: Homepage, https://github.com/anhvth/speedy
6
6
  Project-URL: Repository, https://github.com/anhvth/speedy
@@ -58,13 +58,48 @@ Description-Content-Type: text/markdown
58
58
 
59
59
  **Speedy Utils** is a Python utility library designed to streamline common programming tasks such as caching, parallel processing, file I/O, and data manipulation. It provides a collection of decorators, functions, and classes to enhance productivity and performance in your Python projects.
60
60
 
61
+ ## 🚀 Recent Updates (January 27, 2026)
62
+
63
+ **Enhanced Error Handling in Parallel Processing:**
64
+ - Rich-formatted error tracebacks with code context and syntax highlighting
65
+ - Three error handling modes: 'raise', 'ignore', and 'log'
66
+ - Filtered tracebacks focusing on user code (hiding infrastructure)
67
+ - Real-time progress reporting with error/success statistics
68
+ - Automatic error logging to timestamped files
69
+ - Caller frame information showing where parallel functions were invoked
70
+
71
+ ## Quick Start
72
+
73
+ ### Parallel Processing with Error Handling
74
+
75
+ ```python
76
+ from speedy_utils import multi_thread, multi_process
77
+
78
+ # Simple parallel processing
79
+ results = multi_thread(lambda x: x * 2, [1, 2, 3, 4, 5])
80
+ # Results: [2, 4, 6, 8, 10]
81
+
82
+ # Robust processing with error handling
83
+ def process_item(item):
84
+ if item == 3:
85
+ raise ValueError(f"Cannot process item {item}")
86
+ return item * 2
87
+
88
+ # Continue processing despite errors
89
+ results = multi_thread(process_item, [1, 2, 3, 4, 5], error_handler='log')
90
+ # Results: [2, 4, None, 8, 10] - errors logged automatically
91
+ ```
92
+
61
93
  ## Table of Contents
62
94
 
95
+ - [🚀 Recent Updates](#-recent-updates-january-27-2026)
96
+ - [Quick Start](#quick-start)
63
97
  - [Features](#features)
64
98
  - [Installation](#installation)
65
99
  - [Usage](#usage)
66
- - [Caching](#caching)
67
100
  - [Parallel Processing](#parallel-processing)
101
+ - [Enhanced Error Handling](#enhanced-error-handling)
102
+ - [Caching](#caching)
68
103
  - [File I/O](#file-io)
69
104
  - [Data Manipulation](#data-manipulation)
70
105
  - [Utility Functions](#utility-functions)
@@ -73,11 +108,12 @@ Description-Content-Type: text/markdown
73
108
  ## Features
74
109
 
75
110
  - **Caching Mechanisms**: Disk-based and in-memory caching to optimize function calls.
76
- - **Parallel Processing**: Multi-threading, multi-processing, and asynchronous multi-threading utilities.
111
+ - **Parallel Processing**: Multi-threading, multi-processing, and asynchronous multi-threading utilities with enhanced error handling.
77
112
  - **File I/O**: Simplified JSON, JSONL, and pickle file handling with support for various file extensions.
78
113
  - **Data Manipulation**: Utilities for flattening lists and dictionaries, converting data types, and more.
79
114
  - **Timing Utilities**: Tools to measure and log execution time of functions and processes.
80
115
  - **Pretty Printing**: Enhanced printing functions for structured data, including HTML tables for Jupyter notebooks.
116
+ - **Enhanced Error Handling**: Rich error tracebacks with code context, configurable error handling modes ('raise', 'ignore', 'log'), and detailed progress reporting.
81
117
 
82
118
  ## Installation
83
119
 
@@ -162,20 +198,132 @@ result = compute_sum(5, 7) # Retrieved from in-memory cache
162
198
 
163
199
  ### Parallel Processing
164
200
 
165
- #### Multi-threading
201
+ #### Multi-threading with Enhanced Error Handling
166
202
 
167
- Execute functions concurrently using multiple threads. This approach is straightforward and automatically handles both notebook and Python script executions. In a notebook environment, it delegates the running thread to a separate process. If interrupted, it immediately stops this process, avoiding thread dependency issues where threads continue running until all tasks are completed.
203
+ Execute functions concurrently using multiple threads with comprehensive error handling. The enhanced error handling provides three modes: 'raise' (default), 'ignore', and 'log'. When errors occur, you'll see rich-formatted tracebacks with code context and caller information.
168
204
 
169
205
  ```python
170
206
  from speedy_utils import multi_thread
171
207
 
172
208
  def process_item(item):
173
- # Your processing logic
209
+ # Simulate processing that might fail
210
+ if item == 3:
211
+ raise ValueError(f"Invalid item: {item}")
174
212
  return item * 2
175
213
 
176
214
  items = [1, 2, 3, 4, 5]
177
- results = multi_thread(process_item, items, workers=3)
178
- print(results) # [2, 4, 6, 8, 10]
215
+
216
+ # Default behavior: raise on first error with rich traceback
217
+ try:
218
+ results = multi_thread(process_item, items, workers=3)
219
+ except SystemExit:
220
+ print("Error occurred and was displayed with rich formatting")
221
+
222
+ # Continue processing on errors, return None for failed items
223
+ results = multi_thread(process_item, items, workers=3, error_handler='ignore')
224
+ print(results) # [2, 4, None, 8, 10]
225
+
226
+ # Log errors to files and continue processing
227
+ results = multi_thread(process_item, items, workers=3, error_handler='log', max_error_files=10)
228
+ print(results) # [2, 4, None, 8, 10] - errors logged to .cache/speedy_utils/error_logs/
229
+ ```
230
+
231
+ #### Multi-processing with Error Handling
232
+
233
+ Process items across multiple processes with the same enhanced error handling capabilities.
234
+
235
+ ```python
236
+ from speedy_utils import multi_process
237
+
238
+ def risky_computation(x):
239
+ """Computation that might fail for certain inputs."""
240
+ if x % 5 == 0:
241
+ raise RuntimeError(f"Cannot process multiples of 5: {x}")
242
+ return x ** 2
243
+
244
+ data = list(range(12))
245
+
246
+ # Process with error logging (continues on errors)
247
+ results = multi_process(
248
+ risky_computation,
249
+ data,
250
+ backend='mp',
251
+ error_handler='log',
252
+ max_error_files=5
253
+ )
254
+ print(results) # [0, 1, 4, 9, 16, None, 36, 49, 64, 81, None, 121]
255
+ ```
256
+
257
+ ### Enhanced Error Handling
258
+
259
+ **Speedy Utils** now provides comprehensive error handling for parallel processing with rich formatting and detailed diagnostics.
260
+
261
+ #### Rich Error Tracebacks
262
+
263
+ When errors occur, you'll see beautifully formatted tracebacks with:
264
+ - **Code context**: Lines of code around the error location
265
+ - **Caller information**: Shows where the parallel function was invoked
266
+ - **Filtered frames**: Focuses on user code, hiding infrastructure details
267
+ - **Color coding**: Easy-to-read formatting with syntax highlighting
268
+
269
+ #### Error Handling Modes
270
+
271
+ Choose how to handle errors in parallel processing:
272
+
273
+ - **`'raise'` (default)**: Stop on first error with detailed traceback
274
+ - **`'ignore'`**: Continue processing, return `None` for failed items
275
+ - **`'log'`**: Log errors to files and continue processing
276
+
277
+ #### Error Logging
278
+
279
+ When using `error_handler='log'`, errors are automatically saved to timestamped files in `.cache/speedy_utils/error_logs/` with full context and stack traces.
280
+
281
+ #### Progress Reporting with Error Statistics
282
+
283
+ Progress bars now show real-time error and success counts:
284
+
285
+ ```
286
+ Multi-thread [8/10] [00:02<00:00, 3.45it/s, success=8, errors=2, pending=0]
287
+ ```
288
+
289
+ This makes it easy to monitor processing health at a glance.
290
+
291
+ #### Example: Robust Data Processing
292
+
293
+ ```python
294
+ from speedy_utils import multi_thread
295
+
296
+ def process_data_record(record):
297
+ """Process a data record that might have issues."""
298
+ try:
299
+ # Your processing logic here
300
+ value = record['value'] / record['divisor']
301
+ return {'result': value, 'status': 'success'}
302
+ except KeyError as e:
303
+ raise ValueError(f"Missing required field in record: {e}")
304
+ except ZeroDivisionError:
305
+ raise ValueError("Division by zero in record")
306
+
307
+ # Sample data with some problematic records
308
+ data = [
309
+ {'value': 10, 'divisor': 2}, # OK
310
+ {'value': 15, 'divisor': 0}, # Will error
311
+ {'value': 20, 'divisor': 4}, # OK
312
+ {'value': 25}, # Missing divisor - will error
313
+ ]
314
+
315
+ # Process with error logging - continues despite errors
316
+ results = multi_thread(
317
+ process_data_record,
318
+ data,
319
+ workers=4,
320
+ error_handler='log',
321
+ max_error_files=10
322
+ )
323
+
324
+ print("Results:", results)
325
+ # Output: Results: [{'result': 5.0, 'status': 'success'}, None, {'result': 5.0, 'status': 'success'}, None]
326
+ # Errors are logged to files for later analysis
179
327
  ```
180
328
 
181
329
  ### File I/O
@@ -45,7 +45,7 @@ speedy_utils/common/utils_print.py,sha256=AGDB7mgJnO00QkJBH6kJb46738q3GzMUZPwtQ2
45
45
  speedy_utils/multi_worker/__init__.py,sha256=urcuxzaAJp-Rl3SIwHNre3x2vyHxLR7YGiDdm-Q8GQs,361
46
46
  speedy_utils/multi_worker/dataset_ray.py,sha256=U_l_4Y7CVpaHiApsXQSdNvals8NK87LHPS_XHiJF3qs,10044
47
47
  speedy_utils/multi_worker/parallel_gpu_pool.py,sha256=A7llZcQbRVZqwCqNRku7TpqGCdSoIzpdcTaupgqT5nI,6108
48
- speedy_utils/multi_worker/process.py,sha256=EujMtc9NqDVPqGOrLjlM6k60vEpRmOvlIJAYPKRQO6I,45237
48
+ speedy_utils/multi_worker/process.py,sha256=U-pjHoWZ3xOeplMl2nSxVeiJE0F9V-eswpSdK-8c3dU,45446
49
49
  speedy_utils/multi_worker/progress.py,sha256=Ozeca-t-j1224n_dWwZkWzva9DC16SCLgScKeGtXLaQ,4717
50
50
  speedy_utils/multi_worker/thread.py,sha256=E7o_iUCIKmgk1tFt7mZAFT7c5q229wVzWj-trmVsxVA,27254
51
51
  speedy_utils/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -55,7 +55,7 @@ vision_utils/README.md,sha256=AIDZZj8jo_QNrEjFyHwd00iOO431s-js-M2dLtVTn3I,5740
55
55
  vision_utils/__init__.py,sha256=hF54sT6FAxby8kDVhOvruy4yot8O-Ateey5n96O1pQM,284
56
56
  vision_utils/io_utils.py,sha256=pI0Va6miesBysJcllK6NXCay8HpGZsaMWwlsKB2DMgA,26510
57
57
  vision_utils/plot.py,sha256=HkNj3osA3moPuupP1VguXfPPOW614dZO5tvC-EFKpKM,12028
58
- speedy_utils-1.1.43.dist-info/METADATA,sha256=IiZqjlKf2KUOwRDLZd0TusT3T5PECy5YRJssiw8wHAo,8099
59
- speedy_utils-1.1.43.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
60
- speedy_utils-1.1.43.dist-info/entry_points.txt,sha256=rwn89AYfBUh9SRJtFbpp-u2JIKiqmZ2sczvqyO6s9cI,289
61
- speedy_utils-1.1.43.dist-info/RECORD,,
58
+ speedy_utils-1.1.44.dist-info/METADATA,sha256=Y5wQ_VbeiPTcqUkOCEbEvOKZ-wnwKCF2nvGhSnU3AJs,13067
59
+ speedy_utils-1.1.44.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
60
+ speedy_utils-1.1.44.dist-info/entry_points.txt,sha256=rwn89AYfBUh9SRJtFbpp-u2JIKiqmZ2sczvqyO6s9cI,289
61
+ speedy_utils-1.1.44.dist-info/RECORD,,