speedy-utils 2.0.2__tar.gz → 2.0.5__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 (175) hide show
  1. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/.githooks/pre-commit +28 -54
  2. speedy_utils-2.0.5/.github/skills/make-vscode-happy/SKILL.md +80 -0
  3. speedy_utils-2.0.5/.github/skills/make-vscode-happy/references/diagnostic-playbook.md +94 -0
  4. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/.gitignore +2 -1
  5. speedy_utils-2.0.5/CLAUDE.md +201 -0
  6. speedy_utils-2.0.5/CODING_STYLE.md +521 -0
  7. speedy_utils-2.0.5/PKG-INFO +660 -0
  8. speedy_utils-2.0.5/README.md +607 -0
  9. speedy_utils-2.0.5/debug/test_qwen3_generate.md +50 -0
  10. speedy_utils-2.0.5/docs/GENERATE_QUICKREF.md +138 -0
  11. speedy_utils-2.0.5/docs/MIGRATION_THINKING.md +109 -0
  12. speedy_utils-2.0.5/docs/PR_LIBRARY_ERROR_HANDLING_REFACTOR_PLAN.md +165 -0
  13. speedy_utils-2.0.5/docs/TOKENIZATION.md +105 -0
  14. speedy_utils-2.0.5/docs/TOKENIZATION_IMPLEMENTATION.md +76 -0
  15. speedy_utils-2.0.5/examples/llm_public_api_example.ipynb +164 -0
  16. speedy_utils-2.0.5/notebooks/demo_multi_process.py +128 -0
  17. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/notebooks/llm_utils/llm_as_a_judge.ipynb +4 -16
  18. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/pyproject.toml +8 -2
  19. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/pyrightconfig.json +3 -3
  20. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/ruff.toml +16 -0
  21. speedy_utils-2.0.5/scripts/debug_import_time.py +417 -0
  22. speedy_utils-2.0.5/scripts/debug_multi_process.py +20 -0
  23. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/datasets_utils/viz_chat.py +3 -2
  24. speedy_utils-2.0.5/src/llm_utils/__init__.py +34 -0
  25. speedy_utils-2.0.5/src/llm_utils/_traceback.py +235 -0
  26. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/llm_utils/chat_format/display.py +4 -2
  27. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/llm_utils/lm/__init__.py +0 -2
  28. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/llm_utils/lm/llm.py +28 -14
  29. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/llm_utils/lm/llm_qwen3.py +309 -194
  30. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/llm_utils/lm/llm_signature.py +55 -4
  31. speedy_utils-2.0.5/src/llm_utils/lm/openai_memoize.py +430 -0
  32. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/llm_utils/lm/utils.py +2 -3
  33. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/llm_utils/scripts/sp_chat.py +1 -0
  34. speedy_utils-2.0.5/src/llm_utils/utils.py +42 -0
  35. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/speedy_utils/__imports.py +1 -6
  36. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/speedy_utils/__init__.py +17 -38
  37. speedy_utils-2.0.5/src/speedy_utils/common/exceptions.py +69 -0
  38. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/speedy_utils/common/utils_cache.py +10 -8
  39. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/speedy_utils/common/utils_error.py +8 -14
  40. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/speedy_utils/common/utils_io.py +28 -3
  41. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/speedy_utils/common/utils_misc.py +2 -0
  42. speedy_utils-2.0.5/src/speedy_utils/multi_worker/_mp_backends.py +814 -0
  43. speedy_utils-2.0.5/src/speedy_utils/multi_worker/_mp_progress.py +128 -0
  44. speedy_utils-2.0.5/src/speedy_utils/multi_worker/_mp_spawn.py +335 -0
  45. speedy_utils-2.0.5/src/speedy_utils/multi_worker/_multi_process.py +321 -0
  46. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/speedy_utils/multi_worker/common.py +190 -180
  47. speedy_utils-2.0.5/src/speedy_utils/multi_worker/dataset_sharding.py +226 -0
  48. speedy_utils-2.0.5/src/speedy_utils/multi_worker/process.py +23 -0
  49. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/speedy_utils/multi_worker/thread.py +302 -179
  50. speedy_utils-2.0.5/src/vision_utils/README.md +122 -0
  51. speedy_utils-2.0.5/src/vision_utils/__init__.py +19 -0
  52. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/tests/llm_utils/test_llm_call_contract.py +33 -1
  53. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/tests/llm_utils/test_llm_mixins.py +291 -34
  54. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/tests/llm_utils/test_llm_signature.py +1 -1
  55. speedy_utils-2.0.5/tests/llm_utils/test_public_api.py +117 -0
  56. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/tests/test.py +6 -3
  57. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/tests/test_memoize_typing.py +4 -0
  58. speedy_utils-2.0.5/tests/test_mp_no_main_guard.py +154 -0
  59. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/tests/test_multi_process.py +66 -63
  60. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/tests/test_multi_thread.py +4 -2
  61. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/tests/test_process.py +133 -40
  62. speedy_utils-2.0.5/tests/test_process_update.py +343 -0
  63. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/tests/test_thread.py +14 -2
  64. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/tests/test_tokenization.py +8 -5
  65. speedy_utils-2.0.5/tests/test_utils_io.py +18 -0
  66. speedy_utils-2.0.5/tools/check_syntax.py +185 -0
  67. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/tools/uv_test.sh +1 -1
  68. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/uv.lock +35 -4
  69. speedy_utils-2.0.2/CLAUDE.md +0 -180
  70. speedy_utils-2.0.2/PKG-INFO +0 -710
  71. speedy_utils-2.0.2/README.md +0 -658
  72. speedy_utils-2.0.2/chainlit.md +0 -14
  73. speedy_utils-2.0.2/debug/test_qwen3_generate.md +0 -87
  74. speedy_utils-2.0.2/docs/GENERATE_QUICKREF.md +0 -133
  75. speedy_utils-2.0.2/docs/MIGRATION_THINKING.md +0 -73
  76. speedy_utils-2.0.2/docs/TOKENIZATION.md +0 -325
  77. speedy_utils-2.0.2/docs/TOKENIZATION_IMPLEMENTATION.md +0 -104
  78. speedy_utils-2.0.2/examples/llm_public_api_example.ipynb +0 -273
  79. speedy_utils-2.0.2/experiments/exp1/test.png +0 -0
  80. speedy_utils-2.0.2/notebooks/test_multi_thread.ipynb +0 -82
  81. speedy_utils-2.0.2/scripts/debug_import_time.py +0 -210
  82. speedy_utils-2.0.2/src/llm_utils/__init__.py +0 -75
  83. speedy_utils-2.0.2/src/llm_utils/group_messages.py +0 -123
  84. speedy_utils-2.0.2/src/llm_utils/lm/openai_memoize.py +0 -172
  85. speedy_utils-2.0.2/src/speedy_utils/multi_worker/_multi_process.py +0 -819
  86. speedy_utils-2.0.2/src/speedy_utils/multi_worker/dataset_sharding.py +0 -192
  87. speedy_utils-2.0.2/src/speedy_utils/multi_worker/process.py +0 -71
  88. speedy_utils-2.0.2/src/vision_utils/README.md +0 -202
  89. speedy_utils-2.0.2/src/vision_utils/__init__.py +0 -39
  90. speedy_utils-2.0.2/tests/test_process_update.py +0 -129
  91. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/.codex +0 -0
  92. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/.githooks/pre-push +0 -0
  93. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/.github/prompts/improveParallelErrorHandling.prompt.md +0 -0
  94. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/.github/skills/caching-utilities/SKILL.md +0 -0
  95. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/.github/skills/caching-utilities/examples/caching_example.py +0 -0
  96. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/.github/skills/dataset-processing-multiprocessing/CONFIG_REFERENCE.md +0 -0
  97. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/.github/skills/dataset-processing-multiprocessing/SKILL.md +0 -0
  98. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/.github/skills/dataset-processing-multiprocessing/example_tokenize_pack.py +0 -0
  99. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/.github/skills/edit-llm-inference-style/SKILL.md +0 -0
  100. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/.github/skills/io-utilities/SKILL.md +0 -0
  101. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/.github/skills/io-utilities/examples/io_example.py +0 -0
  102. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/.github/skills/llm-integration/SKILL.md +0 -0
  103. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/.github/skills/llm-integration/examples/llm_example.py +0 -0
  104. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/.github/skills/multi-threading-processing/SKILL.md +0 -0
  105. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/.github/skills/ray-distributed-computing/SKILL.md +0 -0
  106. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/.github/skills/skill-creation/SKILL.md +0 -0
  107. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/.github/skills/vision-utilities/SKILL.md +0 -0
  108. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/.github/skills/vision-utilities/examples/vision_example.py +0 -0
  109. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/.github/workflows/publish.yml +0 -0
  110. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/.pre-commit-config.yaml +0 -0
  111. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/AGENTS.md +0 -0
  112. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/bumpversion.sh +0 -0
  113. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/debug/debug_generate_response.py +0 -0
  114. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/debug/debug_n_param.py +0 -0
  115. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/debug/debug_n_structure.py +0 -0
  116. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/debug/integration_test.py +0 -0
  117. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/debug/multi_thread.py +0 -0
  118. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/debug/test_decode_api.py +0 -0
  119. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/debug/test_endpoints.py +0 -0
  120. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/debug/test_generate.py +0 -0
  121. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/debug/test_generate_endpoint.py +0 -0
  122. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/debug/test_qwen3_generate.py +0 -0
  123. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/examples/generate_example.py +0 -0
  124. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/examples/model_specific_thinking_example.py +0 -0
  125. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/examples/tokenization_example.py +0 -0
  126. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/examples/vision_utils_example.py +0 -0
  127. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/experiments/exp1/dockerfile +0 -0
  128. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/experiments/exp1/run_in_docker.sh +0 -0
  129. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/notebooks/test.ipynb +0 -0
  130. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/scripts/bug_simple.py +0 -0
  131. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/scripts/deploy.sh +0 -0
  132. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/scripts/imports.sh +0 -0
  133. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/scripts/install_hooks.sh +0 -0
  134. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/scripts/test.py +0 -0
  135. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/scripts/test_error_handling.py +0 -0
  136. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/scripts/test_import_time_vision.py +0 -0
  137. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/scripts/test_locals.py +0 -0
  138. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/scripts/test_ray_mp.py +0 -0
  139. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/setup.cfg +0 -0
  140. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/datasets_utils/convert_to_arrow.py +0 -0
  141. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/llm_utils/chat_format/__init__.py +0 -0
  142. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/llm_utils/chat_format/transform.py +0 -0
  143. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/llm_utils/chat_format/utils.py +0 -0
  144. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/llm_utils/lm/base_prompt_builder.py +0 -0
  145. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/llm_utils/lm/lm_base.py +0 -0
  146. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/llm_utils/lm/signature.py +0 -0
  147. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/speedy_utils/common/__init__.py +0 -0
  148. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/speedy_utils/common/clock.py +0 -0
  149. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/speedy_utils/common/function_decorator.py +0 -0
  150. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/speedy_utils/common/logger.py +0 -0
  151. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/speedy_utils/common/notebook_utils.py +0 -0
  152. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/speedy_utils/common/patcher.py +0 -0
  153. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/speedy_utils/common/report_manager.py +0 -0
  154. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/speedy_utils/common/utils_print.py +0 -0
  155. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/speedy_utils/multi_worker/__init__.py +0 -0
  156. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/speedy_utils/scripts/__init__.py +0 -0
  157. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/speedy_utils/scripts/kill_mpython.py +0 -0
  158. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/speedy_utils/scripts/mpython.py +0 -0
  159. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/speedy_utils/scripts/openapi_client_codegen.py +0 -0
  160. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/speedy_utils/scripts/prefetch_large_model.py +0 -0
  161. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/vision_utils/io_utils.py +0 -0
  162. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/src/vision_utils/plot.py +0 -0
  163. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/tests/import_all.py +0 -0
  164. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/tests/import_time_report.py +0 -0
  165. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/tests/llm_utils/test_openai_memoize_completion_cache.py +0 -0
  166. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/tests/llm_utils/test_openai_proxy_localhost.py +0 -0
  167. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/tests/llm_utils/test_sp_chat.py +0 -0
  168. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/tests/sample_objects.py +0 -0
  169. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/tests/test_import_time.py +0 -0
  170. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/tests/test_logger.py +0 -0
  171. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/tests/test_logger_format.py +0 -0
  172. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/tests/test_mpython.py +0 -0
  173. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/tests/test_multithread_error_trace.py +0 -0
  174. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/tests/test_prefetch_large_model.py +0 -0
  175. {speedy_utils-2.0.2 → speedy_utils-2.0.5}/tests/test_viz_chat.py +0 -0
@@ -1,13 +1,5 @@
1
1
  #!/usr/bin/env python3
2
- """
3
- Pre-commit hook to ensure import time is under 0.4 seconds.
4
-
5
- This enforces the project's performance requirement that speedy_utils
6
- must import quickly (< 0.4s). This is critical for user experience.
7
-
8
- Strategy: Use lazy imports for heavy modules (torch, ray, matplotlib, pandas)
9
- inside functions that need them, not at module level.
10
- """
2
+ """Pre-commit hook to enforce import-time budgets with actionable output."""
11
3
 
12
4
  import os
13
5
  import subprocess
@@ -73,57 +65,39 @@ def _build_env() -> dict[str, str]:
73
65
  return env
74
66
 
75
67
 
76
- def check_import_time(module: str) -> tuple[bool, float, str]:
77
- """Check import time for a module. Returns (passed, time_seconds)."""
78
- code = f"import time; start=time.perf_counter(); import {module}; print(time.perf_counter()-start)"
68
+ def _helper_script() -> Path:
69
+ return _REPO_ROOT / "scripts" / "debug_import_time.py"
70
+
71
+
72
+ def main() -> int:
73
+ """Run import-time checks through the shared helper script."""
74
+ print("Checking import times... (max: {:.1f}s)".format(MAX_IMPORT_TIME))
75
+
76
+ helper = _helper_script()
79
77
  result = subprocess.run(
80
- [_PYTHON, "-c", code],
81
- capture_output=True,
82
- text=True,
78
+ [
79
+ _PYTHON,
80
+ str(helper),
81
+ "--max-total-sec",
82
+ str(MAX_IMPORT_TIME),
83
+ "--min-sec",
84
+ "0.01",
85
+ "--top",
86
+ "12",
87
+ "--no-stdlib",
88
+ "--quiet-success",
89
+ *MODULES,
90
+ ],
83
91
  env=_build_env(),
84
92
  cwd=str(_REPO_ROOT),
85
93
  )
86
- if result.returncode != 0:
87
- err = (result.stderr or result.stdout or "").strip()
88
- return False, -1, err
89
- try:
90
- import_time = float(result.stdout.strip())
91
- return import_time <= MAX_IMPORT_TIME, import_time, ""
92
- except ValueError:
93
- err = (result.stderr or result.stdout or "").strip()
94
- return False, -1, err
95
94
 
95
+ if result.returncode != 0:
96
+ print("\nImport time check failed.")
97
+ print("Rerun the helper above after moving heavy imports into function scope")
98
+ print("or a lazy __getattr__ export to pinpoint the slow path.")
96
99
 
97
- def main() -> int:
98
- """Run import time checks."""
99
- failed = False
100
-
101
- print("Checking import times... (max: {:.1f}s)".format(MAX_IMPORT_TIME))
102
-
103
- for module in MODULES:
104
- passed, import_time, err = check_import_time(module)
105
-
106
- if import_time < 0:
107
- print(f" {module}: FAILED - import error")
108
- if err:
109
- last_line = err.splitlines()[-1]
110
- print(f" ↳ {last_line}")
111
- failed = True
112
- elif passed:
113
- print(f" {module}: {import_time:.3f}s")
114
- else:
115
- print(f" {module}: FAILED - {import_time:.3f}s exceeds {MAX_IMPORT_TIME:.1f}s")
116
- failed = True
117
-
118
- if failed:
119
- print("\nImport time check failed! To fix:")
120
- print(" 1. Use lazy imports for heavy modules inside functions")
121
- print(" 2. Move heavy imports to function scope, not module level")
122
- print(" 3. Use the _LazyModule pattern from __imports.py")
123
- print("\nHeavy modules to lazy-load: torch, ray, matplotlib, pandas")
124
- return 1
125
-
126
- return 0
100
+ return result.returncode
127
101
 
128
102
 
129
103
  if __name__ == "__main__":
@@ -0,0 +1,80 @@
1
+ ---
2
+ name: 'make-vscode-happy'
3
+ description: 'Reduce VS Code Python red squiggles to zero in this repository. Use when Pylance or pyright reports errors, when tools/check_syntax.py fails, or when a change should leave VS Code diagnostics clean.'
4
+ argument-hint: 'Optional file path, module name, or failing area to fix'
5
+ ---
6
+
7
+ # Make VS Code Happy
8
+
9
+ Use this skill when the goal is to make VS Code and Pylance happy in this
10
+ repository by driving Python diagnostics to zero with the repo's existing
11
+ checker: `tools/check_syntax.py`.
12
+
13
+ ## When to Use
14
+
15
+ Use this skill when you need to:
16
+ - Fix Python red squiggles in VS Code.
17
+ - Reconcile Pylance diagnostics with command-line validation.
18
+ - Clean up pyright issues before committing.
19
+ - Verify that a targeted change did not leave new diagnostics behind.
20
+
21
+ ## Primary Checker
22
+
23
+ The authoritative checker for this repo is:
24
+
25
+ ```bash
26
+ uv run python tools/check_syntax.py
27
+ ```
28
+
29
+ Useful variants:
30
+
31
+ ```bash
32
+ uv run python tools/check_syntax.py --file src/llm_utils/lm/llm_qwen3.py
33
+ uv run python tools/check_syntax.py --include tests
34
+ uv run python tools/check_syntax.py --json
35
+ ```
36
+
37
+ This script mirrors the diagnostics VS Code Pylance shows for the repository's
38
+ `pyrightconfig.json`.
39
+
40
+ ## Procedure
41
+
42
+ 1. Pick scope first.
43
+ - If the request names a file, start with `--file` for that file.
44
+ - If the issue sounds cross-cutting or unclear, run the full check first.
45
+ 2. Read diagnostics and group them by root cause instead of fixing them one by
46
+ one in isolation.
47
+ 3. Fix the real source of the type error.
48
+ - Prefer correcting annotations, overloads, return types, and control flow.
49
+ - Use repo-approved ignores only when the code is intentionally dynamic.
50
+ 4. Re-run the smallest relevant check after each edit.
51
+ 5. Before concluding, run the broader validation needed for the scope.
52
+ - If you touched one file, re-run that file and then a full check if the
53
+ change affects shared APIs.
54
+ - If you changed common utilities, package exports, or typing helpers, run
55
+ the full check.
56
+ 6. If the fix changes imports in public packages, protect the import-time
57
+ budget as well.
58
+
59
+ ## Decision Points
60
+
61
+ - Single-file symptom vs shared typing pattern:
62
+ Start narrow for local regressions; go broad if the same diagnostic appears in
63
+ multiple files or stems from a shared helper.
64
+ - True bug vs accepted dynamic pattern:
65
+ Prefer a real type fix first. Only use a targeted ignore when the repository
66
+ already treats that pattern as intentionally dynamic.
67
+ - Typing fix vs performance regression:
68
+ Do not fix types by introducing heavy top-level imports in `__init__.py` or
69
+ other import-sensitive modules.
70
+
71
+ ## Completion Criteria
72
+
73
+ - `tools/check_syntax.py` reports zero relevant errors for the changed scope.
74
+ - Touched files do not introduce new warnings unless the user accepted them.
75
+ - The fix matches repository typing conventions.
76
+ - No eager heavy imports were added just to satisfy typing.
77
+
78
+ ## References
79
+
80
+ - [Diagnostic playbook](./references/diagnostic-playbook.md)
@@ -0,0 +1,94 @@
1
+ # Diagnostic Playbook
2
+
3
+ This reference supports the `make-vscode-happy` skill for the `speedy_utils`
4
+ repository.
5
+
6
+ ## Repo Rules That Matter
7
+
8
+ - Use `uv run python tools/check_syntax.py` as the source of truth for Python
9
+ diagnostics.
10
+ - Fix root causes instead of masking errors with broad ignores.
11
+ - Keep public package import time under `0.4s`.
12
+ - Do not introduce heavy top-level imports such as `torch`, `pandas`,
13
+ `matplotlib`, or `IPython` in `__init__.py` files.
14
+
15
+ ## Fast Triage
16
+
17
+ ### If the prompt names a specific file
18
+
19
+ Run:
20
+
21
+ ```bash
22
+ uv run python tools/check_syntax.py --file path/to/file.py
23
+ ```
24
+
25
+ Then fix the reported issue and re-run the same command.
26
+
27
+ ### If the prompt is vague or broad
28
+
29
+ Run:
30
+
31
+ ```bash
32
+ uv run python tools/check_syntax.py
33
+ ```
34
+
35
+ If the change touches tests or test helpers, consider:
36
+
37
+ ```bash
38
+ uv run python tools/check_syntax.py --include tests
39
+ ```
40
+
41
+ ## Common Fix Patterns In This Repo
42
+
43
+ ### Overload ordering
44
+
45
+ Put the `Awaitable[...]` overload before the generic non-awaitable overload to
46
+ avoid overlapping-overload diagnostics.
47
+
48
+ ### Dynamic Pydantic-style attributes
49
+
50
+ When the code intentionally sets attributes not declared in the model schema,
51
+ use a narrow ignore such as:
52
+
53
+ ```python
54
+ # type: ignore[attr-defined]
55
+ ```
56
+
57
+ Do not apply it broadly if a better annotation is possible.
58
+
59
+ ### `tqdm` annotations
60
+
61
+ Use the string literal form in annotations:
62
+
63
+ ```python
64
+ "tqdm"
65
+ ```
66
+
67
+ ### Lazy exports
68
+
69
+ For names loaded through `__getattr__`, follow the existing lazy-export pattern
70
+ instead of forcing eager imports for type convenience.
71
+
72
+ ### `__all__` with heavy lazy names
73
+
74
+ Do not add heavy lazy names to `__all__`, because star imports will defeat lazy
75
+ loading and hurt import time.
76
+
77
+ ## When a Typing Fix Touches Imports
78
+
79
+ If you changed imports in a public package, especially `speedy_utils`,
80
+ `llm_utils`, or `vision_utils`, run:
81
+
82
+ ```bash
83
+ uv run python scripts/debug_import_time.py speedy_utils llm_utils vision_utils --max-total-sec 0.4 --top 12 --min-sec 0.01 --no-stdlib
84
+ ```
85
+
86
+ Use that output to move heavy imports behind lazy boundaries if needed.
87
+
88
+ ## Definition of Done
89
+
90
+ - Targeted diagnostics are gone.
91
+ - Shared changes were validated with a broader repo check.
92
+ - The fix preserves existing lazy-import and typing conventions.
93
+ - VS Code should agree with command-line output because the checker mirrors
94
+ Pylance behavior for this repository.
@@ -125,4 +125,5 @@ dmypy.json
125
125
  edu_results.json
126
126
  .playwright-mcp
127
127
  .DS_Store
128
- .chainlit
128
+ .chainlit
129
+ chainlit.md
@@ -0,0 +1,201 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance for working in this repository.
4
+
5
+ ## Development Commands
6
+
7
+ ```bash
8
+ # Install dependencies
9
+ uv sync
10
+
11
+ # Run tests
12
+ ./tools/uv_test.sh -n 32
13
+
14
+ # Run a single test file
15
+ ./tools/uv_test.sh tests/test_thread.py
16
+
17
+ # Run with verbose output
18
+ ./tools/uv_test.sh -v
19
+
20
+ # Check import time for the exported packages
21
+ uv run python scripts/debug_import_time.py speedy_utils llm_utils vision_utils \
22
+ --max-total-sec 0.4 --top 12 --min-sec 0.01 --no-stdlib
23
+
24
+ # Lint and format
25
+ uv run ruff check .
26
+ uv run ruff format .
27
+
28
+ # Pyright / Pylance parity check
29
+ uv run python tools/check_syntax.py
30
+
31
+ # Bump version (runs tests, then commits and pushes)
32
+ ./bumpversion.sh patch # or minor / major
33
+
34
+ # Deploy to PyPI (requires PYPI_API_TOKEN)
35
+ ./scripts/deploy.sh
36
+ ```
37
+
38
+ ## Performance Requirement: Import Time < 0.4s
39
+
40
+ The repository hook budget is `0.4s` for the exported packages checked by
41
+ `.githooks/pre-commit`:
42
+
43
+ - `speedy_utils`
44
+ - `llm_utils`
45
+ - `vision_utils`
46
+
47
+ Use the shared helper when import time regresses:
48
+
49
+ ```bash
50
+ uv run python scripts/debug_import_time.py speedy_utils llm_utils vision_utils \
51
+ --max-total-sec 0.4 --top 12 --min-sec 0.01 --no-stdlib
52
+ ```
53
+
54
+ Current code structure keeps the budget by avoiding heavy external imports at
55
+ module import time.
56
+
57
+ ### What to keep lazy
58
+
59
+ These imports are intentionally kept behind helpers or function scope because
60
+ they are expensive enough to matter for import time:
61
+
62
+ - `torch`
63
+ - `pandas`
64
+ - `matplotlib`
65
+ - `IPython`
66
+ - tokenizer-loading code in `Qwen3LLM`
67
+
68
+ ### How the current code does it
69
+
70
+ - `speedy_utils.__init__` imports lightweight internal modules directly.
71
+ - heavy external helpers live in `speedy_utils.__imports`.
72
+ - `llm_utils.__init__` exports selected public classes and helpers directly.
73
+ - `vision_utils` keeps plotting and image backends lazy inside function bodies.
74
+
75
+ Do not add new top-level imports for heavy third-party libraries in public
76
+ package `__init__.py` files unless you have rechecked import-time impact.
77
+
78
+ ### Hook vs test budget
79
+
80
+ The pre-commit hook is stricter than the regression test:
81
+
82
+ - `.githooks/pre-commit` enforces `0.4s`
83
+ - `tests/test_import_time.py` currently guards `speedy_utils` at `1.0s`
84
+
85
+ Treat the hook budget as the real policy.
86
+
87
+ ## Architecture
88
+
89
+ ### Package Structure
90
+
91
+ The wheel currently ships four packages from `src/`:
92
+
93
+ - `speedy_utils`: caching, file I/O, formatting, timing, and parallel helpers
94
+ - `llm_utils`: OpenAI-compatible LLM wrappers, memoized clients, chat-format helpers
95
+ - `vision_utils`: image loading, notebook plotting, and mmap-backed image datasets
96
+ - `datasets_utils`: dataset inspection helpers such as `viz_chat`
97
+
98
+ ### Important Modules
99
+
100
+ - `src/speedy_utils/common/utils_cache.py`
101
+ - `memoize`, `imemoize`, `identify`
102
+ - default disk cache root: `~/.cache/speedy_cache`
103
+ - `src/speedy_utils/common/utils_io.py`
104
+ - `load_jsonl`, `fast_load_jsonl`, `load_json_or_pickle`, `load_by_ext`
105
+ - `src/speedy_utils/multi_worker/thread.py`
106
+ - `multi_thread`
107
+ - `src/speedy_utils/multi_worker/_multi_process.py`
108
+ - `multi_process`
109
+ - `src/llm_utils/lm/llm.py`
110
+ - `LLM.chat_completion`, `LLM.generate`, `LLM.pydantic_parse`, `LLM.inspect_history`
111
+ - `src/llm_utils/lm/llm_signature.py`
112
+ - `LLMSignature`
113
+ - `src/llm_utils/lm/llm_qwen3.py`
114
+ - `Qwen3LLM`, `complete_until`, `complete_reasoning`, `complete_content`
115
+ - `src/vision_utils/io_utils.py`
116
+ - `read_images`, `read_images_cpu`, `read_images_gpu`, `ImageMmap`, `ImageMmapDynamic`
117
+ - `src/vision_utils/plot.py`
118
+ - `plot_images_notebook`
119
+ - `src/datasets_utils/viz_chat.py`
120
+ - dataset and conversation inspection CLI
121
+
122
+ ## Public API Notes
123
+
124
+ ### `speedy_utils`
125
+
126
+ - `memoize` supports sync and async functions.
127
+ - `load_json_or_pickle` is for `.json` and pickle-like files.
128
+ - use `load_jsonl` or `fast_load_jsonl` for JSONL.
129
+ - `multi_process(num_procs=None)` currently normalizes to `1`; it does not auto-pick a process count.
130
+
131
+ ### `llm_utils`
132
+
133
+ - `LLM()` defaults to the chat path.
134
+ - `LLM.generate()` uses the completions API and returns a `CompletionChoice`-like object.
135
+ - `LLM.generate()` expects a string prompt and only supports `n=1`.
136
+ - `LLM.pydantic_parse()` is the structured-output API.
137
+ - `LLM(..., return_dict=True)` returns a normalized dict with `completion`, `message`, `messages`, and `parsed`.
138
+ - `LLMSignature` defaults structured outputs to the signature's output model.
139
+ - `Qwen3LLM.chat_completion()` returns an OpenAI-style `ChatCompletionMessage` with optional dynamic attrs such as `reasoning_content`, `usage`, and `call_count`.
140
+ - `Qwen3LLM.complete_until()` returns a continuation-state object, not a `ChatCompletionMessage`.
141
+
142
+ ### `vision_utils`
143
+
144
+ - `read_images*()` returns `dict[path, ndarray | None]`.
145
+ - `plot_images_notebook()` expects arrays/tensors or lists/tuples of arrays.
146
+ - if you loaded images with `read_images*()`, pass `list(images.values())` to the plotter.
147
+ - `ImageMmap` and `ImageMmapDynamic` take image-path sequences and build cache files as needed.
148
+
149
+ ## CLI Tools
150
+
151
+ Registered console scripts in `pyproject.toml`:
152
+
153
+ - `mpython`
154
+ - `kill-mpython`
155
+ - `sp_chat`
156
+ - `spu-prefetch-large-model`
157
+ - `viz_chat`
158
+ - `openapi_client_codegen`
159
+
160
+ ## Code Style
161
+
162
+ - Line length: `88`
163
+ - Quote style: double quotes
164
+ - Ruff is the formatter and linter
165
+ - Avoid unnecessary wrappers and ceremony; see `CODING_STYLE.md`
166
+ - Keep public docs/examples aligned with tests and current implementation, not with historical helper scripts
167
+
168
+ ## Type Checking with Pyright
169
+
170
+ Use:
171
+
172
+ ```bash
173
+ uv run python tools/check_syntax.py
174
+ ```
175
+
176
+ This mirrors what VS Code Pylance reports for the configured project files.
177
+
178
+ ### pyright config (`pyrightconfig.json`)
179
+
180
+ Current notable suppressions:
181
+
182
+ | Rule | Why suppressed |
183
+ |------|----------------|
184
+ | `reportMissingImports` | Optional GPU and backend dependencies are not always installed |
185
+ | `reportAttributeAccessIssue` | OpenAI response models and runtime message objects gain dynamic attrs such as `usage`, `reasoning_content`, and `call_count` |
186
+ | `reportUnsupportedDunderAll` | Some modules rely on broad export patterns that are noisy for pyright |
187
+
188
+ ### Common annotation patterns in this repo
189
+
190
+ - use string literal `"tqdm"` when needed in type hints
191
+ - put `Awaitable[R]` overloads before generic `R` overloads
192
+ - use `# type: ignore[attr-defined]` for dynamic OpenAI message attrs where necessary
193
+ - keep dataset `__getitem__` overrides narrow and explicit
194
+
195
+ ## Version Management
196
+
197
+ Version lives in `pyproject.toml`. `./bumpversion.sh` currently:
198
+
199
+ 1. runs tests
200
+ 2. bumps the package version
201
+ 3. commits and pushes