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
scitex/bridge/__init__.py CHANGED
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
2
  # File: ./src/scitex/bridge/__init__.py
4
3
  # Time-stamp: "2024-12-09 09:30:00 (ywatanabe)"
5
4
  """
@@ -45,40 +44,47 @@ Usage:
45
44
  """
46
45
 
47
46
  # Stats ↔ Plt bridges
48
- from scitex.bridge._stats_plt import (
49
- add_stat_to_axes,
50
- extract_stats_from_axes,
51
- format_stat_for_plot,
47
+ # FigRecipe integration (optional)
48
+ from scitex.bridge._figrecipe import (
49
+ FIGRECIPE_AVAILABLE,
50
+ has_figrecipe,
51
+ load_recipe,
52
+ save_with_recipe,
52
53
  )
53
54
 
54
- # Stats ↔ Vis bridges
55
- from scitex.bridge._stats_vis import (
56
- stat_result_to_annotation,
57
- add_stats_to_figure_model,
58
- position_stat_annotation,
55
+ # High-level helpers
56
+ from scitex.bridge._helpers import (
57
+ add_stats_from_results,
59
58
  )
60
59
 
61
60
  # Plt ↔ Vis bridges
62
61
  from scitex.bridge._plt_vis import (
63
- figure_to_vis_model,
64
62
  axes_to_vis_axes,
65
- tracking_to_plot_configs,
66
63
  collect_figure_data,
67
- )
68
-
69
- # High-level helpers
70
- from scitex.bridge._helpers import (
71
- add_stats_from_results,
64
+ figure_to_vis_model,
65
+ tracking_to_plot_configs,
72
66
  )
73
67
 
74
68
  # Protocol versioning
75
69
  from scitex.bridge._protocol import (
76
70
  BRIDGE_PROTOCOL_VERSION,
71
+ COORDINATE_SYSTEMS,
77
72
  ProtocolInfo,
78
- check_protocol_compatibility,
79
73
  add_protocol_metadata,
74
+ check_protocol_compatibility,
80
75
  extract_protocol_metadata,
81
- COORDINATE_SYSTEMS,
76
+ )
77
+ from scitex.bridge._stats_plt import (
78
+ add_stat_to_axes,
79
+ extract_stats_from_axes,
80
+ format_stat_for_plot,
81
+ )
82
+
83
+ # Stats ↔ Vis bridges
84
+ from scitex.bridge._stats_vis import (
85
+ add_stats_to_figure_model,
86
+ position_stat_annotation,
87
+ stat_result_to_annotation,
82
88
  )
83
89
 
84
90
  __all__ = [
@@ -104,6 +110,11 @@ __all__ = [
104
110
  "collect_figure_data",
105
111
  # High-level helpers
106
112
  "add_stats_from_results",
113
+ # FigRecipe integration
114
+ "save_with_recipe",
115
+ "load_recipe",
116
+ "has_figrecipe",
117
+ "FIGRECIPE_AVAILABLE",
107
118
  ]
108
119
 
109
120
 
@@ -0,0 +1,245 @@
1
+ #!/usr/bin/env python3
2
+ """Bridge adapter for figrecipe integration.
3
+
4
+ This module provides functions to save figures with both:
5
+ - SigmaPlot-compatible CSV (scitex format)
6
+ - figrecipe YAML recipe (reproducible figures)
7
+
8
+ The FTS bundle structure:
9
+ figure/
10
+ ├── recipe.yaml # Source of truth (figrecipe format)
11
+ ├── recipe_data/ # Large arrays (if needed)
12
+ ├── plot.csv # SigmaPlot combined CSV (derived)
13
+ ├── plot.png # Primary image (derived)
14
+ └── meta.yaml # FTS metadata (optional)
15
+ """
16
+
17
+ from pathlib import Path
18
+ from typing import Any, Dict, Optional, Union
19
+
20
+ # Check figrecipe availability
21
+ try:
22
+ import figrecipe as fr
23
+ from figrecipe._serializer import save_recipe as _fr_save_recipe
24
+
25
+ FIGRECIPE_AVAILABLE = True
26
+ except ImportError:
27
+ FIGRECIPE_AVAILABLE = False
28
+
29
+
30
+ def save_with_recipe(
31
+ fig,
32
+ path: Union[str, Path],
33
+ include_csv: bool = True,
34
+ include_recipe: bool = True,
35
+ data_format: str = "csv",
36
+ dpi: int = 300,
37
+ **kwargs,
38
+ ) -> Dict[str, Path]:
39
+ """Save figure with both CSV and figrecipe recipe.
40
+
41
+ Parameters
42
+ ----------
43
+ fig : FigWrapper or matplotlib Figure
44
+ The figure to save.
45
+ path : str or Path
46
+ Output path. Can be:
47
+ - Directory path (creates bundle)
48
+ - File path with .zip extension (creates zip bundle)
49
+ - File path with image extension (saves image + sidecar files)
50
+ include_csv : bool
51
+ If True, save SigmaPlot-compatible CSV.
52
+ include_recipe : bool
53
+ If True, save figrecipe YAML recipe (requires figrecipe).
54
+ data_format : str
55
+ Format for recipe data: 'csv', 'npz', or 'inline'.
56
+ dpi : int
57
+ Resolution for image output.
58
+ **kwargs
59
+ Additional arguments passed to savefig.
60
+
61
+ Returns
62
+ -------
63
+ dict
64
+ Paths to saved files: {'image': Path, 'csv': Path, 'recipe': Path}
65
+ """
66
+ from scitex.fts._bundle._storage import get_storage
67
+
68
+ path = Path(path)
69
+ result = {}
70
+
71
+ # Determine if this is a bundle (directory or zip)
72
+ is_bundle = path.suffix == ".zip" or path.suffix == "" or path.is_dir()
73
+
74
+ if is_bundle:
75
+ # Create bundle storage
76
+ storage = get_storage(path)
77
+ storage.ensure_exists()
78
+
79
+ # Get underlying matplotlib figure
80
+ mpl_fig = fig._fig_mpl if hasattr(fig, "_fig_mpl") else fig
81
+
82
+ # 1. Save image
83
+ image_path = storage.path / "plot.png"
84
+ mpl_fig.savefig(image_path, dpi=dpi, **kwargs)
85
+ result["image"] = image_path
86
+
87
+ # 2. Save SigmaPlot CSV
88
+ if include_csv and hasattr(fig, "export_as_csv"):
89
+ try:
90
+ csv_df = fig.export_as_csv()
91
+ if not csv_df.empty:
92
+ csv_path = storage.path / "plot.csv"
93
+ csv_df.to_csv(csv_path, index=False)
94
+ result["csv"] = csv_path
95
+ except Exception:
96
+ pass # CSV export is optional
97
+
98
+ # 3. Save figrecipe recipe
99
+ if include_recipe:
100
+ recipe_path = _save_recipe_to_path(
101
+ fig, storage.path / "recipe.yaml", data_format
102
+ )
103
+ if recipe_path:
104
+ result["recipe"] = recipe_path
105
+
106
+ else:
107
+ # Single file save (image + sidecars)
108
+ mpl_fig = fig._fig_mpl if hasattr(fig, "_fig_mpl") else fig
109
+ mpl_fig.savefig(path, dpi=dpi, **kwargs)
110
+ result["image"] = path
111
+
112
+ # Save CSV sidecar
113
+ if include_csv and hasattr(fig, "export_as_csv"):
114
+ try:
115
+ csv_df = fig.export_as_csv()
116
+ if not csv_df.empty:
117
+ csv_path = path.with_suffix(".csv")
118
+ csv_df.to_csv(csv_path, index=False)
119
+ result["csv"] = csv_path
120
+ except Exception:
121
+ pass
122
+
123
+ # Save recipe sidecar
124
+ if include_recipe:
125
+ recipe_path = _save_recipe_to_path(
126
+ fig, path.with_suffix(".yaml"), data_format
127
+ )
128
+ if recipe_path:
129
+ result["recipe"] = recipe_path
130
+
131
+ return result
132
+
133
+
134
+ def _save_recipe_to_path(
135
+ fig,
136
+ path: Path,
137
+ data_format: str = "csv",
138
+ ) -> Optional[Path]:
139
+ """Save figrecipe recipe if available.
140
+
141
+ Parameters
142
+ ----------
143
+ fig : FigWrapper
144
+ Figure with optional _figrecipe_recorder attribute.
145
+ path : Path
146
+ Output path for recipe.yaml.
147
+ data_format : str
148
+ Format for data: 'csv', 'npz', or 'inline'.
149
+
150
+ Returns
151
+ -------
152
+ Path or None
153
+ Path to saved recipe, or None if not available.
154
+ """
155
+ if not FIGRECIPE_AVAILABLE:
156
+ return None
157
+
158
+ try:
159
+ # Check if figure has figrecipe recorder
160
+ if hasattr(fig, "_figrecipe_recorder") and fig._figrecipe_enabled:
161
+ recorder = fig._figrecipe_recorder
162
+ figure_record = recorder.figure_record
163
+
164
+ # Capture current figure state into record
165
+ _capture_figure_state(fig, figure_record)
166
+
167
+ # Save using figrecipe's serializer
168
+ _fr_save_recipe(
169
+ figure_record, path, include_data=True, data_format=data_format
170
+ )
171
+ return path
172
+
173
+ # Alternative: if figure was created with fr.subplots() directly
174
+ if hasattr(fig, "save_recipe"):
175
+ fig.save_recipe(path, include_data=True, data_format=data_format)
176
+ return path
177
+
178
+ except Exception:
179
+ pass # Recipe saving is optional
180
+
181
+ return None
182
+
183
+
184
+ def _capture_figure_state(fig, figure_record):
185
+ """Capture current figure state into the record.
186
+
187
+ This syncs the matplotlib figure state with the figrecipe record,
188
+ ensuring the recipe reflects the final figure appearance.
189
+ """
190
+ try:
191
+ mpl_fig = fig._fig_mpl if hasattr(fig, "_fig_mpl") else fig
192
+
193
+ # Update figure dimensions
194
+ figsize = mpl_fig.get_size_inches()
195
+ figure_record.figsize = list(figsize)
196
+ figure_record.dpi = int(mpl_fig.dpi)
197
+
198
+ # Capture style from scitex metadata if available
199
+ if hasattr(mpl_fig, "_scitex_theme"):
200
+ if not hasattr(figure_record, "style") or figure_record.style is None:
201
+ figure_record.style = {}
202
+ figure_record.style["theme"] = mpl_fig._scitex_theme
203
+
204
+ except Exception:
205
+ pass # Non-critical
206
+
207
+
208
+ def load_recipe(
209
+ path: Union[str, Path],
210
+ ) -> Any:
211
+ """Load figrecipe recipe from FTS bundle.
212
+
213
+ Parameters
214
+ ----------
215
+ path : str or Path
216
+ Path to bundle directory, zip file, or recipe.yaml.
217
+
218
+ Returns
219
+ -------
220
+ tuple
221
+ (fig, axes) reproduced from recipe.
222
+ """
223
+ if not FIGRECIPE_AVAILABLE:
224
+ raise ImportError("figrecipe is required for loading recipes")
225
+
226
+ path = Path(path)
227
+
228
+ # Handle bundle paths
229
+ if path.is_dir():
230
+ recipe_path = path / "recipe.yaml"
231
+ elif path.suffix == ".zip":
232
+ # figrecipe can handle zip files directly
233
+ recipe_path = path
234
+ else:
235
+ recipe_path = path
236
+
237
+ return fr.reproduce(recipe_path)
238
+
239
+
240
+ def has_figrecipe() -> bool:
241
+ """Check if figrecipe is available."""
242
+ return FIGRECIPE_AVAILABLE
243
+
244
+
245
+ # EOF
scitex/bridge/_helpers.py CHANGED
@@ -11,7 +11,8 @@ multiple modules, abstracting away backend-specific details.
11
11
 
12
12
  from typing import Union, List, Optional, Literal
13
13
 
14
- from scitex.schema import StatResult
14
+ # StatResult is now a dict - the GUI-specific StatResult is deprecated
15
+ StatResult = dict
15
16
 
16
17
 
17
18
  def add_stats_from_results(
scitex/bridge/_plt_vis.py CHANGED
@@ -14,16 +14,29 @@ Provides adapters to:
14
14
  from typing import Optional, Dict, Any, List, Tuple, Union
15
15
  import warnings
16
16
 
17
- from scitex.fig.model import (
18
- FigureModel,
19
- AxesModel,
20
- PlotModel,
21
- AnnotationModel,
22
- GuideModel,
23
- PlotStyle,
24
- AxesStyle,
25
- TextStyle,
26
- )
17
+ # Legacy model imports - may not be available (deleted module)
18
+ try:
19
+ from scitex.fig.model import (
20
+ FigureModel,
21
+ AxesModel,
22
+ PlotModel,
23
+ AnnotationModel,
24
+ GuideModel,
25
+ PlotStyle,
26
+ AxesStyle,
27
+ TextStyle,
28
+ )
29
+ VIS_MODEL_AVAILABLE = True
30
+ except ImportError:
31
+ FigureModel = None
32
+ AxesModel = None
33
+ PlotModel = None
34
+ AnnotationModel = None
35
+ GuideModel = None
36
+ PlotStyle = None
37
+ AxesStyle = None
38
+ TextStyle = None
39
+ VIS_MODEL_AVAILABLE = False
27
40
 
28
41
 
29
42
  def figure_to_vis_model(
@@ -28,7 +28,11 @@ the caller intends (typically data coordinates unless transform is set).
28
28
  from typing import Optional, Dict, Any, Union, List
29
29
  import warnings
30
30
 
31
- from scitex.schema import StatResult, Position
31
+ # Import GUI classes from FTS (single source of truth)
32
+ from scitex.fts._stats import Position
33
+
34
+ # StatResult is now a dict - the GUI-specific StatResult is deprecated
35
+ StatResult = dict
32
36
 
33
37
 
34
38
  def format_stat_for_plot(
@@ -205,10 +209,19 @@ def _parse_stat_annotation(text: str) -> Optional[StatResult]:
205
209
  Optional[StatResult]
206
210
  Parsed StatResult or None if not parseable
207
211
  """
208
- from scitex.schema import create_stat_result
209
-
210
212
  text = text.strip()
211
213
 
214
+ def _create_stat_dict(test_type, statistic_name, statistic_value, p_value):
215
+ """Create a simple stat result dict."""
216
+ from scitex.stats.utils import p2stars
217
+ return {
218
+ "test_type": test_type,
219
+ "test_category": "other",
220
+ "statistic": {"name": statistic_name, "value": statistic_value},
221
+ "p_value": p_value,
222
+ "stars": p2stars(p_value, ns_symbol=False),
223
+ }
224
+
212
225
  # Try to detect asterisks pattern
213
226
  if text in ["*", "**", "***", "ns", "n.s."]:
214
227
  stars = text.replace("n.s.", "ns")
@@ -219,7 +232,7 @@ def _parse_stat_annotation(text: str) -> Optional[StatResult]:
219
232
  "*": 0.03,
220
233
  "ns": 0.5,
221
234
  }.get(stars, 0.5)
222
- return create_stat_result(
235
+ return _create_stat_dict(
223
236
  test_type="unknown",
224
237
  statistic_name="stat",
225
238
  statistic_value=0.0,
@@ -241,7 +254,7 @@ def _parse_stat_annotation(text: str) -> Optional[StatResult]:
241
254
  "*": 0.03,
242
255
  "ns": 0.5,
243
256
  }.get(stars, 0.5)
244
- return create_stat_result(
257
+ return _create_stat_dict(
245
258
  test_type="unknown",
246
259
  statistic_name=stat_name,
247
260
  statistic_value=stat_value,
@@ -26,8 +26,22 @@ When bridging between plt and vis, coordinate transformation may be needed.
26
26
 
27
27
  from typing import Optional, Dict, Any, List, Tuple
28
28
 
29
- from scitex.schema import StatResult, Position, StatPositioning
30
- from scitex.fig.model import AnnotationModel, FigureModel, AxesModel, TextStyle
29
+ # Import GUI classes from FTS (single source of truth)
30
+ from scitex.fts._stats import Position, StatPositioning
31
+
32
+ # Legacy model imports - may not be available
33
+ try:
34
+ from scitex.fig.model import AnnotationModel, FigureModel, AxesModel, TextStyle
35
+ VIS_MODEL_AVAILABLE = True
36
+ except ImportError:
37
+ AnnotationModel = None
38
+ FigureModel = None
39
+ AxesModel = None
40
+ TextStyle = None
41
+ VIS_MODEL_AVAILABLE = False
42
+
43
+ # StatResult placeholder for type hints (actual usage is through dict)
44
+ StatResult = dict # Use dict as StatResult is deprecated
31
45
 
32
46
 
33
47
  def stat_result_to_annotation(
@@ -1,56 +1,96 @@
1
1
  #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
2
  # SciTeX Browser Utilities - Universal Playwright helpers organized by category
4
3
  # ----------------------------------------
5
4
 
5
+ # All browser utilities require playwright - make them optional
6
+
6
7
  # Debugging utilities
7
- from .debugging import (
8
- browser_logger,
9
- show_grid_async,
10
- highlight_element_async,
11
- # Visual cursor/feedback utilities (sync and async)
12
- inject_visual_effects,
13
- inject_visual_effects_async,
14
- show_cursor_at,
15
- show_cursor_at_async,
16
- show_click_effect,
17
- show_click_effect_async,
18
- show_step,
19
- show_step_async,
20
- show_test_result,
21
- show_test_result_async,
22
- # Failure capture utilities (mirrors console-interceptor.ts)
23
- setup_console_interceptor,
24
- collect_console_logs,
25
- collect_console_logs_detailed,
26
- format_logs_devtools_style,
27
- save_failure_artifacts,
28
- create_failure_capture_fixture,
29
- # Test monitoring (periodic screenshots via scitex.capture)
30
- TestMonitor,
31
- create_test_monitor_fixture,
32
- monitor_test,
33
- # Sync browser session for zombie prevention
34
- SyncBrowserSession,
35
- sync_browser_session,
36
- create_browser_session_fixture,
37
- )
8
+ try:
9
+ from .debugging import (
10
+ # Sync browser session for zombie prevention
11
+ SyncBrowserSession,
12
+ # Test monitoring (periodic screenshots via scitex.capture)
13
+ TestMonitor,
14
+ browser_logger,
15
+ collect_console_logs,
16
+ collect_console_logs_detailed,
17
+ create_browser_session_fixture,
18
+ create_failure_capture_fixture,
19
+ create_test_monitor_fixture,
20
+ format_logs_devtools_style,
21
+ highlight_element_async,
22
+ # Visual cursor/feedback utilities (sync and async)
23
+ inject_visual_effects,
24
+ inject_visual_effects_async,
25
+ monitor_test,
26
+ save_failure_artifacts,
27
+ # Failure capture utilities (mirrors console-interceptor.ts)
28
+ setup_console_interceptor,
29
+ show_click_effect,
30
+ show_click_effect_async,
31
+ show_cursor_at,
32
+ show_cursor_at_async,
33
+ show_grid_async,
34
+ show_step,
35
+ show_step_async,
36
+ show_test_result,
37
+ show_test_result_async,
38
+ sync_browser_session,
39
+ )
40
+ except ImportError:
41
+ browser_logger = None
42
+ show_grid_async = None
43
+ highlight_element_async = None
44
+ inject_visual_effects = None
45
+ inject_visual_effects_async = None
46
+ show_cursor_at = None
47
+ show_cursor_at_async = None
48
+ show_click_effect = None
49
+ show_click_effect_async = None
50
+ show_step = None
51
+ show_step_async = None
52
+ show_test_result = None
53
+ show_test_result_async = None
54
+ setup_console_interceptor = None
55
+ collect_console_logs = None
56
+ collect_console_logs_detailed = None
57
+ format_logs_devtools_style = None
58
+ save_failure_artifacts = None
59
+ create_failure_capture_fixture = None
60
+ TestMonitor = None
61
+ create_test_monitor_fixture = None
62
+ monitor_test = None
63
+ SyncBrowserSession = None
64
+ sync_browser_session = None
65
+ create_browser_session_fixture = None
38
66
 
39
67
  # PDF utilities
40
- from .pdf import (
41
- detect_chrome_pdf_viewer_async,
42
- click_download_for_chrome_pdf_viewer_async,
43
- )
68
+ try:
69
+ from .pdf import (
70
+ click_download_for_chrome_pdf_viewer_async,
71
+ detect_chrome_pdf_viewer_async,
72
+ )
73
+ except ImportError:
74
+ detect_chrome_pdf_viewer_async = None
75
+ click_download_for_chrome_pdf_viewer_async = None
44
76
 
45
77
  # Interaction utilities
46
- from .interaction import (
47
- click_center_async,
48
- click_with_fallbacks_async,
49
- fill_with_fallbacks_async,
50
- PopupHandler,
51
- close_popups_async,
52
- ensure_no_popups_async,
53
- )
78
+ try:
79
+ from .interaction import (
80
+ PopupHandler,
81
+ click_center_async,
82
+ click_with_fallbacks_async,
83
+ close_popups_async,
84
+ ensure_no_popups_async,
85
+ fill_with_fallbacks_async,
86
+ )
87
+ except ImportError:
88
+ click_center_async = None
89
+ click_with_fallbacks_async = None
90
+ fill_with_fallbacks_async = None
91
+ PopupHandler = None
92
+ close_popups_async = None
93
+ ensure_no_popups_async = None
54
94
 
55
95
  __all__ = [
56
96
  # Debugging
@@ -1,6 +1,10 @@
1
1
  """Browser automation utilities."""
2
2
 
3
- from .CookieHandler import CookieAutoAcceptor
3
+ # Optional: CookieAutoAcceptor requires playwright
4
+ try:
5
+ from .CookieHandler import CookieAutoAcceptor
6
+ except ImportError:
7
+ CookieAutoAcceptor = None
4
8
 
5
9
  __all__ = [
6
10
  "CookieAutoAcceptor",
@@ -1,19 +1,31 @@
1
1
  #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
2
  # Timestamp: "2025-08-07 20:04:42 (ywatanabe)"
4
3
  # File: /home/ywatanabe/proj/scitex_repo/src/scitex/scholar/browser/local/_BrowserMixin.py
5
4
  # ----------------------------------------
6
5
  from __future__ import annotations
6
+
7
7
  import os
8
8
 
9
9
  __FILE__ = __file__
10
10
  __DIR__ = os.path.dirname(__FILE__)
11
11
  # ----------------------------------------
12
12
 
13
- import aiohttp
14
- from playwright.async_api import Browser, async_playwright
13
+ # Optional dependencies - browser module requires these
14
+ try:
15
+ import aiohttp
16
+ except ImportError:
17
+ aiohttp = None
18
+
19
+ try:
20
+ from playwright.async_api import Browser, async_playwright
21
+ except ImportError:
22
+ Browser = None
23
+ async_playwright = None
15
24
 
16
- from scitex.browser.automation import CookieAutoAcceptor
25
+ try:
26
+ from scitex.browser.automation import CookieAutoAcceptor
27
+ except ImportError:
28
+ CookieAutoAcceptor = None
17
29
 
18
30
 
19
31
  class BrowserMixin:
@@ -236,6 +248,7 @@ class BrowserMixin:
236
248
  def main(args):
237
249
  """Demonstrate BrowserMixin functionality."""
238
250
  import asyncio
251
+
239
252
  from scitex.browser.core import BrowserMixin
240
253
 
241
254
  class DemoBrowser(BrowserMixin):
@@ -1,7 +1,16 @@
1
1
  """Core browser management components."""
2
2
 
3
- from .BrowserMixin import BrowserMixin
4
- from .ChromeProfileManager import ChromeProfileManager
3
+ # Optional: BrowserMixin requires playwright
4
+ try:
5
+ from .BrowserMixin import BrowserMixin
6
+ except ImportError:
7
+ BrowserMixin = None
8
+
9
+ # Optional: ChromeProfileManager may have dependencies
10
+ try:
11
+ from .ChromeProfileManager import ChromeProfileManager
12
+ except ImportError:
13
+ ChromeProfileManager = None
5
14
 
6
15
  __all__ = [
7
16
  "BrowserMixin",
@@ -40,7 +40,7 @@ import aiohttp
40
40
  import json
41
41
 
42
42
  from scitex import logging
43
- from scitex.errors import ScholarError
43
+ from scitex.logging import ScholarError
44
44
 
45
45
  logger = logging.getLogger(__name__)
46
46