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,279 @@
1
+ #!/usr/bin/env python3
2
+ # Timestamp: 2026-01-25
3
+ # File: src/scitex/stats/_mcp/_handlers/_run_test.py
4
+
5
+ """Statistical test execution handler."""
6
+
7
+ from __future__ import annotations
8
+
9
+ import asyncio
10
+ from datetime import datetime
11
+
12
+ import numpy as np
13
+
14
+ __all__ = ["run_test_handler"]
15
+
16
+
17
+ async def run_test_handler(
18
+ test_name: str,
19
+ data: list[list[float]],
20
+ alternative: str = "two-sided",
21
+ ) -> dict:
22
+ """Execute a statistical test on provided data."""
23
+ try:
24
+ from scipy import stats as scipy_stats
25
+
26
+ loop = asyncio.get_event_loop()
27
+
28
+ def do_test():
29
+ # Convert data to numpy arrays
30
+ groups = [np.array(g, dtype=float) for g in data]
31
+
32
+ result = {}
33
+
34
+ # Run the appropriate test
35
+ if test_name == "ttest_ind":
36
+ result = _run_ttest_ind(groups, alternative, scipy_stats)
37
+ elif test_name == "ttest_paired":
38
+ result = _run_ttest_paired(groups, alternative, scipy_stats)
39
+ elif test_name == "ttest_1samp":
40
+ result = _run_ttest_1samp(groups, alternative, scipy_stats)
41
+ elif test_name == "brunner_munzel":
42
+ result = _run_brunner_munzel(groups, alternative, scipy_stats)
43
+ elif test_name == "mannwhitneyu":
44
+ result = _run_mannwhitneyu(groups, alternative, scipy_stats)
45
+ elif test_name == "wilcoxon":
46
+ result = _run_wilcoxon(groups, alternative, scipy_stats)
47
+ elif test_name == "anova":
48
+ result = _run_anova(groups, scipy_stats)
49
+ elif test_name == "kruskal":
50
+ result = _run_kruskal(groups, scipy_stats)
51
+ elif test_name == "chi2":
52
+ result = _run_chi2(data, scipy_stats)
53
+ elif test_name == "fisher_exact":
54
+ result = _run_fisher_exact(data, alternative, scipy_stats)
55
+ elif test_name == "pearson":
56
+ result = _run_pearson(groups, scipy_stats)
57
+ elif test_name == "spearman":
58
+ result = _run_spearman(groups, scipy_stats)
59
+ elif test_name == "kendall":
60
+ result = _run_kendall(groups, scipy_stats)
61
+ else:
62
+ raise ValueError(f"Unknown test: {test_name}")
63
+
64
+ # Calculate effect size if applicable
65
+ if test_name in [
66
+ "ttest_ind",
67
+ "ttest_paired",
68
+ "brunner_munzel",
69
+ "mannwhitneyu",
70
+ ]:
71
+ result = _add_effect_size(result, groups)
72
+
73
+ # Add significance determination
74
+ alpha = 0.05
75
+ result["significant"] = result["p_value"] < alpha
76
+ result["alpha"] = alpha
77
+
78
+ return result
79
+
80
+ result = await loop.run_in_executor(None, do_test)
81
+
82
+ return {
83
+ "success": True,
84
+ "test_name": test_name,
85
+ "alternative": alternative,
86
+ **result,
87
+ "timestamp": datetime.now().isoformat(),
88
+ }
89
+
90
+ except Exception as e:
91
+ return {"success": False, "error": str(e)}
92
+
93
+
94
+ def _run_ttest_ind(groups, alternative, scipy_stats):
95
+ if len(groups) != 2:
96
+ raise ValueError("t-test requires exactly 2 groups")
97
+ stat, p_value = scipy_stats.ttest_ind(groups[0], groups[1], alternative=alternative)
98
+ df = len(groups[0]) + len(groups[1]) - 2
99
+ return {
100
+ "test": "Independent t-test",
101
+ "statistic": float(stat),
102
+ "statistic_name": "t",
103
+ "p_value": float(p_value),
104
+ "df": df,
105
+ }
106
+
107
+
108
+ def _run_ttest_paired(groups, alternative, scipy_stats):
109
+ if len(groups) != 2:
110
+ raise ValueError("Paired t-test requires exactly 2 groups")
111
+ stat, p_value = scipy_stats.ttest_rel(groups[0], groups[1], alternative=alternative)
112
+ df = len(groups[0]) - 1
113
+ return {
114
+ "test": "Paired t-test",
115
+ "statistic": float(stat),
116
+ "statistic_name": "t",
117
+ "p_value": float(p_value),
118
+ "df": df,
119
+ }
120
+
121
+
122
+ def _run_ttest_1samp(groups, alternative, scipy_stats):
123
+ if len(groups) != 1:
124
+ raise ValueError("One-sample t-test requires exactly 1 group")
125
+ stat, p_value = scipy_stats.ttest_1samp(groups[0], 0, alternative=alternative)
126
+ df = len(groups[0]) - 1
127
+ return {
128
+ "test": "One-sample t-test",
129
+ "statistic": float(stat),
130
+ "statistic_name": "t",
131
+ "p_value": float(p_value),
132
+ "df": df,
133
+ }
134
+
135
+
136
+ def _run_brunner_munzel(groups, alternative, scipy_stats):
137
+ if len(groups) != 2:
138
+ raise ValueError("Brunner-Munzel requires exactly 2 groups")
139
+ res = scipy_stats.brunnermunzel(groups[0], groups[1], alternative=alternative)
140
+ return {
141
+ "test": "Brunner-Munzel test",
142
+ "statistic": float(res.statistic),
143
+ "statistic_name": "BM",
144
+ "p_value": float(res.pvalue),
145
+ }
146
+
147
+
148
+ def _run_mannwhitneyu(groups, alternative, scipy_stats):
149
+ if len(groups) != 2:
150
+ raise ValueError("Mann-Whitney U requires exactly 2 groups")
151
+ stat, p_value = scipy_stats.mannwhitneyu(
152
+ groups[0], groups[1], alternative=alternative
153
+ )
154
+ return {
155
+ "test": "Mann-Whitney U test",
156
+ "statistic": float(stat),
157
+ "statistic_name": "U",
158
+ "p_value": float(p_value),
159
+ }
160
+
161
+
162
+ def _run_wilcoxon(groups, alternative, scipy_stats):
163
+ if len(groups) != 2:
164
+ raise ValueError("Wilcoxon requires exactly 2 paired groups")
165
+ stat, p_value = scipy_stats.wilcoxon(groups[0], groups[1], alternative=alternative)
166
+ return {
167
+ "test": "Wilcoxon signed-rank test",
168
+ "statistic": float(stat),
169
+ "statistic_name": "W",
170
+ "p_value": float(p_value),
171
+ }
172
+
173
+
174
+ def _run_anova(groups, scipy_stats):
175
+ if len(groups) < 2:
176
+ raise ValueError("ANOVA requires at least 2 groups")
177
+ stat, p_value = scipy_stats.f_oneway(*groups)
178
+ df_between = len(groups) - 1
179
+ df_within = sum(len(g) for g in groups) - len(groups)
180
+ return {
181
+ "test": "One-way ANOVA",
182
+ "statistic": float(stat),
183
+ "statistic_name": "F",
184
+ "p_value": float(p_value),
185
+ "df_between": df_between,
186
+ "df_within": df_within,
187
+ }
188
+
189
+
190
+ def _run_kruskal(groups, scipy_stats):
191
+ if len(groups) < 2:
192
+ raise ValueError("Kruskal-Wallis requires at least 2 groups")
193
+ stat, p_value = scipy_stats.kruskal(*groups)
194
+ return {
195
+ "test": "Kruskal-Wallis H test",
196
+ "statistic": float(stat),
197
+ "statistic_name": "H",
198
+ "p_value": float(p_value),
199
+ "df": len(groups) - 1,
200
+ }
201
+
202
+
203
+ def _run_chi2(data, scipy_stats):
204
+ table = np.array(data)
205
+ chi2, p_value, dof, expected = scipy_stats.chi2_contingency(table)
206
+ return {
207
+ "test": "Chi-square test of independence",
208
+ "statistic": float(chi2),
209
+ "statistic_name": "chi2",
210
+ "p_value": float(p_value),
211
+ "df": int(dof),
212
+ "expected_frequencies": expected.tolist(),
213
+ }
214
+
215
+
216
+ def _run_fisher_exact(data, alternative, scipy_stats):
217
+ table = np.array(data)
218
+ if table.shape != (2, 2):
219
+ raise ValueError("Fisher's exact test requires a 2x2 table")
220
+ odds_ratio, p_value = scipy_stats.fisher_exact(table, alternative=alternative)
221
+ return {
222
+ "test": "Fisher's exact test",
223
+ "statistic": float(odds_ratio),
224
+ "statistic_name": "odds_ratio",
225
+ "p_value": float(p_value),
226
+ }
227
+
228
+
229
+ def _run_pearson(groups, scipy_stats):
230
+ if len(groups) != 2:
231
+ raise ValueError("Pearson correlation requires exactly 2 variables")
232
+ r, p_value = scipy_stats.pearsonr(groups[0], groups[1])
233
+ return {
234
+ "test": "Pearson correlation",
235
+ "statistic": float(r),
236
+ "statistic_name": "r",
237
+ "p_value": float(p_value),
238
+ }
239
+
240
+
241
+ def _run_spearman(groups, scipy_stats):
242
+ if len(groups) != 2:
243
+ raise ValueError("Spearman correlation requires exactly 2 variables")
244
+ r, p_value = scipy_stats.spearmanr(groups[0], groups[1])
245
+ return {
246
+ "test": "Spearman correlation",
247
+ "statistic": float(r),
248
+ "statistic_name": "rho",
249
+ "p_value": float(p_value),
250
+ }
251
+
252
+
253
+ def _run_kendall(groups, scipy_stats):
254
+ if len(groups) != 2:
255
+ raise ValueError("Kendall correlation requires exactly 2 variables")
256
+ tau, p_value = scipy_stats.kendalltau(groups[0], groups[1])
257
+ return {
258
+ "test": "Kendall tau correlation",
259
+ "statistic": float(tau),
260
+ "statistic_name": "tau",
261
+ "p_value": float(p_value),
262
+ }
263
+
264
+
265
+ def _add_effect_size(result, groups):
266
+ """Add effect size calculations to result."""
267
+ from scitex.stats.effect_sizes import cliffs_delta, cohens_d
268
+
269
+ if len(groups) == 2:
270
+ d = cohens_d(groups[0], groups[1])
271
+ delta = cliffs_delta(groups[0], groups[1])
272
+ result["effect_size"] = {
273
+ "cohens_d": float(d),
274
+ "cliffs_delta": float(delta),
275
+ }
276
+ return result
277
+
278
+
279
+ # EOF
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env python3
2
+ # Timestamp: 2026-01-25
3
+ # File: src/scitex/stats/_mcp/_handlers/_stars.py
4
+
5
+ """P-value to stars conversion handler."""
6
+
7
+ from __future__ import annotations
8
+
9
+ from datetime import datetime
10
+
11
+ __all__ = ["p_to_stars_handler"]
12
+
13
+
14
+ async def p_to_stars_handler(
15
+ p_value: float,
16
+ thresholds: list[float] | None = None,
17
+ ) -> dict:
18
+ """Convert p-value to significance stars."""
19
+ try:
20
+ thresh = thresholds or [0.001, 0.01, 0.05]
21
+
22
+ if p_value < thresh[0]:
23
+ stars = "***"
24
+ significance = f"p < {thresh[0]}"
25
+ elif p_value < thresh[1]:
26
+ stars = "**"
27
+ significance = f"p < {thresh[1]}"
28
+ elif p_value < thresh[2]:
29
+ stars = "*"
30
+ significance = f"p < {thresh[2]}"
31
+ else:
32
+ stars = "ns"
33
+ significance = f"p >= {thresh[2]} (not significant)"
34
+
35
+ return {
36
+ "success": True,
37
+ "p_value": p_value,
38
+ "stars": stars,
39
+ "significance": significance,
40
+ "thresholds": thresh,
41
+ "timestamp": datetime.now().isoformat(),
42
+ }
43
+
44
+ except Exception as e:
45
+ return {"success": False, "error": str(e)}
46
+
47
+
48
+ # EOF