scitex 2.10.3__py3-none-any.whl → 2.13.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 (504) hide show
  1. scitex/__init__.py +1 -4
  2. scitex/__main__.py +24 -5
  3. scitex/__version__.py +1 -1
  4. scitex/_install_guide.py +14 -2
  5. scitex/_optional_deps.py +33 -0
  6. scitex/ai/classification/reporters/_ClassificationReporter.py +1 -1
  7. scitex/ai/classification/timeseries/_TimeSeriesBlockingSplit.py +2 -2
  8. scitex/ai/classification/timeseries/_TimeSeriesCalendarSplit.py +2 -2
  9. scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit.py +2 -2
  10. scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit_v01-not-using-n_splits.py +2 -2
  11. scitex/ai/classification/timeseries/_TimeSeriesStratifiedSplit.py +2 -2
  12. scitex/ai/classification/timeseries/_normalize_timestamp.py +1 -1
  13. scitex/ai/metrics/_calc_seizure_prediction_metrics.py +1 -1
  14. scitex/ai/plt/_plot_feature_importance.py +1 -1
  15. scitex/ai/plt/_plot_learning_curve.py +1 -1
  16. scitex/ai/plt/_plot_optuna_study.py +1 -1
  17. scitex/ai/plt/_plot_pre_rec_curve.py +1 -1
  18. scitex/ai/plt/_plot_roc_curve.py +1 -1
  19. scitex/ai/plt/_stx_conf_mat.py +1 -1
  20. scitex/ai/training/_LearningCurveLogger.py +1 -1
  21. scitex/audio/mcp_server.py +38 -8
  22. scitex/bridge/_figrecipe.py +1 -1
  23. scitex/bridge/_helpers.py +1 -1
  24. scitex/bridge/_plt_vis.py +1 -1
  25. scitex/bridge/_stats_plt.py +1 -1
  26. scitex/bridge/_stats_vis.py +2 -2
  27. scitex/browser/automation/CookieHandler.py +1 -1
  28. scitex/browser/core/BrowserMixin.py +1 -1
  29. scitex/browser/core/ChromeProfileManager.py +1 -1
  30. scitex/browser/debugging/_browser_logger.py +1 -1
  31. scitex/browser/debugging/_highlight_element.py +1 -1
  32. scitex/browser/debugging/_show_grid.py +1 -1
  33. scitex/browser/interaction/click_center.py +1 -1
  34. scitex/browser/interaction/click_with_fallbacks.py +1 -1
  35. scitex/browser/interaction/close_popups.py +1 -1
  36. scitex/browser/interaction/fill_with_fallbacks.py +1 -1
  37. scitex/browser/pdf/click_download_for_chrome_pdf_viewer.py +1 -1
  38. scitex/browser/pdf/detect_chrome_pdf_viewer.py +1 -1
  39. scitex/browser/stealth/HumanBehavior.py +1 -1
  40. scitex/browser/stealth/StealthManager.py +1 -1
  41. scitex/{fig → canvas}/__init__.py +84 -96
  42. scitex/canvas/_mcp_handlers.py +372 -0
  43. scitex/canvas/_mcp_tool_schemas.py +219 -0
  44. scitex/{fig → canvas}/backend/_parser.py +1 -1
  45. scitex/{fig → canvas}/canvas.py +13 -14
  46. scitex/{fts/_fig/_editor → canvas/editor}/_defaults.py +2 -2
  47. scitex/{fig → canvas}/editor/edit/__init__.py +11 -14
  48. scitex/{fig → canvas}/editor/edit/bundle_resolver.py +56 -48
  49. scitex/{fig → canvas}/editor/edit/editor_launcher.py +79 -26
  50. scitex/{fts/_fig/_editor/_cui/_panel_loader.py → canvas/editor/edit/panel_loader.py} +8 -8
  51. scitex/{fts/_fig/_editor/_gui/_flask_editor → canvas/editor/flask_editor}/_bbox.py +2 -1
  52. scitex/{fts/_fig/_editor/_gui/_flask_editor → canvas/editor/flask_editor}/_core.py +84 -84
  53. scitex/{fts/_fig/_editor/_gui/_flask_editor → canvas/editor/flask_editor}/_renderer.py +7 -6
  54. scitex/{fts/_fig/_editor/_gui/_flask_editor → canvas/editor/flask_editor}/static/css/features/canvas.css +2 -2
  55. scitex/{fig → canvas}/editor/flask_editor/static/css/features/panel-grid.css +1 -1
  56. scitex/{fig → canvas}/editor/flask_editor/static/js/core/api.js +3 -4
  57. scitex/{fig → canvas}/editor/flask_editor/static/js/editor/preview.js +5 -5
  58. scitex/{fig → canvas}/editor/flask_editor/templates/_html.py +3 -3
  59. scitex/{fig → canvas}/editor/flask_editor/templates/_scripts.py +10 -10
  60. scitex/{fig → canvas}/editor/flask_editor/templates/_styles.py +3 -3
  61. scitex/{fig → canvas}/io/__init__.py +32 -38
  62. scitex/{fig → canvas}/io/_bundle.py +217 -154
  63. scitex/{fig → canvas}/io/_canvas.py +1 -1
  64. scitex/{fig → canvas}/io/_data.py +1 -1
  65. scitex/{fig → canvas}/io/_export.py +1 -1
  66. scitex/{fig → canvas}/io/_load.py +1 -1
  67. scitex/{fig → canvas}/io/_panel.py +1 -1
  68. scitex/{fig → canvas}/io/_save.py +1 -1
  69. scitex/canvas/mcp_server.py +151 -0
  70. scitex/{fig → canvas}/model/__init__.py +1 -1
  71. scitex/{fig → canvas}/model/_annotations.py +1 -1
  72. scitex/{fig → canvas}/model/_axes.py +1 -1
  73. scitex/{fig → canvas}/model/_figure.py +1 -1
  74. scitex/{fig → canvas}/model/_guides.py +1 -1
  75. scitex/{fig → canvas}/model/_plot.py +1 -1
  76. scitex/{fig → canvas}/model/_styles.py +1 -1
  77. scitex/{fig → canvas}/utils/__init__.py +1 -1
  78. scitex/capture/mcp_server.py +41 -12
  79. scitex/cli/audio.py +233 -0
  80. scitex/cli/capture.py +307 -0
  81. scitex/cli/convert.py +10 -6
  82. scitex/cli/main.py +27 -4
  83. scitex/cli/repro.py +233 -0
  84. scitex/cli/resource.py +240 -0
  85. scitex/cli/stats.py +325 -0
  86. scitex/cli/template.py +236 -0
  87. scitex/cli/tex.py +286 -0
  88. scitex/cli/web.py +11 -12
  89. scitex/dev/__init__.py +3 -0
  90. scitex/dev/_pyproject.py +405 -0
  91. scitex/dev/plt/__init__.py +2 -2
  92. scitex/dev/plt/mpl/get_dir_ax.py +1 -1
  93. scitex/dev/plt/mpl/get_signatures.py +1 -1
  94. scitex/dev/plt/mpl/get_signatures_details.py +1 -1
  95. scitex/diagram/README.md +7 -7
  96. scitex/diagram/_mcp_handlers.py +400 -0
  97. scitex/diagram/_mcp_tool_schemas.py +157 -0
  98. scitex/diagram/mcp_server.py +151 -0
  99. scitex/dsp/_demo_sig.py +51 -5
  100. scitex/dsp/_mne.py +13 -2
  101. scitex/dsp/_modulation_index.py +15 -3
  102. scitex/dsp/_pac.py +23 -5
  103. scitex/dsp/_psd.py +16 -4
  104. scitex/dsp/_resample.py +24 -4
  105. scitex/dsp/_transform.py +16 -3
  106. scitex/dsp/add_noise.py +15 -1
  107. scitex/dsp/norm.py +17 -2
  108. scitex/dsp/reference.py +17 -1
  109. scitex/dsp/utils/_differential_bandpass_filters.py +20 -2
  110. scitex/dsp/utils/_zero_pad.py +18 -4
  111. scitex/dt/_normalize_timestamp.py +1 -1
  112. scitex/git/_session.py +1 -1
  113. scitex/io/__init__.py +7 -19
  114. scitex/io/_load.py +15 -19
  115. scitex/io/_load_modules/_canvas.py +2 -2
  116. scitex/io/_load_modules/_con.py +17 -6
  117. scitex/io/_load_modules/_eeg.py +28 -13
  118. scitex/io/_load_modules/_optuna.py +21 -63
  119. scitex/io/_load_modules/_torch.py +11 -3
  120. scitex/io/_save.py +11 -16
  121. scitex/io/_save_modules/__init__.py +6 -10
  122. scitex/io/_save_modules/_canvas.py +3 -3
  123. scitex/io/_save_modules/_optuna_study_as_csv_and_pngs.py +13 -2
  124. scitex/io/_save_modules/_plot_bundle.py +112 -0
  125. scitex/io/_save_modules/{_pltz_stx.py → _plot_scitex.py} +7 -7
  126. scitex/io/_save_modules/_stx_bundle.py +16 -16
  127. scitex/io/_save_modules/_torch.py +11 -3
  128. scitex/io/bundle/README.md +89 -80
  129. scitex/{fts/_bundle/_FTS.py → io/bundle/_Bundle.py} +197 -95
  130. scitex/io/bundle/__init__.py +67 -35
  131. scitex/{fts/_bundle → io/bundle}/_children.py +32 -40
  132. scitex/io/bundle/_core.py +184 -97
  133. scitex/{fts/_bundle/_dataclasses/_Node.py → io/bundle/_dataclasses/_Spec.py} +29 -23
  134. scitex/{fts/_bundle/_dataclasses/_NodeRefs.py → io/bundle/_dataclasses/_SpecRefs.py} +6 -6
  135. scitex/{fts/_bundle → io/bundle}/_dataclasses/__init__.py +4 -4
  136. scitex/{fts/_bundle → io/bundle}/_loader.py +19 -19
  137. scitex/io/bundle/_manifest.py +99 -0
  138. scitex/{fts/_bundle → io/bundle}/_mpl_helpers.py +119 -28
  139. scitex/io/bundle/_nested.py +113 -100
  140. scitex/{fts/_bundle → io/bundle}/_saver.py +13 -14
  141. scitex/{fts/_bundle → io/bundle}/_storage.py +3 -3
  142. scitex/io/bundle/_types.py +41 -16
  143. scitex/{fts/_bundle → io/bundle}/_validation.py +20 -18
  144. scitex/io/bundle/_zip.py +21 -31
  145. scitex/{fts/_kinds → io/bundle/kinds}/_plot/_backend/_parser.py +1 -1
  146. scitex/{fts/_kinds → io/bundle/kinds}/_plot/_models/_Annotations.py +1 -1
  147. scitex/{fts/_kinds → io/bundle/kinds}/_plot/_models/_Axes.py +1 -1
  148. scitex/{fts/_kinds → io/bundle/kinds}/_plot/_models/_Figure.py +1 -1
  149. scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_Guides.py +1 -1
  150. scitex/{fts/_kinds → io/bundle/kinds}/_plot/_models/_Plot.py +1 -1
  151. scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_Styles.py +1 -1
  152. scitex/{fts/_kinds → io/bundle/kinds}/_plot/_utils/_plot_layout.py +1 -1
  153. scitex/{fts/_kinds → io/bundle/kinds}/_table/_latex/__init__.py +1 -1
  154. scitex/{fts/_kinds → io/bundle/kinds}/_table/_latex/_editor/_app.py +1 -1
  155. scitex/{fts/_tables → io/bundle/kinds/_table}/_latex/_export.py +1 -1
  156. scitex/{fts/_kinds → io/bundle/kinds}/_table/_latex/_figure_exporter.py +1 -1
  157. scitex/{fts/_kinds → io/bundle/kinds}/_table/_latex/_table_exporter.py +1 -1
  158. scitex/io/bundle/schemas/__init__.py +30 -0
  159. scitex/mcp_server.py +159 -0
  160. scitex/parallel/_run.py +5 -4
  161. scitex/path/_find.py +60 -83
  162. scitex/path/_get_module_path.py +23 -21
  163. scitex/path/_get_spath.py +6 -27
  164. scitex/path/_getsize.py +23 -9
  165. scitex/path/_increment_version.py +31 -38
  166. scitex/path/_mk_spath.py +26 -29
  167. scitex/path/_path.py +5 -12
  168. scitex/path/_split.py +27 -15
  169. scitex/path/_this_path.py +23 -9
  170. scitex/plt/_mcp_handlers.py +361 -0
  171. scitex/plt/_mcp_tool_schemas.py +169 -0
  172. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/__init__.py +2 -1
  173. scitex/plt/_subplots/_AxisWrapperMixins/__init__.py +2 -2
  174. scitex/plt/gallery/_generate.py +76 -50
  175. scitex/plt/io/__init__.py +17 -19
  176. scitex/plt/io/_bundle.py +99 -52
  177. scitex/plt/io/_layered_bundle.py +303 -168
  178. scitex/plt/mcp_server.py +205 -0
  179. scitex/plt/utils/_csv_column_naming.py +250 -118
  180. scitex/repro/README_RandomStateManager.md +3 -3
  181. scitex/repro/_RandomStateManager.py +14 -14
  182. scitex/repro/_gen_ID.py +1 -1
  183. scitex/repro/_gen_timestamp.py +1 -1
  184. scitex/repro/_hash_array.py +4 -4
  185. scitex/schema/__init__.py +69 -73
  186. scitex/schema/_canvas.py +1 -1
  187. scitex/schema/_stats.py +2 -2
  188. scitex/scholar/__main__.py +24 -2
  189. scitex/scholar/_mcp_handlers.py +685 -0
  190. scitex/scholar/_mcp_tool_schemas.py +339 -0
  191. scitex/scholar/docs/template.py +1 -1
  192. scitex/scholar/examples/07_storage_integration.py +1 -1
  193. scitex/scholar/impact_factor/jcr/ImpactFactorJCREngine.py +1 -1
  194. scitex/scholar/impact_factor/jcr/build_database.py +1 -1
  195. scitex/scholar/mcp_server.py +315 -0
  196. scitex/scholar/pdf_download/ScholarPDFDownloader.py +1 -1
  197. scitex/scholar/pipelines/ScholarPipelineBibTeX.py +1 -1
  198. scitex/scholar/pipelines/ScholarPipelineParallel.py +1 -1
  199. scitex/scholar/pipelines/ScholarPipelineSingle.py +1 -1
  200. scitex/scholar/storage/PaperIO.py +1 -1
  201. scitex/session/README.md +4 -4
  202. scitex/session/__init__.py +1 -1
  203. scitex/session/_decorator.py +9 -9
  204. scitex/session/_lifecycle.py +5 -5
  205. scitex/session/template.py +1 -1
  206. scitex/stats/__init__.py +30 -33
  207. scitex/stats/__main__.py +281 -0
  208. scitex/stats/_mcp_handlers.py +1191 -0
  209. scitex/stats/_mcp_tool_schemas.py +384 -0
  210. scitex/stats/_schema.py +1 -1
  211. scitex/stats/correct/_correct_bonferroni.py +1 -1
  212. scitex/stats/correct/_correct_fdr.py +1 -1
  213. scitex/stats/correct/_correct_fdr_.py +1 -1
  214. scitex/stats/correct/_correct_holm.py +1 -1
  215. scitex/stats/correct/_correct_sidak.py +1 -1
  216. scitex/stats/effect_sizes/_cliffs_delta.py +1 -1
  217. scitex/stats/effect_sizes/_cohens_d.py +1 -1
  218. scitex/stats/effect_sizes/_epsilon_squared.py +1 -1
  219. scitex/stats/effect_sizes/_eta_squared.py +1 -1
  220. scitex/stats/effect_sizes/_prob_superiority.py +1 -1
  221. scitex/stats/io/__init__.py +10 -11
  222. scitex/stats/io/_bundle.py +16 -16
  223. scitex/stats/mcp_server.py +405 -0
  224. scitex/stats/posthoc/_dunnett.py +1 -1
  225. scitex/stats/posthoc/_games_howell.py +1 -1
  226. scitex/stats/posthoc/_tukey_hsd.py +1 -1
  227. scitex/stats/power/_power.py +1 -1
  228. scitex/stats/utils/_effect_size.py +1 -1
  229. scitex/stats/utils/_formatters.py +1 -1
  230. scitex/stats/utils/_power.py +1 -1
  231. scitex/template/_mcp_handlers.py +259 -0
  232. scitex/template/_mcp_tool_schemas.py +112 -0
  233. scitex/template/mcp_server.py +186 -0
  234. scitex/utils/_verify_scitex_format.py +2 -2
  235. scitex/utils/template.py +1 -1
  236. scitex/web/__init__.py +12 -11
  237. scitex/web/_scraping.py +26 -265
  238. scitex/web/download_images.py +316 -0
  239. scitex/writer/Writer.py +1 -1
  240. scitex/writer/_clone_writer_project.py +1 -1
  241. scitex/writer/_validate_tree_structures.py +1 -1
  242. scitex/writer/dataclasses/config/_WriterConfig.py +1 -1
  243. scitex/writer/dataclasses/contents/_ManuscriptContents.py +1 -1
  244. scitex/writer/dataclasses/core/_Document.py +1 -1
  245. scitex/writer/dataclasses/core/_DocumentSection.py +1 -1
  246. scitex/writer/dataclasses/results/_CompilationResult.py +1 -1
  247. scitex/writer/dataclasses/results/_LaTeXIssue.py +1 -1
  248. scitex/writer/utils/.legacy_git_retry.py +7 -5
  249. scitex/writer/utils/_parse_latex_logs.py +1 -1
  250. scitex-2.13.0.dist-info/METADATA +1231 -0
  251. {scitex-2.10.3.dist-info → scitex-2.13.0.dist-info}/RECORD +376 -470
  252. scitex-2.13.0.dist-info/entry_points.txt +11 -0
  253. scitex/fig/editor/_defaults.py +0 -300
  254. scitex/fig/editor/edit/panel_loader.py +0 -232
  255. scitex/fig/editor/flask_editor/_bbox.py +0 -1299
  256. scitex/fig/editor/flask_editor/_core.py +0 -1429
  257. scitex/fig/editor/flask_editor/_renderer.py +0 -813
  258. scitex/fig/editor/flask_editor/static/css/features/canvas.css +0 -176
  259. scitex/fts/README.md +0 -262
  260. scitex/fts/TODO.md +0 -66
  261. scitex/fts/__init__.py +0 -90
  262. scitex/fts/_bundle/README_IN_BUNDLE.md +0 -102
  263. scitex/fts/_bundle/__init__.py +0 -38
  264. scitex/fts/_bundle/_utils/__init__.py +0 -55
  265. scitex/fts/_bundle/_utils/_const.py +0 -26
  266. scitex/fts/_bundle/_utils/_errors.py +0 -73
  267. scitex/fts/_bundle/_utils/_generate.py +0 -21
  268. scitex/fts/_bundle/_utils/_types.py +0 -76
  269. scitex/fts/_bundle/_zipbundle.py +0 -165
  270. scitex/fts/_fig/__init__.py +0 -22
  271. scitex/fts/_fig/_backend/_parser.py +0 -188
  272. scitex/fts/_fig/_editor/__init__.py +0 -14
  273. scitex/fts/_fig/_editor/_cui/__init__.py +0 -33
  274. scitex/fts/_fig/_editor/_cui/_backend_detector.py +0 -39
  275. scitex/fts/_fig/_editor/_cui/_bundle_resolver.py +0 -366
  276. scitex/fts/_fig/_editor/_cui/_editor_launcher.py +0 -175
  277. scitex/fts/_fig/_editor/_cui/_manual_handler.py +0 -52
  278. scitex/fts/_fig/_editor/_cui/_path_resolver.py +0 -66
  279. scitex/fts/_fig/_editor/_gui/__init__.py +0 -11
  280. scitex/fts/_fig/_editor/_gui/_flask_editor/__init__.py +0 -20
  281. scitex/fts/_fig/_editor/_gui/_flask_editor/_plotter.py +0 -664
  282. scitex/fts/_fig/_editor/_gui/_flask_editor/_utils.py +0 -79
  283. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/base/reset.css +0 -41
  284. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/base/typography.css +0 -16
  285. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/base/variables.css +0 -85
  286. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/buttons.css +0 -217
  287. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/context-menu.css +0 -93
  288. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/dropdown.css +0 -57
  289. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/forms.css +0 -112
  290. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/modal.css +0 -59
  291. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/sections.css +0 -212
  292. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/element-inspector.css +0 -190
  293. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/loading.css +0 -59
  294. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/overlay.css +0 -45
  295. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/panel-grid.css +0 -95
  296. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/selection.css +0 -101
  297. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/statistics.css +0 -138
  298. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/index.css +0 -31
  299. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/layout/container.css +0 -7
  300. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/layout/controls.css +0 -56
  301. scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/layout/preview.css +0 -78
  302. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/alignment/axis.js +0 -314
  303. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/alignment/basic.js +0 -107
  304. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/alignment/distribute.js +0 -54
  305. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/canvas/canvas.js +0 -172
  306. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/canvas/dragging.js +0 -258
  307. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/canvas/resize.js +0 -48
  308. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/canvas/selection.js +0 -71
  309. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/core/api.js +0 -288
  310. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/core/state.js +0 -143
  311. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/core/utils.js +0 -245
  312. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/dev/element-inspector.js +0 -992
  313. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/editor/bbox.js +0 -339
  314. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/editor/element-drag.js +0 -286
  315. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/editor/overlay.js +0 -371
  316. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/editor/preview.js +0 -293
  317. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/main.js +0 -426
  318. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/shortcuts/context-menu.js +0 -152
  319. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/shortcuts/keyboard.js +0 -265
  320. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/ui/controls.js +0 -184
  321. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/ui/download.js +0 -57
  322. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/ui/help.js +0 -100
  323. scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/ui/theme.js +0 -34
  324. scitex/fts/_fig/_editor/_gui/_flask_editor/templates/__init__.py +0 -124
  325. scitex/fts/_fig/_editor/_gui/_flask_editor/templates/_html.py +0 -851
  326. scitex/fts/_fig/_editor/_gui/_flask_editor/templates/_scripts.py +0 -4932
  327. scitex/fts/_fig/_editor/_gui/_flask_editor/templates/_styles.py +0 -1657
  328. scitex/fts/_fig/_editor/_gui/_flask_editor.py +0 -36
  329. scitex/fts/_fig/_models/_Annotations.py +0 -115
  330. scitex/fts/_fig/_models/_Axes.py +0 -152
  331. scitex/fts/_fig/_models/_Figure.py +0 -138
  332. scitex/fts/_fig/_models/_Plot.py +0 -123
  333. scitex/fts/_fig/_utils/_plot_layout.py +0 -397
  334. scitex/fts/_kinds/_figure/_composite.py +0 -345
  335. scitex/fts/_kinds/_plot/_backend/__init__.py +0 -53
  336. scitex/fts/_kinds/_plot/_backend/_export.py +0 -165
  337. scitex/fts/_kinds/_plot/_backend/_render.py +0 -538
  338. scitex/fts/_kinds/_plot/_dataclasses/_ChannelEncoding.py +0 -46
  339. scitex/fts/_kinds/_plot/_dataclasses/_Encoding.py +0 -82
  340. scitex/fts/_kinds/_plot/_dataclasses/_Theme.py +0 -441
  341. scitex/fts/_kinds/_plot/_dataclasses/_TraceEncoding.py +0 -52
  342. scitex/fts/_kinds/_plot/_dataclasses/__init__.py +0 -47
  343. scitex/fts/_kinds/_plot/_models/_Guides.py +0 -104
  344. scitex/fts/_kinds/_plot/_models/_Styles.py +0 -245
  345. scitex/fts/_kinds/_plot/_models/__init__.py +0 -80
  346. scitex/fts/_kinds/_plot/_models/_plot_types/__init__.py +0 -156
  347. scitex/fts/_kinds/_plot/_models/_plot_types/_bar.py +0 -43
  348. scitex/fts/_kinds/_plot/_models/_plot_types/_box.py +0 -38
  349. scitex/fts/_kinds/_plot/_models/_plot_types/_distribution.py +0 -36
  350. scitex/fts/_kinds/_plot/_models/_plot_types/_errorbar.py +0 -60
  351. scitex/fts/_kinds/_plot/_models/_plot_types/_histogram.py +0 -30
  352. scitex/fts/_kinds/_plot/_models/_plot_types/_image.py +0 -61
  353. scitex/fts/_kinds/_plot/_models/_plot_types/_line.py +0 -57
  354. scitex/fts/_kinds/_plot/_models/_plot_types/_scatter.py +0 -30
  355. scitex/fts/_kinds/_plot/_models/_plot_types/_seaborn.py +0 -121
  356. scitex/fts/_kinds/_plot/_models/_plot_types/_violin.py +0 -36
  357. scitex/fts/_kinds/_plot/_utils/__init__.py +0 -129
  358. scitex/fts/_kinds/_plot/_utils/_auto_layout.py +0 -127
  359. scitex/fts/_kinds/_plot/_utils/_calc_bounds.py +0 -111
  360. scitex/fts/_kinds/_plot/_utils/_const_sizes.py +0 -48
  361. scitex/fts/_kinds/_plot/_utils/_convert_coords.py +0 -77
  362. scitex/fts/_kinds/_plot/_utils/_get_template.py +0 -178
  363. scitex/fts/_kinds/_plot/_utils/_normalize.py +0 -73
  364. scitex/fts/_kinds/_plot/_utils/_validate.py +0 -197
  365. scitex/fts/_kinds/_table/_latex/_export.py +0 -279
  366. scitex/fts/_stats/__init__.py +0 -48
  367. scitex/fts/_stats/_dataclasses/_Stats.py +0 -423
  368. scitex/fts/_stats/_dataclasses/__init__.py +0 -48
  369. scitex/fts/_tables/__init__.py +0 -65
  370. scitex/fts/_tables/_latex/__init__.py +0 -93
  371. scitex/fts/_tables/_latex/_editor/__init__.py +0 -11
  372. scitex/fts/_tables/_latex/_editor/_app.py +0 -725
  373. scitex/fts/_tables/_latex/_figure_exporter.py +0 -153
  374. scitex/fts/_tables/_latex/_stats_formatter.py +0 -274
  375. scitex/fts/_tables/_latex/_table_exporter.py +0 -362
  376. scitex/fts/_tables/_latex/_utils.py +0 -369
  377. scitex/fts/_tables/_latex/_validator.py +0 -445
  378. scitex/io/_save_modules/_pltz_bundle.py +0 -356
  379. scitex-2.10.3.dist-info/METADATA +0 -952
  380. scitex-2.10.3.dist-info/entry_points.txt +0 -2
  381. /scitex/{fig → canvas}/README.md +0 -0
  382. /scitex/{fig → canvas}/backend/__init__.py +0 -0
  383. /scitex/{fig → canvas}/backend/_export.py +0 -0
  384. /scitex/{fig → canvas}/backend/_render.py +0 -0
  385. /scitex/{fig → canvas}/docs/CANVAS_ARCHITECTURE.md +0 -0
  386. /scitex/{fig → canvas}/editor/__init__.py +0 -0
  387. /scitex/{fig → canvas}/editor/_dearpygui_editor.py +0 -0
  388. /scitex/{fig → canvas}/editor/_flask_editor.py +0 -0
  389. /scitex/{fig → canvas}/editor/_mpl_editor.py +0 -0
  390. /scitex/{fig → canvas}/editor/_qt_editor.py +0 -0
  391. /scitex/{fig → canvas}/editor/_tkinter_editor.py +0 -0
  392. /scitex/{fig → canvas}/editor/edit/backend_detector.py +0 -0
  393. /scitex/{fig → canvas}/editor/edit/manual_handler.py +0 -0
  394. /scitex/{fig → canvas}/editor/edit/path_resolver.py +0 -0
  395. /scitex/{fig → canvas}/editor/flask_editor/__init__.py +0 -0
  396. /scitex/{fig → canvas}/editor/flask_editor/_plotter.py +0 -0
  397. /scitex/{fig → canvas}/editor/flask_editor/_utils.py +0 -0
  398. /scitex/{fig → canvas}/editor/flask_editor/static/css/base/reset.css +0 -0
  399. /scitex/{fig → canvas}/editor/flask_editor/static/css/base/typography.css +0 -0
  400. /scitex/{fig → canvas}/editor/flask_editor/static/css/base/variables.css +0 -0
  401. /scitex/{fig → canvas}/editor/flask_editor/static/css/components/buttons.css +0 -0
  402. /scitex/{fig → canvas}/editor/flask_editor/static/css/components/context-menu.css +0 -0
  403. /scitex/{fig → canvas}/editor/flask_editor/static/css/components/dropdown.css +0 -0
  404. /scitex/{fig → canvas}/editor/flask_editor/static/css/components/forms.css +0 -0
  405. /scitex/{fig → canvas}/editor/flask_editor/static/css/components/modal.css +0 -0
  406. /scitex/{fig → canvas}/editor/flask_editor/static/css/components/sections.css +0 -0
  407. /scitex/{fig → canvas}/editor/flask_editor/static/css/features/element-inspector.css +0 -0
  408. /scitex/{fig → canvas}/editor/flask_editor/static/css/features/loading.css +0 -0
  409. /scitex/{fig → canvas}/editor/flask_editor/static/css/features/overlay.css +0 -0
  410. /scitex/{fig → canvas}/editor/flask_editor/static/css/features/selection.css +0 -0
  411. /scitex/{fig → canvas}/editor/flask_editor/static/css/features/statistics.css +0 -0
  412. /scitex/{fig → canvas}/editor/flask_editor/static/css/index.css +0 -0
  413. /scitex/{fig → canvas}/editor/flask_editor/static/css/layout/container.css +0 -0
  414. /scitex/{fig → canvas}/editor/flask_editor/static/css/layout/controls.css +0 -0
  415. /scitex/{fig → canvas}/editor/flask_editor/static/css/layout/preview.css +0 -0
  416. /scitex/{fig → canvas}/editor/flask_editor/static/js/alignment/axis.js +0 -0
  417. /scitex/{fig → canvas}/editor/flask_editor/static/js/alignment/basic.js +0 -0
  418. /scitex/{fig → canvas}/editor/flask_editor/static/js/alignment/distribute.js +0 -0
  419. /scitex/{fig → canvas}/editor/flask_editor/static/js/canvas/canvas.js +0 -0
  420. /scitex/{fig → canvas}/editor/flask_editor/static/js/canvas/dragging.js +0 -0
  421. /scitex/{fig → canvas}/editor/flask_editor/static/js/canvas/resize.js +0 -0
  422. /scitex/{fig → canvas}/editor/flask_editor/static/js/canvas/selection.js +0 -0
  423. /scitex/{fig → canvas}/editor/flask_editor/static/js/core/state.js +0 -0
  424. /scitex/{fig → canvas}/editor/flask_editor/static/js/core/utils.js +0 -0
  425. /scitex/{fig → canvas}/editor/flask_editor/static/js/dev/element-inspector.js +0 -0
  426. /scitex/{fig → canvas}/editor/flask_editor/static/js/editor/bbox.js +0 -0
  427. /scitex/{fig → canvas}/editor/flask_editor/static/js/editor/element-drag.js +0 -0
  428. /scitex/{fig → canvas}/editor/flask_editor/static/js/editor/overlay.js +0 -0
  429. /scitex/{fig → canvas}/editor/flask_editor/static/js/main.js +0 -0
  430. /scitex/{fig → canvas}/editor/flask_editor/static/js/shortcuts/context-menu.js +0 -0
  431. /scitex/{fig → canvas}/editor/flask_editor/static/js/shortcuts/keyboard.js +0 -0
  432. /scitex/{fig → canvas}/editor/flask_editor/static/js/ui/controls.js +0 -0
  433. /scitex/{fig → canvas}/editor/flask_editor/static/js/ui/download.js +0 -0
  434. /scitex/{fig → canvas}/editor/flask_editor/static/js/ui/help.js +0 -0
  435. /scitex/{fig → canvas}/editor/flask_editor/static/js/ui/theme.js +0 -0
  436. /scitex/{fig → canvas}/editor/flask_editor/templates/__init__.py +0 -0
  437. /scitex/{fig → canvas}/io/_directory.py +0 -0
  438. /scitex/{fig → canvas}/model/_plot_types.py +0 -0
  439. /scitex/{fig → canvas}/utils/_defaults.py +0 -0
  440. /scitex/{fig → canvas}/utils/_validate.py +0 -0
  441. /scitex/{fts/_bundle → io/bundle}/_conversion/__init__.py +0 -0
  442. /scitex/{fts/_bundle → io/bundle}/_conversion/_bundle2dict.py +0 -0
  443. /scitex/{fts/_bundle → io/bundle}/_conversion/_dict2bundle.py +0 -0
  444. /scitex/{fts/_bundle → io/bundle}/_dataclasses/_Axes.py +0 -0
  445. /scitex/{fts/_bundle → io/bundle}/_dataclasses/_BBox.py +0 -0
  446. /scitex/{fts/_bundle → io/bundle}/_dataclasses/_ColumnDef.py +0 -0
  447. /scitex/{fts/_bundle → io/bundle}/_dataclasses/_DataFormat.py +0 -0
  448. /scitex/{fts/_bundle → io/bundle}/_dataclasses/_DataInfo.py +0 -0
  449. /scitex/{fts/_bundle → io/bundle}/_dataclasses/_DataSource.py +0 -0
  450. /scitex/{fts/_bundle → io/bundle}/_dataclasses/_SizeMM.py +0 -0
  451. /scitex/{fts/_bundle → io/bundle}/_extractors/__init__.py +0 -0
  452. /scitex/{fts/_bundle → io/bundle}/_extractors/_extract_bar.py +0 -0
  453. /scitex/{fts/_bundle → io/bundle}/_extractors/_extract_line.py +0 -0
  454. /scitex/{fts/_bundle → io/bundle}/_extractors/_extract_scatter.py +0 -0
  455. /scitex/{fts/_kinds → io/bundle/kinds}/__init__.py +0 -0
  456. /scitex/{fts/_kinds → io/bundle/kinds}/_figure/__init__.py +0 -0
  457. /scitex/{fts/_fig → io/bundle/kinds/_figure}/_composite.py +0 -0
  458. /scitex/{fts/_kinds → io/bundle/kinds}/_plot/__init__.py +0 -0
  459. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_backend/__init__.py +0 -0
  460. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_backend/_export.py +0 -0
  461. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_backend/_render.py +0 -0
  462. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_dataclasses/_ChannelEncoding.py +0 -0
  463. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_dataclasses/_Encoding.py +0 -0
  464. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_dataclasses/_Theme.py +0 -0
  465. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_dataclasses/_TraceEncoding.py +0 -0
  466. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_dataclasses/__init__.py +0 -0
  467. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/__init__.py +0 -0
  468. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/__init__.py +0 -0
  469. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_bar.py +0 -0
  470. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_box.py +0 -0
  471. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_distribution.py +0 -0
  472. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_errorbar.py +0 -0
  473. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_histogram.py +0 -0
  474. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_image.py +0 -0
  475. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_line.py +0 -0
  476. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_scatter.py +0 -0
  477. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_seaborn.py +0 -0
  478. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_models/_plot_types/_violin.py +0 -0
  479. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_utils/__init__.py +0 -0
  480. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_utils/_auto_layout.py +0 -0
  481. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_utils/_calc_bounds.py +0 -0
  482. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_utils/_const_sizes.py +0 -0
  483. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_utils/_convert_coords.py +0 -0
  484. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_utils/_get_template.py +0 -0
  485. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_utils/_normalize.py +0 -0
  486. /scitex/{fts/_fig → io/bundle/kinds/_plot}/_utils/_validate.py +0 -0
  487. /scitex/{fts/_kinds → io/bundle/kinds}/_shape/__init__.py +0 -0
  488. /scitex/{fts/_kinds → io/bundle/kinds}/_stats/__init__.py +0 -0
  489. /scitex/{fts/_kinds → io/bundle/kinds}/_stats/_dataclasses/_Stats.py +0 -0
  490. /scitex/{fts/_kinds → io/bundle/kinds}/_stats/_dataclasses/__init__.py +0 -0
  491. /scitex/{fts/_kinds → io/bundle/kinds}/_table/__init__.py +0 -0
  492. /scitex/{fts/_kinds → io/bundle/kinds}/_table/_latex/_editor/__init__.py +0 -0
  493. /scitex/{fts/_kinds → io/bundle/kinds}/_table/_latex/_stats_formatter.py +0 -0
  494. /scitex/{fts/_kinds → io/bundle/kinds}/_table/_latex/_utils.py +0 -0
  495. /scitex/{fts/_kinds → io/bundle/kinds}/_table/_latex/_validator.py +0 -0
  496. /scitex/{fts/_kinds → io/bundle/kinds}/_text/__init__.py +0 -0
  497. /scitex/{fts/_schemas → io/bundle/schemas}/data_info.schema.json +0 -0
  498. /scitex/{fts/_schemas → io/bundle/schemas}/encoding.schema.json +0 -0
  499. /scitex/{fts/_schemas → io/bundle/schemas}/node.schema.json +0 -0
  500. /scitex/{fts/_schemas → io/bundle/schemas}/render_manifest.schema.json +0 -0
  501. /scitex/{fts/_schemas → io/bundle/schemas}/stats.schema.json +0 -0
  502. /scitex/{fts/_schemas → io/bundle/schemas}/theme.schema.json +0 -0
  503. {scitex-2.10.3.dist-info → scitex-2.13.0.dist-info}/WHEEL +0 -0
  504. {scitex-2.10.3.dist-info → scitex-2.13.0.dist-info}/licenses/LICENSE +0 -0
scitex/io/bundle/_core.py CHANGED
@@ -1,31 +1,24 @@
1
1
  #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- # Timestamp: "2025-12-16 (ywatanabe)"
4
- # File: /home/ywatanabe/proj/scitex-code/src/scitex/io/bundle/_core.py
2
+ # Timestamp: 2026-01-07
3
+ # File: src/scitex/io/bundle/_core.py
5
4
 
6
5
  """
7
6
  SciTeX Bundle Core Operations.
8
7
 
9
8
  Provides load, save, copy, pack, unpack, and validate operations for
10
- .figz, .pltz, and .statsz bundle formats.
9
+ .figure.zip, .plot.zip, .stats.zip bundle formats.
11
10
 
12
11
  Each bundle can exist in two forms:
13
- - Directory: Figure1.figz.d/
14
- - ZIP archive: Figure1.figz
12
+ - Directory: Figure1.figure/, plot.plot/, results.stats/
13
+ - ZIP archive: Figure1.figure.zip, plot.plot.zip, results.stats.zip
15
14
  """
16
15
 
17
- import json
18
16
  import shutil
19
17
  import zipfile
20
18
  from pathlib import Path
21
19
  from typing import Any, Dict, List, Optional, Union
22
20
 
23
- from ._types import (
24
- EXTENSIONS,
25
- BundleNotFoundError,
26
- BundleType,
27
- BundleValidationError,
28
- )
21
+ from ._types import EXTENSIONS, BundleNotFoundError, BundleType, BundleValidationError
29
22
 
30
23
  __all__ = [
31
24
  "load",
@@ -45,31 +38,99 @@ __all__ = [
45
38
  def get_type(path: Union[str, Path]) -> Optional[str]:
46
39
  """Get bundle type from path.
47
40
 
41
+ Checks manifest.json first for reliable type detection, then falls back
42
+ to extension-based detection.
43
+
48
44
  Args:
49
45
  path: Path to bundle (directory or ZIP).
50
46
 
51
47
  Returns:
52
- Bundle type string ('figz', 'pltz', 'statsz') or None if not a bundle.
48
+ Bundle type string ('figure', 'plot', 'stats') or None if not a bundle.
53
49
 
54
50
  Example:
55
- >>> get_type("Figure1.figz")
56
- 'figz'
57
- >>> get_type("plot.pltz.d")
58
- 'pltz'
51
+ >>> get_type("Figure1.figure.zip")
52
+ 'figure'
53
+ >>> get_type("plot.plot")
54
+ 'plot'
59
55
  """
60
56
  p = Path(path)
61
57
 
62
- # Directory bundle: ends with .figz.d, .pltz.d, .statsz.d
63
- if p.is_dir() and p.suffix == ".d":
64
- stem = p.stem # e.g., "Figure1.figz"
65
- for ext in EXTENSIONS:
66
- if stem.endswith(ext):
67
- return ext[1:] # Remove leading dot
68
- return None
58
+ if not p.exists():
59
+ # Fall back to extension-based detection for non-existent paths
60
+ return _get_type_from_extension(p)
61
+
62
+ # Try manifest.json first (most reliable)
63
+ manifest_type = _get_type_from_manifest(p)
64
+ if manifest_type:
65
+ return manifest_type
66
+
67
+ # Fall back to extension-based detection
68
+ return _get_type_from_extension(p)
69
69
 
70
- # ZIP bundle: ends with .figz, .pltz, .statsz
71
- if p.suffix in EXTENSIONS:
72
- return p.suffix[1:] # Remove leading dot
70
+
71
+ def _get_type_from_manifest(path: Path) -> Optional[str]:
72
+ """Get bundle type from manifest.json.
73
+
74
+ Args:
75
+ path: Path to bundle (directory or ZIP).
76
+
77
+ Returns:
78
+ Bundle type from manifest or None if not found.
79
+ """
80
+ import json
81
+
82
+ from ._types import EXTENSIONS
83
+
84
+ if path.is_dir():
85
+ # Directory bundle - read manifest.json directly
86
+ manifest_path = path / "manifest.json"
87
+ if manifest_path.exists():
88
+ try:
89
+ with open(manifest_path) as f:
90
+ manifest = json.load(f)
91
+ return manifest.get("scitex", {}).get("type")
92
+ except (OSError, json.JSONDecodeError):
93
+ pass
94
+ elif path.is_file():
95
+ # Check if it's a ZIP bundle by extension
96
+ name = path.name.lower()
97
+ is_zip_bundle = any(name.endswith(ext) for ext in EXTENSIONS)
98
+ if is_zip_bundle:
99
+ try:
100
+ with zipfile.ZipFile(path, "r") as zf:
101
+ if "manifest.json" in zf.namelist():
102
+ content = zf.read("manifest.json")
103
+ manifest = json.loads(content)
104
+ return manifest.get("scitex", {}).get("type")
105
+ except (zipfile.BadZipFile, OSError, json.JSONDecodeError):
106
+ pass
107
+
108
+ return None
109
+
110
+
111
+ def _get_type_from_extension(path: Path) -> Optional[str]:
112
+ """Get bundle type from file extension (fallback method).
113
+
114
+ Args:
115
+ path: Path to bundle.
116
+
117
+ Returns:
118
+ Bundle type from extension or None.
119
+ """
120
+ from ._types import DIR_EXTENSIONS, EXTENSIONS
121
+
122
+ name = path.name.lower()
123
+
124
+ # Check ZIP extensions (.figure.zip, .plot.zip, .stats.zip)
125
+ for ext in EXTENSIONS:
126
+ if name.endswith(ext):
127
+ # Return type without dots: 'figure', 'plot', 'stats'
128
+ return ext.split(".")[1]
129
+
130
+ # Check directory extensions (.figure, .plot, .stats)
131
+ for ext in DIR_EXTENSIONS:
132
+ if name.endswith(ext) and (not path.exists() or path.is_dir()):
133
+ return ext[1:] # Remove leading dot
73
134
 
74
135
  return None
75
136
 
@@ -84,7 +145,7 @@ def is_bundle(path: Union[str, Path]) -> bool:
84
145
  True if path is a bundle.
85
146
 
86
147
  Example:
87
- >>> is_bundle("Figure1.figz")
148
+ >>> is_bundle("Figure1.figure.zip")
88
149
  True
89
150
  >>> is_bundle("data.csv")
90
151
  False
@@ -96,22 +157,25 @@ def dir_to_zip_path(dir_path: Path) -> Path:
96
157
  """Convert directory path to ZIP path.
97
158
 
98
159
  Example:
99
- >>> dir_to_zip_path(Path("Figure1.figz.d"))
100
- Path('Figure1.figz')
160
+ >>> dir_to_zip_path(Path("Figure1.figure"))
161
+ Path('Figure1.figure.zip')
101
162
  """
102
- if dir_path.suffix == ".d":
103
- return dir_path.with_suffix("")
104
- return dir_path
163
+ # .figure -> .figure.zip, .plot -> .plot.zip, .stats -> .stats.zip
164
+ return Path(str(dir_path) + ".zip")
105
165
 
106
166
 
107
167
  def zip_to_dir_path(zip_path: Path) -> Path:
108
168
  """Convert ZIP path to directory path.
109
169
 
110
170
  Example:
111
- >>> zip_to_dir_path(Path("Figure1.figz"))
112
- Path('Figure1.figz.d')
171
+ >>> zip_to_dir_path(Path("Figure1.figure.zip"))
172
+ Path('Figure1.figure')
113
173
  """
114
- return Path(str(zip_path) + ".d")
174
+ # .figure.zip -> .figure, .plot.zip -> .plot, .stats.zip -> .stats
175
+ s = str(zip_path)
176
+ if s.endswith(".zip"):
177
+ return Path(s[:-4])
178
+ return zip_path
115
179
 
116
180
 
117
181
  def pack(
@@ -119,19 +183,16 @@ def pack(
119
183
  ) -> Path:
120
184
  """Pack a bundle directory into a ZIP archive.
121
185
 
122
- The ZIP archive includes the .d directory as a top-level folder so that
123
- standard unzip extracts to: fname.pltz.d/fname.csv, fname.pltz.d/fname.json, etc.
124
-
125
186
  Args:
126
- dir_path: Path to bundle directory (e.g., Figure1.figz.d/).
187
+ dir_path: Path to bundle directory (e.g., Figure1.figure/).
127
188
  output_path: Output ZIP path. Auto-generated if None.
128
189
 
129
190
  Returns:
130
191
  Path to created ZIP archive.
131
192
 
132
193
  Example:
133
- >>> pack("plot.pltz.d")
134
- Path('plot.pltz')
194
+ >>> pack("plot.plot")
195
+ Path('plot.plot.zip')
135
196
  """
136
197
  dir_path = Path(dir_path)
137
198
 
@@ -163,15 +224,15 @@ def unpack(
163
224
  """Unpack a bundle ZIP archive into a directory.
164
225
 
165
226
  Args:
166
- zip_path: Path to bundle ZIP (e.g., Figure1.figz).
227
+ zip_path: Path to bundle ZIP (e.g., Figure1.figure.zip).
167
228
  output_path: Output directory path. Auto-generated if None.
168
229
 
169
230
  Returns:
170
231
  Path to created directory.
171
232
 
172
233
  Example:
173
- >>> unpack("plot.pltz")
174
- Path('plot.pltz.d')
234
+ >>> unpack("plot.plot.zip")
235
+ Path('plot.plot')
175
236
  """
176
237
  zip_path = Path(zip_path)
177
238
 
@@ -199,7 +260,7 @@ def validate_spec(
199
260
 
200
261
  Args:
201
262
  spec: The specification dictionary to validate.
202
- bundle_type: Bundle type ('figz', 'pltz', 'statsz').
263
+ bundle_type: Bundle type ('figure', 'plot', 'stats').
203
264
  strict: If True, raise BundleValidationError on failure.
204
265
 
205
266
  Returns:
@@ -223,18 +284,18 @@ def validate_spec(
223
284
  errors.append("schema.version is required")
224
285
 
225
286
  # Delegate to domain-specific validators
226
- if bundle_type == BundleType.FIGZ:
227
- from scitex.fig.io._bundle import validate_figz_spec
287
+ if bundle_type == BundleType.FIGURE:
288
+ from scitex.canvas.io._bundle import validate_figure_spec
228
289
 
229
- errors.extend(validate_figz_spec(spec))
230
- elif bundle_type == BundleType.PLTZ:
231
- from scitex.plt.io._bundle import validate_pltz_spec
290
+ errors.extend(validate_figure_spec(spec))
291
+ elif bundle_type == BundleType.PLOT:
292
+ from scitex.plt.io._bundle import validate_plot_spec
232
293
 
233
- errors.extend(validate_pltz_spec(spec))
234
- elif bundle_type == BundleType.STATSZ:
235
- from scitex.stats.io._bundle import validate_statsz_spec
294
+ errors.extend(validate_plot_spec(spec))
295
+ elif bundle_type == BundleType.STATS:
296
+ from scitex.stats.io._bundle import validate_stats_spec
236
297
 
237
- errors.extend(validate_statsz_spec(spec))
298
+ errors.extend(validate_stats_spec(spec))
238
299
  else:
239
300
  errors.append(f"Unknown bundle type: {bundle_type}")
240
301
 
@@ -314,18 +375,18 @@ def load(path: Union[str, Path], in_memory: bool = True) -> Dict[str, Any]:
314
375
 
315
376
  Returns:
316
377
  Bundle data as dictionary with:
317
- - 'type': Bundle type ('figz', 'pltz', 'statsz')
378
+ - 'type': Bundle type ('figure', 'plot', 'stats')
318
379
  - 'spec': Parsed JSON specification
319
380
  - 'path': Original path
320
381
  - 'is_zip': Whether loaded from ZIP
321
382
  - Additional fields based on bundle type
322
383
 
323
384
  Example:
324
- >>> bundle = load("Figure1.figz")
385
+ >>> bundle = load("Figure1.figure.zip")
325
386
  >>> bundle['type']
326
- 'figz'
387
+ 'figure'
327
388
  >>> bundle['spec']['schema']['name']
328
- 'scitex.fig'
389
+ 'scitex.canvas'
329
390
  """
330
391
  p = Path(path)
331
392
  bundle_type = get_type(p)
@@ -340,7 +401,7 @@ def load(path: Union[str, Path], in_memory: bool = True) -> Dict[str, Any]:
340
401
  }
341
402
 
342
403
  # Handle ZIP vs directory
343
- if p.is_file() and p.suffix in EXTENSIONS:
404
+ if p.is_file() and any(str(p).lower().endswith(ext) for ext in EXTENSIONS):
344
405
  result["is_zip"] = True
345
406
 
346
407
  if in_memory:
@@ -375,18 +436,18 @@ def load(path: Union[str, Path], in_memory: bool = True) -> Dict[str, Any]:
375
436
  bundle_dir = p
376
437
 
377
438
  # Delegate to domain-specific loaders
378
- if bundle_type == BundleType.FIGZ:
379
- from scitex.fig.io._bundle import load_figz_bundle
439
+ if bundle_type == BundleType.FIGURE:
440
+ from scitex.canvas.io._bundle import load_figure_bundle
380
441
 
381
- result.update(load_figz_bundle(bundle_dir))
382
- elif bundle_type == BundleType.PLTZ:
383
- from scitex.plt.io import load_layered_pltz_bundle
442
+ result.update(load_figure_bundle(bundle_dir))
443
+ elif bundle_type == BundleType.PLOT:
444
+ from scitex.plt.io._bundle import load_plot_bundle
384
445
 
385
- result.update(load_layered_pltz_bundle(bundle_dir))
386
- elif bundle_type == BundleType.STATSZ:
387
- from scitex.stats.io._bundle import load_statsz_bundle
446
+ result.update(load_plot_bundle(bundle_dir))
447
+ elif bundle_type == BundleType.STATS:
448
+ from scitex.stats.io._bundle import load_stats_bundle
388
449
 
389
- result.update(load_statsz_bundle(bundle_dir))
450
+ result.update(load_stats_bundle(bundle_dir))
390
451
 
391
452
  return result
392
453
 
@@ -402,8 +463,8 @@ def save(
402
463
 
403
464
  Args:
404
465
  data: Bundle data dictionary.
405
- path: Output path (with or without .d suffix).
406
- bundle_type: Bundle type ('figz', 'pltz', 'statsz'). Auto-detected if None.
466
+ path: Output path (e.g., 'plot.plot' or 'plot.plot.zip').
467
+ bundle_type: Bundle type ('figure', 'plot', 'stats'). Auto-detected if None.
407
468
  as_zip: If True, save as ZIP archive.
408
469
  atomic: If True, use atomic write (temp file + rename) for ZIP.
409
470
 
@@ -411,8 +472,8 @@ def save(
411
472
  Path to saved bundle.
412
473
 
413
474
  Example:
414
- >>> save({"spec": {...}, "data": df}, "plot.pltz", as_zip=True)
415
- Path('plot.pltz')
475
+ >>> save({"spec": {...}, "data": df}, "plot.plot.zip", as_zip=True)
476
+ Path('plot.plot.zip')
416
477
  """
417
478
  p = Path(path)
418
479
 
@@ -422,25 +483,36 @@ def save(
422
483
  raise ValueError(f"Cannot determine bundle type from path: {path}")
423
484
 
424
485
  # Determine if saving as directory or ZIP
425
- if as_zip or (p.suffix in EXTENSIONS and not str(p).endswith(".d")):
486
+ from ._types import DIR_EXTENSIONS
487
+
488
+ path_str = str(p).lower()
489
+ is_zip_path = any(path_str.endswith(ext) for ext in EXTENSIONS)
490
+ is_dir_path = any(path_str.endswith(ext) for ext in DIR_EXTENSIONS)
491
+
492
+ if as_zip or is_zip_path:
426
493
  save_as_zip = True
427
- if p.suffix == ".d":
494
+ if is_dir_path:
428
495
  zip_path = dir_to_zip_path(p)
429
496
  else:
430
497
  zip_path = p
431
498
  dir_path = zip_to_dir_path(zip_path)
432
499
  else:
433
500
  save_as_zip = False
434
- if not str(p).endswith(".d"):
435
- dir_path = Path(str(p) + ".d")
436
- else:
437
- dir_path = p
501
+ dir_path = p
502
+
503
+ # Normalize bundle type for manifest (use new names: plot, figure, stats)
504
+ manifest_type = BundleType.normalize(bundle_type)
438
505
 
439
506
  # For direct ZIP saving with atomic writes
440
- if save_as_zip and atomic and bundle_type != BundleType.FIGZ:
507
+ if save_as_zip and atomic and bundle_type != BundleType.FIGURE:
508
+ from ._manifest import create_manifest
441
509
  from ._zip import ZipBundle
442
510
 
443
511
  with ZipBundle(zip_path, mode="w") as zb:
512
+ # Write manifest.json first
513
+ manifest = create_manifest(manifest_type)
514
+ zb.write_json("manifest.json", manifest)
515
+
444
516
  if "spec" in data:
445
517
  zb.write_json("spec.json", data["spec"])
446
518
 
@@ -464,21 +536,26 @@ def save(
464
536
  dir_path.mkdir(parents=True, exist_ok=True)
465
537
 
466
538
  # Delegate to domain-specific savers
467
- if bundle_type == BundleType.FIGZ:
468
- from scitex.fig.io._bundle import save_figz_bundle
539
+ if bundle_type == BundleType.FIGURE:
540
+ from scitex.canvas.io._bundle import save_figure_bundle
469
541
 
470
- save_figz_bundle(data, dir_path)
471
- elif bundle_type == BundleType.PLTZ:
472
- from scitex.plt.io._bundle import save_pltz_bundle
542
+ save_figure_bundle(data, dir_path)
543
+ elif bundle_type == BundleType.PLOT:
544
+ from scitex.plt.io._bundle import save_plot_bundle
473
545
 
474
- save_pltz_bundle(data, dir_path)
475
- elif bundle_type == BundleType.STATSZ:
476
- from scitex.stats.io._bundle import save_statsz_bundle
546
+ save_plot_bundle(data, dir_path)
547
+ elif bundle_type == BundleType.STATS:
548
+ from scitex.stats.io._bundle import save_stats_bundle
477
549
 
478
- save_statsz_bundle(data, dir_path)
550
+ save_stats_bundle(data, dir_path)
479
551
  else:
480
552
  raise ValueError(f"Unknown bundle type: {bundle_type}")
481
553
 
554
+ # Write manifest.json for directory bundles
555
+ from ._manifest import write_manifest
556
+
557
+ write_manifest(dir_path, manifest_type)
558
+
482
559
  if save_as_zip:
483
560
  pack(dir_path, zip_path)
484
561
  shutil.rmtree(dir_path)
@@ -511,24 +588,32 @@ def copy(
511
588
  FileExistsError: If destination exists and overwrite=False.
512
589
 
513
590
  Example:
514
- >>> copy("gallery/line/plot.pltz.d", "my_project/A.pltz.d")
515
- >>> copy("template.pltz", "output/panel.pltz.d")
591
+ >>> copy("gallery/line/plot.plot", "my_project/A.plot")
592
+ >>> copy("template.plot.zip", "output/panel.plot")
516
593
  """
594
+ from ._types import DIR_EXTENSIONS
595
+
517
596
  src_path = Path(src)
518
597
  dst_path = Path(dst)
598
+ src_str = str(src_path).lower()
599
+
600
+ # Check if path is a ZIP or directory bundle
601
+ is_zip_path = any(src_str.endswith(ext) for ext in EXTENSIONS)
602
+ is_dir_path = any(src_str.endswith(ext) for ext in DIR_EXTENSIONS)
519
603
 
520
604
  # Validate source exists
521
605
  if not src_path.exists():
522
- if src_path.suffix in EXTENSIONS:
523
- alt_path = Path(str(src_path) + ".d")
606
+ # Try alternate form (ZIP <-> directory)
607
+ if is_zip_path:
608
+ alt_path = zip_to_dir_path(src_path)
524
609
  if alt_path.exists():
525
610
  src_path = alt_path
526
611
  else:
527
612
  raise BundleNotFoundError(
528
613
  f"Bundle not found: {src} (also tried {alt_path})"
529
614
  )
530
- elif str(src_path).endswith(".d"):
531
- alt_path = Path(str(src_path)[:-2])
615
+ elif is_dir_path:
616
+ alt_path = dir_to_zip_path(src_path)
532
617
  if alt_path.exists():
533
618
  src_path = alt_path
534
619
  else:
@@ -553,7 +638,9 @@ def copy(
553
638
  # Copy based on source type
554
639
  if src_path.is_dir():
555
640
  shutil.copytree(src_path, dst_path)
556
- elif src_path.suffix in EXTENSIONS or zipfile.is_zipfile(src_path):
641
+ elif any(
642
+ str(src_path).lower().endswith(ext) for ext in EXTENSIONS
643
+ ) or zipfile.is_zipfile(src_path):
557
644
  unpack(src_path, dst_path)
558
645
  else:
559
646
  raise ValueError(f"Unknown bundle format: {src_path}")
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env python3
2
2
  # Timestamp: 2025-12-21
3
- # File: /home/ywatanabe/proj/scitex-code/src/scitex/fts/_bundle/_dataclasses/_Node.py
3
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/io/bundle/_dataclasses/_Spec.py
4
4
 
5
- """Node - Core FTS Node model with kind-based constraints."""
5
+ """Spec - Core bundle specification model with kind-based constraints."""
6
6
 
7
7
  from dataclasses import dataclass, field
8
8
  from datetime import datetime
@@ -10,13 +10,13 @@ from typing import Any, ClassVar, Dict, List, Optional, Set
10
10
 
11
11
  from ._Axes import Axes
12
12
  from ._BBox import BBox
13
- from ._NodeRefs import NodeRefs
14
13
  from ._SizeMM import SizeMM
14
+ from ._SpecRefs import SpecRefs
15
15
 
16
16
 
17
17
  @dataclass
18
18
  class TextContent:
19
- """Text content for kind=text nodes."""
19
+ """Text content for kind=text specs."""
20
20
 
21
21
  content: str = ""
22
22
  fontsize: Optional[float] = None
@@ -45,7 +45,7 @@ class TextContent:
45
45
 
46
46
  @dataclass
47
47
  class ShapeParams:
48
- """Shape parameters for kind=shape nodes."""
48
+ """Shape parameters for kind=shape specs."""
49
49
 
50
50
  shape_type: str = "rectangle" # "rectangle" | "ellipse" | "arrow" | "line"
51
51
  color: str = "#000000"
@@ -71,15 +71,15 @@ class ShapeParams:
71
71
 
72
72
 
73
73
  @dataclass
74
- class Node:
75
- """Core FTS Node model with kind-based constraints.
74
+ class Spec:
75
+ """Core bundle specification model with kind-based constraints.
76
76
 
77
- The central structural element of an FTS bundle.
77
+ The central structural element of a bundle.
78
78
  Stored in canonical/spec.json.
79
79
 
80
80
  Kind categories:
81
81
  - Data leaf kinds (plot, table, stats): require payload data files
82
- - Annotation leaf kinds (text, shape): no payload required, params in node
82
+ - Annotation leaf kinds (text, shape): no payload required, params in spec
83
83
  - Image leaf kinds (image): require payload image file
84
84
  - Composite kinds (figure): contain children, no payload
85
85
 
@@ -95,7 +95,7 @@ class Node:
95
95
  kind: str # "figure" | "plot" | "table" | "stats" | "text" | "shape" | "image"
96
96
 
97
97
  # Schema versioning for forward compatibility
98
- scitex_schema: str = "scitex.fts.spec"
98
+ scitex_schema: str = "scitex.io.bundle.spec"
99
99
  scitex_schema_version: str = "1.0.0"
100
100
 
101
101
  # Children and layout (for composite kinds)
@@ -116,7 +116,7 @@ class Node:
116
116
  shape: Optional[ShapeParams] = None # For kind=shape
117
117
 
118
118
  # References and timestamps
119
- refs: NodeRefs = field(default_factory=NodeRefs)
119
+ refs: SpecRefs = field(default_factory=SpecRefs)
120
120
  created_at: Optional[str] = None
121
121
  modified_at: Optional[str] = None
122
122
 
@@ -128,7 +128,9 @@ class Node:
128
128
  # Image leaf kinds: require payload image file, forbid children
129
129
  IMAGE_LEAF_KINDS: ClassVar[Set[str]] = {"image"}
130
130
  # All leaf kinds (for convenience)
131
- LEAF_KINDS: ClassVar[Set[str]] = DATA_LEAF_KINDS | ANNOTATION_LEAF_KINDS | IMAGE_LEAF_KINDS
131
+ LEAF_KINDS: ClassVar[Set[str]] = (
132
+ DATA_LEAF_KINDS | ANNOTATION_LEAF_KINDS | IMAGE_LEAF_KINDS
133
+ )
132
134
  # Composite kinds: allow children, forbid payload
133
135
  COMPOSITE_KINDS: ClassVar[Set[str]] = {"figure"}
134
136
  # All valid kinds
@@ -136,10 +138,10 @@ class Node:
136
138
 
137
139
  # Payload schema -> required file mapping
138
140
  PAYLOAD_REQUIRED_FILES: ClassVar[Dict[str, str]] = {
139
- "scitex.fts.payload.plot@1": "payload/data.csv",
140
- "scitex.fts.payload.table@1": "payload/table.csv",
141
- "scitex.fts.payload.stats@1": "payload/stats.json",
142
- "scitex.fts.payload.image@1": "payload/image.png",
141
+ "scitex.io.bundle.payload.plot@1": "payload/data.csv",
142
+ "scitex.io.bundle.payload.table@1": "payload/table.csv",
143
+ "scitex.io.bundle.payload.stats@1": "payload/stats.json",
144
+ "scitex.io.bundle.payload.image@1": "payload/image.png",
143
145
  }
144
146
 
145
147
  def __post_init__(self):
@@ -186,7 +188,9 @@ class Node:
186
188
 
187
189
  # Check: kind is valid
188
190
  if self.kind not in self.ALL_KINDS:
189
- errors.append(f"Unknown kind: {self.kind}. Valid kinds: {sorted(self.ALL_KINDS)}")
191
+ errors.append(
192
+ f"Unknown kind: {self.kind}. Valid kinds: {sorted(self.ALL_KINDS)}"
193
+ )
190
194
  return errors # Early return - other checks don't make sense
191
195
 
192
196
  # Check: children list has no duplicates
@@ -216,7 +220,9 @@ class Node:
216
220
  # Check: panel child references must be subset of children
217
221
  for child_ref in panel_children:
218
222
  if child_ref not in self.children:
219
- errors.append(f"layout.panels references unknown child: {child_ref}")
223
+ errors.append(
224
+ f"layout.panels references unknown child: {child_ref}"
225
+ )
220
226
 
221
227
  # Check: no duplicate panel child references
222
228
  if len(panel_children) != len(set(panel_children)):
@@ -259,8 +265,8 @@ class Node:
259
265
  return result
260
266
 
261
267
  @classmethod
262
- def from_dict(cls, data: Dict[str, Any]) -> "Node":
263
- """Create Node from dictionary."""
268
+ def from_dict(cls, data: Dict[str, Any]) -> "Spec":
269
+ """Create Spec from dictionary."""
264
270
  # Handle legacy 'type' field
265
271
  kind = data.get("kind") or data.get("type", "plot")
266
272
 
@@ -293,7 +299,7 @@ class Node:
293
299
  return cls(
294
300
  id=data.get("id", "unknown"),
295
301
  kind=kind,
296
- scitex_schema=data.get("scitex_schema", "scitex.fts.spec"),
302
+ scitex_schema=data.get("scitex_schema", "scitex.io.bundle.spec"),
297
303
  scitex_schema_version=data.get("scitex_schema_version", "1.0.0"),
298
304
  children=data.get("children", []),
299
305
  layout=data.get("layout"),
@@ -304,7 +310,7 @@ class Node:
304
310
  axes=Axes.from_dict(data["axes"]) if "axes" in data else None,
305
311
  text=text,
306
312
  shape=shape,
307
- refs=NodeRefs.from_dict(data.get("refs", {})),
313
+ refs=SpecRefs.from_dict(data.get("refs", {})),
308
314
  created_at=data.get("created_at"),
309
315
  modified_at=data.get("modified_at"),
310
316
  )
@@ -314,6 +320,6 @@ class Node:
314
320
  self.modified_at = datetime.utcnow().isoformat() + "Z"
315
321
 
316
322
 
317
- __all__ = ["Node", "TextContent", "ShapeParams"]
323
+ __all__ = ["Spec", "TextContent", "ShapeParams"]
318
324
 
319
325
  # EOF
@@ -1,15 +1,15 @@
1
1
  #!/usr/bin/env python3
2
- # Timestamp: 2025-12-20
3
- # File: /home/ywatanabe/proj/scitex-code/src/scitex/fsb/_dataclasses/NodeRefs.py
2
+ # Timestamp: 2025-12-21
3
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/io/bundle/_dataclasses/_SpecRefs.py
4
4
 
5
- """NodeRefs - References to associated files within the bundle."""
5
+ """SpecRefs - References to associated files within the bundle."""
6
6
 
7
7
  from dataclasses import dataclass
8
8
  from typing import Any, Dict, Optional
9
9
 
10
10
 
11
11
  @dataclass
12
- class NodeRefs:
12
+ class SpecRefs:
13
13
  """References to associated files within the bundle.
14
14
 
15
15
  All paths are relative to the bundle root.
@@ -31,7 +31,7 @@ class NodeRefs:
31
31
  return result
32
32
 
33
33
  @classmethod
34
- def from_dict(cls, data: Dict[str, Any]) -> "NodeRefs":
34
+ def from_dict(cls, data: Dict[str, Any]) -> "SpecRefs":
35
35
  return cls(
36
36
  encoding=data.get("encoding", "encoding.json"),
37
37
  theme=data.get("theme", "theme.json"),
@@ -40,6 +40,6 @@ class NodeRefs:
40
40
  )
41
41
 
42
42
 
43
- __all__ = ["NodeRefs"]
43
+ __all__ = ["SpecRefs"]
44
44
 
45
45
  # EOF