speedy-utils 1.1.44__tar.gz → 1.1.46__tar.gz

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.
Files changed (149) hide show
  1. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/PKG-INFO +4 -2
  2. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/README.md +3 -1
  3. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/pyproject.toml +2 -1
  4. speedy_utils-1.1.46/scripts/bug.py +12 -0
  5. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/lm/llm.py +3 -0
  6. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/speedy_utils/__init__.py +6 -0
  7. speedy_utils-1.1.46/src/speedy_utils/common/utils_error.py +261 -0
  8. speedy_utils-1.1.46/src/speedy_utils/scripts/kill_mpython.py +58 -0
  9. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/speedy_utils/scripts/mpython.py +51 -11
  10. speedy_utils-1.1.46/test.py +8 -0
  11. speedy_utils-1.1.44/scripts/bug.py +0 -34
  12. speedy_utils-1.1.44/test_s3.py +0 -34
  13. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/.githooks/pre-push +0 -0
  14. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/.github/copilot-instructions.md +0 -0
  15. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/.github/prompts/improveParallelErrorHandling.prompt.md +0 -0
  16. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/.github/skills/caching-utilities/SKILL.md +0 -0
  17. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/.github/skills/caching-utilities/examples/caching_example.py +0 -0
  18. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/.github/skills/io-utilities/SKILL.md +0 -0
  19. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/.github/skills/io-utilities/examples/io_example.py +0 -0
  20. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/.github/skills/llm-integration/SKILL.md +0 -0
  21. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/.github/skills/llm-integration/examples/llm_example.py +0 -0
  22. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/.github/skills/multi-threading-processing/SKILL.md +0 -0
  23. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/.github/skills/ray-distributed-computing/SKILL.md +0 -0
  24. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/.github/skills/skill-creation/SKILL.md +0 -0
  25. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/.github/skills/vision-utilities/SKILL.md +0 -0
  26. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/.github/skills/vision-utilities/examples/vision_example.py +0 -0
  27. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/.github/workflows/publish.yml +0 -0
  28. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/.gitignore +0 -0
  29. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/.pre-commit-config.yaml +0 -0
  30. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/AGENTS.md +0 -0
  31. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/bumpversion.sh +0 -0
  32. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/debug/debug_generate_response.py +0 -0
  33. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/debug/debug_n_param.py +0 -0
  34. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/debug/debug_n_structure.py +0 -0
  35. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/debug/integration_test.py +0 -0
  36. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/debug/test_decode_api.py +0 -0
  37. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/debug/test_endpoints.py +0 -0
  38. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/debug/test_generate.py +0 -0
  39. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/debug/test_generate_endpoint.py +0 -0
  40. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/docs/GENERATE_QUICKREF.md +0 -0
  41. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/docs/IMPLEMENTATION.md +0 -0
  42. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/docs/QUICKSTART.md +0 -0
  43. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/docs/TOKENIZATION.md +0 -0
  44. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/docs/TOKENIZATION_IMPLEMENTATION.md +0 -0
  45. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/docs/zero_copy_sharing.md +0 -0
  46. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/examples/generate_example.py +0 -0
  47. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/examples/llm_ray_example.py +0 -0
  48. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/examples/pytorch_large_model.py +0 -0
  49. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/examples/shared_kwargs_example.py +0 -0
  50. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/examples/temperature_range_example.py +0 -0
  51. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/examples/test_parallel_gpu.py +0 -0
  52. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/examples/test_share_ray.py +0 -0
  53. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/examples/tokenization_example.py +0 -0
  54. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/examples/vision_utils_example.py +0 -0
  55. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/experiments/exp1/dockerfile +0 -0
  56. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/experiments/exp1/run_in_docker.sh +0 -0
  57. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/experiments/exp1/test.png +0 -0
  58. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/experiments/test_read_image.py +0 -0
  59. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/notebooks/README.ipynb +0 -0
  60. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/notebooks/llm_utils/llm_as_a_judge.ipynb +0 -0
  61. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/notebooks/parallel_gpu_pool.ipynb +0 -0
  62. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/notebooks/ray_tutorial.ipynb +0 -0
  63. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/notebooks/test_multi_thread.ipynb +0 -0
  64. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/ruff.toml +0 -0
  65. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/scripts/bug_simple.py +0 -0
  66. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/scripts/debug_import_time.py +0 -0
  67. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/scripts/deploy.sh +0 -0
  68. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/scripts/imports.sh +0 -0
  69. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/scripts/test.py +0 -0
  70. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/scripts/test_both_backends.py +0 -0
  71. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/scripts/test_error_handling.py +0 -0
  72. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/scripts/test_import_time_vision.py +0 -0
  73. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/scripts/test_locals.py +0 -0
  74. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/scripts/test_ray_locals.py +0 -0
  75. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/scripts/test_ray_mp.py +0 -0
  76. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/setup.cfg +0 -0
  77. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/datasets_utils/convert_to_arrow.py +0 -0
  78. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/__init__.py +0 -0
  79. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/chat_format/__init__.py +0 -0
  80. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/chat_format/display.py +0 -0
  81. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/chat_format/transform.py +0 -0
  82. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/chat_format/utils.py +0 -0
  83. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/group_messages.py +0 -0
  84. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/llm_ray.py +0 -0
  85. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/lm/__init__.py +0 -0
  86. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/lm/async_lm/__init__.py +0 -0
  87. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/lm/async_lm/_utils.py +0 -0
  88. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/lm/async_lm/async_llm_task.py +0 -0
  89. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/lm/async_lm/async_lm.py +0 -0
  90. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/lm/async_lm/async_lm_base.py +0 -0
  91. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/lm/async_lm/lm_specific.py +0 -0
  92. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/lm/base_prompt_builder.py +0 -0
  93. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/lm/llm_signature.py +0 -0
  94. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/lm/lm_base.py +0 -0
  95. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/lm/mixins.py +0 -0
  96. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/lm/openai_memoize.py +0 -0
  97. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/lm/signature.py +0 -0
  98. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/lm/utils.py +0 -0
  99. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/scripts/README.md +0 -0
  100. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/scripts/fast_vllm.py +0 -0
  101. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/scripts/vllm_load_balancer.py +0 -0
  102. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/scripts/vllm_serve.py +0 -0
  103. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/vector_cache/__init__.py +0 -0
  104. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/vector_cache/cli.py +0 -0
  105. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/vector_cache/core.py +0 -0
  106. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/vector_cache/types.py +0 -0
  107. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/llm_utils/vector_cache/utils.py +0 -0
  108. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/speedy_utils/__imports.py +0 -0
  109. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/speedy_utils/common/__init__.py +0 -0
  110. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/speedy_utils/common/clock.py +0 -0
  111. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/speedy_utils/common/function_decorator.py +0 -0
  112. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/speedy_utils/common/logger.py +0 -0
  113. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/speedy_utils/common/notebook_utils.py +0 -0
  114. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/speedy_utils/common/patcher.py +0 -0
  115. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/speedy_utils/common/report_manager.py +0 -0
  116. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/speedy_utils/common/utils_cache.py +0 -0
  117. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/speedy_utils/common/utils_io.py +0 -0
  118. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/speedy_utils/common/utils_misc.py +0 -0
  119. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/speedy_utils/common/utils_print.py +0 -0
  120. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/speedy_utils/multi_worker/__init__.py +0 -0
  121. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/speedy_utils/multi_worker/dataset_ray.py +0 -0
  122. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/speedy_utils/multi_worker/parallel_gpu_pool.py +0 -0
  123. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/speedy_utils/multi_worker/process.py +0 -0
  124. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/speedy_utils/multi_worker/progress.py +0 -0
  125. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/speedy_utils/multi_worker/thread.py +0 -0
  126. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/speedy_utils/scripts/__init__.py +0 -0
  127. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/speedy_utils/scripts/openapi_client_codegen.py +0 -0
  128. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/vision_utils/README.md +0 -0
  129. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/vision_utils/__init__.py +0 -0
  130. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/vision_utils/io_utils.py +0 -0
  131. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/src/vision_utils/plot.py +0 -0
  132. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/tests/import_all.py +0 -0
  133. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/tests/import_time_report.py +0 -0
  134. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/tests/integration_test.py +0 -0
  135. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/tests/llm_utils/test_llm_mixins.py +0 -0
  136. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/tests/sample_objects.py +0 -0
  137. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/tests/test.py +0 -0
  138. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/tests/test_logger.py +0 -0
  139. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/tests/test_logger_format.py +0 -0
  140. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/tests/test_memoize_typing.py +0 -0
  141. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/tests/test_mpython.py +0 -0
  142. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/tests/test_multithread_error_trace.py +0 -0
  143. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/tests/test_process.py +0 -0
  144. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/tests/test_process_update.py +0 -0
  145. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/tests/test_pytorch_sharing.py +0 -0
  146. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/tests/test_shared_kwargs.py +0 -0
  147. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/tests/test_thread.py +0 -0
  148. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/tests/test_tokenization.py +0 -0
  149. {speedy_utils-1.1.44 → speedy_utils-1.1.46}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: speedy-utils
3
- Version: 1.1.44
3
+ Version: 1.1.46
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
@@ -61,6 +61,7 @@ Description-Content-Type: text/markdown
61
61
  ## 🚀 Recent Updates (January 27, 2026)
62
62
 
63
63
  **Enhanced Error Handling in Parallel Processing:**
64
+
64
65
  - Rich-formatted error tracebacks with code context and syntax highlighting
65
66
  - Three error handling modes: 'raise', 'ignore', and 'log'
66
67
  - Filtered tracebacks focusing on user code (hiding infrastructure)
@@ -261,6 +262,7 @@ print(results) # [0, 1, 4, 9, 16, None, 36, 49, 64, 81, None, 121]
261
262
  #### Rich Error Tracebacks
262
263
 
263
264
  When errors occur, you'll see beautifully formatted tracebacks with:
265
+
264
266
  - **Code context**: Lines of code around the error location
265
267
  - **Caller information**: Shows where the parallel function was invoked
266
268
  - **Filtered frames**: Focuses on user code, hiding infrastructure details
@@ -282,7 +284,7 @@ When using `error_handler='log'`, errors are automatically saved to timestamped
282
284
 
283
285
  Progress bars now show real-time error and success counts:
284
286
 
285
- ```
287
+ ```bash
286
288
  Multi-thread [8/10] [00:02<00:00, 3.45it/s, success=8, errors=2, pending=0]
287
289
  ```
288
290
 
@@ -9,6 +9,7 @@
9
9
  ## 🚀 Recent Updates (January 27, 2026)
10
10
 
11
11
  **Enhanced Error Handling in Parallel Processing:**
12
+
12
13
  - Rich-formatted error tracebacks with code context and syntax highlighting
13
14
  - Three error handling modes: 'raise', 'ignore', and 'log'
14
15
  - Filtered tracebacks focusing on user code (hiding infrastructure)
@@ -209,6 +210,7 @@ print(results) # [0, 1, 4, 9, 16, None, 36, 49, 64, 81, None, 121]
209
210
  #### Rich Error Tracebacks
210
211
 
211
212
  When errors occur, you'll see beautifully formatted tracebacks with:
213
+
212
214
  - **Code context**: Lines of code around the error location
213
215
  - **Caller information**: Shows where the parallel function was invoked
214
216
  - **Filtered frames**: Focuses on user code, hiding infrastructure details
@@ -230,7 +232,7 @@ When using `error_handler='log'`, errors are automatically saved to timestamped
230
232
 
231
233
  Progress bars now show real-time error and success counts:
232
234
 
233
- ```
235
+ ```bash
234
236
  Multi-thread [8/10] [00:02<00:00, 3.45it/s, success=8, errors=2, pending=0]
235
237
  ```
236
238
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "speedy-utils"
3
- version = "1.1.44"
3
+ version = "1.1.46"
4
4
  description = "Fast and easy-to-use package for data science"
5
5
  authors = [{ name = "AnhVTH", email = "anhvth.226@gmail.com" }]
6
6
  readme = "README.md"
@@ -65,6 +65,7 @@ svllm = "llm_utils.scripts.vllm_serve:main"
65
65
  svllm-lb = "llm_utils.scripts.vllm_load_balancer:run_load_balancer"
66
66
  openapi_client_codegen = "speedy_utils.scripts.openapi_client_codegen:main"
67
67
  fast-vllm = "llm_utils.scripts.fast_vllm:main"
68
+ kill-mpython = "speedy_utils.scripts.kill_mpython:main"
68
69
 
69
70
  [build-system]
70
71
  requires = ["hatchling"]
@@ -0,0 +1,12 @@
1
+ import llm_utils
2
+ from speedy_utils import multi_process
3
+
4
+ llm = llm_utils.LLM(client=8666, timeout=3)
5
+
6
+ def f(x):
7
+ return llm('hello world')
8
+
9
+
10
+ # multi_process(f, range(10), backend='mp', error_handler='ignore')
11
+
12
+ f(0)
@@ -16,6 +16,7 @@ from openai.types.chat import ChatCompletionMessageParam
16
16
  from pydantic import BaseModel
17
17
 
18
18
  from speedy_utils.common.utils_io import jdumps
19
+ from speedy_utils import clean_traceback
19
20
 
20
21
  from .base_prompt_builder import BasePromptBuilder
21
22
  from .mixins import (
@@ -159,6 +160,7 @@ class LLM(
159
160
  messages.append({'role': 'user', 'content': user_content})
160
161
  return cast(Messages, messages)
161
162
 
163
+ @clean_traceback
162
164
  def text_completion(
163
165
  self, input_data: str | BaseModel | list[dict], **runtime_kwargs
164
166
  ) -> list[dict[str, Any]]:
@@ -214,6 +216,7 @@ class LLM(
214
216
  results.append(result_dict)
215
217
  return results
216
218
 
219
+ @clean_traceback
217
220
  def pydantic_parse(
218
221
  self,
219
222
  input_data: str | BaseModel | list[dict],
@@ -58,6 +58,9 @@ from .common.utils_print import (
58
58
  fprint,
59
59
  )
60
60
 
61
+ # Error handling utilities
62
+ from .common.utils_error import clean_traceback, handle_exceptions_with_clean_traceback
63
+
61
64
  # Multi-worker processing
62
65
  from .multi_worker.process import multi_process
63
66
  from .multi_worker.thread import kill_all_thread, multi_thread
@@ -156,6 +159,9 @@ __all__ = [
156
159
  'print_table',
157
160
  'setup_logger',
158
161
  'log',
162
+ # Error handling utilities
163
+ 'clean_traceback',
164
+ 'handle_exceptions_with_clean_traceback',
159
165
  # Multi-worker processing
160
166
  'multi_process',
161
167
  'multi_thread',
@@ -0,0 +1,261 @@
1
+ """
2
+ Error handling utilities for clean, user-focused tracebacks.
3
+ """
4
+
5
+ import inspect
6
+ import linecache
7
+ import sys
8
+ import traceback
9
+ from typing import Any, Callable, TypeVar
10
+
11
+ try:
12
+ from rich.console import Console
13
+ from rich.panel import Panel
14
+ from rich.text import Text
15
+ except ImportError:
16
+ Console = None
17
+ Panel = None
18
+ Text = None
19
+
20
+ F = TypeVar('F', bound=Callable[..., Any])
21
+
22
+
23
+ class CleanTracebackError(Exception):
24
+ """Exception wrapper that provides clean, user-focused tracebacks."""
25
+
26
+ def __init__(
27
+ self,
28
+ original_exception: Exception,
29
+ user_traceback: list[traceback.FrameSummary],
30
+ caller_frame: traceback.FrameSummary | None = None,
31
+ func_name: str | None = None,
32
+ ) -> None:
33
+ self.original_exception = original_exception
34
+ self.user_traceback = user_traceback
35
+ self.caller_frame = caller_frame
36
+ self.func_name = func_name
37
+
38
+ # Create a focused error message
39
+ tb_str = ''.join(traceback.format_list(user_traceback))
40
+ func_part = f' in {func_name}' if func_name else ''
41
+ msg = (
42
+ f'Error{func_part}:\n'
43
+ f'\nUser code traceback:\n{tb_str}'
44
+ f'{type(original_exception).__name__}: {original_exception}'
45
+ )
46
+ super().__init__(msg)
47
+
48
+ def __str__(self) -> str:
49
+ return super().__str__()
50
+
51
+ def format_rich(self) -> None:
52
+ """Format and print error with rich panels and code context."""
53
+ if Console is None or Panel is None or Text is None:
54
+ print(str(self), file=sys.stderr)
55
+ return
56
+
57
+ console = Console(stderr=True, force_terminal=True)
58
+
59
+ # Build traceback display with code context
60
+ tb_parts: list[str] = []
61
+
62
+ # Show caller frame first if available
63
+ if self.caller_frame and self.caller_frame.lineno is not None:
64
+ tb_parts.append(
65
+ f'[cyan]{self.caller_frame.filename}[/cyan]:[yellow]{self.caller_frame.lineno}[/yellow] '
66
+ f'in [green]{self.caller_frame.name}[/green]'
67
+ )
68
+ tb_parts.append('')
69
+ context = _get_code_context_rich(self.caller_frame.filename, self.caller_frame.lineno, 3)
70
+ tb_parts.extend(context)
71
+ tb_parts.append('')
72
+
73
+ # Show user code frames with context
74
+ for frame in self.user_traceback:
75
+ if frame.lineno is not None:
76
+ func_name = f' {self.func_name}' if self.func_name else ''
77
+ tb_parts.append(
78
+ f'[cyan]{frame.filename}[/cyan]:[yellow]{frame.lineno}[/yellow] '
79
+ f'in [green]{frame.name}{func_name}[/green]'
80
+ )
81
+ tb_parts.append('')
82
+ context = _get_code_context_rich(frame.filename, frame.lineno, 3)
83
+ tb_parts.extend(context)
84
+ tb_parts.append('')
85
+
86
+ # Print with rich Panel
87
+ console.print()
88
+ console.print(
89
+ Panel(
90
+ '\n'.join(tb_parts),
91
+ title='[bold red]Traceback (most recent call last)[/bold red]',
92
+ border_style='red',
93
+ expand=False,
94
+ )
95
+ )
96
+ console.print(
97
+ f'[bold red]{type(self.original_exception).__name__}[/bold red]: '
98
+ f'{self.original_exception}'
99
+ )
100
+ console.print()
101
+
102
+
103
+ def _get_code_context(filename: str, lineno: int, context_lines: int = 3) -> list[str]:
104
+ """Get code context around a line with line numbers and highlighting."""
105
+ lines: list[str] = []
106
+ start = max(1, lineno - context_lines)
107
+ end = lineno + context_lines
108
+
109
+ for i in range(start, end + 1):
110
+ line = linecache.getline(filename, i)
111
+ if not line:
112
+ continue
113
+ line = line.rstrip()
114
+ marker = '❱' if i == lineno else ' '
115
+ lines.append(f' {i:4d} {marker} {line}')
116
+
117
+ return lines
118
+
119
+
120
+ def _get_code_context_rich(filename: str, lineno: int, context_lines: int = 3) -> list[str]:
121
+ """Get code context with rich formatting (colors)."""
122
+ lines: list[str] = []
123
+ start = max(1, lineno - context_lines)
124
+ end = lineno + context_lines
125
+
126
+ for i in range(start, end + 1):
127
+ line = linecache.getline(filename, i)
128
+ if not line:
129
+ continue
130
+ line = line.rstrip()
131
+ num_str = f'{i:4d}'
132
+
133
+ if i == lineno:
134
+ # Highlight error line
135
+ lines.append(f'[dim]{num_str}[/dim] [red]❱[/red] {line}')
136
+ else:
137
+ # Normal context line
138
+ lines.append(f'[dim]{num_str} │[/dim] {line}')
139
+
140
+ return lines
141
+
142
+
143
+ def _filter_traceback_frames(tb_list: list[traceback.FrameSummary]) -> list[traceback.FrameSummary]:
144
+ """Filter traceback frames to show only user code."""
145
+ user_frames = []
146
+ skip_patterns = [
147
+ 'site-packages/',
148
+ 'dist-packages/',
149
+ 'python3.',
150
+ 'lib/python',
151
+ 'concurrent/futures/',
152
+ 'threading.py',
153
+ 'multiprocessing/',
154
+ 'urllib/',
155
+ 'httpx/',
156
+ 'httpcore/',
157
+ 'openai/',
158
+ 'requests/',
159
+ 'aiohttp/',
160
+ 'urllib3/',
161
+ 'speedy_utils/common/',
162
+ 'speedy_utils/multi_worker/',
163
+ 'llm_utils/lm/',
164
+ 'llm_utils/chat_format/',
165
+ 'llm_utils/vector_cache/',
166
+ ]
167
+
168
+ skip_functions = [
169
+ 'wrapper', # Our decorator wrapper
170
+ '__call__', # Internal calls
171
+ '__inner_call__', # Internal calls
172
+ '_worker', # Multi-thread worker
173
+ '_run_batch', # Batch runner
174
+ ]
175
+
176
+ for frame in tb_list:
177
+ # Skip frames matching skip patterns
178
+ if any(pattern in frame.filename for pattern in skip_patterns):
179
+ continue
180
+ # Skip specific function names
181
+ if frame.name in skip_functions:
182
+ continue
183
+ # Skip frames that are too deep in the call stack (internal implementation)
184
+ if 'speedy_utils' in frame.filename and any(
185
+ name in frame.name for name in ['__inner_call__', '_worker', '_run_batch']
186
+ ):
187
+ continue
188
+ user_frames.append(frame)
189
+
190
+ # If no user frames found, keep frames that are likely user code (not deep library internals)
191
+ if not user_frames:
192
+ for frame in reversed(tb_list):
193
+ # Keep if it's not in site-packages and not in standard library
194
+ if ('site-packages/' not in frame.filename and
195
+ 'dist-packages/' not in frame.filename and
196
+ not frame.filename.startswith('/usr/') and
197
+ not frame.filename.startswith('/opt/') and
198
+ 'python3.' not in frame.filename and
199
+ frame.name not in skip_functions):
200
+ user_frames.append(frame)
201
+ if len(user_frames) >= 5: # Keep up to 5 frames
202
+ break
203
+ user_frames.reverse()
204
+
205
+ return user_frames
206
+
207
+
208
+ def clean_traceback(func: F) -> F:
209
+ """Decorator to wrap function calls with clean traceback handling."""
210
+ def wrapper(*args, **kwargs):
211
+ try:
212
+ return func(*args, **kwargs)
213
+ except Exception as exc:
214
+ # Get the current traceback
215
+ exc_tb = sys.exc_info()[2]
216
+
217
+ if exc_tb is not None:
218
+ tb_list = traceback.extract_tb(exc_tb)
219
+
220
+ # Filter to keep only user code frames
221
+ user_frames = _filter_traceback_frames(tb_list)
222
+
223
+ # Get caller frame - walk up the stack to find the original caller
224
+ caller_context = None
225
+ frame = inspect.currentframe()
226
+ while frame:
227
+ frame = frame.f_back
228
+ if frame and frame.f_code.co_name not in ['wrapper', '__call__', '__inner_call__']:
229
+ caller_info = inspect.getframeinfo(frame)
230
+ if not any(skip in caller_info.filename for skip in [
231
+ 'speedy_utils/common/', 'speedy_utils/multi_worker/',
232
+ 'llm_utils/lm/', 'site-packages/', 'dist-packages/'
233
+ ]):
234
+ caller_context = traceback.FrameSummary(
235
+ caller_info.filename,
236
+ caller_info.lineno,
237
+ caller_info.function,
238
+ )
239
+ break
240
+
241
+ # If we have user frames, create and format our custom exception
242
+ if user_frames:
243
+ func_name = getattr(func, '__name__', repr(func))
244
+ clean_error = CleanTracebackError(
245
+ exc,
246
+ user_frames,
247
+ caller_context,
248
+ func_name,
249
+ )
250
+ clean_error.format_rich()
251
+ sys.exit(1) # Exit after formatting
252
+
253
+ # Fallback: re-raise original if we couldn't extract frames
254
+ raise
255
+
256
+ return wrapper # type: ignore
257
+
258
+
259
+ def handle_exceptions_with_clean_traceback(func: F) -> F:
260
+ """Alias for clean_traceback decorator."""
261
+ return clean_traceback(func)
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env python3
2
+ """Script to kill all tmux sessions matching 'mpython*' pattern."""
3
+
4
+ import subprocess
5
+ import sys
6
+
7
+
8
+ def main():
9
+ """Kill all tmux sessions with names starting with 'mpython'."""
10
+ try:
11
+ # Get list of tmux sessions matching the pattern
12
+ result = subprocess.run(
13
+ ["tmux", "ls"],
14
+ capture_output=True,
15
+ text=True
16
+ )
17
+ if result.returncode != 0:
18
+ if "no server running" in result.stderr.lower():
19
+ print("No tmux server running.")
20
+ return
21
+ print(f"Error listing tmux sessions: {result.stderr}")
22
+ sys.exit(result.returncode)
23
+
24
+ sessions = []
25
+ for line in result.stdout.strip().split('\n'):
26
+ if line.strip():
27
+ session_name = line.split(':')[0]
28
+ if session_name.startswith('mpython'):
29
+ sessions.append(session_name)
30
+
31
+ if not sessions:
32
+ print("No tmux sessions found matching 'mpython*'")
33
+ return
34
+
35
+ print(f"Found {len(sessions)} tmux session(s) to kill: {', '.join(sessions)}")
36
+
37
+ # Kill each session
38
+ for session in sessions:
39
+ kill_result = subprocess.run(
40
+ ["tmux", "kill-session", "-t", session],
41
+ capture_output=True,
42
+ text=True
43
+ )
44
+ if kill_result.returncode == 0:
45
+ print(f"Successfully killed tmux session '{session}'")
46
+ else:
47
+ print(f"Error killing tmux session '{session}': {kill_result.stderr}")
48
+
49
+ except FileNotFoundError:
50
+ print("Error: tmux command not found. Please ensure tmux is installed.")
51
+ sys.exit(1)
52
+ except Exception as e:
53
+ print(f"Unexpected error: {e}")
54
+ sys.exit(1)
55
+
56
+
57
+ if __name__ == "__main__":
58
+ main()
@@ -7,6 +7,19 @@ import re
7
7
  import shlex # To properly escape command line arguments
8
8
  import shutil
9
9
  import subprocess
10
+ import sys
11
+
12
+ try:
13
+ from rich.console import Console, Group
14
+ from rich.panel import Panel
15
+ from rich.text import Text
16
+ from rich.syntax import Syntax
17
+ except ImportError:
18
+ Console = None
19
+ Group = None
20
+ Panel = None
21
+ Text = None
22
+ Syntax = None
10
23
 
11
24
 
12
25
  taskset_path = shutil.which('taskset')
@@ -60,18 +73,34 @@ def assert_script(python_path):
60
73
  with open(python_path) as f:
61
74
  code_str = f.read()
62
75
  if 'MP_ID' not in code_str or 'MP_TOTAL' not in code_str:
63
- example_code = (
64
- 'import os; MP_TOTAL = int(os.environ.get("MP_TOTAL"));MP_ID = int(os.environ.get("MP_ID"))\n'
76
+ helper_code = (
77
+ 'import os\n'
78
+ 'MP_ID = int(os.getenv("MP_ID", "0"))\n'
79
+ 'MP_TOTAL = int(os.getenv("MP_TOTAL", "1"))\n'
65
80
  'inputs = list(inputs[MP_ID::MP_TOTAL])'
66
81
  )
67
- # ANSI escape codes for coloring
68
- YELLOW = '\033[93m'
69
- RESET = '\033[0m'
70
- raise_msg = (
71
- f'MP_ID and MP_TOTAL not found in {python_path}, please add them.\n\n'
72
- f'Example:\n{YELLOW}{example_code}{RESET}'
73
- )
74
- raise Exception(raise_msg)
82
+ if Console and Panel and Text and Syntax and Group:
83
+ console = Console(stderr=True, force_terminal=True)
84
+ syntax = Syntax(helper_code, "python", theme="monokai", line_numbers=False)
85
+ console.print()
86
+ console.print(
87
+ Panel(
88
+ f'Your script {python_path} is missing MP_ID and/or MP_TOTAL variables.\n\n'
89
+ f'Add the following code to enable multi-process sharding:',
90
+ title='[bold yellow]Warning: Missing Multi-Process Variables[/bold yellow]',
91
+ border_style='yellow',
92
+ expand=False,
93
+ )
94
+ )
95
+ console.print()
96
+ console.print("```python")
97
+ console.print(syntax)
98
+ console.print("```")
99
+ console.print("-"*80)
100
+ else:
101
+ # Fallback to plain text
102
+ print(f'Warning: MP_ID and MP_TOTAL not found in {python_path}, please add them.', file=sys.stderr)
103
+ print(f'Example:\n{helper_code}', file=sys.stderr)
75
104
 
76
105
 
77
106
  def run_in_tmux(commands_to_run, tmux_name, num_windows):
@@ -96,7 +125,18 @@ def run_in_tmux(commands_to_run, tmux_name, num_windows):
96
125
  def main():
97
126
  # Assert that MP_ID and MP_TOTAL are not already set
98
127
 
99
- parser = argparse.ArgumentParser(description='Process fold arguments')
128
+ helper_code = (
129
+ 'import os\n'
130
+ 'MP_ID = int(os.getenv("MP_ID", "0"))\n'
131
+ 'MP_TOTAL = int(os.getenv("MP_TOTAL", "1"))\n'
132
+ 'inputs = list(inputs[MP_ID::MP_TOTAL])'
133
+ )
134
+
135
+ parser = argparse.ArgumentParser(
136
+ description='Process fold arguments',
137
+ epilog=f'Helper code for multi-process sharding:\n{helper_code}',
138
+ formatter_class=argparse.RawDescriptionHelpFormatter
139
+ )
100
140
  parser.add_argument(
101
141
  '--total_fold', '-t', default=16, type=int, help='total number of folds'
102
142
  )
@@ -0,0 +1,8 @@
1
+ import os
2
+ MP_ID = int(os.getenv("MP_ID", "0"))
3
+ MP_TOTAL = int(os.getenv("MP_TOTAL", "1"))
4
+
5
+ inputs = range(1000)
6
+ def f(x):
7
+ print(x)
8
+ inputs = list(inputs[MP_ID::MP_TOTAL])
@@ -1,34 +0,0 @@
1
- # type: ignore
2
- from speedy_utils import multi_process, multi_thread
3
-
4
-
5
- def do_something(x):
6
- if x % 3 == 0:
7
- raise ValueError(f'Error at index {x}')
8
- return x * 2
9
-
10
-
11
- inputs = range(10)
12
-
13
-
14
- if __name__ == '__main__':
15
- print('Testing error_handler="log" with mp backend:')
16
- results = multi_process(
17
- do_something,
18
- inputs,
19
- backend='mp',
20
- error_handler='log',
21
- max_error_files=5,
22
- )
23
- print(f'Results: {results}')
24
- print()
25
-
26
- # print('Testing error_handler="log" with multi_thread:')
27
- # results = multi_thread(
28
- # do_something,
29
- # inputs,
30
- # error_handler='log',
31
- # max_error_files=5,
32
- # )
33
- # print(f'Results: {results}')
34
-
@@ -1,34 +0,0 @@
1
- import boto3
2
- from botocore.client import Config
3
-
4
- # Configuration
5
- BUCKET_NAME = 'llm-data'
6
- ENDPOINT = 'https://s3-han02.fptcloud.com'
7
- ACCESS_KEY = 'BO40L9SQNZ7VS944GZ6T' # Replace with your preferred key
8
- SECRET_KEY = 'wS6jOi26RE7vvmWmLxWyYMPpXYcwG8u830Ca2UAQ' # You must use the secret key paired with the access key
9
- REGION_NAME = 'HN-02'
10
-
11
- # Initialize the S3 client
12
- s3_client = boto3.client(
13
- 's3',
14
- aws_access_key_id=ACCESS_KEY,
15
- aws_secret_access_key=SECRET_KEY,
16
- endpoint_url=ENDPOINT,
17
- # Important: Many S3-compatible providers require Signature V4
18
- config=boto3.session.Config(signature_version='s3v4'),
19
- verify=False,
20
- # region_name=REGION_NAME
21
- )
22
-
23
- def upload_file(file_name, bucket, object_name=None):
24
- if object_name is None:
25
- object_name = file_name
26
-
27
- try:
28
- s3_client.upload_file(file_name, bucket, object_name)
29
- print(f"Successfully uploaded {file_name} to {bucket}/{object_name}")
30
- except Exception as e:
31
- print(f"Error: {e}")
32
-
33
- # Usage
34
- upload_file('test2.txt', BUCKET_NAME)
File without changes
File without changes
File without changes
File without changes
File without changes