scitex 2.8.1__py3-none-any.whl → 2.10.0__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 (415) hide show
  1. scitex/__init__.py +15 -7
  2. scitex/__version__.py +1 -2
  3. scitex/_install_guide.py +250 -0
  4. scitex/_optional_deps.py +206 -39
  5. scitex/ai/_gen_ai/_Groq.py +2 -4
  6. scitex/ai/_gen_ai/_OpenAI.py +5 -2
  7. scitex/ai/_gen_ai/_Perplexity.py +20 -6
  8. scitex/audio/__init__.py +24 -15
  9. scitex/audio/_cross_process_lock.py +139 -0
  10. scitex/audio/_mcp_handlers.py +256 -0
  11. scitex/audio/_mcp_tool_schemas.py +203 -0
  12. scitex/audio/engines/elevenlabs_engine.py +5 -2
  13. scitex/audio/mcp_server.py +98 -457
  14. scitex/bridge/__init__.py +30 -19
  15. scitex/bridge/_figrecipe.py +245 -0
  16. scitex/bridge/_helpers.py +2 -1
  17. scitex/bridge/_plt_vis.py +23 -10
  18. scitex/bridge/_stats_plt.py +18 -5
  19. scitex/bridge/_stats_vis.py +16 -2
  20. scitex/browser/__init__.py +84 -44
  21. scitex/browser/automation/__init__.py +5 -1
  22. scitex/browser/core/BrowserMixin.py +17 -4
  23. scitex/browser/core/__init__.py +11 -2
  24. scitex/browser/remote/CaptchaHandler.py +1 -1
  25. scitex/browser/remote/ZenRowsAPIClient.py +1 -1
  26. scitex/capture/grid.py +487 -0
  27. scitex/capture/mcp_handlers.py +401 -0
  28. scitex/capture/mcp_tool_defs.py +192 -0
  29. scitex/capture/mcp_tools.py +241 -0
  30. scitex/capture/mcp_utils.py +30 -0
  31. scitex/cli/convert.py +421 -0
  32. scitex/cli/main.py +6 -4
  33. scitex/datetime/__init__.py +46 -0
  34. scitex/datetime/_linspace.py +100 -0
  35. scitex/datetime/_normalize_timestamp.py +306 -0
  36. scitex/db/_delete_duplicates.py +4 -4
  37. scitex/db/_sqlite3/_delete_duplicates.py +11 -2
  38. scitex/dev/plt/__init__.py +61 -62
  39. scitex/dev/plt/demo_plotters/__init__.py +0 -0
  40. scitex/dev/plt/demo_plotters/plot_mpl_axhline.py +28 -0
  41. scitex/dev/plt/demo_plotters/plot_mpl_axhspan.py +28 -0
  42. scitex/dev/plt/demo_plotters/plot_mpl_axvline.py +28 -0
  43. scitex/dev/plt/demo_plotters/plot_mpl_axvspan.py +28 -0
  44. scitex/dev/plt/demo_plotters/plot_mpl_bar.py +29 -0
  45. scitex/dev/plt/demo_plotters/plot_mpl_barh.py +29 -0
  46. scitex/dev/plt/demo_plotters/plot_mpl_boxplot.py +28 -0
  47. scitex/dev/plt/demo_plotters/plot_mpl_contour.py +31 -0
  48. scitex/dev/plt/demo_plotters/plot_mpl_contourf.py +31 -0
  49. scitex/dev/plt/demo_plotters/plot_mpl_errorbar.py +30 -0
  50. scitex/dev/plt/demo_plotters/plot_mpl_eventplot.py +28 -0
  51. scitex/dev/plt/demo_plotters/plot_mpl_fill.py +30 -0
  52. scitex/dev/plt/demo_plotters/plot_mpl_fill_between.py +31 -0
  53. scitex/dev/plt/demo_plotters/plot_mpl_hexbin.py +28 -0
  54. scitex/dev/plt/demo_plotters/plot_mpl_hist.py +28 -0
  55. scitex/dev/plt/demo_plotters/plot_mpl_hist2d.py +28 -0
  56. scitex/dev/plt/demo_plotters/plot_mpl_imshow.py +29 -0
  57. scitex/dev/plt/demo_plotters/plot_mpl_pcolormesh.py +31 -0
  58. scitex/dev/plt/demo_plotters/plot_mpl_pie.py +29 -0
  59. scitex/dev/plt/demo_plotters/plot_mpl_plot.py +29 -0
  60. scitex/dev/plt/demo_plotters/plot_mpl_quiver.py +31 -0
  61. scitex/dev/plt/demo_plotters/plot_mpl_scatter.py +28 -0
  62. scitex/dev/plt/demo_plotters/plot_mpl_stackplot.py +31 -0
  63. scitex/dev/plt/demo_plotters/plot_mpl_stem.py +29 -0
  64. scitex/dev/plt/demo_plotters/plot_mpl_step.py +29 -0
  65. scitex/dev/plt/demo_plotters/plot_mpl_violinplot.py +28 -0
  66. scitex/dev/plt/demo_plotters/plot_sns_barplot.py +29 -0
  67. scitex/dev/plt/demo_plotters/plot_sns_boxplot.py +29 -0
  68. scitex/dev/plt/demo_plotters/plot_sns_heatmap.py +28 -0
  69. scitex/dev/plt/demo_plotters/plot_sns_histplot.py +29 -0
  70. scitex/dev/plt/demo_plotters/plot_sns_kdeplot.py +29 -0
  71. scitex/dev/plt/demo_plotters/plot_sns_lineplot.py +31 -0
  72. scitex/dev/plt/demo_plotters/plot_sns_scatterplot.py +29 -0
  73. scitex/dev/plt/demo_plotters/plot_sns_stripplot.py +29 -0
  74. scitex/dev/plt/demo_plotters/plot_sns_swarmplot.py +29 -0
  75. scitex/dev/plt/demo_plotters/plot_sns_violinplot.py +29 -0
  76. scitex/dev/plt/demo_plotters/plot_stx_bar.py +29 -0
  77. scitex/dev/plt/demo_plotters/plot_stx_barh.py +29 -0
  78. scitex/dev/plt/demo_plotters/plot_stx_box.py +28 -0
  79. scitex/dev/plt/demo_plotters/plot_stx_boxplot.py +28 -0
  80. scitex/dev/plt/demo_plotters/plot_stx_conf_mat.py +28 -0
  81. scitex/dev/plt/demo_plotters/plot_stx_contour.py +31 -0
  82. scitex/dev/plt/demo_plotters/plot_stx_ecdf.py +28 -0
  83. scitex/dev/plt/demo_plotters/plot_stx_errorbar.py +30 -0
  84. scitex/dev/plt/demo_plotters/plot_stx_fill_between.py +31 -0
  85. scitex/dev/plt/demo_plotters/plot_stx_fillv.py +28 -0
  86. scitex/dev/plt/demo_plotters/plot_stx_heatmap.py +28 -0
  87. scitex/dev/plt/demo_plotters/plot_stx_image.py +28 -0
  88. scitex/dev/plt/demo_plotters/plot_stx_imshow.py +28 -0
  89. scitex/dev/plt/demo_plotters/plot_stx_joyplot.py +28 -0
  90. scitex/dev/plt/demo_plotters/plot_stx_kde.py +28 -0
  91. scitex/dev/plt/demo_plotters/plot_stx_line.py +28 -0
  92. scitex/dev/plt/demo_plotters/plot_stx_mean_ci.py +28 -0
  93. scitex/dev/plt/demo_plotters/plot_stx_mean_std.py +28 -0
  94. scitex/dev/plt/demo_plotters/plot_stx_median_iqr.py +28 -0
  95. scitex/dev/plt/demo_plotters/plot_stx_raster.py +28 -0
  96. scitex/dev/plt/demo_plotters/plot_stx_rectangle.py +28 -0
  97. scitex/dev/plt/demo_plotters/plot_stx_scatter.py +29 -0
  98. scitex/dev/plt/demo_plotters/plot_stx_shaded_line.py +29 -0
  99. scitex/dev/plt/demo_plotters/plot_stx_violin.py +28 -0
  100. scitex/dev/plt/demo_plotters/plot_stx_violinplot.py +28 -0
  101. scitex/dev/plt/mpl/get_dir_ax.py +46 -0
  102. scitex/dev/plt/mpl/get_signatures.py +176 -0
  103. scitex/dev/plt/mpl/get_signatures_details.py +522 -0
  104. scitex/dict/_pop_keys.py +1 -7
  105. scitex/dsp/__init__.py +15 -10
  106. scitex/dsp/add_noise.py +5 -2
  107. scitex/dsp/example.py +35 -22
  108. scitex/dsp/filt.py +8 -3
  109. scitex/dsp/reference.py +3 -2
  110. scitex/dsp/utils/__init__.py +2 -1
  111. scitex/dsp/utils/_differential_bandpass_filters.py +14 -4
  112. scitex/dt/__init__.py +39 -2
  113. scitex/errors.py +82 -521
  114. scitex/fig/__init__.py +4 -4
  115. scitex/fig/editor/edit/panel_loader.py +1 -1
  116. scitex/fig/io/_bundle.py +7 -7
  117. scitex/fts/README.md +262 -0
  118. scitex/fts/TODO.md +66 -0
  119. scitex/fts/__init__.py +90 -0
  120. scitex/fts/_bundle/README_IN_BUNDLE.md +102 -0
  121. scitex/fts/_bundle/_FTS.py +657 -0
  122. scitex/fts/_bundle/__init__.py +38 -0
  123. scitex/fts/_bundle/_children.py +216 -0
  124. scitex/fts/_bundle/_conversion/__init__.py +15 -0
  125. scitex/fts/_bundle/_conversion/_bundle2dict.py +44 -0
  126. scitex/fts/_bundle/_conversion/_dict2bundle.py +50 -0
  127. scitex/fts/_bundle/_dataclasses/_Axes.py +57 -0
  128. scitex/fts/_bundle/_dataclasses/_BBox.py +54 -0
  129. scitex/fts/_bundle/_dataclasses/_ColumnDef.py +72 -0
  130. scitex/fts/_bundle/_dataclasses/_DataFormat.py +40 -0
  131. scitex/fts/_bundle/_dataclasses/_DataInfo.py +135 -0
  132. scitex/fts/_bundle/_dataclasses/_DataSource.py +44 -0
  133. scitex/fts/_bundle/_dataclasses/_Node.py +319 -0
  134. scitex/fts/_bundle/_dataclasses/_NodeRefs.py +45 -0
  135. scitex/fts/_bundle/_dataclasses/_SizeMM.py +38 -0
  136. scitex/fts/_bundle/_dataclasses/__init__.py +35 -0
  137. scitex/fts/_bundle/_extractors/__init__.py +32 -0
  138. scitex/fts/_bundle/_extractors/_extract_bar.py +131 -0
  139. scitex/fts/_bundle/_extractors/_extract_line.py +71 -0
  140. scitex/fts/_bundle/_extractors/_extract_scatter.py +79 -0
  141. scitex/fts/_bundle/_loader.py +134 -0
  142. scitex/fts/_bundle/_mpl_helpers.py +389 -0
  143. scitex/fts/_bundle/_saver.py +269 -0
  144. scitex/fts/_bundle/_storage.py +200 -0
  145. scitex/fts/_bundle/_utils/__init__.py +55 -0
  146. scitex/fts/_bundle/_utils/_const.py +26 -0
  147. scitex/fts/_bundle/_utils/_errors.py +73 -0
  148. scitex/fts/_bundle/_utils/_generate.py +21 -0
  149. scitex/fts/_bundle/_utils/_types.py +76 -0
  150. scitex/fts/_bundle/_validation.py +434 -0
  151. scitex/fts/_bundle/_zipbundle.py +165 -0
  152. scitex/fts/_fig/__init__.py +22 -0
  153. scitex/fts/_fig/_backend/__init__.py +53 -0
  154. scitex/fts/_fig/_backend/_export.py +165 -0
  155. scitex/fts/_fig/_backend/_parser.py +188 -0
  156. scitex/fts/_fig/_backend/_render.py +538 -0
  157. scitex/fts/_fig/_composite.py +345 -0
  158. scitex/fts/_fig/_dataclasses/_ChannelEncoding.py +46 -0
  159. scitex/fts/_fig/_dataclasses/_Encoding.py +82 -0
  160. scitex/fts/_fig/_dataclasses/_Theme.py +441 -0
  161. scitex/fts/_fig/_dataclasses/_TraceEncoding.py +52 -0
  162. scitex/fts/_fig/_dataclasses/__init__.py +47 -0
  163. scitex/fts/_fig/_editor/__init__.py +14 -0
  164. scitex/fts/_fig/_editor/_cui/__init__.py +33 -0
  165. scitex/fts/_fig/_editor/_cui/_backend_detector.py +39 -0
  166. scitex/fts/_fig/_editor/_cui/_bundle_resolver.py +366 -0
  167. scitex/fts/_fig/_editor/_cui/_editor_launcher.py +175 -0
  168. scitex/fts/_fig/_editor/_cui/_manual_handler.py +52 -0
  169. scitex/fts/_fig/_editor/_cui/_panel_loader.py +246 -0
  170. scitex/fts/_fig/_editor/_cui/_path_resolver.py +66 -0
  171. scitex/fts/_fig/_editor/_defaults.py +300 -0
  172. scitex/fts/_fig/_editor/_gui/__init__.py +11 -0
  173. scitex/fts/_fig/_editor/_gui/_flask_editor/__init__.py +20 -0
  174. scitex/fts/_fig/_editor/_gui/_flask_editor/_bbox.py +1339 -0
  175. scitex/fts/_fig/_editor/_gui/_flask_editor/_core.py +1688 -0
  176. scitex/fts/_fig/_editor/_gui/_flask_editor/_plotter.py +664 -0
  177. scitex/fts/_fig/_editor/_gui/_flask_editor/_renderer.py +853 -0
  178. scitex/fts/_fig/_editor/_gui/_flask_editor/_utils.py +79 -0
  179. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/base/reset.css +41 -0
  180. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/base/typography.css +16 -0
  181. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/base/variables.css +85 -0
  182. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/buttons.css +217 -0
  183. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/context-menu.css +93 -0
  184. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/dropdown.css +57 -0
  185. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/forms.css +112 -0
  186. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/modal.css +59 -0
  187. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/sections.css +212 -0
  188. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/canvas.css +176 -0
  189. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/element-inspector.css +190 -0
  190. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/loading.css +59 -0
  191. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/overlay.css +45 -0
  192. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/panel-grid.css +95 -0
  193. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/selection.css +101 -0
  194. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/statistics.css +138 -0
  195. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/index.css +31 -0
  196. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/layout/container.css +7 -0
  197. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/layout/controls.css +56 -0
  198. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/layout/preview.css +78 -0
  199. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/alignment/axis.js +314 -0
  200. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/alignment/basic.js +107 -0
  201. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/alignment/distribute.js +54 -0
  202. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/canvas/canvas.js +172 -0
  203. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/canvas/dragging.js +258 -0
  204. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/canvas/resize.js +48 -0
  205. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/canvas/selection.js +71 -0
  206. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/core/api.js +288 -0
  207. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/core/state.js +143 -0
  208. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/core/utils.js +245 -0
  209. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/dev/element-inspector.js +992 -0
  210. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/editor/bbox.js +339 -0
  211. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/editor/element-drag.js +286 -0
  212. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/editor/overlay.js +371 -0
  213. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/editor/preview.js +293 -0
  214. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/main.js +426 -0
  215. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/shortcuts/context-menu.js +152 -0
  216. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/shortcuts/keyboard.js +265 -0
  217. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/ui/controls.js +184 -0
  218. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/ui/download.js +57 -0
  219. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/ui/help.js +100 -0
  220. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/ui/theme.js +34 -0
  221. scitex/fts/_fig/_editor/_gui/_flask_editor/templates/__init__.py +124 -0
  222. scitex/fts/_fig/_editor/_gui/_flask_editor/templates/_html.py +851 -0
  223. scitex/fts/_fig/_editor/_gui/_flask_editor/templates/_scripts.py +4932 -0
  224. scitex/fts/_fig/_editor/_gui/_flask_editor/templates/_styles.py +1657 -0
  225. scitex/fts/_fig/_editor/_gui/_flask_editor.py +36 -0
  226. scitex/fts/_fig/_models/_Annotations.py +115 -0
  227. scitex/fts/_fig/_models/_Axes.py +152 -0
  228. scitex/fts/_fig/_models/_Figure.py +138 -0
  229. scitex/fts/_fig/_models/_Guides.py +104 -0
  230. scitex/fts/_fig/_models/_Plot.py +123 -0
  231. scitex/fts/_fig/_models/_Styles.py +245 -0
  232. scitex/fts/_fig/_models/__init__.py +80 -0
  233. scitex/fts/_fig/_models/_plot_types/__init__.py +156 -0
  234. scitex/fts/_fig/_models/_plot_types/_bar.py +43 -0
  235. scitex/fts/_fig/_models/_plot_types/_box.py +38 -0
  236. scitex/fts/_fig/_models/_plot_types/_distribution.py +36 -0
  237. scitex/fts/_fig/_models/_plot_types/_errorbar.py +60 -0
  238. scitex/fts/_fig/_models/_plot_types/_histogram.py +30 -0
  239. scitex/fts/_fig/_models/_plot_types/_image.py +61 -0
  240. scitex/fts/_fig/_models/_plot_types/_line.py +57 -0
  241. scitex/fts/_fig/_models/_plot_types/_scatter.py +30 -0
  242. scitex/fts/_fig/_models/_plot_types/_seaborn.py +121 -0
  243. scitex/fts/_fig/_models/_plot_types/_violin.py +36 -0
  244. scitex/fts/_fig/_utils/__init__.py +129 -0
  245. scitex/fts/_fig/_utils/_auto_layout.py +127 -0
  246. scitex/fts/_fig/_utils/_calc_bounds.py +111 -0
  247. scitex/fts/_fig/_utils/_const_sizes.py +48 -0
  248. scitex/fts/_fig/_utils/_convert_coords.py +77 -0
  249. scitex/fts/_fig/_utils/_get_template.py +178 -0
  250. scitex/fts/_fig/_utils/_normalize.py +73 -0
  251. scitex/fts/_fig/_utils/_plot_layout.py +397 -0
  252. scitex/fts/_fig/_utils/_validate.py +197 -0
  253. scitex/fts/_kinds/__init__.py +45 -0
  254. scitex/fts/_kinds/_figure/__init__.py +19 -0
  255. scitex/fts/_kinds/_figure/_composite.py +345 -0
  256. scitex/fts/_kinds/_plot/__init__.py +25 -0
  257. scitex/fts/_kinds/_plot/_backend/__init__.py +53 -0
  258. scitex/fts/_kinds/_plot/_backend/_export.py +165 -0
  259. scitex/fts/_kinds/_plot/_backend/_parser.py +188 -0
  260. scitex/fts/_kinds/_plot/_backend/_render.py +538 -0
  261. scitex/fts/_kinds/_plot/_dataclasses/_ChannelEncoding.py +46 -0
  262. scitex/fts/_kinds/_plot/_dataclasses/_Encoding.py +82 -0
  263. scitex/fts/_kinds/_plot/_dataclasses/_Theme.py +441 -0
  264. scitex/fts/_kinds/_plot/_dataclasses/_TraceEncoding.py +52 -0
  265. scitex/fts/_kinds/_plot/_dataclasses/__init__.py +47 -0
  266. scitex/fts/_kinds/_plot/_models/_Annotations.py +115 -0
  267. scitex/fts/_kinds/_plot/_models/_Axes.py +152 -0
  268. scitex/fts/_kinds/_plot/_models/_Figure.py +138 -0
  269. scitex/fts/_kinds/_plot/_models/_Guides.py +104 -0
  270. scitex/fts/_kinds/_plot/_models/_Plot.py +123 -0
  271. scitex/fts/_kinds/_plot/_models/_Styles.py +245 -0
  272. scitex/fts/_kinds/_plot/_models/__init__.py +80 -0
  273. scitex/fts/_kinds/_plot/_models/_plot_types/__init__.py +156 -0
  274. scitex/fts/_kinds/_plot/_models/_plot_types/_bar.py +43 -0
  275. scitex/fts/_kinds/_plot/_models/_plot_types/_box.py +38 -0
  276. scitex/fts/_kinds/_plot/_models/_plot_types/_distribution.py +36 -0
  277. scitex/fts/_kinds/_plot/_models/_plot_types/_errorbar.py +60 -0
  278. scitex/fts/_kinds/_plot/_models/_plot_types/_histogram.py +30 -0
  279. scitex/fts/_kinds/_plot/_models/_plot_types/_image.py +61 -0
  280. scitex/fts/_kinds/_plot/_models/_plot_types/_line.py +57 -0
  281. scitex/fts/_kinds/_plot/_models/_plot_types/_scatter.py +30 -0
  282. scitex/fts/_kinds/_plot/_models/_plot_types/_seaborn.py +121 -0
  283. scitex/fts/_kinds/_plot/_models/_plot_types/_violin.py +36 -0
  284. scitex/fts/_kinds/_plot/_utils/__init__.py +129 -0
  285. scitex/fts/_kinds/_plot/_utils/_auto_layout.py +127 -0
  286. scitex/fts/_kinds/_plot/_utils/_calc_bounds.py +111 -0
  287. scitex/fts/_kinds/_plot/_utils/_const_sizes.py +48 -0
  288. scitex/fts/_kinds/_plot/_utils/_convert_coords.py +77 -0
  289. scitex/fts/_kinds/_plot/_utils/_get_template.py +178 -0
  290. scitex/fts/_kinds/_plot/_utils/_normalize.py +73 -0
  291. scitex/fts/_kinds/_plot/_utils/_plot_layout.py +397 -0
  292. scitex/fts/_kinds/_plot/_utils/_validate.py +197 -0
  293. scitex/fts/_kinds/_shape/__init__.py +141 -0
  294. scitex/fts/_kinds/_stats/__init__.py +56 -0
  295. scitex/fts/_kinds/_stats/_dataclasses/_Stats.py +423 -0
  296. scitex/fts/_kinds/_stats/_dataclasses/__init__.py +48 -0
  297. scitex/fts/_kinds/_table/__init__.py +72 -0
  298. scitex/fts/_kinds/_table/_latex/__init__.py +93 -0
  299. scitex/fts/_kinds/_table/_latex/_editor/__init__.py +11 -0
  300. scitex/fts/_kinds/_table/_latex/_editor/_app.py +725 -0
  301. scitex/fts/_kinds/_table/_latex/_export.py +279 -0
  302. scitex/fts/_kinds/_table/_latex/_figure_exporter.py +153 -0
  303. scitex/fts/_kinds/_table/_latex/_stats_formatter.py +274 -0
  304. scitex/fts/_kinds/_table/_latex/_table_exporter.py +362 -0
  305. scitex/fts/_kinds/_table/_latex/_utils.py +369 -0
  306. scitex/fts/_kinds/_table/_latex/_validator.py +445 -0
  307. scitex/fts/_kinds/_text/__init__.py +77 -0
  308. scitex/fts/_schemas/data_info.schema.json +75 -0
  309. scitex/fts/_schemas/encoding.schema.json +90 -0
  310. scitex/fts/_schemas/node.schema.json +145 -0
  311. scitex/fts/_schemas/render_manifest.schema.json +62 -0
  312. scitex/fts/_schemas/stats.schema.json +132 -0
  313. scitex/fts/_schemas/theme.schema.json +141 -0
  314. scitex/fts/_stats/__init__.py +48 -0
  315. scitex/fts/_stats/_dataclasses/_Stats.py +423 -0
  316. scitex/fts/_stats/_dataclasses/__init__.py +48 -0
  317. scitex/fts/_tables/__init__.py +65 -0
  318. scitex/fts/_tables/_latex/__init__.py +93 -0
  319. scitex/fts/_tables/_latex/_editor/__init__.py +11 -0
  320. scitex/fts/_tables/_latex/_editor/_app.py +725 -0
  321. scitex/fts/_tables/_latex/_export.py +279 -0
  322. scitex/fts/_tables/_latex/_figure_exporter.py +153 -0
  323. scitex/fts/_tables/_latex/_stats_formatter.py +274 -0
  324. scitex/fts/_tables/_latex/_table_exporter.py +362 -0
  325. scitex/fts/_tables/_latex/_utils.py +369 -0
  326. scitex/fts/_tables/_latex/_validator.py +445 -0
  327. scitex/gen/__init__.py +66 -25
  328. scitex/gen/misc.py +28 -0
  329. scitex/io/__init__.py +47 -32
  330. scitex/io/_load.py +87 -36
  331. scitex/io/_load_modules/__init__.py +10 -7
  332. scitex/io/_load_modules/_pandas.py +6 -1
  333. scitex/io/_save.py +299 -1556
  334. scitex/io/_save_modules/__init__.py +76 -19
  335. scitex/io/_save_modules/_figure_utils.py +90 -0
  336. scitex/io/_save_modules/_image_csv.py +497 -0
  337. scitex/io/_save_modules/_legends.py +91 -0
  338. scitex/io/_save_modules/_pltz_bundle.py +356 -0
  339. scitex/io/_save_modules/_pltz_stx.py +536 -0
  340. scitex/io/_save_modules/_stx_bundle.py +104 -0
  341. scitex/io/_save_modules/_symlink.py +96 -0
  342. scitex/io/_save_modules/_yaml.py +1 -1
  343. scitex/io/_save_modules/_zarr.py +64 -18
  344. scitex/io/bundle/README.md +212 -0
  345. scitex/io/bundle/__init__.py +110 -0
  346. scitex/io/{_bundle.py → bundle/_core.py} +168 -97
  347. scitex/io/bundle/_nested.py +713 -0
  348. scitex/io/bundle/_types.py +74 -0
  349. scitex/io/{_zip_bundle.py → bundle/_zip.py} +93 -45
  350. scitex/io/utils/h5_to_zarr.py +1 -1
  351. scitex/logging/__init__.py +108 -13
  352. scitex/logging/_errors.py +508 -0
  353. scitex/logging/_formatters.py +30 -6
  354. scitex/logging/_warnings.py +261 -0
  355. scitex/plt/__init__.py +4 -1
  356. scitex/plt/_figrecipe.py +236 -0
  357. scitex/plt/_subplots/_AxisWrapper.py +6 -0
  358. scitex/plt/_subplots/_AxisWrapperMixins/_UnitAwareMixin.py +112 -1
  359. scitex/plt/_subplots/_FigWrapper.py +15 -0
  360. scitex/plt/_subplots/_SubplotsWrapper.py +125 -489
  361. scitex/plt/_subplots/_export_as_csv.py +11 -0
  362. scitex/plt/_subplots/_export_as_csv_formatters/__init__.py +2 -0
  363. scitex/plt/_subplots/_export_as_csv_formatters/_format_pcolormesh.py +66 -0
  364. scitex/plt/_subplots/_export_as_csv_formatters/_format_stackplot.py +62 -0
  365. scitex/plt/_subplots/_export_as_csv_formatters/test_formatters.py +208 -0
  366. scitex/plt/_subplots/_fonts.py +71 -0
  367. scitex/plt/_subplots/_mm_layout.py +282 -0
  368. scitex/plt/gallery/__init__.py +99 -2
  369. scitex/plt/styles/_plot_postprocess.py +3 -1
  370. scitex/plt/utils/_configure_mpl.py +16 -19
  371. scitex/repro/_RandomStateManager.py +13 -8
  372. scitex/resource/__init__.py +19 -1
  373. scitex/resource/_utils/_get_env_info.py +13 -25
  374. scitex/schema/__init__.py +149 -160
  375. scitex/schema/_encoding.py +273 -0
  376. scitex/schema/_figure_elements.py +406 -0
  377. scitex/schema/_theme.py +360 -0
  378. scitex/schema/_validation.py +0 -98
  379. scitex/scholar/__init__.py +56 -14
  380. scitex/scholar/auth/ScholarAuthManager.py +1 -1
  381. scitex/scholar/auth/__init__.py +11 -2
  382. scitex/scholar/auth/providers/BaseAuthenticator.py +1 -1
  383. scitex/scholar/auth/providers/EZProxyAuthenticator.py +1 -1
  384. scitex/scholar/auth/providers/OpenAthensAuthenticator.py +1 -1
  385. scitex/scholar/auth/providers/ShibbolethAuthenticator.py +1 -1
  386. scitex/scholar/config/ScholarConfig.py +1 -1
  387. scitex/scholar/core/Scholar.py +1 -1
  388. scitex/session/_decorator.py +18 -16
  389. scitex/session/_lifecycle.py +9 -11
  390. scitex/session/template.py +9 -8
  391. scitex/sh/test_sh.py +72 -0
  392. scitex/sh/test_sh_simple.py +61 -0
  393. scitex/stats/__init__.py +221 -97
  394. scitex/stats/_schema.py +21 -22
  395. scitex/stats/descriptive/_circular.py +212 -351
  396. scitex/stats/descriptive/_describe.py +81 -132
  397. scitex/stats/descriptive/_nan.py +205 -433
  398. scitex/stats/descriptive/_real.py +127 -141
  399. scitex/str/_format_plot_text.py +5 -5
  400. scitex/str/_latex.py +26 -84
  401. scitex/str/_latex_fallback.py +53 -47
  402. scitex/web/_search_pubmed.py +5 -4
  403. scitex/writer/tests/test_diff_between.py +451 -0
  404. scitex/writer/tests/test_document_section.py +311 -0
  405. scitex/writer/tests/test_document_workflow.py +393 -0
  406. scitex/writer/tests/test_writer.py +361 -0
  407. scitex/writer/tests/test_writer_integration.py +303 -0
  408. {scitex-2.8.1.dist-info → scitex-2.10.0.dist-info}/METADATA +364 -181
  409. {scitex-2.8.1.dist-info → scitex-2.10.0.dist-info}/RECORD +412 -97
  410. scitex/scholar/docs/to_claude/guidelines/examples/mgmt/ARCHITECTURE_EXAMPLE.md +0 -905
  411. scitex/scholar/docs/to_claude/guidelines/examples/mgmt/BULLETIN_BOARD_EXAMPLE.md +0 -99
  412. scitex/scholar/docs/to_claude/guidelines/examples/mgmt/PROJECT_DESCRIPTION_EXAMPLE.md +0 -96
  413. {scitex-2.8.1.dist-info → scitex-2.10.0.dist-info}/WHEEL +0 -0
  414. {scitex-2.8.1.dist-info → scitex-2.10.0.dist-info}/entry_points.txt +0 -0
  415. {scitex-2.8.1.dist-info → scitex-2.10.0.dist-info}/licenses/LICENSE +0 -0
@@ -185,18 +185,19 @@ def _run_with_session(
185
185
  func_globals["rng_manager"] = rng_manager
186
186
  func_globals["logger"] = script_logger
187
187
 
188
- # Log injected globals for user awareness
189
- _decorator_logger.info("=" * 60)
190
- _decorator_logger.info("Injected Global Variables (available in your function):")
191
- _decorator_logger.info(" CONFIG - Session configuration dict")
192
- _decorator_logger.info(f" - CONFIG['ID']: {CONFIG['ID']}")
193
- _decorator_logger.info(f" - CONFIG['SDIR_RUN']: {CONFIG['SDIR_RUN']}")
194
- _decorator_logger.info(f" - CONFIG['PID']: {CONFIG['PID']}")
195
- _decorator_logger.info(" • plt - matplotlib.pyplot (configured for session)")
196
- _decorator_logger.info(" • COLORS - CustomColors (for consistent plotting)")
197
- _decorator_logger.info(" • rng_manager - RandomStateManager (for reproducibility)")
198
- _decorator_logger.info(" • logger - SciTeX logger (configured for your script)")
199
- _decorator_logger.info("=" * 60)
188
+ # Log injected globals for user awareness (only in verbose mode)
189
+ if verbose:
190
+ _decorator_logger.info("=" * 60)
191
+ _decorator_logger.info("Injected Global Variables (available in your function):")
192
+ _decorator_logger.info(" CONFIG - Session configuration dict")
193
+ _decorator_logger.info(f" - CONFIG['ID']: {CONFIG['ID']}")
194
+ _decorator_logger.info(f" - CONFIG['SDIR_RUN']: {CONFIG['SDIR_RUN']}")
195
+ _decorator_logger.info(f" - CONFIG['PID']: {CONFIG['PID']}")
196
+ _decorator_logger.info(" • plt - matplotlib.pyplot (configured for session)")
197
+ _decorator_logger.info(" • COLORS - CustomColors (for consistent plotting)")
198
+ _decorator_logger.info(" • rng_manager - RandomStateManager (for reproducibility)")
199
+ _decorator_logger.info(" logger - SciTeX logger (configured for your script)")
200
+ _decorator_logger.info("=" * 60)
200
201
 
201
202
  # Run function
202
203
  exit_status = 0
@@ -235,10 +236,11 @@ def _run_with_session(
235
236
  if param_name in injection_map:
236
237
  filtered_kwargs[param_name] = injection_map[param_name]
237
238
 
238
- # Log injected arguments summary
239
- args_summary = {k: type(v).__name__ for k, v in filtered_kwargs.items()}
240
- _decorator_logger.info(f"Running {func.__name__} with injected parameters:")
241
- _decorator_logger.info(args_summary, pprint=True, indent=2)
239
+ # Log injected arguments summary (only in verbose mode)
240
+ if verbose:
241
+ args_summary = {k: type(v).__name__ for k, v in filtered_kwargs.items()}
242
+ _decorator_logger.info(f"Running {func.__name__} with injected parameters:")
243
+ _decorator_logger.info(args_summary, pprint=True, indent=2)
242
244
 
243
245
  # Execute function
244
246
  result = func(**filtered_kwargs)
@@ -123,20 +123,18 @@ def _print_header(
123
123
 
124
124
  _printc(
125
125
  (
126
- f"SciTeX v{_get_scitex_version()}\n"
127
- f"{ID} (PID: {PID})\n\n"
126
+ f"SciTeX v{_get_scitex_version()} | {ID} (PID: {PID})\n\n"
128
127
  f"{file}\n\n"
129
128
  f"{args_str}"
130
- # f"{args}"
131
129
  ),
132
130
  char="=",
133
131
  )
134
132
 
135
133
  sleep(1)
136
134
  if verbose:
137
- print(f"\n{'-' * 40}\n")
138
- pprint(configs.to_dict())
139
- print(f"\n{'-' * 40}\n")
135
+ from pprint import pformat
136
+ config_str = pformat(configs.to_dict())
137
+ logger.info(f"\n{'-' * 40}\n\n{config_str}\n\n{'-' * 40}\n")
140
138
  sleep(1)
141
139
 
142
140
 
@@ -579,11 +577,11 @@ def _process_timestamp(CONFIG, verbose=True):
579
577
  CONFIG["END_DATETIME"] - CONFIG["START_DATETIME"]
580
578
  )
581
579
  if verbose:
582
- print()
583
- print(f"START TIME: {CONFIG['START_DATETIME']}")
584
- print(f"END TIME: {CONFIG['END_DATETIME']}")
585
- print(f"RUN DURATION: {CONFIG['RUN_DURATION']}")
586
- print()
580
+ logger.info(
581
+ f"\nSTART TIME: {CONFIG['START_DATETIME']}\n"
582
+ f"END TIME: {CONFIG['END_DATETIME']}\n"
583
+ f"RUN DURATION: {CONFIG['RUN_DURATION']}\n"
584
+ )
587
585
 
588
586
  except Exception as e:
589
587
  print(e)
@@ -1,22 +1,23 @@
1
1
  #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
2
  # Timestamp: "2025-11-18 09:08:38 (ywatanabe)"
4
3
  # File: /home/ywatanabe/proj/scitex-code/src/scitex/session/template.py
5
4
 
6
5
 
7
6
  from pprint import pprint
8
- import scitex as stx
9
7
 
8
+ from scitex import INJECTED
9
+ from scitex.session import session
10
10
 
11
- @stx.session(verbose=False)
11
+
12
+ @session(verbose=False)
12
13
  def main(
13
14
  arg1=None,
14
15
  arg2=None,
15
- CONFIG=stx.INJECTED,
16
- plt=stx.INJECTED,
17
- COLORS=stx.INJECTED,
18
- rng_manager=stx.INJECTED,
19
- logger=stx.INJECTED,
16
+ CONFIG=INJECTED,
17
+ plt=INJECTED,
18
+ COLORS=INJECTED,
19
+ rng_manager=INJECTED,
20
+ logger=INJECTED,
20
21
  ):
21
22
  """Demonstration for scitex.session.session"""
22
23
  pprint(CONFIG)
scitex/sh/test_sh.py ADDED
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # Timestamp: "2025-10-29 07:23:59 (ywatanabe)"
4
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/sh/test_sh.py
5
+ # ----------------------------------------
6
+ from __future__ import annotations
7
+
8
+ import os
9
+
10
+ __FILE__ = (
11
+ "./src/scitex/sh/test_sh.py"
12
+ )
13
+ __DIR__ = os.path.dirname(__FILE__)
14
+ # ----------------------------------------
15
+
16
+ __FILE__ = __file__
17
+
18
+ import sys
19
+
20
+ import matplotlib.pyplot as plt
21
+
22
+ import scitex
23
+
24
+ CONFIG, sys.stdout, sys.stderr, plt, CC = scitex.session.start(
25
+ sys, plt, verbose=False
26
+ )
27
+
28
+ # Test 1: Basic list command
29
+ print("Test 1: Basic list command")
30
+ result = scitex.sh(["echo", "Hello World"], verbose=True)
31
+ print(f"Result: {result}\n")
32
+
33
+ # Test 2: String command should be rejected
34
+ print("Test 2: String command rejection")
35
+ try:
36
+ result = scitex.sh("echo 'Hello'")
37
+ print("ERROR: Should have raised TypeError")
38
+ except TypeError as ee:
39
+ print(f"Correctly rejected: {ee}\n")
40
+
41
+ # Test 3: sh_run convenience function
42
+ print("Test 3: sh_run convenience function")
43
+ result = scitex.sh_run(["ls", "-la"])
44
+ print(f"Success: {result['success']}, Exit code: {result['exit_code']}\n")
45
+
46
+ # Test 4: Error handling
47
+ print("Test 4: Error handling")
48
+ result = scitex.sh_run(["cat", "/nonexistent/file"], verbose=False)
49
+ print(f"Success: {result['success']}")
50
+ print(f"Exit code: {result['exit_code']}")
51
+ print(f"Stderr: {result['stderr']}\n")
52
+
53
+ # Test 5: Security - quote function
54
+ print("Test 5: Security - quote function")
55
+ from scitex.sh import quote
56
+
57
+ dangerous_input = "file; rm -rf /"
58
+ safe_quoted = quote(dangerous_input)
59
+ print(f"Original: {dangerous_input}")
60
+ print(f"Quoted: {safe_quoted}\n")
61
+
62
+ # Test 6: Security - null byte rejection
63
+ print("Test 6: Security - null byte rejection")
64
+ try:
65
+ scitex.sh(["echo", "test\0malicious"])
66
+ print("ERROR: Should have raised ValueError")
67
+ except ValueError as ee:
68
+ print(f"Correctly rejected: {ee}\n")
69
+
70
+ scitex.session.close(CONFIG, verbose=False, notify=False)
71
+
72
+ # EOF
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # Timestamp: "2025-10-29 07:24:00 (ywatanabe)"
4
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/sh/test_sh_simple.py
5
+ # ----------------------------------------
6
+ from __future__ import annotations
7
+
8
+ import os
9
+
10
+ __FILE__ = (
11
+ "./src/scitex/sh/test_sh_simple.py"
12
+ )
13
+ __DIR__ = os.path.dirname(__FILE__)
14
+ # ----------------------------------------
15
+
16
+ __FILE__ = __file__
17
+
18
+ import sys
19
+
20
+ sys.path.insert(0, "/home/ywatanabe/proj/scitex_repo/src")
21
+
22
+ from scitex.sh import quote, sh, sh_run
23
+
24
+ # Test 1: Basic list command
25
+ print("Test 1: Basic list command")
26
+ result = sh(["echo", "Hello World"], verbose=True)
27
+ print(f"Result: {result}\n")
28
+
29
+ # Test 2: String command should be rejected
30
+ print("Test 2: String command rejection")
31
+ try:
32
+ result = sh_run("echo test")
33
+ print("ERROR: Should have raised TypeError")
34
+ except TypeError as ee:
35
+ print(f"Correctly rejected: {ee}\n")
36
+
37
+ # Test 3: Error handling
38
+ print("Test 3: Error handling")
39
+ result = sh_run(["cat", "/nonexistent/file"], verbose=False)
40
+ print(f"Success: {result['success']}")
41
+ print(f"Exit code: {result['exit_code']}")
42
+ print(f"Stderr: {result['stderr'][:50]}\n")
43
+
44
+ # Test 4: Security - quote function
45
+ print("Test 4: Security - quote function")
46
+ dangerous_input = "file; rm -rf /"
47
+ safe_quoted = quote(dangerous_input)
48
+ print(f"Original: {dangerous_input}")
49
+ print(f"Quoted: {safe_quoted}\n")
50
+
51
+ # Test 5: Security - null byte rejection
52
+ print("Test 5: Security - null byte rejection")
53
+ try:
54
+ sh(["echo", "test\0malicious"])
55
+ print("ERROR: Should have raised ValueError")
56
+ except ValueError as ee:
57
+ print(f"Correctly rejected: {ee}\n")
58
+
59
+ print("All tests passed!")
60
+
61
+ # EOF
scitex/stats/__init__.py CHANGED
@@ -13,7 +13,6 @@ Organized submodules:
13
13
  - tests: Statistical tests (correlation, etc.)
14
14
  - descriptive: Descriptive statistics
15
15
  - utils: Formatters and normalizers
16
- - _schema: Core StatResult schema for standardized test results
17
16
 
18
17
  Quick Start (Auto Selection):
19
18
  ----------------------------
@@ -32,44 +31,168 @@ Quick Start (Auto Selection):
32
31
  """
33
32
 
34
33
  # Import organized submodules
35
- from . import auto
36
- from . import correct
37
- from . import effect_sizes
38
- from . import power
39
- from . import utils
40
- from . import posthoc
41
- from . import descriptive
42
- from . import tests
43
- from . import _schema
44
-
45
- # Export commonly used functions and classes for convenience
34
+ from . import auto, correct, descriptive, effect_sizes, posthoc, power, tests, utils
46
35
  from .descriptive import describe
47
- from ._schema import (
48
- StatResult,
49
- Position,
50
- StatStyling,
51
- StatPositioning,
52
- create_stat_result,
53
- )
36
+
37
+ # Check if torch is available for GPU acceleration
38
+ try:
39
+ import torch
40
+
41
+ TORCH_AVAILABLE = True
42
+ except ImportError:
43
+ TORCH_AVAILABLE = False
54
44
 
55
45
  # Export key auto module classes at top level for convenience
56
46
  from .auto import (
47
+ TEST_RULES,
57
48
  StatContext,
49
+ StatStyle,
58
50
  TestRule,
59
- TEST_RULES,
60
51
  check_applicable,
61
- recommend_tests,
52
+ format_test_line,
62
53
  get_menu_items,
63
- StatStyle,
64
54
  get_stat_style,
65
- format_test_line,
66
55
  p_to_stars,
56
+ recommend_tests,
67
57
  )
68
58
 
69
59
  # =============================================================================
70
- # .statsz Bundle Support
60
+ # Stats Schema - Use scitex.fts.Stats as single source of truth
71
61
  # =============================================================================
72
62
 
63
+ # For backward compatibility, re-export from fts
64
+ try:
65
+ from scitex.fts import Stats
66
+
67
+ FTS_AVAILABLE = True
68
+ except ImportError:
69
+ Stats = None
70
+ FTS_AVAILABLE = False
71
+
72
+
73
+ def test_result_to_stats(result: dict) -> "Stats":
74
+ """Convert test result dict to FTS Stats schema.
75
+
76
+ Parameters
77
+ ----------
78
+ result : dict
79
+ Test result dictionary. Supports both formats:
80
+
81
+ Legacy flat format (from examples):
82
+ - name: "Control vs Treatment"
83
+ - method: "t-test" # string
84
+ - p_value: 0.003
85
+ - effect_size: 1.21
86
+ - ci95: [0.5, 1.8]
87
+
88
+ New nested format (from test functions):
89
+ - method: {"name": "t-test", "variant": "independent"}
90
+ - results: {"statistic": 2.5, "statistic_name": "t", "p_value": 0.01}
91
+
92
+ Returns
93
+ -------
94
+ Stats
95
+ FTS Stats object suitable for bundle storage
96
+
97
+ Example
98
+ -------
99
+ >>> result = stats.t_test(x, y)
100
+ >>> fts_stats = stats.test_result_to_stats(result)
101
+ >>> bundle.stats = fts_stats
102
+ """
103
+ if not FTS_AVAILABLE:
104
+ raise ImportError("scitex.fts is required for Stats conversion")
105
+
106
+ import uuid
107
+
108
+ from scitex.fts._stats._dataclasses._Stats import (
109
+ Analysis,
110
+ EffectSize,
111
+ StatMethod,
112
+ )
113
+ from scitex.fts._stats._dataclasses._Stats import (
114
+ StatResult as FTSStatResult,
115
+ )
116
+
117
+ # Handle legacy flat format vs new nested format
118
+ method_data = result.get("method", {})
119
+ if isinstance(method_data, str):
120
+ # Legacy format: method is a string
121
+ method = StatMethod(
122
+ name=method_data,
123
+ variant=None,
124
+ parameters={},
125
+ )
126
+ # Legacy format has flat p_value, effect_size
127
+ effect_size = None
128
+ es_val = result.get("effect_size")
129
+ if es_val is not None:
130
+ ci = result.get("ci95", [])
131
+ effect_size = EffectSize(
132
+ name="d",
133
+ value=float(es_val),
134
+ ci_lower=ci[0] if len(ci) > 0 else None,
135
+ ci_upper=ci[1] if len(ci) > 1 else None,
136
+ )
137
+ stat_result = FTSStatResult(
138
+ statistic=result.get("statistic", 0.0),
139
+ statistic_name=result.get("statistic_name", ""),
140
+ p_value=result.get("p_value", 1.0),
141
+ df=result.get("df"),
142
+ effect_size=effect_size,
143
+ significant=result.get("p_value", 1.0) < 0.05,
144
+ alpha=0.05,
145
+ )
146
+ analysis_name = result.get("name", "comparison")
147
+ else:
148
+ # New nested format
149
+ method = StatMethod(
150
+ name=method_data.get("name", "unknown"),
151
+ variant=method_data.get("variant"),
152
+ parameters=method_data.get("parameters", {}),
153
+ )
154
+
155
+ # Build result
156
+ results_data = result.get("results", {})
157
+ effect_size = None
158
+ if "effect_size" in results_data:
159
+ es = results_data["effect_size"]
160
+ effect_size = EffectSize(
161
+ name=es.get("name", ""),
162
+ value=es.get("value", 0.0),
163
+ ci_lower=es.get("ci_lower"),
164
+ ci_upper=es.get("ci_upper"),
165
+ )
166
+
167
+ stat_result = FTSStatResult(
168
+ statistic=results_data.get("statistic", 0.0),
169
+ statistic_name=results_data.get("statistic_name", ""),
170
+ p_value=results_data.get("p_value", 1.0),
171
+ df=results_data.get("df"),
172
+ effect_size=effect_size,
173
+ significant=results_data.get("significant"),
174
+ alpha=results_data.get("alpha", 0.05),
175
+ )
176
+ analysis_name = result.get("name", "analysis")
177
+
178
+ # Build analysis (name stored in inputs for reference)
179
+ inputs = result.get("inputs", {})
180
+ inputs["comparison_name"] = analysis_name
181
+ analysis = Analysis(
182
+ result_id=str(uuid.uuid4()),
183
+ method=method,
184
+ results=stat_result,
185
+ inputs=inputs,
186
+ )
187
+
188
+ return Stats(analyses=[analysis])
189
+
190
+
191
+ # =============================================================================
192
+ # .statsz Bundle Support - Using FTS
193
+ # =============================================================================
194
+
195
+
73
196
  def save_statsz(
74
197
  comparisons,
75
198
  path,
@@ -77,22 +200,16 @@ def save_statsz(
77
200
  as_zip=False,
78
201
  ):
79
202
  """
80
- Save statistical results as a .statsz bundle.
203
+ Save statistical results as an FTS bundle.
81
204
 
82
205
  Parameters
83
206
  ----------
84
- comparisons : list of dict or list of StatResult
85
- List of comparison results. Each should have:
86
- - name: Comparison name (e.g., "Control vs Treatment")
87
- - method: Test method (e.g., "t-test")
88
- - p_value: P-value
89
- - effect_size: Effect size (optional)
90
- - ci95: 95% confidence interval (optional)
91
- - formatted: Star notation (optional)
207
+ comparisons : list of dict
208
+ List of comparison results.
92
209
  path : str or Path
93
- Output path (e.g., "comparison.statsz.d" or "comparison.statsz").
210
+ Output path (e.g., "results.zip").
94
211
  metadata : dict, optional
95
- Additional metadata (n, seed, bootstrap_iters, etc.).
212
+ Additional metadata.
96
213
  as_zip : bool, optional
97
214
  If True, save as ZIP archive (default: False).
98
215
 
@@ -100,83 +217,89 @@ def save_statsz(
100
217
  -------
101
218
  Path
102
219
  Path to saved bundle.
103
-
104
- Examples
105
- --------
106
- >>> import scitex.stats as sstats
107
- >>> comparisons = [
108
- ... {
109
- ... "name": "Control vs Treatment",
110
- ... "method": "t-test",
111
- ... "p_value": 0.003,
112
- ... "effect_size": 1.21,
113
- ... "ci95": [0.5, 1.8],
114
- ... "formatted": "**"
115
- ... }
116
- ... ]
117
- >>> sstats.save_statsz(comparisons, "results.statsz.d")
118
220
  """
119
221
  from pathlib import Path
120
- from scitex.io._bundle import save_bundle, BundleType
222
+
223
+ from scitex.fts import FTS
121
224
 
122
225
  p = Path(path)
226
+ if as_zip and not p.suffix == ".zip":
227
+ p = p.with_suffix(".zip")
123
228
 
124
- # Convert StatResult objects to dicts if needed
125
- comp_dicts = []
126
- for comp in comparisons:
127
- if hasattr(comp, 'to_dict'):
128
- comp_dicts.append(comp.to_dict())
129
- elif hasattr(comp, '__dict__'):
130
- comp_dicts.append(vars(comp))
131
- else:
132
- comp_dicts.append(comp)
229
+ # Create FTS bundle
230
+ bundle = FTS(p, create=True, node_type="stats")
133
231
 
134
- # Build spec
135
- spec = {
136
- 'schema': {'name': 'scitex.stats.stats', 'version': '1.0.0'},
137
- 'comparisons': comp_dicts,
138
- 'metadata': metadata or {},
139
- }
140
-
141
- bundle_data = {'spec': spec}
232
+ # Convert comparisons to Stats
233
+ if comparisons:
234
+ if isinstance(comparisons[0], dict):
235
+ # Convert list of dicts to Stats
236
+ stats = Stats(analyses=[])
237
+ for comp in comparisons:
238
+ analysis_stats = test_result_to_stats(comp)
239
+ stats.analyses.extend(analysis_stats.analyses)
240
+ bundle.stats = stats
241
+ else:
242
+ # Already Stats objects
243
+ bundle.stats = comparisons
142
244
 
143
- return save_bundle(bundle_data, p, bundle_type=BundleType.STATSZ, as_zip=as_zip)
245
+ bundle.save()
246
+ return p
144
247
 
145
248
 
146
249
  def load_statsz(path):
147
250
  """
148
- Load a .statsz bundle.
251
+ Load a stats bundle using FTS.
149
252
 
150
253
  Parameters
151
254
  ----------
152
255
  path : str or Path
153
- Path to .statsz bundle (directory or ZIP).
256
+ Path to bundle.
154
257
 
155
258
  Returns
156
259
  -------
157
260
  dict
158
- Stats data with:
159
- - 'comparisons': List of comparison dicts
160
- - 'metadata': Metadata dict
161
-
162
- Examples
163
- --------
164
- >>> stats = scitex.stats.load_statsz("results.statsz.d")
165
- >>> for comp in stats['comparisons']:
166
- ... print(f"{comp['name']}: p={comp['p_value']}")
261
+ Stats data with 'comparisons' and 'metadata'.
262
+ Each comparison is a flat dict with:
263
+ - name, method, p_value, effect_size, ci95, formatted
167
264
  """
168
- from scitex.io._bundle import load_bundle
265
+ from scitex.fts import FTS
266
+
267
+ bundle = FTS(path)
169
268
 
170
- bundle = load_bundle(path)
269
+ comparisons = []
270
+ if bundle.stats and bundle.stats.analyses:
271
+ for analysis in bundle.stats.analyses:
272
+ # Convert back to flat format for compatibility
273
+ ad = analysis.to_dict()
274
+ p_val = ad.get("results", {}).get("p_value", 1.0)
275
+ es_data = ad.get("results", {}).get("effect_size", {})
276
+ es_val = es_data.get("value", 0.0) if es_data else 0.0
277
+ ci = [es_data.get("ci_lower"), es_data.get("ci_upper")] if es_data else []
278
+ ci = [v for v in ci if v is not None]
171
279
 
172
- if bundle['type'] != 'statsz':
173
- raise ValueError(f"Not a .statsz bundle: {path}")
280
+ # Format p-value as stars
281
+ if p_val < 0.001:
282
+ formatted = "***"
283
+ elif p_val < 0.01:
284
+ formatted = "**"
285
+ elif p_val < 0.05:
286
+ formatted = "*"
287
+ else:
288
+ formatted = "ns"
174
289
 
175
- spec = bundle.get('spec', {})
290
+ flat = {
291
+ "name": ad.get("inputs", {}).get("comparison_name", "comparison"),
292
+ "method": ad.get("method", {}).get("name", "unknown"),
293
+ "p_value": p_val,
294
+ "effect_size": es_val,
295
+ "ci95": ci,
296
+ "formatted": formatted,
297
+ }
298
+ comparisons.append(flat)
176
299
 
177
300
  return {
178
- 'comparisons': spec.get('comparisons', []),
179
- 'metadata': spec.get('metadata', {}),
301
+ "comparisons": comparisons,
302
+ "metadata": bundle.node.to_dict() if bundle.node else {},
180
303
  }
181
304
 
182
305
 
@@ -184,20 +307,19 @@ __all__ = [
184
307
  # Main submodules
185
308
  "auto",
186
309
  "correct",
310
+ "descriptive",
187
311
  "effect_sizes",
188
312
  "power",
189
313
  "utils",
190
314
  "posthoc",
191
- "descriptive",
192
315
  "tests",
193
- "_schema",
194
- # Schema exports
316
+ # Descriptive convenience export
195
317
  "describe",
196
- "StatResult",
197
- "Position",
198
- "StatStyling",
199
- "StatPositioning",
200
- "create_stat_result",
318
+ # Torch availability flag (for GPU acceleration)
319
+ "TORCH_AVAILABLE",
320
+ # Stats schema (from FTS)
321
+ "Stats",
322
+ "FTS_AVAILABLE",
201
323
  # Auto module convenience exports
202
324
  "StatContext",
203
325
  "TestRule",
@@ -209,9 +331,11 @@ __all__ = [
209
331
  "get_stat_style",
210
332
  "format_test_line",
211
333
  "p_to_stars",
212
- # .statsz bundle
334
+ # Conversion utilities
335
+ "test_result_to_stats",
336
+ # Bundle functions
213
337
  "save_statsz",
214
338
  "load_statsz",
215
339
  ]
216
340
 
217
- __version__ = "2.1.0"
341
+ __version__ = "2.2.0"