scitex 2.14.0__py3-none-any.whl → 2.15.2__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.
Files changed (300) hide show
  1. scitex/__init__.py +71 -17
  2. scitex/_env_loader.py +156 -0
  3. scitex/_mcp_resources/__init__.py +37 -0
  4. scitex/_mcp_resources/_cheatsheet.py +135 -0
  5. scitex/_mcp_resources/_figrecipe.py +138 -0
  6. scitex/_mcp_resources/_formats.py +102 -0
  7. scitex/_mcp_resources/_modules.py +337 -0
  8. scitex/_mcp_resources/_session.py +149 -0
  9. scitex/_mcp_tools/__init__.py +4 -0
  10. scitex/_mcp_tools/audio.py +66 -0
  11. scitex/_mcp_tools/diagram.py +11 -95
  12. scitex/_mcp_tools/introspect.py +210 -0
  13. scitex/_mcp_tools/plt.py +260 -305
  14. scitex/_mcp_tools/scholar.py +74 -0
  15. scitex/_mcp_tools/social.py +244 -0
  16. scitex/_mcp_tools/template.py +24 -0
  17. scitex/_mcp_tools/writer.py +21 -204
  18. scitex/ai/_gen_ai/_PARAMS.py +10 -7
  19. scitex/ai/classification/reporters/_SingleClassificationReporter.py +45 -1603
  20. scitex/ai/classification/reporters/_mixins/__init__.py +36 -0
  21. scitex/ai/classification/reporters/_mixins/_constants.py +67 -0
  22. scitex/ai/classification/reporters/_mixins/_cv_summary.py +387 -0
  23. scitex/ai/classification/reporters/_mixins/_feature_importance.py +119 -0
  24. scitex/ai/classification/reporters/_mixins/_metrics.py +275 -0
  25. scitex/ai/classification/reporters/_mixins/_plotting.py +179 -0
  26. scitex/ai/classification/reporters/_mixins/_reports.py +153 -0
  27. scitex/ai/classification/reporters/_mixins/_storage.py +160 -0
  28. scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit.py +30 -1550
  29. scitex/ai/classification/timeseries/_sliding_window_core.py +467 -0
  30. scitex/ai/classification/timeseries/_sliding_window_plotting.py +369 -0
  31. scitex/audio/README.md +40 -36
  32. scitex/audio/__init__.py +129 -61
  33. scitex/audio/_branding.py +185 -0
  34. scitex/audio/_mcp/__init__.py +32 -0
  35. scitex/audio/_mcp/handlers.py +59 -6
  36. scitex/audio/_mcp/speak_handlers.py +238 -0
  37. scitex/audio/_relay.py +225 -0
  38. scitex/audio/_tts.py +18 -10
  39. scitex/audio/engines/base.py +17 -10
  40. scitex/audio/engines/elevenlabs_engine.py +7 -2
  41. scitex/audio/mcp_server.py +228 -75
  42. scitex/canvas/README.md +1 -1
  43. scitex/canvas/editor/_dearpygui/__init__.py +25 -0
  44. scitex/canvas/editor/_dearpygui/_editor.py +147 -0
  45. scitex/canvas/editor/_dearpygui/_handlers.py +476 -0
  46. scitex/canvas/editor/_dearpygui/_panels/__init__.py +17 -0
  47. scitex/canvas/editor/_dearpygui/_panels/_control.py +119 -0
  48. scitex/canvas/editor/_dearpygui/_panels/_element_controls.py +190 -0
  49. scitex/canvas/editor/_dearpygui/_panels/_preview.py +43 -0
  50. scitex/canvas/editor/_dearpygui/_panels/_sections.py +390 -0
  51. scitex/canvas/editor/_dearpygui/_plotting.py +187 -0
  52. scitex/canvas/editor/_dearpygui/_rendering.py +504 -0
  53. scitex/canvas/editor/_dearpygui/_selection.py +295 -0
  54. scitex/canvas/editor/_dearpygui/_state.py +93 -0
  55. scitex/canvas/editor/_dearpygui/_utils.py +61 -0
  56. scitex/canvas/editor/flask_editor/_core/__init__.py +27 -0
  57. scitex/canvas/editor/flask_editor/_core/_bbox_extraction.py +200 -0
  58. scitex/canvas/editor/flask_editor/_core/_editor.py +173 -0
  59. scitex/canvas/editor/flask_editor/_core/_export_helpers.py +353 -0
  60. scitex/canvas/editor/flask_editor/_core/_routes_basic.py +190 -0
  61. scitex/canvas/editor/flask_editor/_core/_routes_export.py +332 -0
  62. scitex/canvas/editor/flask_editor/_core/_routes_panels.py +252 -0
  63. scitex/canvas/editor/flask_editor/_core/_routes_save.py +218 -0
  64. scitex/canvas/editor/flask_editor/_core.py +25 -1684
  65. scitex/canvas/editor/flask_editor/templates/__init__.py +32 -70
  66. scitex/cli/__init__.py +38 -43
  67. scitex/cli/audio.py +76 -27
  68. scitex/cli/capture.py +13 -20
  69. scitex/cli/introspect.py +481 -0
  70. scitex/cli/main.py +200 -109
  71. scitex/cli/mcp.py +60 -34
  72. scitex/cli/plt.py +357 -0
  73. scitex/cli/repro.py +15 -8
  74. scitex/cli/resource.py +15 -8
  75. scitex/cli/scholar/__init__.py +23 -8
  76. scitex/cli/scholar/_crossref_scitex.py +296 -0
  77. scitex/cli/scholar/_fetch.py +25 -3
  78. scitex/cli/social.py +314 -0
  79. scitex/cli/stats.py +15 -8
  80. scitex/cli/template.py +129 -12
  81. scitex/cli/tex.py +15 -8
  82. scitex/cli/writer.py +132 -8
  83. scitex/cloud/__init__.py +41 -2
  84. scitex/config/README.md +1 -1
  85. scitex/config/__init__.py +16 -2
  86. scitex/config/_env_registry.py +256 -0
  87. scitex/context/__init__.py +22 -0
  88. scitex/dev/__init__.py +20 -1
  89. scitex/diagram/__init__.py +42 -19
  90. scitex/diagram/mcp_server.py +13 -125
  91. scitex/gen/__init__.py +50 -14
  92. scitex/gen/_list_packages.py +4 -4
  93. scitex/introspect/__init__.py +82 -0
  94. scitex/introspect/_call_graph.py +303 -0
  95. scitex/introspect/_class_hierarchy.py +163 -0
  96. scitex/introspect/_core.py +41 -0
  97. scitex/introspect/_docstring.py +131 -0
  98. scitex/introspect/_examples.py +113 -0
  99. scitex/introspect/_imports.py +271 -0
  100. scitex/{gen/_inspect_module.py → introspect/_list_api.py} +43 -54
  101. scitex/introspect/_mcp/__init__.py +41 -0
  102. scitex/introspect/_mcp/handlers.py +233 -0
  103. scitex/introspect/_members.py +155 -0
  104. scitex/introspect/_resolve.py +89 -0
  105. scitex/introspect/_signature.py +131 -0
  106. scitex/introspect/_source.py +80 -0
  107. scitex/introspect/_type_hints.py +172 -0
  108. scitex/io/_save.py +1 -2
  109. scitex/io/bundle/README.md +1 -1
  110. scitex/logging/_formatters.py +19 -9
  111. scitex/mcp_server.py +98 -5
  112. scitex/os/__init__.py +4 -0
  113. scitex/{gen → os}/_check_host.py +4 -5
  114. scitex/plt/__init__.py +245 -550
  115. scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_wrappers.py +5 -10
  116. scitex/plt/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
  117. scitex/plt/gallery/README.md +1 -1
  118. scitex/plt/utils/_hitmap/__init__.py +82 -0
  119. scitex/plt/utils/_hitmap/_artist_extraction.py +343 -0
  120. scitex/plt/utils/_hitmap/_color_application.py +346 -0
  121. scitex/plt/utils/_hitmap/_color_conversion.py +121 -0
  122. scitex/plt/utils/_hitmap/_constants.py +40 -0
  123. scitex/plt/utils/_hitmap/_hitmap_core.py +334 -0
  124. scitex/plt/utils/_hitmap/_path_extraction.py +357 -0
  125. scitex/plt/utils/_hitmap/_query.py +113 -0
  126. scitex/plt/utils/_hitmap.py +46 -1616
  127. scitex/plt/utils/_metadata/__init__.py +80 -0
  128. scitex/plt/utils/_metadata/_artists/__init__.py +25 -0
  129. scitex/plt/utils/_metadata/_artists/_base.py +195 -0
  130. scitex/plt/utils/_metadata/_artists/_collections.py +356 -0
  131. scitex/plt/utils/_metadata/_artists/_extract.py +57 -0
  132. scitex/plt/utils/_metadata/_artists/_images.py +80 -0
  133. scitex/plt/utils/_metadata/_artists/_lines.py +261 -0
  134. scitex/plt/utils/_metadata/_artists/_patches.py +247 -0
  135. scitex/plt/utils/_metadata/_artists/_text.py +106 -0
  136. scitex/plt/utils/_metadata/_csv.py +416 -0
  137. scitex/plt/utils/_metadata/_detect.py +225 -0
  138. scitex/plt/utils/_metadata/_legend.py +127 -0
  139. scitex/plt/utils/_metadata/_rounding.py +117 -0
  140. scitex/plt/utils/_metadata/_verification.py +202 -0
  141. scitex/schema/README.md +1 -1
  142. scitex/scholar/__init__.py +8 -0
  143. scitex/scholar/_mcp/crossref_handlers.py +265 -0
  144. scitex/scholar/core/Scholar.py +63 -1700
  145. scitex/scholar/core/_mixins/__init__.py +36 -0
  146. scitex/scholar/core/_mixins/_enrichers.py +270 -0
  147. scitex/scholar/core/_mixins/_library_handlers.py +100 -0
  148. scitex/scholar/core/_mixins/_loaders.py +103 -0
  149. scitex/scholar/core/_mixins/_pdf_download.py +375 -0
  150. scitex/scholar/core/_mixins/_pipeline.py +312 -0
  151. scitex/scholar/core/_mixins/_project_handlers.py +125 -0
  152. scitex/scholar/core/_mixins/_savers.py +69 -0
  153. scitex/scholar/core/_mixins/_search.py +103 -0
  154. scitex/scholar/core/_mixins/_services.py +88 -0
  155. scitex/scholar/core/_mixins/_url_finding.py +105 -0
  156. scitex/scholar/crossref_scitex.py +367 -0
  157. scitex/scholar/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
  158. scitex/scholar/examples/00_run_all.sh +120 -0
  159. scitex/scholar/jobs/_executors.py +27 -3
  160. scitex/scholar/pdf_download/ScholarPDFDownloader.py +38 -416
  161. scitex/scholar/pdf_download/_cli.py +154 -0
  162. scitex/scholar/pdf_download/strategies/__init__.py +11 -8
  163. scitex/scholar/pdf_download/strategies/manual_download_fallback.py +80 -3
  164. scitex/scholar/pipelines/ScholarPipelineBibTeX.py +73 -121
  165. scitex/scholar/pipelines/ScholarPipelineParallel.py +80 -138
  166. scitex/scholar/pipelines/ScholarPipelineSingle.py +43 -63
  167. scitex/scholar/pipelines/_single_steps.py +71 -36
  168. scitex/scholar/storage/_LibraryManager.py +97 -1695
  169. scitex/scholar/storage/_mixins/__init__.py +30 -0
  170. scitex/scholar/storage/_mixins/_bibtex_handlers.py +128 -0
  171. scitex/scholar/storage/_mixins/_library_operations.py +218 -0
  172. scitex/scholar/storage/_mixins/_metadata_conversion.py +226 -0
  173. scitex/scholar/storage/_mixins/_paper_saving.py +456 -0
  174. scitex/scholar/storage/_mixins/_resolution.py +376 -0
  175. scitex/scholar/storage/_mixins/_storage_helpers.py +121 -0
  176. scitex/scholar/storage/_mixins/_symlink_handlers.py +226 -0
  177. scitex/scholar/url_finder/.tmp/open_url/KNOWN_RESOLVERS.py +462 -0
  178. scitex/scholar/url_finder/.tmp/open_url/README.md +223 -0
  179. scitex/scholar/url_finder/.tmp/open_url/_DOIToURLResolver.py +694 -0
  180. scitex/scholar/url_finder/.tmp/open_url/_OpenURLResolver.py +1160 -0
  181. scitex/scholar/url_finder/.tmp/open_url/_ResolverLinkFinder.py +344 -0
  182. scitex/scholar/url_finder/.tmp/open_url/__init__.py +24 -0
  183. scitex/security/README.md +3 -3
  184. scitex/session/README.md +1 -1
  185. scitex/session/__init__.py +26 -7
  186. scitex/session/_decorator.py +1 -1
  187. scitex/sh/README.md +1 -1
  188. scitex/sh/__init__.py +7 -4
  189. scitex/social/__init__.py +155 -0
  190. scitex/social/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
  191. scitex/stats/_mcp/_handlers/__init__.py +31 -0
  192. scitex/stats/_mcp/_handlers/_corrections.py +113 -0
  193. scitex/stats/_mcp/_handlers/_descriptive.py +78 -0
  194. scitex/stats/_mcp/_handlers/_effect_size.py +106 -0
  195. scitex/stats/_mcp/_handlers/_format.py +94 -0
  196. scitex/stats/_mcp/_handlers/_normality.py +110 -0
  197. scitex/stats/_mcp/_handlers/_posthoc.py +224 -0
  198. scitex/stats/_mcp/_handlers/_power.py +247 -0
  199. scitex/stats/_mcp/_handlers/_recommend.py +102 -0
  200. scitex/stats/_mcp/_handlers/_run_test.py +279 -0
  201. scitex/stats/_mcp/_handlers/_stars.py +48 -0
  202. scitex/stats/_mcp/handlers.py +19 -1171
  203. scitex/stats/auto/_stat_style.py +175 -0
  204. scitex/stats/auto/_style_definitions.py +411 -0
  205. scitex/stats/auto/_styles.py +22 -620
  206. scitex/stats/descriptive/__init__.py +11 -8
  207. scitex/stats/descriptive/_ci.py +39 -0
  208. scitex/stats/power/_power.py +15 -4
  209. scitex/str/__init__.py +2 -1
  210. scitex/str/_title_case.py +63 -0
  211. scitex/template/README.md +1 -1
  212. scitex/template/__init__.py +25 -10
  213. scitex/template/_code_templates.py +147 -0
  214. scitex/template/_mcp/handlers.py +81 -0
  215. scitex/template/_mcp/tool_schemas.py +55 -0
  216. scitex/template/_templates/__init__.py +51 -0
  217. scitex/template/_templates/audio.py +233 -0
  218. scitex/template/_templates/canvas.py +312 -0
  219. scitex/template/_templates/capture.py +268 -0
  220. scitex/template/_templates/config.py +43 -0
  221. scitex/template/_templates/diagram.py +294 -0
  222. scitex/template/_templates/io.py +107 -0
  223. scitex/template/_templates/module.py +53 -0
  224. scitex/template/_templates/plt.py +202 -0
  225. scitex/template/_templates/scholar.py +267 -0
  226. scitex/template/_templates/session.py +130 -0
  227. scitex/template/_templates/session_minimal.py +43 -0
  228. scitex/template/_templates/session_plot.py +67 -0
  229. scitex/template/_templates/session_stats.py +77 -0
  230. scitex/template/_templates/stats.py +323 -0
  231. scitex/template/_templates/writer.py +296 -0
  232. scitex/template/clone_writer_directory.py +5 -5
  233. scitex/ui/_backends/_email.py +10 -2
  234. scitex/ui/_backends/_webhook.py +5 -1
  235. scitex/web/_search_pubmed.py +10 -6
  236. scitex/writer/README.md +1 -1
  237. scitex/writer/_mcp/handlers.py +11 -744
  238. scitex/writer/_mcp/tool_schemas.py +5 -335
  239. scitex-2.15.2.dist-info/METADATA +648 -0
  240. {scitex-2.14.0.dist-info → scitex-2.15.2.dist-info}/RECORD +246 -150
  241. scitex/canvas/editor/flask_editor/templates/_scripts.py +0 -4933
  242. scitex/canvas/editor/flask_editor/templates/_styles.py +0 -1658
  243. scitex/dev/plt/data/mpl/PLOTTING_FUNCTIONS.yaml +0 -90
  244. scitex/dev/plt/data/mpl/PLOTTING_SIGNATURES.yaml +0 -1571
  245. scitex/dev/plt/data/mpl/PLOTTING_SIGNATURES_DETAILED.yaml +0 -6262
  246. scitex/dev/plt/data/mpl/SIGNATURES_FLATTENED.yaml +0 -1274
  247. scitex/dev/plt/data/mpl/dir_ax.txt +0 -459
  248. scitex/diagram/_compile.py +0 -312
  249. scitex/diagram/_diagram.py +0 -355
  250. scitex/diagram/_mcp/__init__.py +0 -4
  251. scitex/diagram/_mcp/handlers.py +0 -400
  252. scitex/diagram/_mcp/tool_schemas.py +0 -157
  253. scitex/diagram/_presets.py +0 -173
  254. scitex/diagram/_schema.py +0 -182
  255. scitex/diagram/_split.py +0 -278
  256. scitex/gen/_ci.py +0 -12
  257. scitex/gen/_title_case.py +0 -89
  258. scitex/plt/_mcp/__init__.py +0 -4
  259. scitex/plt/_mcp/_handlers_annotation.py +0 -102
  260. scitex/plt/_mcp/_handlers_figure.py +0 -195
  261. scitex/plt/_mcp/_handlers_plot.py +0 -252
  262. scitex/plt/_mcp/_handlers_style.py +0 -219
  263. scitex/plt/_mcp/handlers.py +0 -74
  264. scitex/plt/_mcp/tool_schemas.py +0 -497
  265. scitex/plt/mcp_server.py +0 -231
  266. scitex/scholar/data/.gitkeep +0 -0
  267. scitex/scholar/data/README.md +0 -44
  268. scitex/scholar/data/bib_files/bibliography.bib +0 -1952
  269. scitex/scholar/data/bib_files/neurovista.bib +0 -277
  270. scitex/scholar/data/bib_files/neurovista_enriched.bib +0 -441
  271. scitex/scholar/data/bib_files/neurovista_enriched_enriched.bib +0 -441
  272. scitex/scholar/data/bib_files/neurovista_processed.bib +0 -338
  273. scitex/scholar/data/bib_files/openaccess.bib +0 -89
  274. scitex/scholar/data/bib_files/pac-seizure_prediction_enriched.bib +0 -2178
  275. scitex/scholar/data/bib_files/pac.bib +0 -698
  276. scitex/scholar/data/bib_files/pac_enriched.bib +0 -1061
  277. scitex/scholar/data/bib_files/pac_processed.bib +0 -0
  278. scitex/scholar/data/bib_files/pac_titles.txt +0 -75
  279. scitex/scholar/data/bib_files/paywalled.bib +0 -98
  280. scitex/scholar/data/bib_files/related-papers-by-coauthors.bib +0 -58
  281. scitex/scholar/data/bib_files/related-papers-by-coauthors_enriched.bib +0 -87
  282. scitex/scholar/data/bib_files/seizure_prediction.bib +0 -694
  283. scitex/scholar/data/bib_files/seizure_prediction_processed.bib +0 -0
  284. scitex/scholar/data/bib_files/test_complete_enriched.bib +0 -437
  285. scitex/scholar/data/bib_files/test_final_enriched.bib +0 -437
  286. scitex/scholar/data/bib_files/test_seizure.bib +0 -46
  287. scitex/scholar/data/impact_factor/JCR_IF_2022.xlsx +0 -0
  288. scitex/scholar/data/impact_factor/JCR_IF_2024.db +0 -0
  289. scitex/scholar/data/impact_factor/JCR_IF_2024.xlsx +0 -0
  290. scitex/scholar/data/impact_factor/JCR_IF_2024_v01.db +0 -0
  291. scitex/scholar/data/impact_factor.db +0 -0
  292. scitex/scholar/examples/SUGGESTIONS.md +0 -865
  293. scitex/scholar/examples/dev.py +0 -38
  294. scitex-2.14.0.dist-info/METADATA +0 -1238
  295. /scitex/{gen → context}/_detect_environment.py +0 -0
  296. /scitex/{gen → context}/_get_notebook_path.py +0 -0
  297. /scitex/{gen/_shell.py → sh/_shell_legacy.py} +0 -0
  298. {scitex-2.14.0.dist-info → scitex-2.15.2.dist-info}/WHEEL +0 -0
  299. {scitex-2.14.0.dist-info → scitex-2.15.2.dist-info}/entry_points.txt +0 -0
  300. {scitex-2.14.0.dist-info → scitex-2.15.2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env python3
2
+ # Timestamp: 2025-01-20
3
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/introspect/_core.py
4
+
5
+ """Core introspection module - re-exports all utilities."""
6
+
7
+ from ._call_graph import get_call_graph, get_function_calls
8
+ from ._class_hierarchy import get_class_hierarchy, get_mro
9
+ from ._docstring import get_docstring
10
+ from ._examples import find_examples
11
+ from ._imports import get_dependencies, get_imports
12
+ from ._members import dir, get_exports
13
+ from ._resolve import get_type_info, resolve_object
14
+ from ._signature import q
15
+ from ._source import qq
16
+ from ._type_hints import get_class_annotations, get_type_hints_detailed
17
+
18
+ __all__ = [
19
+ # IPython-style names
20
+ "q", # signature (like func?)
21
+ "qq", # source (like func??)
22
+ "dir", # members (like dir())
23
+ # Basic
24
+ "get_docstring",
25
+ "get_exports",
26
+ "find_examples",
27
+ "resolve_object",
28
+ "get_type_info",
29
+ # Advanced - Class hierarchy
30
+ "get_class_hierarchy",
31
+ "get_mro",
32
+ # Advanced - Type hints
33
+ "get_type_hints_detailed",
34
+ "get_class_annotations",
35
+ # Advanced - Imports
36
+ "get_imports",
37
+ "get_dependencies",
38
+ # Advanced - Call graph
39
+ "get_call_graph",
40
+ "get_function_calls",
41
+ ]
@@ -0,0 +1,131 @@
1
+ #!/usr/bin/env python3
2
+ # Timestamp: 2025-01-20
3
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/introspect/_docstring.py
4
+
5
+ """Docstring extraction and parsing utilities."""
6
+
7
+ from __future__ import annotations
8
+
9
+ import inspect
10
+ import re
11
+ from typing import Literal
12
+
13
+ from ._resolve import get_type_info, resolve_object
14
+
15
+
16
+ def _parse_docstring(docstring: str) -> dict:
17
+ """Parse numpy/google style docstring into sections."""
18
+ sections = {
19
+ "summary": "",
20
+ "description": "",
21
+ "parameters": "",
22
+ "returns": "",
23
+ "examples": "",
24
+ "notes": "",
25
+ }
26
+
27
+ if not docstring:
28
+ return sections
29
+
30
+ section_patterns = [
31
+ (r"Parameters?\s*\n[-=]+", "parameters"),
32
+ (r"Returns?\s*\n[-=]+", "returns"),
33
+ (r"Examples?\s*\n[-=]+", "examples"),
34
+ (r"Notes?\s*\n[-=]+", "notes"),
35
+ (r"Raises?\s*\n[-=]+", "raises"),
36
+ (r"See Also\s*\n[-=]+", "see_also"),
37
+ ]
38
+
39
+ lines = docstring.split("\n")
40
+
41
+ i = 0
42
+ summary_lines = []
43
+ while i < len(lines):
44
+ line = lines[i].strip()
45
+ if not line:
46
+ if summary_lines:
47
+ break
48
+ elif any(re.match(p, line, re.IGNORECASE) for p, _ in section_patterns):
49
+ break
50
+ else:
51
+ summary_lines.append(line)
52
+ i += 1
53
+
54
+ sections["summary"] = " ".join(summary_lines)
55
+
56
+ current_section = "description"
57
+ current_content = []
58
+
59
+ for line in lines[i:]:
60
+ matched = False
61
+ for pattern, section_name in section_patterns:
62
+ if re.match(pattern, line, re.IGNORECASE):
63
+ if current_content:
64
+ sections[current_section] = "\n".join(current_content).strip()
65
+ current_section = section_name
66
+ current_content = []
67
+ matched = True
68
+ break
69
+
70
+ if not matched:
71
+ current_content.append(line)
72
+
73
+ if current_content:
74
+ sections[current_section] = "\n".join(current_content).strip()
75
+
76
+ return sections
77
+
78
+
79
+ def get_docstring(
80
+ dotted_path: str,
81
+ format: Literal["raw", "parsed", "summary"] = "raw",
82
+ ) -> dict:
83
+ """
84
+ Get the docstring of a Python object.
85
+
86
+ Parameters
87
+ ----------
88
+ dotted_path : str
89
+ Dotted path to the object
90
+ format : str
91
+ 'raw' - Return full docstring as-is
92
+ 'parsed' - Parse numpy/google style into sections
93
+ 'summary' - Return only first line/paragraph
94
+
95
+ Returns
96
+ -------
97
+ dict
98
+ docstring: str
99
+ sections: dict (if format='parsed')
100
+ type_info: dict
101
+ """
102
+ obj, error = resolve_object(dotted_path)
103
+ if error:
104
+ return {"success": False, "error": error}
105
+
106
+ type_info = get_type_info(obj)
107
+ docstring = inspect.getdoc(obj) or ""
108
+
109
+ if format == "summary":
110
+ lines = docstring.split("\n\n")
111
+ summary = lines[0].strip() if lines else ""
112
+ return {
113
+ "success": True,
114
+ "docstring": summary,
115
+ "type_info": type_info,
116
+ }
117
+
118
+ if format == "parsed":
119
+ sections = _parse_docstring(docstring)
120
+ return {
121
+ "success": True,
122
+ "docstring": docstring,
123
+ "sections": sections,
124
+ "type_info": type_info,
125
+ }
126
+
127
+ return {
128
+ "success": True,
129
+ "docstring": docstring,
130
+ "type_info": type_info,
131
+ }
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env python3
2
+ # Timestamp: 2025-01-20
3
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/introspect/_examples.py
4
+
5
+ """Usage example finding utilities."""
6
+
7
+ from __future__ import annotations
8
+
9
+ import importlib
10
+ from pathlib import Path
11
+
12
+ from ._resolve import resolve_object
13
+
14
+
15
+ def find_examples(
16
+ dotted_path: str,
17
+ search_paths: list[str] | None = None,
18
+ max_results: int = 10,
19
+ ) -> dict:
20
+ """
21
+ Find usage examples of a function/class in tests and examples.
22
+
23
+ Parameters
24
+ ----------
25
+ dotted_path : str
26
+ Dotted path to search for (e.g., 'scitex.plt.plot')
27
+ search_paths : list[str] | None
28
+ Paths to search. If None, auto-detect from module location
29
+ max_results : int
30
+ Maximum number of examples to return
31
+
32
+ Returns
33
+ -------
34
+ dict
35
+ examples: list[dict] - Each with file, line, context
36
+ count: int
37
+ """
38
+ obj, error = resolve_object(dotted_path)
39
+ if error:
40
+ return {"success": False, "error": error}
41
+
42
+ name = getattr(obj, "__name__", dotted_path.split(".")[-1])
43
+
44
+ if search_paths is None:
45
+ search_paths = []
46
+
47
+ module = dotted_path.split(".")[0]
48
+ try:
49
+ mod = importlib.import_module(module)
50
+ if hasattr(mod, "__file__") and mod.__file__:
51
+ mod_dir = Path(mod.__file__).parent
52
+ project_root = mod_dir.parent
53
+ for subdir in ["tests", "test", "examples", "example"]:
54
+ test_dir = project_root / subdir
55
+ if test_dir.exists():
56
+ search_paths.append(str(test_dir))
57
+ except ImportError:
58
+ pass
59
+
60
+ if not search_paths:
61
+ return {
62
+ "success": True,
63
+ "examples": [],
64
+ "count": 0,
65
+ "message": "No test/example directories found",
66
+ }
67
+
68
+ examples = []
69
+
70
+ for search_path in search_paths:
71
+ path = Path(search_path)
72
+ if not path.exists():
73
+ continue
74
+
75
+ for py_file in path.rglob("*.py"):
76
+ try:
77
+ content = py_file.read_text()
78
+ except Exception:
79
+ continue
80
+
81
+ if name not in content:
82
+ continue
83
+
84
+ lines = content.split("\n")
85
+ for i, line in enumerate(lines):
86
+ if name in line:
87
+ start = max(0, i - 2)
88
+ end = min(len(lines), i + 3)
89
+ context = "\n".join(lines[start:end])
90
+
91
+ examples.append(
92
+ {
93
+ "file": str(py_file),
94
+ "line": i + 1,
95
+ "context": context,
96
+ }
97
+ )
98
+
99
+ if len(examples) >= max_results:
100
+ break
101
+
102
+ if len(examples) >= max_results:
103
+ break
104
+
105
+ if len(examples) >= max_results:
106
+ break
107
+
108
+ return {
109
+ "success": True,
110
+ "examples": examples,
111
+ "count": len(examples),
112
+ "search_paths": search_paths,
113
+ }
@@ -0,0 +1,271 @@
1
+ #!/usr/bin/env python3
2
+ # Timestamp: 2025-01-20
3
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/introspect/_imports.py
4
+
5
+ """Import analysis utilities using AST."""
6
+
7
+ from __future__ import annotations
8
+
9
+ import ast
10
+ import inspect
11
+ from pathlib import Path
12
+
13
+ from ._resolve import get_type_info, resolve_object
14
+
15
+
16
+ def get_imports(
17
+ dotted_path: str,
18
+ categorize: bool = True,
19
+ ) -> dict:
20
+ """
21
+ Get all imports from a module's source code using AST.
22
+
23
+ Parameters
24
+ ----------
25
+ dotted_path : str
26
+ Dotted path to the module
27
+ categorize : bool
28
+ Group imports by category (stdlib, third-party, local)
29
+
30
+ Returns
31
+ -------
32
+ dict
33
+ imports: list[dict] - All imports with details
34
+ categories: dict - Grouped by category (if categorize=True)
35
+
36
+ Examples
37
+ --------
38
+ >>> get_imports("scitex.audio")
39
+ """
40
+ obj, error = resolve_object(dotted_path)
41
+ if error:
42
+ return {"success": False, "error": error}
43
+
44
+ type_info = get_type_info(obj)
45
+
46
+ if not inspect.ismodule(obj):
47
+ return {
48
+ "success": False,
49
+ "error": f"'{dotted_path}' is not a module",
50
+ "type_info": type_info,
51
+ }
52
+
53
+ # Get source file
54
+ try:
55
+ source_file = inspect.getfile(obj)
56
+ except TypeError:
57
+ return {
58
+ "success": False,
59
+ "error": "Cannot get source file (builtin module?)",
60
+ "type_info": type_info,
61
+ }
62
+
63
+ # Read and parse source
64
+ try:
65
+ source = Path(source_file).read_text()
66
+ tree = ast.parse(source)
67
+ except Exception as e:
68
+ return {
69
+ "success": False,
70
+ "error": f"Cannot parse source: {e}",
71
+ "type_info": type_info,
72
+ }
73
+
74
+ imports = _extract_imports(tree)
75
+
76
+ result = {
77
+ "success": True,
78
+ "module": dotted_path,
79
+ "source_file": source_file,
80
+ "imports": imports,
81
+ "import_count": len(imports),
82
+ "type_info": type_info,
83
+ }
84
+
85
+ if categorize:
86
+ result["categories"] = _categorize_imports(imports)
87
+
88
+ return result
89
+
90
+
91
+ def _extract_imports(tree: ast.AST) -> list[dict]:
92
+ """Extract all imports from an AST."""
93
+ imports = []
94
+
95
+ for node in ast.walk(tree):
96
+ if isinstance(node, ast.Import):
97
+ for alias in node.names:
98
+ imports.append(
99
+ {
100
+ "type": "import",
101
+ "module": alias.name,
102
+ "alias": alias.asname,
103
+ "line": node.lineno,
104
+ }
105
+ )
106
+ elif isinstance(node, ast.ImportFrom):
107
+ module = node.module or ""
108
+ level = node.level # Relative import level
109
+
110
+ for alias in node.names:
111
+ imports.append(
112
+ {
113
+ "type": "from",
114
+ "module": module,
115
+ "name": alias.name,
116
+ "alias": alias.asname,
117
+ "level": level,
118
+ "line": node.lineno,
119
+ }
120
+ )
121
+
122
+ return imports
123
+
124
+
125
+ def _categorize_imports(imports: list[dict]) -> dict:
126
+ """Categorize imports into stdlib, third-party, local."""
127
+ import sys
128
+
129
+ stdlib_modules = (
130
+ set(sys.stdlib_module_names)
131
+ if hasattr(sys, "stdlib_module_names")
132
+ else _get_stdlib_modules()
133
+ )
134
+
135
+ categories = {
136
+ "stdlib": [],
137
+ "third_party": [],
138
+ "local": [],
139
+ }
140
+
141
+ for imp in imports:
142
+ module = imp["module"]
143
+ top_level = module.split(".")[0] if module else ""
144
+
145
+ # Relative imports are local
146
+ if imp.get("level", 0) > 0:
147
+ categories["local"].append(imp)
148
+ elif top_level in stdlib_modules:
149
+ categories["stdlib"].append(imp)
150
+ else:
151
+ categories["third_party"].append(imp)
152
+
153
+ return categories
154
+
155
+
156
+ def _get_stdlib_modules() -> set:
157
+ """Get stdlib module names for Python < 3.10."""
158
+ import pkgutil
159
+
160
+ stdlib = set()
161
+ for module in pkgutil.iter_modules():
162
+ if module.name.startswith("_"):
163
+ continue
164
+ try:
165
+ spec = __import__(module.name).__spec__
166
+ if spec and spec.origin:
167
+ if "site-packages" not in spec.origin:
168
+ stdlib.add(module.name)
169
+ except Exception:
170
+ pass
171
+
172
+ # Add common ones that might be missed
173
+ stdlib.update(
174
+ [
175
+ "abc",
176
+ "ast",
177
+ "asyncio",
178
+ "collections",
179
+ "contextlib",
180
+ "dataclasses",
181
+ "datetime",
182
+ "functools",
183
+ "inspect",
184
+ "io",
185
+ "itertools",
186
+ "json",
187
+ "logging",
188
+ "os",
189
+ "pathlib",
190
+ "re",
191
+ "sys",
192
+ "typing",
193
+ "unittest",
194
+ "warnings",
195
+ ]
196
+ )
197
+
198
+ return stdlib
199
+
200
+
201
+ def get_dependencies(
202
+ dotted_path: str,
203
+ recursive: bool = False,
204
+ max_depth: int = 3,
205
+ ) -> dict:
206
+ """
207
+ Get module dependencies (what it imports).
208
+
209
+ Parameters
210
+ ----------
211
+ dotted_path : str
212
+ Dotted path to the module
213
+ recursive : bool
214
+ Recursively analyze imported modules
215
+ max_depth : int
216
+ Maximum recursion depth
217
+
218
+ Returns
219
+ -------
220
+ dict
221
+ dependencies: list[str] - Direct dependencies
222
+ tree: dict - Dependency tree (if recursive)
223
+ """
224
+ result = get_imports(dotted_path, categorize=True)
225
+ if not result.get("success"):
226
+ return result
227
+
228
+ # Get unique module names
229
+ deps = set()
230
+ for imp in result["imports"]:
231
+ module = imp["module"]
232
+ if module:
233
+ deps.add(module.split(".")[0])
234
+
235
+ result["dependencies"] = sorted(deps)
236
+ result["dependency_count"] = len(deps)
237
+
238
+ if recursive:
239
+ result["tree"] = _build_dep_tree(dotted_path, max_depth, set())
240
+
241
+ return result
242
+
243
+
244
+ def _build_dep_tree(
245
+ module_path: str,
246
+ max_depth: int,
247
+ visited: set,
248
+ current_depth: int = 0,
249
+ ) -> dict:
250
+ """Build dependency tree recursively."""
251
+ if current_depth >= max_depth or module_path in visited:
252
+ return {"module": module_path, "truncated": True}
253
+
254
+ visited.add(module_path)
255
+
256
+ result = {"module": module_path, "imports": []}
257
+
258
+ imports_result = get_imports(module_path, categorize=False)
259
+ if not imports_result.get("success"):
260
+ return result
261
+
262
+ for imp in imports_result.get("imports", []):
263
+ module = imp["module"]
264
+ if module and module not in visited:
265
+ top_level = module.split(".")[0]
266
+ # Only recurse into non-stdlib
267
+ if top_level not in _get_stdlib_modules():
268
+ child = _build_dep_tree(module, max_depth, visited, current_depth + 1)
269
+ result["imports"].append(child)
270
+
271
+ return result
@@ -1,18 +1,18 @@
1
1
  #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- # Time-stamp: "2024-11-07 18:58:55 (ywatanabe)"
4
- # File: ./scitex_repo/src/scitex/gen/_inspect_module.py
2
+ # Timestamp: 2025-01-27
3
+ # File: /home/ywatanabe/proj/scitex-python/src/scitex/introspect/_list_api.py
4
+
5
+ """Module API listing utilities."""
5
6
 
6
7
  import inspect
7
8
  import sys
8
9
  import warnings
9
10
  from typing import Any, List, Optional, Set, Union
10
11
 
11
- import scitex
12
12
  import pandas as pd
13
13
 
14
14
 
15
- def inspect_module(
15
+ def list_api(
16
16
  module: Union[str, Any],
17
17
  columns: List[str] = ["Type", "Name", "Docstring", "Depth"],
18
18
  prefix: str = "",
@@ -26,41 +26,14 @@ def inspect_module(
26
26
  drop_duplicates: bool = True,
27
27
  root_only: bool = False,
28
28
  ) -> pd.DataFrame:
29
- return _inspect_module(
30
- module=module,
31
- prefix=prefix,
32
- max_depth=max_depth,
33
- visited=visited,
34
- docstring=docstring,
35
- tree=tree,
36
- current_depth=current_depth,
37
- print_output=print_output,
38
- skip_depwarnings=skip_depwarnings,
39
- drop_duplicates=drop_duplicates,
40
- root_only=root_only,
41
- )[columns]
42
-
29
+ """
30
+ List the API of a module recursively and return as a DataFrame.
43
31
 
44
- def _inspect_module(
45
- module: Union[str, Any],
46
- columns: List[str] = ["Type", "Name", "Docstring", "Depth"],
47
- prefix: str = "",
48
- max_depth: int = 5,
49
- visited: Optional[Set[str]] = None,
50
- docstring: bool = False,
51
- tree: bool = True,
52
- current_depth: int = 0,
53
- print_output: bool = False,
54
- skip_depwarnings: bool = True,
55
- drop_duplicates: bool = True,
56
- root_only: bool = False,
57
- ) -> pd.DataFrame:
58
- """List the contents of a module recursively and return as a DataFrame.
32
+ Like a recursive `dir()` that shows the entire module tree.
59
33
 
60
34
  Example
61
35
  -------
62
- >>>
63
- >>> df = inspect_module(scitex)
36
+ >>> df = list_api(scitex)
64
37
  >>> print(df)
65
38
  Type Name Docstring Depth
66
39
  0 M scitex Module description 0
@@ -100,6 +73,36 @@ def _inspect_module(
100
73
  pd.DataFrame
101
74
  Module structure with specified columns
102
75
  """
76
+ return _list_api_impl(
77
+ module=module,
78
+ prefix=prefix,
79
+ max_depth=max_depth,
80
+ visited=visited,
81
+ docstring=docstring,
82
+ tree=tree,
83
+ current_depth=current_depth,
84
+ print_output=print_output,
85
+ skip_depwarnings=skip_depwarnings,
86
+ drop_duplicates=drop_duplicates,
87
+ root_only=root_only,
88
+ )[columns]
89
+
90
+
91
+ def _list_api_impl(
92
+ module: Union[str, Any],
93
+ columns: List[str] = ["Type", "Name", "Docstring", "Depth"],
94
+ prefix: str = "",
95
+ max_depth: int = 5,
96
+ visited: Optional[Set[str]] = None,
97
+ docstring: bool = False,
98
+ tree: bool = True,
99
+ current_depth: int = 0,
100
+ print_output: bool = False,
101
+ skip_depwarnings: bool = True,
102
+ drop_duplicates: bool = True,
103
+ root_only: bool = False,
104
+ ) -> pd.DataFrame:
105
+ """Internal implementation of list_api."""
103
106
  if skip_depwarnings:
104
107
  warnings.filterwarnings("ignore", category=DeprecationWarning)
105
108
  warnings.filterwarnings("ignore", category=UserWarning)
@@ -150,7 +153,7 @@ def _inspect_module(
150
153
  )
151
154
  )
152
155
  try:
153
- sub_df = _inspect_module(
156
+ sub_df = _list_api_impl(
154
157
  obj,
155
158
  columns=columns,
156
159
  prefix=full_path,
@@ -235,22 +238,8 @@ def _print_module_contents(df: pd.DataFrame) -> None:
235
238
 
236
239
 
237
240
  if __name__ == "__main__":
241
+ import scitex
242
+
238
243
  sys.setrecursionlimit(10_000)
239
- df = inspect_module(scitex, docstring=True, print_output=False, columns=["Name"])
244
+ df = list_api(scitex, docstring=True, print_output=False, columns=["Name"])
240
245
  print(scitex.pd.round(df))
241
- # Name
242
- # 0 scitex
243
- # 1 scitex.ai
244
- # 3 scitex.ai.ClassificationReporter
245
- # 4 scitex.ai.ClassifierServer
246
- # 5 scitex.ai.EarlyStopping
247
- # ... ...
248
- # 5373 scitex.typing
249
- # 5375 scitex.typing.Any
250
- # 5376 scitex.typing.Iterable
251
- # 5377 scitex.web
252
- # 5379 scitex.web.summarize_url
253
-
254
- # [5361 rows x 1 columns]
255
-
256
- # EOF