scitex 2.7.3__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.
- scitex/__init__.py +15 -7
- scitex/__version__.py +1 -2
- scitex/_install_guide.py +250 -0
- scitex/_optional_deps.py +206 -39
- scitex/ai/_gen_ai/_Groq.py +2 -4
- scitex/ai/_gen_ai/_OpenAI.py +5 -2
- scitex/ai/_gen_ai/_Perplexity.py +20 -6
- scitex/audio/__init__.py +24 -15
- scitex/audio/_cross_process_lock.py +139 -0
- scitex/audio/_mcp_handlers.py +256 -0
- scitex/audio/_mcp_tool_schemas.py +203 -0
- scitex/audio/engines/elevenlabs_engine.py +5 -2
- scitex/audio/mcp_server.py +98 -457
- scitex/bridge/__init__.py +30 -19
- scitex/bridge/_figrecipe.py +245 -0
- scitex/bridge/_helpers.py +2 -1
- scitex/bridge/_plt_vis.py +23 -10
- scitex/bridge/_stats_plt.py +18 -5
- scitex/bridge/_stats_vis.py +16 -2
- scitex/browser/__init__.py +84 -44
- scitex/browser/automation/__init__.py +5 -1
- scitex/browser/core/BrowserMixin.py +17 -4
- scitex/browser/core/__init__.py +11 -2
- scitex/browser/remote/CaptchaHandler.py +1 -1
- scitex/browser/remote/ZenRowsAPIClient.py +1 -1
- scitex/capture/grid.py +487 -0
- scitex/capture/mcp_handlers.py +401 -0
- scitex/capture/mcp_tool_defs.py +192 -0
- scitex/capture/mcp_tools.py +241 -0
- scitex/capture/mcp_utils.py +30 -0
- scitex/cli/convert.py +421 -0
- scitex/cli/main.py +6 -4
- scitex/datetime/__init__.py +46 -0
- scitex/datetime/_linspace.py +100 -0
- scitex/datetime/_normalize_timestamp.py +306 -0
- scitex/db/_delete_duplicates.py +4 -4
- scitex/db/_sqlite3/_delete_duplicates.py +11 -2
- scitex/dev/plt/__init__.py +61 -62
- scitex/dev/plt/demo_plotters/__init__.py +0 -0
- scitex/dev/plt/demo_plotters/plot_mpl_axhline.py +28 -0
- scitex/dev/plt/demo_plotters/plot_mpl_axhspan.py +28 -0
- scitex/dev/plt/demo_plotters/plot_mpl_axvline.py +28 -0
- scitex/dev/plt/demo_plotters/plot_mpl_axvspan.py +28 -0
- scitex/dev/plt/demo_plotters/plot_mpl_bar.py +29 -0
- scitex/dev/plt/demo_plotters/plot_mpl_barh.py +29 -0
- scitex/dev/plt/demo_plotters/plot_mpl_boxplot.py +28 -0
- scitex/dev/plt/demo_plotters/plot_mpl_contour.py +31 -0
- scitex/dev/plt/demo_plotters/plot_mpl_contourf.py +31 -0
- scitex/dev/plt/demo_plotters/plot_mpl_errorbar.py +30 -0
- scitex/dev/plt/demo_plotters/plot_mpl_eventplot.py +28 -0
- scitex/dev/plt/demo_plotters/plot_mpl_fill.py +30 -0
- scitex/dev/plt/demo_plotters/plot_mpl_fill_between.py +31 -0
- scitex/dev/plt/demo_plotters/plot_mpl_hexbin.py +28 -0
- scitex/dev/plt/demo_plotters/plot_mpl_hist.py +28 -0
- scitex/dev/plt/demo_plotters/plot_mpl_hist2d.py +28 -0
- scitex/dev/plt/demo_plotters/plot_mpl_imshow.py +29 -0
- scitex/dev/plt/demo_plotters/plot_mpl_pcolormesh.py +31 -0
- scitex/dev/plt/demo_plotters/plot_mpl_pie.py +29 -0
- scitex/dev/plt/demo_plotters/plot_mpl_plot.py +29 -0
- scitex/dev/plt/demo_plotters/plot_mpl_quiver.py +31 -0
- scitex/dev/plt/demo_plotters/plot_mpl_scatter.py +28 -0
- scitex/dev/plt/demo_plotters/plot_mpl_stackplot.py +31 -0
- scitex/dev/plt/demo_plotters/plot_mpl_stem.py +29 -0
- scitex/dev/plt/demo_plotters/plot_mpl_step.py +29 -0
- scitex/dev/plt/demo_plotters/plot_mpl_violinplot.py +28 -0
- scitex/dev/plt/demo_plotters/plot_sns_barplot.py +29 -0
- scitex/dev/plt/demo_plotters/plot_sns_boxplot.py +29 -0
- scitex/dev/plt/demo_plotters/plot_sns_heatmap.py +28 -0
- scitex/dev/plt/demo_plotters/plot_sns_histplot.py +29 -0
- scitex/dev/plt/demo_plotters/plot_sns_kdeplot.py +29 -0
- scitex/dev/plt/demo_plotters/plot_sns_lineplot.py +31 -0
- scitex/dev/plt/demo_plotters/plot_sns_scatterplot.py +29 -0
- scitex/dev/plt/demo_plotters/plot_sns_stripplot.py +29 -0
- scitex/dev/plt/demo_plotters/plot_sns_swarmplot.py +29 -0
- scitex/dev/plt/demo_plotters/plot_sns_violinplot.py +29 -0
- scitex/dev/plt/demo_plotters/plot_stx_bar.py +29 -0
- scitex/dev/plt/demo_plotters/plot_stx_barh.py +29 -0
- scitex/dev/plt/demo_plotters/plot_stx_box.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_boxplot.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_conf_mat.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_contour.py +31 -0
- scitex/dev/plt/demo_plotters/plot_stx_ecdf.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_errorbar.py +30 -0
- scitex/dev/plt/demo_plotters/plot_stx_fill_between.py +31 -0
- scitex/dev/plt/demo_plotters/plot_stx_fillv.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_heatmap.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_image.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_imshow.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_joyplot.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_kde.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_line.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_mean_ci.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_mean_std.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_median_iqr.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_raster.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_rectangle.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_scatter.py +29 -0
- scitex/dev/plt/demo_plotters/plot_stx_shaded_line.py +29 -0
- scitex/dev/plt/demo_plotters/plot_stx_violin.py +28 -0
- scitex/dev/plt/demo_plotters/plot_stx_violinplot.py +28 -0
- scitex/dev/plt/mpl/get_dir_ax.py +46 -0
- scitex/dev/plt/mpl/get_signatures.py +176 -0
- scitex/dev/plt/mpl/get_signatures_details.py +522 -0
- scitex/dev/plt/plot_mpl_axhline.py +0 -0
- scitex/dev/plt/plot_mpl_axhspan.py +0 -0
- scitex/dev/plt/plot_mpl_axvline.py +0 -0
- scitex/dev/plt/plot_mpl_axvspan.py +0 -0
- scitex/dev/plt/plot_mpl_bar.py +0 -0
- scitex/dev/plt/plot_mpl_barh.py +0 -0
- scitex/dev/plt/plot_mpl_boxplot.py +0 -0
- scitex/dev/plt/plot_mpl_contour.py +0 -0
- scitex/dev/plt/plot_mpl_contourf.py +0 -0
- scitex/dev/plt/plot_mpl_errorbar.py +0 -0
- scitex/dev/plt/plot_mpl_eventplot.py +0 -0
- scitex/dev/plt/plot_mpl_fill.py +0 -0
- scitex/dev/plt/plot_mpl_fill_between.py +0 -0
- scitex/dev/plt/plot_mpl_hexbin.py +0 -0
- scitex/dev/plt/plot_mpl_hist.py +0 -0
- scitex/dev/plt/plot_mpl_hist2d.py +0 -0
- scitex/dev/plt/plot_mpl_imshow.py +0 -0
- scitex/dev/plt/plot_mpl_pcolormesh.py +0 -0
- scitex/dev/plt/plot_mpl_pie.py +0 -0
- scitex/dev/plt/plot_mpl_plot.py +0 -0
- scitex/dev/plt/plot_mpl_quiver.py +0 -0
- scitex/dev/plt/plot_mpl_scatter.py +0 -0
- scitex/dev/plt/plot_mpl_stackplot.py +0 -0
- scitex/dev/plt/plot_mpl_stem.py +0 -0
- scitex/dev/plt/plot_mpl_step.py +0 -0
- scitex/dev/plt/plot_mpl_violinplot.py +0 -0
- scitex/dev/plt/plot_sns_barplot.py +0 -0
- scitex/dev/plt/plot_sns_boxplot.py +0 -0
- scitex/dev/plt/plot_sns_heatmap.py +0 -0
- scitex/dev/plt/plot_sns_histplot.py +0 -0
- scitex/dev/plt/plot_sns_kdeplot.py +0 -0
- scitex/dev/plt/plot_sns_lineplot.py +0 -0
- scitex/dev/plt/plot_sns_scatterplot.py +0 -0
- scitex/dev/plt/plot_sns_stripplot.py +0 -0
- scitex/dev/plt/plot_sns_swarmplot.py +0 -0
- scitex/dev/plt/plot_sns_violinplot.py +0 -0
- scitex/dev/plt/plot_stx_bar.py +0 -0
- scitex/dev/plt/plot_stx_barh.py +0 -0
- scitex/dev/plt/plot_stx_box.py +0 -0
- scitex/dev/plt/plot_stx_boxplot.py +0 -0
- scitex/dev/plt/plot_stx_conf_mat.py +0 -0
- scitex/dev/plt/plot_stx_contour.py +0 -0
- scitex/dev/plt/plot_stx_ecdf.py +0 -0
- scitex/dev/plt/plot_stx_errorbar.py +0 -0
- scitex/dev/plt/plot_stx_fill_between.py +0 -0
- scitex/dev/plt/plot_stx_fillv.py +0 -0
- scitex/dev/plt/plot_stx_heatmap.py +0 -0
- scitex/dev/plt/plot_stx_image.py +0 -0
- scitex/dev/plt/plot_stx_imshow.py +0 -0
- scitex/dev/plt/plot_stx_joyplot.py +0 -0
- scitex/dev/plt/plot_stx_kde.py +0 -0
- scitex/dev/plt/plot_stx_line.py +0 -0
- scitex/dev/plt/plot_stx_mean_ci.py +0 -0
- scitex/dev/plt/plot_stx_mean_std.py +0 -0
- scitex/dev/plt/plot_stx_median_iqr.py +0 -0
- scitex/dev/plt/plot_stx_raster.py +0 -0
- scitex/dev/plt/plot_stx_rectangle.py +0 -0
- scitex/dev/plt/plot_stx_scatter.py +0 -0
- scitex/dev/plt/plot_stx_shaded_line.py +0 -0
- scitex/dev/plt/plot_stx_violin.py +0 -0
- scitex/dev/plt/plot_stx_violinplot.py +0 -0
- scitex/diagram/README.md +197 -0
- scitex/diagram/__init__.py +48 -0
- scitex/diagram/_compile.py +312 -0
- scitex/diagram/_diagram.py +355 -0
- scitex/diagram/_presets.py +173 -0
- scitex/diagram/_schema.py +182 -0
- scitex/diagram/_split.py +278 -0
- scitex/dict/_pop_keys.py +1 -7
- scitex/dsp/__init__.py +15 -10
- scitex/dsp/add_noise.py +5 -2
- scitex/dsp/example.py +35 -22
- scitex/dsp/filt.py +8 -3
- scitex/dsp/reference.py +3 -2
- scitex/dsp/utils/__init__.py +2 -1
- scitex/dsp/utils/_differential_bandpass_filters.py +14 -4
- scitex/dt/__init__.py +39 -2
- scitex/errors.py +82 -521
- scitex/fig/__init__.py +4 -4
- scitex/fig/editor/__init__.py +5 -2
- scitex/fig/editor/_dearpygui_editor.py +1 -1
- scitex/fig/editor/_mpl_editor.py +1 -1
- scitex/fig/editor/_qt_editor.py +1 -1
- scitex/fig/editor/_tkinter_editor.py +1 -1
- scitex/fig/editor/edit/__init__.py +50 -0
- scitex/fig/editor/edit/backend_detector.py +109 -0
- scitex/fig/editor/edit/bundle_resolver.py +240 -0
- scitex/fig/editor/edit/editor_launcher.py +239 -0
- scitex/fig/editor/edit/manual_handler.py +53 -0
- scitex/fig/editor/edit/panel_loader.py +232 -0
- scitex/fig/editor/edit/path_resolver.py +67 -0
- scitex/fig/editor/flask_editor/_bbox.py +23 -0
- scitex/fig/editor/flask_editor/_core.py +908 -103
- scitex/fig/editor/flask_editor/_renderer.py +74 -0
- scitex/fig/editor/flask_editor/static/css/base/reset.css +41 -0
- scitex/fig/editor/flask_editor/static/css/base/typography.css +16 -0
- scitex/fig/editor/flask_editor/static/css/base/variables.css +85 -0
- scitex/fig/editor/flask_editor/static/css/components/buttons.css +217 -0
- scitex/fig/editor/flask_editor/static/css/components/context-menu.css +93 -0
- scitex/fig/editor/flask_editor/static/css/components/dropdown.css +57 -0
- scitex/fig/editor/flask_editor/static/css/components/forms.css +112 -0
- scitex/fig/editor/flask_editor/static/css/components/modal.css +59 -0
- scitex/fig/editor/flask_editor/static/css/components/sections.css +212 -0
- scitex/fig/editor/flask_editor/static/css/features/canvas.css +176 -0
- scitex/fig/editor/flask_editor/static/css/features/element-inspector.css +190 -0
- scitex/fig/editor/flask_editor/static/css/features/loading.css +59 -0
- scitex/fig/editor/flask_editor/static/css/features/overlay.css +45 -0
- scitex/fig/editor/flask_editor/static/css/features/panel-grid.css +95 -0
- scitex/fig/editor/flask_editor/static/css/features/selection.css +101 -0
- scitex/fig/editor/flask_editor/static/css/features/statistics.css +138 -0
- scitex/fig/editor/flask_editor/static/css/index.css +31 -0
- scitex/fig/editor/flask_editor/static/css/layout/container.css +7 -0
- scitex/fig/editor/flask_editor/static/css/layout/controls.css +56 -0
- scitex/fig/editor/flask_editor/static/css/layout/preview.css +78 -0
- scitex/fig/editor/flask_editor/static/js/alignment/axis.js +314 -0
- scitex/fig/editor/flask_editor/static/js/alignment/basic.js +107 -0
- scitex/fig/editor/flask_editor/static/js/alignment/distribute.js +54 -0
- scitex/fig/editor/flask_editor/static/js/canvas/canvas.js +172 -0
- scitex/fig/editor/flask_editor/static/js/canvas/dragging.js +258 -0
- scitex/fig/editor/flask_editor/static/js/canvas/resize.js +48 -0
- scitex/fig/editor/flask_editor/static/js/canvas/selection.js +71 -0
- scitex/fig/editor/flask_editor/static/js/core/api.js +288 -0
- scitex/fig/editor/flask_editor/static/js/core/state.js +143 -0
- scitex/fig/editor/flask_editor/static/js/core/utils.js +245 -0
- scitex/fig/editor/flask_editor/static/js/dev/element-inspector.js +992 -0
- scitex/fig/editor/flask_editor/static/js/editor/bbox.js +339 -0
- scitex/fig/editor/flask_editor/static/js/editor/element-drag.js +286 -0
- scitex/fig/editor/flask_editor/static/js/editor/overlay.js +371 -0
- scitex/fig/editor/flask_editor/static/js/editor/preview.js +293 -0
- scitex/fig/editor/flask_editor/static/js/main.js +426 -0
- scitex/fig/editor/flask_editor/static/js/shortcuts/context-menu.js +152 -0
- scitex/fig/editor/flask_editor/static/js/shortcuts/keyboard.js +265 -0
- scitex/fig/editor/flask_editor/static/js/ui/controls.js +184 -0
- scitex/fig/editor/flask_editor/static/js/ui/download.js +57 -0
- scitex/fig/editor/flask_editor/static/js/ui/help.js +100 -0
- scitex/fig/editor/flask_editor/static/js/ui/theme.js +34 -0
- scitex/fig/editor/flask_editor/templates/__init__.py +95 -5
- scitex/fig/editor/flask_editor/templates/_html.py +27 -9
- scitex/fig/editor/flask_editor/templates/_scripts.py +1928 -131
- scitex/fig/editor/flask_editor/templates/_styles.py +363 -51
- scitex/fig/io/_bundle.py +104 -19
- scitex/fts/README.md +262 -0
- scitex/fts/TODO.md +66 -0
- scitex/fts/__init__.py +90 -0
- scitex/fts/_bundle/README_IN_BUNDLE.md +102 -0
- scitex/fts/_bundle/_FTS.py +657 -0
- scitex/fts/_bundle/__init__.py +38 -0
- scitex/fts/_bundle/_children.py +216 -0
- scitex/fts/_bundle/_conversion/__init__.py +15 -0
- scitex/fts/_bundle/_conversion/_bundle2dict.py +44 -0
- scitex/fts/_bundle/_conversion/_dict2bundle.py +50 -0
- scitex/fts/_bundle/_dataclasses/_Axes.py +57 -0
- scitex/fts/_bundle/_dataclasses/_BBox.py +54 -0
- scitex/fts/_bundle/_dataclasses/_ColumnDef.py +72 -0
- scitex/fts/_bundle/_dataclasses/_DataFormat.py +40 -0
- scitex/fts/_bundle/_dataclasses/_DataInfo.py +135 -0
- scitex/fts/_bundle/_dataclasses/_DataSource.py +44 -0
- scitex/fts/_bundle/_dataclasses/_Node.py +319 -0
- scitex/fts/_bundle/_dataclasses/_NodeRefs.py +45 -0
- scitex/fts/_bundle/_dataclasses/_SizeMM.py +38 -0
- scitex/fts/_bundle/_dataclasses/__init__.py +35 -0
- scitex/fts/_bundle/_extractors/__init__.py +32 -0
- scitex/fts/_bundle/_extractors/_extract_bar.py +131 -0
- scitex/fts/_bundle/_extractors/_extract_line.py +71 -0
- scitex/fts/_bundle/_extractors/_extract_scatter.py +79 -0
- scitex/fts/_bundle/_loader.py +134 -0
- scitex/fts/_bundle/_mpl_helpers.py +389 -0
- scitex/fts/_bundle/_saver.py +269 -0
- scitex/fts/_bundle/_storage.py +200 -0
- scitex/fts/_bundle/_utils/__init__.py +55 -0
- scitex/fts/_bundle/_utils/_const.py +26 -0
- scitex/fts/_bundle/_utils/_errors.py +73 -0
- scitex/fts/_bundle/_utils/_generate.py +21 -0
- scitex/fts/_bundle/_utils/_types.py +76 -0
- scitex/fts/_bundle/_validation.py +434 -0
- scitex/fts/_bundle/_zipbundle.py +165 -0
- scitex/fts/_fig/__init__.py +22 -0
- scitex/fts/_fig/_backend/__init__.py +53 -0
- scitex/fts/_fig/_backend/_export.py +165 -0
- scitex/fts/_fig/_backend/_parser.py +188 -0
- scitex/fts/_fig/_backend/_render.py +538 -0
- scitex/fts/_fig/_composite.py +345 -0
- scitex/fts/_fig/_dataclasses/_ChannelEncoding.py +46 -0
- scitex/fts/_fig/_dataclasses/_Encoding.py +82 -0
- scitex/fts/_fig/_dataclasses/_Theme.py +441 -0
- scitex/fts/_fig/_dataclasses/_TraceEncoding.py +52 -0
- scitex/fts/_fig/_dataclasses/__init__.py +47 -0
- scitex/fts/_fig/_editor/__init__.py +14 -0
- scitex/fts/_fig/_editor/_cui/__init__.py +33 -0
- scitex/fts/_fig/_editor/_cui/_backend_detector.py +39 -0
- scitex/fts/_fig/_editor/_cui/_bundle_resolver.py +366 -0
- scitex/fts/_fig/_editor/_cui/_editor_launcher.py +175 -0
- scitex/fts/_fig/_editor/_cui/_manual_handler.py +52 -0
- scitex/fts/_fig/_editor/_cui/_panel_loader.py +246 -0
- scitex/fts/_fig/_editor/_cui/_path_resolver.py +66 -0
- scitex/fts/_fig/_editor/_defaults.py +300 -0
- scitex/fts/_fig/_editor/_gui/__init__.py +11 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/__init__.py +20 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/_bbox.py +1339 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/_core.py +1688 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/_plotter.py +664 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/_renderer.py +853 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/_utils.py +79 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/base/reset.css +41 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/base/typography.css +16 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/base/variables.css +85 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/buttons.css +217 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/context-menu.css +93 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/dropdown.css +57 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/forms.css +112 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/modal.css +59 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/components/sections.css +212 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/canvas.css +176 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/element-inspector.css +190 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/loading.css +59 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/overlay.css +45 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/panel-grid.css +95 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/selection.css +101 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/features/statistics.css +138 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/index.css +31 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/layout/container.css +7 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/layout/controls.css +56 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/css/layout/preview.css +78 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/alignment/axis.js +314 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/alignment/basic.js +107 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/alignment/distribute.js +54 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/canvas/canvas.js +172 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/canvas/dragging.js +258 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/canvas/resize.js +48 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/canvas/selection.js +71 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/core/api.js +288 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/core/state.js +143 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/core/utils.js +245 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/dev/element-inspector.js +992 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/editor/bbox.js +339 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/editor/element-drag.js +286 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/editor/overlay.js +371 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/editor/preview.js +293 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/main.js +426 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/shortcuts/context-menu.js +152 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/shortcuts/keyboard.js +265 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/ui/controls.js +184 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/ui/download.js +57 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/ui/help.js +100 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/static/js/ui/theme.js +34 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/templates/__init__.py +124 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/templates/_html.py +851 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/templates/_scripts.py +4932 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor/templates/_styles.py +1657 -0
- scitex/fts/_fig/_editor/_gui/_flask_editor.py +36 -0
- scitex/fts/_fig/_models/_Annotations.py +115 -0
- scitex/fts/_fig/_models/_Axes.py +152 -0
- scitex/fts/_fig/_models/_Figure.py +138 -0
- scitex/fts/_fig/_models/_Guides.py +104 -0
- scitex/fts/_fig/_models/_Plot.py +123 -0
- scitex/fts/_fig/_models/_Styles.py +245 -0
- scitex/fts/_fig/_models/__init__.py +80 -0
- scitex/fts/_fig/_models/_plot_types/__init__.py +156 -0
- scitex/fts/_fig/_models/_plot_types/_bar.py +43 -0
- scitex/fts/_fig/_models/_plot_types/_box.py +38 -0
- scitex/fts/_fig/_models/_plot_types/_distribution.py +36 -0
- scitex/fts/_fig/_models/_plot_types/_errorbar.py +60 -0
- scitex/fts/_fig/_models/_plot_types/_histogram.py +30 -0
- scitex/fts/_fig/_models/_plot_types/_image.py +61 -0
- scitex/fts/_fig/_models/_plot_types/_line.py +57 -0
- scitex/fts/_fig/_models/_plot_types/_scatter.py +30 -0
- scitex/fts/_fig/_models/_plot_types/_seaborn.py +121 -0
- scitex/fts/_fig/_models/_plot_types/_violin.py +36 -0
- scitex/fts/_fig/_utils/__init__.py +129 -0
- scitex/fts/_fig/_utils/_auto_layout.py +127 -0
- scitex/fts/_fig/_utils/_calc_bounds.py +111 -0
- scitex/fts/_fig/_utils/_const_sizes.py +48 -0
- scitex/fts/_fig/_utils/_convert_coords.py +77 -0
- scitex/fts/_fig/_utils/_get_template.py +178 -0
- scitex/fts/_fig/_utils/_normalize.py +73 -0
- scitex/fts/_fig/_utils/_plot_layout.py +397 -0
- scitex/fts/_fig/_utils/_validate.py +197 -0
- scitex/fts/_kinds/__init__.py +45 -0
- scitex/fts/_kinds/_figure/__init__.py +19 -0
- scitex/fts/_kinds/_figure/_composite.py +345 -0
- scitex/fts/_kinds/_plot/__init__.py +25 -0
- scitex/fts/_kinds/_plot/_backend/__init__.py +53 -0
- scitex/fts/_kinds/_plot/_backend/_export.py +165 -0
- scitex/fts/_kinds/_plot/_backend/_parser.py +188 -0
- scitex/fts/_kinds/_plot/_backend/_render.py +538 -0
- scitex/fts/_kinds/_plot/_dataclasses/_ChannelEncoding.py +46 -0
- scitex/fts/_kinds/_plot/_dataclasses/_Encoding.py +82 -0
- scitex/fts/_kinds/_plot/_dataclasses/_Theme.py +441 -0
- scitex/fts/_kinds/_plot/_dataclasses/_TraceEncoding.py +52 -0
- scitex/fts/_kinds/_plot/_dataclasses/__init__.py +47 -0
- scitex/fts/_kinds/_plot/_models/_Annotations.py +115 -0
- scitex/fts/_kinds/_plot/_models/_Axes.py +152 -0
- scitex/fts/_kinds/_plot/_models/_Figure.py +138 -0
- scitex/fts/_kinds/_plot/_models/_Guides.py +104 -0
- scitex/fts/_kinds/_plot/_models/_Plot.py +123 -0
- scitex/fts/_kinds/_plot/_models/_Styles.py +245 -0
- scitex/fts/_kinds/_plot/_models/__init__.py +80 -0
- scitex/fts/_kinds/_plot/_models/_plot_types/__init__.py +156 -0
- scitex/fts/_kinds/_plot/_models/_plot_types/_bar.py +43 -0
- scitex/fts/_kinds/_plot/_models/_plot_types/_box.py +38 -0
- scitex/fts/_kinds/_plot/_models/_plot_types/_distribution.py +36 -0
- scitex/fts/_kinds/_plot/_models/_plot_types/_errorbar.py +60 -0
- scitex/fts/_kinds/_plot/_models/_plot_types/_histogram.py +30 -0
- scitex/fts/_kinds/_plot/_models/_plot_types/_image.py +61 -0
- scitex/fts/_kinds/_plot/_models/_plot_types/_line.py +57 -0
- scitex/fts/_kinds/_plot/_models/_plot_types/_scatter.py +30 -0
- scitex/fts/_kinds/_plot/_models/_plot_types/_seaborn.py +121 -0
- scitex/fts/_kinds/_plot/_models/_plot_types/_violin.py +36 -0
- scitex/fts/_kinds/_plot/_utils/__init__.py +129 -0
- scitex/fts/_kinds/_plot/_utils/_auto_layout.py +127 -0
- scitex/fts/_kinds/_plot/_utils/_calc_bounds.py +111 -0
- scitex/fts/_kinds/_plot/_utils/_const_sizes.py +48 -0
- scitex/fts/_kinds/_plot/_utils/_convert_coords.py +77 -0
- scitex/fts/_kinds/_plot/_utils/_get_template.py +178 -0
- scitex/fts/_kinds/_plot/_utils/_normalize.py +73 -0
- scitex/fts/_kinds/_plot/_utils/_plot_layout.py +397 -0
- scitex/fts/_kinds/_plot/_utils/_validate.py +197 -0
- scitex/fts/_kinds/_shape/__init__.py +141 -0
- scitex/fts/_kinds/_stats/__init__.py +56 -0
- scitex/fts/_kinds/_stats/_dataclasses/_Stats.py +423 -0
- scitex/fts/_kinds/_stats/_dataclasses/__init__.py +48 -0
- scitex/fts/_kinds/_table/__init__.py +72 -0
- scitex/fts/_kinds/_table/_latex/__init__.py +93 -0
- scitex/fts/_kinds/_table/_latex/_editor/__init__.py +11 -0
- scitex/fts/_kinds/_table/_latex/_editor/_app.py +725 -0
- scitex/fts/_kinds/_table/_latex/_export.py +279 -0
- scitex/fts/_kinds/_table/_latex/_figure_exporter.py +153 -0
- scitex/fts/_kinds/_table/_latex/_stats_formatter.py +274 -0
- scitex/fts/_kinds/_table/_latex/_table_exporter.py +362 -0
- scitex/fts/_kinds/_table/_latex/_utils.py +369 -0
- scitex/fts/_kinds/_table/_latex/_validator.py +445 -0
- scitex/fts/_kinds/_text/__init__.py +77 -0
- scitex/fts/_schemas/data_info.schema.json +75 -0
- scitex/fts/_schemas/encoding.schema.json +90 -0
- scitex/fts/_schemas/node.schema.json +145 -0
- scitex/fts/_schemas/render_manifest.schema.json +62 -0
- scitex/fts/_schemas/stats.schema.json +132 -0
- scitex/fts/_schemas/theme.schema.json +141 -0
- scitex/fts/_stats/__init__.py +48 -0
- scitex/fts/_stats/_dataclasses/_Stats.py +423 -0
- scitex/fts/_stats/_dataclasses/__init__.py +48 -0
- scitex/fts/_tables/__init__.py +65 -0
- scitex/fts/_tables/_latex/__init__.py +93 -0
- scitex/fts/_tables/_latex/_editor/__init__.py +11 -0
- scitex/fts/_tables/_latex/_editor/_app.py +725 -0
- scitex/fts/_tables/_latex/_export.py +279 -0
- scitex/fts/_tables/_latex/_figure_exporter.py +153 -0
- scitex/fts/_tables/_latex/_stats_formatter.py +274 -0
- scitex/fts/_tables/_latex/_table_exporter.py +362 -0
- scitex/fts/_tables/_latex/_utils.py +369 -0
- scitex/fts/_tables/_latex/_validator.py +445 -0
- scitex/gen/__init__.py +66 -25
- scitex/gen/misc.py +28 -0
- scitex/io/__init__.py +47 -20
- scitex/io/_load.py +87 -36
- scitex/io/_load_modules/__init__.py +10 -7
- scitex/io/_load_modules/_pandas.py +6 -1
- scitex/io/_save.py +299 -1556
- scitex/io/_save_modules/__init__.py +76 -19
- scitex/io/_save_modules/_figure_utils.py +90 -0
- scitex/io/_save_modules/_image_csv.py +497 -0
- scitex/io/_save_modules/_legends.py +91 -0
- scitex/io/_save_modules/_pltz_bundle.py +356 -0
- scitex/io/_save_modules/_pltz_stx.py +536 -0
- scitex/io/_save_modules/_stx_bundle.py +104 -0
- scitex/io/_save_modules/_symlink.py +96 -0
- scitex/io/_save_modules/_yaml.py +1 -1
- scitex/io/_save_modules/_zarr.py +64 -18
- scitex/io/bundle/README.md +212 -0
- scitex/io/bundle/__init__.py +110 -0
- scitex/io/{_bundle.py → bundle/_core.py} +219 -89
- scitex/io/bundle/_nested.py +713 -0
- scitex/io/bundle/_types.py +74 -0
- scitex/io/bundle/_zip.py +487 -0
- scitex/io/utils/h5_to_zarr.py +1 -1
- scitex/logging/__init__.py +108 -13
- scitex/logging/_errors.py +508 -0
- scitex/logging/_formatters.py +30 -6
- scitex/logging/_warnings.py +261 -0
- scitex/plt/__init__.py +4 -1
- scitex/plt/_figrecipe.py +236 -0
- scitex/plt/_subplots/_AxisWrapper.py +6 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/__init__.py +0 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/_labels.py +0 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/_metadata.py +0 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin/_visual.py +0 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/__init__.py +0 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_base.py +0 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_scientific.py +0 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_statistical.py +0 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin/_stx_aliases.py +0 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_RawMatplotlibMixin.py +0 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/__init__.py +0 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_base.py +0 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_wrappers.py +0 -0
- scitex/plt/_subplots/_AxisWrapperMixins/_UnitAwareMixin.py +112 -1
- scitex/plt/_subplots/_FigWrapper.py +15 -0
- scitex/plt/_subplots/_SubplotsWrapper.py +125 -489
- scitex/plt/_subplots/_export_as_csv.py +11 -0
- scitex/plt/_subplots/_export_as_csv_formatters/__init__.py +2 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_pcolormesh.py +66 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stackplot.py +62 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_bar.py +0 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_barh.py +0 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_errorbar.py +0 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_stx_scatter.py +0 -0
- scitex/plt/_subplots/_export_as_csv_formatters/test_formatters.py +208 -0
- scitex/plt/_subplots/_fonts.py +71 -0
- scitex/plt/_subplots/_mm_layout.py +282 -0
- scitex/plt/gallery/__init__.py +99 -2
- scitex/plt/io/_layered_bundle.py +0 -0
- scitex/plt/styles/_plot_postprocess.py +3 -1
- scitex/plt/utils/_configure_mpl.py +16 -19
- scitex/repro/_RandomStateManager.py +13 -8
- scitex/resource/__init__.py +19 -1
- scitex/resource/_utils/_get_env_info.py +13 -25
- scitex/schema/__init__.py +149 -160
- scitex/schema/_encoding.py +273 -0
- scitex/schema/_figure_elements.py +406 -0
- scitex/schema/_plot.py +0 -0
- scitex/schema/_theme.py +360 -0
- scitex/schema/_validation.py +0 -98
- scitex/scholar/__init__.py +56 -14
- scitex/scholar/auth/ScholarAuthManager.py +1 -1
- scitex/scholar/auth/__init__.py +11 -2
- scitex/scholar/auth/providers/BaseAuthenticator.py +1 -1
- scitex/scholar/auth/providers/EZProxyAuthenticator.py +1 -1
- scitex/scholar/auth/providers/OpenAthensAuthenticator.py +1 -1
- scitex/scholar/auth/providers/ShibbolethAuthenticator.py +1 -1
- scitex/scholar/config/ScholarConfig.py +1 -1
- scitex/scholar/core/Scholar.py +1 -1
- scitex/session/_decorator.py +18 -16
- scitex/session/_lifecycle.py +9 -11
- scitex/session/template.py +9 -8
- scitex/sh/test_sh.py +72 -0
- scitex/sh/test_sh_simple.py +61 -0
- scitex/stats/__init__.py +221 -97
- scitex/stats/_schema.py +21 -22
- scitex/stats/descriptive/_circular.py +212 -351
- scitex/stats/descriptive/_describe.py +81 -132
- scitex/stats/descriptive/_nan.py +205 -433
- scitex/stats/descriptive/_real.py +127 -141
- scitex/str/_format_plot_text.py +5 -5
- scitex/str/_latex.py +26 -84
- scitex/str/_latex_fallback.py +53 -47
- scitex/web/_search_pubmed.py +5 -4
- scitex/writer/tests/test_diff_between.py +451 -0
- scitex/writer/tests/test_document_section.py +311 -0
- scitex/writer/tests/test_document_workflow.py +393 -0
- scitex/writer/tests/test_writer.py +361 -0
- scitex/writer/tests/test_writer_integration.py +303 -0
- {scitex-2.7.3.dist-info → scitex-2.10.0.dist-info}/METADATA +364 -181
- {scitex-2.7.3.dist-info → scitex-2.10.0.dist-info}/RECORD +479 -108
- scitex/fig/editor/_edit.py +0 -751
- scitex/scholar/docs/to_claude/guidelines/examples/mgmt/ARCHITECTURE_EXAMPLE.md +0 -905
- scitex/scholar/docs/to_claude/guidelines/examples/mgmt/BULLETIN_BOARD_EXAMPLE.md +0 -99
- scitex/scholar/docs/to_claude/guidelines/examples/mgmt/PROJECT_DESCRIPTION_EXAMPLE.md +0 -96
- {scitex-2.7.3.dist-info → scitex-2.10.0.dist-info}/WHEEL +0 -0
- {scitex-2.7.3.dist-info → scitex-2.10.0.dist-info}/entry_points.txt +0 -0
- {scitex-2.7.3.dist-info → scitex-2.10.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,24 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
|
-
# Timestamp: "2025-12-
|
|
4
|
-
# File: /home/ywatanabe/proj/scitex-code/src/scitex/io/
|
|
3
|
+
# Timestamp: "2025-12-16 (ywatanabe)"
|
|
4
|
+
# File: /home/ywatanabe/proj/scitex-code/src/scitex/io/bundle/_core.py
|
|
5
5
|
|
|
6
6
|
"""
|
|
7
|
-
SciTeX Bundle
|
|
7
|
+
SciTeX Bundle Core Operations.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
- scitex.fig.io._bundle (figz: panel composition, nested pltz)
|
|
12
|
-
- scitex.stats.io._bundle (statsz: comparison metadata)
|
|
9
|
+
Provides load, save, copy, pack, unpack, and validate operations for
|
|
10
|
+
.figz, .pltz, and .statsz bundle formats.
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
.statsz - Statistical Results Bundle (stats + metadata)
|
|
18
|
-
|
|
19
|
-
Each bundle can be:
|
|
20
|
-
- Directory form: Figure1.figz.d/
|
|
21
|
-
- ZIP archive form: Figure1.figz
|
|
12
|
+
Each bundle can exist in two forms:
|
|
13
|
+
- Directory: Figure1.figz.d/
|
|
14
|
+
- ZIP archive: Figure1.figz
|
|
22
15
|
"""
|
|
23
16
|
|
|
24
17
|
import json
|
|
@@ -27,59 +20,55 @@ import zipfile
|
|
|
27
20
|
from pathlib import Path
|
|
28
21
|
from typing import Any, Dict, List, Optional, Union
|
|
29
22
|
|
|
23
|
+
from ._types import (
|
|
24
|
+
EXTENSIONS,
|
|
25
|
+
BundleNotFoundError,
|
|
26
|
+
BundleType,
|
|
27
|
+
BundleValidationError,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
30
|
__all__ = [
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
31
|
+
"load",
|
|
32
|
+
"save",
|
|
33
|
+
"copy",
|
|
34
|
+
"pack",
|
|
35
|
+
"unpack",
|
|
36
|
+
"validate",
|
|
37
37
|
"validate_spec",
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"BUNDLE_EXTENSIONS",
|
|
41
|
-
"get_bundle_type",
|
|
38
|
+
"is_bundle",
|
|
39
|
+
"get_type",
|
|
42
40
|
"dir_to_zip_path",
|
|
43
41
|
"zip_to_dir_path",
|
|
44
42
|
]
|
|
45
43
|
|
|
46
|
-
# Bundle extensions
|
|
47
|
-
BUNDLE_EXTENSIONS = (".figz", ".pltz", ".statsz")
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
class BundleValidationError(ValueError):
|
|
51
|
-
"""Error raised when bundle validation fails."""
|
|
52
|
-
pass
|
|
53
|
-
|
|
54
44
|
|
|
55
|
-
|
|
56
|
-
"""Bundle type constants."""
|
|
57
|
-
FIGZ = "figz"
|
|
58
|
-
PLTZ = "pltz"
|
|
59
|
-
STATSZ = "statsz"
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
def get_bundle_type(path: Union[str, Path]) -> Optional[str]:
|
|
45
|
+
def get_type(path: Union[str, Path]) -> Optional[str]:
|
|
63
46
|
"""Get bundle type from path.
|
|
64
47
|
|
|
65
48
|
Args:
|
|
66
49
|
path: Path to bundle (directory or ZIP).
|
|
67
50
|
|
|
68
51
|
Returns:
|
|
69
|
-
Bundle type string or None if not a bundle.
|
|
52
|
+
Bundle type string ('figz', 'pltz', 'statsz') or None if not a bundle.
|
|
53
|
+
|
|
54
|
+
Example:
|
|
55
|
+
>>> get_type("Figure1.figz")
|
|
56
|
+
'figz'
|
|
57
|
+
>>> get_type("plot.pltz.d")
|
|
58
|
+
'pltz'
|
|
70
59
|
"""
|
|
71
60
|
p = Path(path)
|
|
72
61
|
|
|
73
62
|
# Directory bundle: ends with .figz.d, .pltz.d, .statsz.d
|
|
74
63
|
if p.is_dir() and p.suffix == ".d":
|
|
75
64
|
stem = p.stem # e.g., "Figure1.figz"
|
|
76
|
-
for ext in
|
|
65
|
+
for ext in EXTENSIONS:
|
|
77
66
|
if stem.endswith(ext):
|
|
78
67
|
return ext[1:] # Remove leading dot
|
|
79
68
|
return None
|
|
80
69
|
|
|
81
70
|
# ZIP bundle: ends with .figz, .pltz, .statsz
|
|
82
|
-
if p.suffix in
|
|
71
|
+
if p.suffix in EXTENSIONS:
|
|
83
72
|
return p.suffix[1:] # Remove leading dot
|
|
84
73
|
|
|
85
74
|
return None
|
|
@@ -93,14 +82,22 @@ def is_bundle(path: Union[str, Path]) -> bool:
|
|
|
93
82
|
|
|
94
83
|
Returns:
|
|
95
84
|
True if path is a bundle.
|
|
85
|
+
|
|
86
|
+
Example:
|
|
87
|
+
>>> is_bundle("Figure1.figz")
|
|
88
|
+
True
|
|
89
|
+
>>> is_bundle("data.csv")
|
|
90
|
+
False
|
|
96
91
|
"""
|
|
97
|
-
return
|
|
92
|
+
return get_type(path) is not None
|
|
98
93
|
|
|
99
94
|
|
|
100
95
|
def dir_to_zip_path(dir_path: Path) -> Path:
|
|
101
96
|
"""Convert directory path to ZIP path.
|
|
102
97
|
|
|
103
|
-
Example:
|
|
98
|
+
Example:
|
|
99
|
+
>>> dir_to_zip_path(Path("Figure1.figz.d"))
|
|
100
|
+
Path('Figure1.figz')
|
|
104
101
|
"""
|
|
105
102
|
if dir_path.suffix == ".d":
|
|
106
103
|
return dir_path.with_suffix("")
|
|
@@ -110,12 +107,14 @@ def dir_to_zip_path(dir_path: Path) -> Path:
|
|
|
110
107
|
def zip_to_dir_path(zip_path: Path) -> Path:
|
|
111
108
|
"""Convert ZIP path to directory path.
|
|
112
109
|
|
|
113
|
-
Example:
|
|
110
|
+
Example:
|
|
111
|
+
>>> zip_to_dir_path(Path("Figure1.figz"))
|
|
112
|
+
Path('Figure1.figz.d')
|
|
114
113
|
"""
|
|
115
114
|
return Path(str(zip_path) + ".d")
|
|
116
115
|
|
|
117
116
|
|
|
118
|
-
def
|
|
117
|
+
def pack(
|
|
119
118
|
dir_path: Union[str, Path], output_path: Optional[Union[str, Path]] = None
|
|
120
119
|
) -> Path:
|
|
121
120
|
"""Pack a bundle directory into a ZIP archive.
|
|
@@ -129,6 +128,10 @@ def pack_bundle(
|
|
|
129
128
|
|
|
130
129
|
Returns:
|
|
131
130
|
Path to created ZIP archive.
|
|
131
|
+
|
|
132
|
+
Example:
|
|
133
|
+
>>> pack("plot.pltz.d")
|
|
134
|
+
Path('plot.pltz')
|
|
132
135
|
"""
|
|
133
136
|
dir_path = Path(dir_path)
|
|
134
137
|
|
|
@@ -141,15 +144,12 @@ def pack_bundle(
|
|
|
141
144
|
output_path = Path(output_path)
|
|
142
145
|
|
|
143
146
|
# Get the directory name to use as top-level folder in ZIP
|
|
144
|
-
# e.g., "stx_line.pltz.d" for path "/path/to/stx_line.pltz.d"
|
|
145
147
|
dir_name = dir_path.name
|
|
146
148
|
|
|
147
149
|
# Create ZIP archive with directory structure preserved
|
|
148
150
|
with zipfile.ZipFile(output_path, "w", zipfile.ZIP_DEFLATED) as zf:
|
|
149
151
|
for file_path in dir_path.rglob("*"):
|
|
150
152
|
if file_path.is_file():
|
|
151
|
-
# Include directory name in archive path
|
|
152
|
-
# e.g., "stx_line.pltz.d/stx_line.csv"
|
|
153
153
|
rel_path = file_path.relative_to(dir_path)
|
|
154
154
|
arcname = Path(dir_name) / rel_path
|
|
155
155
|
zf.write(file_path, arcname)
|
|
@@ -157,29 +157,28 @@ def pack_bundle(
|
|
|
157
157
|
return output_path
|
|
158
158
|
|
|
159
159
|
|
|
160
|
-
def
|
|
160
|
+
def unpack(
|
|
161
161
|
zip_path: Union[str, Path], output_path: Optional[Union[str, Path]] = None
|
|
162
162
|
) -> Path:
|
|
163
163
|
"""Unpack a bundle ZIP archive into a directory.
|
|
164
164
|
|
|
165
|
-
The ZIP archive contains a top-level .d directory, so extraction goes to
|
|
166
|
-
the parent directory. E.g., stx_line.pltz extracts to create stx_line.pltz.d/
|
|
167
|
-
|
|
168
165
|
Args:
|
|
169
166
|
zip_path: Path to bundle ZIP (e.g., Figure1.figz).
|
|
170
167
|
output_path: Output directory path. Auto-generated if None.
|
|
171
168
|
|
|
172
169
|
Returns:
|
|
173
170
|
Path to created directory.
|
|
171
|
+
|
|
172
|
+
Example:
|
|
173
|
+
>>> unpack("plot.pltz")
|
|
174
|
+
Path('plot.pltz.d')
|
|
174
175
|
"""
|
|
175
176
|
zip_path = Path(zip_path)
|
|
176
177
|
|
|
177
178
|
if not zip_path.is_file():
|
|
178
179
|
raise ValueError(f"Not a file: {zip_path}")
|
|
179
180
|
|
|
180
|
-
# Determine extraction target
|
|
181
181
|
if output_path is None:
|
|
182
|
-
# Extract to same directory as ZIP file (ZIP contains .d folder structure)
|
|
183
182
|
extract_to = zip_path.parent
|
|
184
183
|
expected_dir = zip_to_dir_path(zip_path)
|
|
185
184
|
else:
|
|
@@ -187,7 +186,6 @@ def unpack_bundle(
|
|
|
187
186
|
extract_to = output_path.parent
|
|
188
187
|
expected_dir = output_path
|
|
189
188
|
|
|
190
|
-
# Extract ZIP archive (contains .d directory structure)
|
|
191
189
|
with zipfile.ZipFile(zip_path, "r") as zf:
|
|
192
190
|
zf.extractall(extract_to)
|
|
193
191
|
|
|
@@ -227,12 +225,15 @@ def validate_spec(
|
|
|
227
225
|
# Delegate to domain-specific validators
|
|
228
226
|
if bundle_type == BundleType.FIGZ:
|
|
229
227
|
from scitex.fig.io._bundle import validate_figz_spec
|
|
228
|
+
|
|
230
229
|
errors.extend(validate_figz_spec(spec))
|
|
231
230
|
elif bundle_type == BundleType.PLTZ:
|
|
232
231
|
from scitex.plt.io._bundle import validate_pltz_spec
|
|
232
|
+
|
|
233
233
|
errors.extend(validate_pltz_spec(spec))
|
|
234
234
|
elif bundle_type == BundleType.STATSZ:
|
|
235
235
|
from scitex.stats.io._bundle import validate_statsz_spec
|
|
236
|
+
|
|
236
237
|
errors.extend(validate_statsz_spec(spec))
|
|
237
238
|
else:
|
|
238
239
|
errors.append(f"Unknown bundle type: {bundle_type}")
|
|
@@ -243,9 +244,7 @@ def validate_spec(
|
|
|
243
244
|
return errors
|
|
244
245
|
|
|
245
246
|
|
|
246
|
-
def
|
|
247
|
-
path: Union[str, Path], strict: bool = False
|
|
248
|
-
) -> Dict[str, Any]:
|
|
247
|
+
def validate(path: Union[str, Path], strict: bool = False) -> Dict[str, Any]:
|
|
249
248
|
"""Validate a bundle and return validation results.
|
|
250
249
|
|
|
251
250
|
Args:
|
|
@@ -271,8 +270,7 @@ def validate_bundle(
|
|
|
271
270
|
|
|
272
271
|
p = Path(path)
|
|
273
272
|
|
|
274
|
-
|
|
275
|
-
bundle_type = get_bundle_type(p)
|
|
273
|
+
bundle_type = get_type(p)
|
|
276
274
|
if bundle_type is None:
|
|
277
275
|
result["valid"] = False
|
|
278
276
|
result["errors"].append(f"Not a valid bundle path: {path}")
|
|
@@ -282,9 +280,8 @@ def validate_bundle(
|
|
|
282
280
|
|
|
283
281
|
result["bundle_type"] = bundle_type
|
|
284
282
|
|
|
285
|
-
# Try to load and validate
|
|
286
283
|
try:
|
|
287
|
-
bundle =
|
|
284
|
+
bundle = load(path)
|
|
288
285
|
spec = bundle.get("spec")
|
|
289
286
|
result["spec"] = spec
|
|
290
287
|
|
|
@@ -307,11 +304,13 @@ def validate_bundle(
|
|
|
307
304
|
return result
|
|
308
305
|
|
|
309
306
|
|
|
310
|
-
def
|
|
307
|
+
def load(path: Union[str, Path], in_memory: bool = True) -> Dict[str, Any]:
|
|
311
308
|
"""Load bundle from directory or ZIP transparently.
|
|
312
309
|
|
|
313
310
|
Args:
|
|
314
311
|
path: Path to bundle (directory or ZIP).
|
|
312
|
+
in_memory: If True, load ZIP contents in-memory without extracting.
|
|
313
|
+
If False, extract to temp directory (legacy behavior).
|
|
315
314
|
|
|
316
315
|
Returns:
|
|
317
316
|
Bundle data as dictionary with:
|
|
@@ -320,12 +319,19 @@ def load_bundle(path: Union[str, Path]) -> Dict[str, Any]:
|
|
|
320
319
|
- 'path': Original path
|
|
321
320
|
- 'is_zip': Whether loaded from ZIP
|
|
322
321
|
- Additional fields based on bundle type
|
|
322
|
+
|
|
323
|
+
Example:
|
|
324
|
+
>>> bundle = load("Figure1.figz")
|
|
325
|
+
>>> bundle['type']
|
|
326
|
+
'figz'
|
|
327
|
+
>>> bundle['spec']['schema']['name']
|
|
328
|
+
'scitex.fig'
|
|
323
329
|
"""
|
|
324
330
|
p = Path(path)
|
|
325
|
-
bundle_type =
|
|
331
|
+
bundle_type = get_type(p)
|
|
326
332
|
|
|
327
333
|
if bundle_type is None:
|
|
328
|
-
raise
|
|
334
|
+
raise BundleNotFoundError(f"Not a valid bundle: {path}")
|
|
329
335
|
|
|
330
336
|
result = {
|
|
331
337
|
"type": bundle_type,
|
|
@@ -334,36 +340,63 @@ def load_bundle(path: Union[str, Path]) -> Dict[str, Any]:
|
|
|
334
340
|
}
|
|
335
341
|
|
|
336
342
|
# Handle ZIP vs directory
|
|
337
|
-
if p.is_file() and p.suffix in
|
|
338
|
-
# ZIP archive - extract to temp and load
|
|
343
|
+
if p.is_file() and p.suffix in EXTENSIONS:
|
|
339
344
|
result["is_zip"] = True
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
+
|
|
346
|
+
if in_memory:
|
|
347
|
+
from ._zip import ZipBundle
|
|
348
|
+
|
|
349
|
+
with ZipBundle(p, mode="r") as zb:
|
|
350
|
+
result["_zip_bundle"] = zb
|
|
351
|
+
try:
|
|
352
|
+
result["spec"] = zb.read_json("spec.json")
|
|
353
|
+
except FileNotFoundError:
|
|
354
|
+
result["spec"] = None
|
|
355
|
+
try:
|
|
356
|
+
result["style"] = zb.read_json("style.json")
|
|
357
|
+
except FileNotFoundError:
|
|
358
|
+
result["style"] = None
|
|
359
|
+
try:
|
|
360
|
+
result["data"] = zb.read_csv("data.csv")
|
|
361
|
+
except FileNotFoundError:
|
|
362
|
+
result["data"] = None
|
|
363
|
+
|
|
364
|
+
result["files"] = zb.namelist()
|
|
365
|
+
|
|
366
|
+
return result
|
|
367
|
+
else:
|
|
368
|
+
import tempfile
|
|
369
|
+
|
|
370
|
+
temp_dir = Path(tempfile.mkdtemp())
|
|
371
|
+
with zipfile.ZipFile(p, "r") as zf:
|
|
372
|
+
zf.extractall(temp_dir)
|
|
373
|
+
bundle_dir = temp_dir
|
|
345
374
|
else:
|
|
346
375
|
bundle_dir = p
|
|
347
376
|
|
|
348
377
|
# Delegate to domain-specific loaders
|
|
349
378
|
if bundle_type == BundleType.FIGZ:
|
|
350
379
|
from scitex.fig.io._bundle import load_figz_bundle
|
|
380
|
+
|
|
351
381
|
result.update(load_figz_bundle(bundle_dir))
|
|
352
382
|
elif bundle_type == BundleType.PLTZ:
|
|
353
383
|
from scitex.plt.io import load_layered_pltz_bundle
|
|
384
|
+
|
|
354
385
|
result.update(load_layered_pltz_bundle(bundle_dir))
|
|
355
386
|
elif bundle_type == BundleType.STATSZ:
|
|
356
387
|
from scitex.stats.io._bundle import load_statsz_bundle
|
|
388
|
+
|
|
357
389
|
result.update(load_statsz_bundle(bundle_dir))
|
|
358
390
|
|
|
359
391
|
return result
|
|
360
392
|
|
|
361
393
|
|
|
362
|
-
def
|
|
394
|
+
def save(
|
|
363
395
|
data: Dict[str, Any],
|
|
364
396
|
path: Union[str, Path],
|
|
365
397
|
bundle_type: Optional[str] = None,
|
|
366
398
|
as_zip: bool = False,
|
|
399
|
+
atomic: bool = True,
|
|
367
400
|
) -> Path:
|
|
368
401
|
"""Save data as a bundle.
|
|
369
402
|
|
|
@@ -372,20 +405,24 @@ def save_bundle(
|
|
|
372
405
|
path: Output path (with or without .d suffix).
|
|
373
406
|
bundle_type: Bundle type ('figz', 'pltz', 'statsz'). Auto-detected if None.
|
|
374
407
|
as_zip: If True, save as ZIP archive.
|
|
408
|
+
atomic: If True, use atomic write (temp file + rename) for ZIP.
|
|
375
409
|
|
|
376
410
|
Returns:
|
|
377
411
|
Path to saved bundle.
|
|
412
|
+
|
|
413
|
+
Example:
|
|
414
|
+
>>> save({"spec": {...}, "data": df}, "plot.pltz", as_zip=True)
|
|
415
|
+
Path('plot.pltz')
|
|
378
416
|
"""
|
|
379
417
|
p = Path(path)
|
|
380
418
|
|
|
381
|
-
# Determine bundle type
|
|
382
419
|
if bundle_type is None:
|
|
383
|
-
bundle_type =
|
|
420
|
+
bundle_type = get_type(p)
|
|
384
421
|
if bundle_type is None:
|
|
385
422
|
raise ValueError(f"Cannot determine bundle type from path: {path}")
|
|
386
423
|
|
|
387
424
|
# Determine if saving as directory or ZIP
|
|
388
|
-
if as_zip or (p.suffix in
|
|
425
|
+
if as_zip or (p.suffix in EXTENSIONS and not str(p).endswith(".d")):
|
|
389
426
|
save_as_zip = True
|
|
390
427
|
if p.suffix == ".d":
|
|
391
428
|
zip_path = dir_to_zip_path(p)
|
|
@@ -399,36 +436,129 @@ def save_bundle(
|
|
|
399
436
|
else:
|
|
400
437
|
dir_path = p
|
|
401
438
|
|
|
402
|
-
#
|
|
439
|
+
# For direct ZIP saving with atomic writes
|
|
440
|
+
if save_as_zip and atomic and bundle_type != BundleType.FIGZ:
|
|
441
|
+
from ._zip import ZipBundle
|
|
442
|
+
|
|
443
|
+
with ZipBundle(zip_path, mode="w") as zb:
|
|
444
|
+
if "spec" in data:
|
|
445
|
+
zb.write_json("spec.json", data["spec"])
|
|
446
|
+
|
|
447
|
+
if "style" in data:
|
|
448
|
+
zb.write_json("style.json", data["style"])
|
|
449
|
+
|
|
450
|
+
if "data" in data and data["data"] is not None:
|
|
451
|
+
import pandas as pd
|
|
452
|
+
|
|
453
|
+
if isinstance(data["data"], pd.DataFrame):
|
|
454
|
+
zb.write_csv("data.csv", data["data"])
|
|
455
|
+
|
|
456
|
+
for key in ["png", "svg", "pdf"]:
|
|
457
|
+
if key in data and data[key] is not None:
|
|
458
|
+
export_data = data[key]
|
|
459
|
+
if isinstance(export_data, bytes):
|
|
460
|
+
zb.write_bytes(f"exports/figure.{key}", export_data)
|
|
461
|
+
|
|
462
|
+
return zip_path
|
|
463
|
+
|
|
403
464
|
dir_path.mkdir(parents=True, exist_ok=True)
|
|
404
465
|
|
|
405
466
|
# Delegate to domain-specific savers
|
|
406
467
|
if bundle_type == BundleType.FIGZ:
|
|
407
468
|
from scitex.fig.io._bundle import save_figz_bundle
|
|
469
|
+
|
|
408
470
|
save_figz_bundle(data, dir_path)
|
|
409
471
|
elif bundle_type == BundleType.PLTZ:
|
|
410
|
-
# Note: This path is only reached when calling save_bundle() directly
|
|
411
|
-
# The main stx.io.save() flow uses _save_pltz_bundle() which handles layered format
|
|
412
472
|
from scitex.plt.io._bundle import save_pltz_bundle
|
|
473
|
+
|
|
413
474
|
save_pltz_bundle(data, dir_path)
|
|
414
475
|
elif bundle_type == BundleType.STATSZ:
|
|
415
476
|
from scitex.stats.io._bundle import save_statsz_bundle
|
|
477
|
+
|
|
416
478
|
save_statsz_bundle(data, dir_path)
|
|
417
479
|
else:
|
|
418
480
|
raise ValueError(f"Unknown bundle type: {bundle_type}")
|
|
419
481
|
|
|
420
|
-
# Pack to ZIP if requested
|
|
421
482
|
if save_as_zip:
|
|
422
|
-
|
|
423
|
-
shutil.rmtree(dir_path)
|
|
483
|
+
pack(dir_path, zip_path)
|
|
484
|
+
shutil.rmtree(dir_path)
|
|
424
485
|
return zip_path
|
|
425
486
|
|
|
426
487
|
return dir_path
|
|
427
488
|
|
|
428
489
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
490
|
+
def copy(
|
|
491
|
+
src: Union[str, Path],
|
|
492
|
+
dst: Union[str, Path],
|
|
493
|
+
overwrite: bool = False,
|
|
494
|
+
) -> Path:
|
|
495
|
+
"""Copy a bundle from source to destination.
|
|
496
|
+
|
|
497
|
+
Handles both directory (.d) and ZIP formats transparently.
|
|
498
|
+
If source is ZIP, extracts to destination directory.
|
|
499
|
+
If source is directory, copies to destination directory.
|
|
500
|
+
|
|
501
|
+
Args:
|
|
502
|
+
src: Source bundle path (directory or ZIP).
|
|
503
|
+
dst: Destination path (will be created as directory).
|
|
504
|
+
overwrite: If True, overwrite existing destination.
|
|
505
|
+
|
|
506
|
+
Returns:
|
|
507
|
+
Path to copied bundle (directory form).
|
|
508
|
+
|
|
509
|
+
Raises:
|
|
510
|
+
BundleNotFoundError: If source bundle doesn't exist.
|
|
511
|
+
FileExistsError: If destination exists and overwrite=False.
|
|
512
|
+
|
|
513
|
+
Example:
|
|
514
|
+
>>> copy("gallery/line/plot.pltz.d", "my_project/A.pltz.d")
|
|
515
|
+
>>> copy("template.pltz", "output/panel.pltz.d")
|
|
516
|
+
"""
|
|
517
|
+
src_path = Path(src)
|
|
518
|
+
dst_path = Path(dst)
|
|
519
|
+
|
|
520
|
+
# Validate source exists
|
|
521
|
+
if not src_path.exists():
|
|
522
|
+
if src_path.suffix in EXTENSIONS:
|
|
523
|
+
alt_path = Path(str(src_path) + ".d")
|
|
524
|
+
if alt_path.exists():
|
|
525
|
+
src_path = alt_path
|
|
526
|
+
else:
|
|
527
|
+
raise BundleNotFoundError(
|
|
528
|
+
f"Bundle not found: {src} (also tried {alt_path})"
|
|
529
|
+
)
|
|
530
|
+
elif str(src_path).endswith(".d"):
|
|
531
|
+
alt_path = Path(str(src_path)[:-2])
|
|
532
|
+
if alt_path.exists():
|
|
533
|
+
src_path = alt_path
|
|
534
|
+
else:
|
|
535
|
+
raise BundleNotFoundError(
|
|
536
|
+
f"Bundle not found: {src} (also tried {alt_path})"
|
|
537
|
+
)
|
|
538
|
+
else:
|
|
539
|
+
raise BundleNotFoundError(f"Bundle not found: {src}")
|
|
540
|
+
|
|
541
|
+
# Handle destination
|
|
542
|
+
if dst_path.exists():
|
|
543
|
+
if overwrite:
|
|
544
|
+
if dst_path.is_dir():
|
|
545
|
+
shutil.rmtree(dst_path)
|
|
546
|
+
else:
|
|
547
|
+
dst_path.unlink()
|
|
548
|
+
else:
|
|
549
|
+
raise FileExistsError(f"Destination exists: {dst}")
|
|
550
|
+
|
|
551
|
+
dst_path.parent.mkdir(parents=True, exist_ok=True)
|
|
552
|
+
|
|
553
|
+
# Copy based on source type
|
|
554
|
+
if src_path.is_dir():
|
|
555
|
+
shutil.copytree(src_path, dst_path)
|
|
556
|
+
elif src_path.suffix in EXTENSIONS or zipfile.is_zipfile(src_path):
|
|
557
|
+
unpack(src_path, dst_path)
|
|
558
|
+
else:
|
|
559
|
+
raise ValueError(f"Unknown bundle format: {src_path}")
|
|
560
|
+
|
|
561
|
+
return dst_path
|
|
562
|
+
|
|
433
563
|
|
|
434
564
|
# EOF
|