scitex 2.8.1__py3-none-any.whl → 2.10.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/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/edit/panel_loader.py +1 -1
- scitex/fig/io/_bundle.py +7 -7
- 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 -32
- 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} +168 -97
- scitex/io/bundle/_nested.py +713 -0
- scitex/io/bundle/_types.py +74 -0
- scitex/io/{_zip_bundle.py → bundle/_zip.py} +93 -45
- 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/_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/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/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/_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.8.1.dist-info → scitex-2.10.2.dist-info}/METADATA +368 -183
- {scitex-2.8.1.dist-info → scitex-2.10.2.dist-info}/RECORD +412 -97
- 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.8.1.dist-info → scitex-2.10.2.dist-info}/WHEEL +0 -0
- {scitex-2.8.1.dist-info → scitex-2.10.2.dist-info}/entry_points.txt +0 -0
- {scitex-2.8.1.dist-info → scitex-2.10.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Timestamp: "2025-12-21 13:11:56 (ywatanabe)"
|
|
4
|
+
# File: /home/ywatanabe/proj/scitex-code/src/scitex/io/_save_modules/_symlink.py
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# Timestamp: 2025-12-19
|
|
8
|
+
|
|
9
|
+
"""Symlink creation utilities for save operations."""
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
from scitex import logging
|
|
15
|
+
from scitex.path._clean import clean
|
|
16
|
+
from scitex.sh import sh
|
|
17
|
+
from scitex.str._color_text import color_text
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def symlink(spath, spath_cwd, symlink_from_cwd, verbose):
|
|
23
|
+
"""Create a symbolic link from the current working directory."""
|
|
24
|
+
if symlink_from_cwd and (spath != spath_cwd):
|
|
25
|
+
os.makedirs(os.path.dirname(spath_cwd), exist_ok=True)
|
|
26
|
+
sh(["rm", "-f", f"{spath_cwd}"], verbose=False)
|
|
27
|
+
sh(["ln", "-sfr", f"{spath}", f"{spath_cwd}"], verbose=False)
|
|
28
|
+
if verbose:
|
|
29
|
+
# Get file extension to provide more informative message
|
|
30
|
+
ext = os.path.splitext(spath_cwd)[1].lower()
|
|
31
|
+
logger.success(color_text(f"(Symlinked to: {spath_cwd})"))
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# def symlink_to(spath_final, symlink_to_path, verbose):
|
|
35
|
+
# """Create a symbolic link at the specified path pointing to the saved file."""
|
|
36
|
+
# if symlink_to_path:
|
|
37
|
+
# # Convert Path objects to strings for consistency
|
|
38
|
+
# if isinstance(symlink_to_path, Path):
|
|
39
|
+
# symlink_to_path = str(symlink_to_path)
|
|
40
|
+
|
|
41
|
+
# # Clean the symlink path
|
|
42
|
+
# symlink_to_path = clean(symlink_to_path)
|
|
43
|
+
|
|
44
|
+
# # Ensure the symlink directory exists (only if there is a directory component)
|
|
45
|
+
# symlink_dir = os.path.dirname(symlink_to_path)
|
|
46
|
+
# if symlink_dir: # Only create directory if there's a directory component
|
|
47
|
+
# os.makedirs(symlink_dir, exist_ok=True)
|
|
48
|
+
|
|
49
|
+
# # Remove existing symlink or file
|
|
50
|
+
# sh(["rm", "-f", f"{symlink_to_path}"], verbose=False)
|
|
51
|
+
|
|
52
|
+
# # Create the symlink using relative path for robustness
|
|
53
|
+
# sh(["ln", "-sfr", f"{spath_final}", f"{symlink_to_path}"], verbose=False)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# if verbose:
|
|
57
|
+
# symlink_to_full = (
|
|
58
|
+
# os.path.realpath(symlink_to_path) + "/" + os.path.basename(spath_final)
|
|
59
|
+
# )
|
|
60
|
+
# logger.success(f"Symlinked: {spath_final} ->\n {symlink_to_full}")
|
|
61
|
+
def symlink_to(spath_final, symlink_to_path, verbose):
|
|
62
|
+
"""Create a symbolic link at the specified path pointing to the saved file."""
|
|
63
|
+
if symlink_to_path:
|
|
64
|
+
if isinstance(symlink_to_path, Path):
|
|
65
|
+
symlink_to_path = str(symlink_to_path)
|
|
66
|
+
|
|
67
|
+
symlink_to_path = clean(symlink_to_path)
|
|
68
|
+
|
|
69
|
+
if not os.path.isabs(symlink_to_path):
|
|
70
|
+
symlink_to_path = os.path.abspath(symlink_to_path)
|
|
71
|
+
|
|
72
|
+
if os.path.isdir(symlink_to_path) or (
|
|
73
|
+
not os.path.exists(symlink_to_path)
|
|
74
|
+
and not os.path.splitext(symlink_to_path)[1]
|
|
75
|
+
):
|
|
76
|
+
symlink_to_path = os.path.join(
|
|
77
|
+
symlink_to_path, os.path.basename(spath_final)
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
symlink_dir = os.path.dirname(symlink_to_path)
|
|
81
|
+
if symlink_dir:
|
|
82
|
+
os.makedirs(symlink_dir, exist_ok=True)
|
|
83
|
+
|
|
84
|
+
sh(["rm", "-f", f"{symlink_to_path}"], verbose=False)
|
|
85
|
+
sh(
|
|
86
|
+
["ln", "-sfr", f"{spath_final}", f"{symlink_to_path}"],
|
|
87
|
+
verbose=False,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
if verbose:
|
|
91
|
+
logger.success(
|
|
92
|
+
f"Symlinked: {spath_final} ->\n"
|
|
93
|
+
f" {symlink_to_path}"
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# EOF
|
scitex/io/_save_modules/_yaml.py
CHANGED
scitex/io/_save_modules/_zarr.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
2
|
# Timestamp: "2025-07-11 15:44:00 (ywatanabe)"
|
|
4
3
|
# File: /ssh:sp:/home/ywatanabe/proj/scitex_repo/src/scitex/io/_save_modules/_zarr.py
|
|
5
4
|
# ----------------------------------------
|
|
@@ -13,7 +12,55 @@ from typing import Any, Optional
|
|
|
13
12
|
|
|
14
13
|
import numpy as np
|
|
15
14
|
import zarr
|
|
16
|
-
|
|
15
|
+
|
|
16
|
+
# Detect Zarr version for API compatibility
|
|
17
|
+
ZARR_V3 = int(zarr.__version__.split(".")[0]) >= 3
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _get_compressor(compressor_name):
|
|
21
|
+
"""Get compressor based on Zarr version."""
|
|
22
|
+
if ZARR_V3:
|
|
23
|
+
from zarr.codecs import GzipCodec, ZstdCodec
|
|
24
|
+
|
|
25
|
+
compressor_map = {
|
|
26
|
+
"zstd": ZstdCodec(level=3),
|
|
27
|
+
"gzip": GzipCodec(level=5),
|
|
28
|
+
}
|
|
29
|
+
return compressor_map.get(compressor_name.lower(), ZstdCodec(level=3))
|
|
30
|
+
else:
|
|
31
|
+
from numcodecs import LZ4, GZip, Zstd
|
|
32
|
+
|
|
33
|
+
compressor_map = {
|
|
34
|
+
"zstd": Zstd(level=3),
|
|
35
|
+
"lz4": LZ4(acceleration=1),
|
|
36
|
+
"gzip": GZip(level=5),
|
|
37
|
+
}
|
|
38
|
+
return compressor_map.get(compressor_name.lower(), Zstd(level=3))
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _create_array(group, name, data, chunks=True, compressor=None, **kwargs):
|
|
42
|
+
"""Create array with version-appropriate API."""
|
|
43
|
+
if ZARR_V3:
|
|
44
|
+
# Zarr v3 API: use create_array with compressors list
|
|
45
|
+
comp_kwargs = {}
|
|
46
|
+
if compressor is not None:
|
|
47
|
+
comp_kwargs["compressors"] = [compressor]
|
|
48
|
+
|
|
49
|
+
# Handle chunks parameter: v3 doesn't accept True/None
|
|
50
|
+
if chunks is True:
|
|
51
|
+
chunks = "auto"
|
|
52
|
+
elif chunks is None or chunks is False:
|
|
53
|
+
# Don't pass chunks, let zarr use defaults
|
|
54
|
+
return group.create_array(name, data=data, **comp_kwargs, **kwargs)
|
|
55
|
+
|
|
56
|
+
return group.create_array(
|
|
57
|
+
name, data=data, chunks=chunks, **comp_kwargs, **kwargs
|
|
58
|
+
)
|
|
59
|
+
else:
|
|
60
|
+
# Zarr v2 API: use create_dataset with compressor
|
|
61
|
+
return group.create_dataset(
|
|
62
|
+
name, data=data, chunks=chunks, compressor=compressor, **kwargs
|
|
63
|
+
)
|
|
17
64
|
|
|
18
65
|
|
|
19
66
|
def _save_zarr(
|
|
@@ -38,7 +85,7 @@ def _save_zarr(
|
|
|
38
85
|
key : str, optional
|
|
39
86
|
Key/group path within Zarr store
|
|
40
87
|
compressor : str
|
|
41
|
-
Compression algorithm ('zstd', '
|
|
88
|
+
Compression algorithm ('zstd', 'gzip')
|
|
42
89
|
chunks : bool or tuple
|
|
43
90
|
Chunking strategy
|
|
44
91
|
store_type : str
|
|
@@ -60,7 +107,7 @@ def _save_zarr(
|
|
|
60
107
|
# Create appropriate store
|
|
61
108
|
if store_type == "zip":
|
|
62
109
|
# Single file ZIP store
|
|
63
|
-
store = zarr.ZipStore(spath, mode="w")
|
|
110
|
+
store = zarr.storage.ZipStore(spath, mode="w")
|
|
64
111
|
root = zarr.open(store, mode="w")
|
|
65
112
|
else:
|
|
66
113
|
# Directory store
|
|
@@ -71,17 +118,12 @@ def _save_zarr(
|
|
|
71
118
|
# Open or create Zarr store
|
|
72
119
|
try:
|
|
73
120
|
root = zarr.open(spath, mode="a")
|
|
74
|
-
except:
|
|
121
|
+
except Exception:
|
|
75
122
|
root = zarr.open(spath, mode="w")
|
|
76
123
|
|
|
77
124
|
# Handle compressor configuration
|
|
78
125
|
if isinstance(compressor, str):
|
|
79
|
-
|
|
80
|
-
"zstd": Zstd(level=3),
|
|
81
|
-
"lz4": LZ4(acceleration=1),
|
|
82
|
-
"gzip": GZip(level=5),
|
|
83
|
-
}
|
|
84
|
-
compressor = compressor_map.get(compressor.lower(), Zstd(level=3))
|
|
126
|
+
compressor = _get_compressor(compressor)
|
|
85
127
|
|
|
86
128
|
# Navigate to target group
|
|
87
129
|
if key:
|
|
@@ -109,12 +151,14 @@ def _save_zarr(
|
|
|
109
151
|
for dataset_name, data in obj.items():
|
|
110
152
|
if isinstance(data, str):
|
|
111
153
|
# String data
|
|
112
|
-
|
|
113
|
-
dataset_name, data=np.array(data), compressor=None
|
|
154
|
+
_create_array(
|
|
155
|
+
target_group, dataset_name, data=np.array(data), compressor=None
|
|
114
156
|
)
|
|
115
157
|
elif isinstance(data, (int, float, bool)):
|
|
116
|
-
# Scalar data -
|
|
117
|
-
|
|
158
|
+
# Scalar data - convert to 0-d array
|
|
159
|
+
_create_array(
|
|
160
|
+
target_group, dataset_name, data=np.array(data), compressor=None
|
|
161
|
+
)
|
|
118
162
|
else:
|
|
119
163
|
# Array data
|
|
120
164
|
data_array = np.asarray(data)
|
|
@@ -124,7 +168,8 @@ def _save_zarr(
|
|
|
124
168
|
import pickle
|
|
125
169
|
|
|
126
170
|
pickled_data = pickle.dumps(data)
|
|
127
|
-
dataset =
|
|
171
|
+
dataset = _create_array(
|
|
172
|
+
target_group,
|
|
128
173
|
dataset_name,
|
|
129
174
|
data=np.frombuffer(pickled_data, dtype=np.uint8),
|
|
130
175
|
compressor=compressor,
|
|
@@ -132,7 +177,8 @@ def _save_zarr(
|
|
|
132
177
|
dataset.attrs["_type"] = "pickled"
|
|
133
178
|
else:
|
|
134
179
|
# Regular array data
|
|
135
|
-
|
|
180
|
+
_create_array(
|
|
181
|
+
target_group,
|
|
136
182
|
dataset_name,
|
|
137
183
|
data=data_array,
|
|
138
184
|
chunks=chunks,
|
|
@@ -151,7 +197,7 @@ def _save_zarr(
|
|
|
151
197
|
print(
|
|
152
198
|
f"✅ Saved to Zarr (consolidated): {spath}" + (f"/{key}" if key else "")
|
|
153
199
|
)
|
|
154
|
-
except:
|
|
200
|
+
except Exception:
|
|
155
201
|
print(f"✅ Saved to Zarr: {spath}" + (f"/{key}" if key else ""))
|
|
156
202
|
else:
|
|
157
203
|
print(f"✅ Saved to Zarr ({store_type}): {spath}" + (f"/{key}" if key else ""))
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
<!-- ---
|
|
2
|
+
!-- Timestamp: 2025-12-16 20:36:14
|
|
3
|
+
!-- Author: ywatanabe
|
|
4
|
+
!-- File: /home/ywatanabe/proj/scitex-code/src/scitex/io/bundle/README.md
|
|
5
|
+
!-- --- -->
|
|
6
|
+
|
|
7
|
+
# SciTeX Bundle I/O
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
SciTeX uses bundle formats for reproducible scientific figures:
|
|
12
|
+
|
|
13
|
+
| Format | Purpose | Contents |
|
|
14
|
+
|-----------|---------------------|---------------------------------------------|
|
|
15
|
+
| `.pltz` | Single plot bundle | spec.json, style.json, data.csv, exports/ |
|
|
16
|
+
| `.figz` | Multi-panel figure | spec.json, style.json, nested .pltz bundles |
|
|
17
|
+
| `.statsz` | Statistical results | spec.json, stats data, comparison metadata |
|
|
18
|
+
|
|
19
|
+
## Format Variants
|
|
20
|
+
|
|
21
|
+
Each bundle can exist in two forms:
|
|
22
|
+
|
|
23
|
+
| Suffix | Type | Use Case |
|
|
24
|
+
|-------------------------------------|-------------|-----------------------------|
|
|
25
|
+
| `.pltz` / `.figz` / `.statsz` | ZIP archive | Storage, transfer, download |
|
|
26
|
+
| `.pltz.d` / `.figz.d` / `.statsz.d` | Directory | Editing, development |
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
import scitex.io.bundle as bundle
|
|
32
|
+
|
|
33
|
+
# Load a bundle (works with both ZIP and directory)
|
|
34
|
+
data = bundle.load("Figure1.figz")
|
|
35
|
+
print(data['spec'])
|
|
36
|
+
print(data['type']) # 'figz'
|
|
37
|
+
|
|
38
|
+
# Save a bundle
|
|
39
|
+
bundle.save(data, "output.pltz", as_zip=True)
|
|
40
|
+
|
|
41
|
+
# Copy a bundle
|
|
42
|
+
bundle.copy("template.pltz", "my_plot.pltz.d")
|
|
43
|
+
|
|
44
|
+
# Pack/unpack between formats
|
|
45
|
+
bundle.pack("plot.pltz.d") # -> plot.pltz
|
|
46
|
+
bundle.unpack("plot.pltz") # -> plot.pltz.d/
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## ZipBundle Class
|
|
50
|
+
|
|
51
|
+
In-memory access to ZIP bundles without extraction:
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from scitex.io.bundle import ZipBundle
|
|
55
|
+
|
|
56
|
+
# Reading
|
|
57
|
+
with ZipBundle("figure.figz") as zb:
|
|
58
|
+
spec = zb.read_json("spec.json")
|
|
59
|
+
data = zb.read_csv("data.csv")
|
|
60
|
+
png = zb.read_bytes("exports/figure.png")
|
|
61
|
+
|
|
62
|
+
# Writing (atomic)
|
|
63
|
+
with ZipBundle("output.pltz", mode="w") as zb:
|
|
64
|
+
zb.write_json("spec.json", spec_dict)
|
|
65
|
+
zb.write_csv("data.csv", dataframe)
|
|
66
|
+
zb.write_bytes("exports/plot.png", png_bytes)
|
|
67
|
+
|
|
68
|
+
# Modifying (read + write atomically)
|
|
69
|
+
with ZipBundle("figure.figz", mode="a") as zb:
|
|
70
|
+
spec = zb.read_json("spec.json")
|
|
71
|
+
spec["title"] = "Updated"
|
|
72
|
+
zb.write_json("spec.json", spec)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Nested Bundle Access
|
|
76
|
+
|
|
77
|
+
Access pltz bundles nested inside figz:
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from scitex.io.bundle import nested
|
|
81
|
+
|
|
82
|
+
# Get preview image
|
|
83
|
+
preview = nested.get_preview("Figure1.figz/A.pltz.d")
|
|
84
|
+
|
|
85
|
+
# Get JSON
|
|
86
|
+
spec = nested.get_json("Figure1.figz/A.pltz.d/spec.json")
|
|
87
|
+
|
|
88
|
+
# Get any file
|
|
89
|
+
png = nested.get_file("Figure1.figz/A.pltz.d/exports/plot.png")
|
|
90
|
+
|
|
91
|
+
# Write to nested bundle
|
|
92
|
+
nested.put_json("Figure1.figz/A.pltz.d/spec.json", updated_spec)
|
|
93
|
+
|
|
94
|
+
# List files
|
|
95
|
+
files = nested.list_files("Figure1.figz/A.pltz.d")
|
|
96
|
+
|
|
97
|
+
# Resolve full bundle data
|
|
98
|
+
data = nested.resolve("Figure1.figz/A.pltz.d")
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Bundle Structure
|
|
102
|
+
|
|
103
|
+
### .pltz Bundle
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
plot.pltz.d/
|
|
107
|
+
├── spec.json # Plot specification (traces, axes, data refs)
|
|
108
|
+
├── style.json # Visual styling (colors, fonts, sizes)
|
|
109
|
+
├── data.csv # Source data
|
|
110
|
+
├── exports/
|
|
111
|
+
│ ├── plot.png # Rendered preview
|
|
112
|
+
│ ├── plot_hitmap.png
|
|
113
|
+
│ └── plot.svg
|
|
114
|
+
└── cache/
|
|
115
|
+
└── geometry_px.json
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### .figz Bundle
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
Figure1.figz.d/
|
|
122
|
+
├── spec.json # Figure layout, panel positions
|
|
123
|
+
├── style.json # Figure-level styling
|
|
124
|
+
├── A.pltz.d/ # Panel A (nested pltz)
|
|
125
|
+
├── B.pltz.d/ # Panel B (nested pltz)
|
|
126
|
+
└── exports/
|
|
127
|
+
└── Figure1.png # Composed figure
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## API Reference
|
|
131
|
+
|
|
132
|
+
### Core Operations
|
|
133
|
+
|
|
134
|
+
| Function | Description |
|
|
135
|
+
|----------|-------------|
|
|
136
|
+
| `load(path)` | Load bundle from ZIP or directory |
|
|
137
|
+
| `save(data, path)` | Save bundle to ZIP or directory |
|
|
138
|
+
| `copy(src, dst)` | Copy bundle between locations |
|
|
139
|
+
| `pack(dir_path)` | Convert directory to ZIP |
|
|
140
|
+
| `unpack(zip_path)` | Convert ZIP to directory |
|
|
141
|
+
| `validate(path)` | Validate bundle structure |
|
|
142
|
+
| `is_bundle(path)` | Check if path is a bundle |
|
|
143
|
+
| `get_type(path)` | Get bundle type ('figz', 'pltz', 'statsz') |
|
|
144
|
+
|
|
145
|
+
### ZipBundle Methods
|
|
146
|
+
|
|
147
|
+
| Method | Description |
|
|
148
|
+
|--------|-------------|
|
|
149
|
+
| `read_bytes(name)` | Read file as bytes |
|
|
150
|
+
| `read_text(name)` | Read file as string |
|
|
151
|
+
| `read_json(name)` | Read and parse JSON |
|
|
152
|
+
| `read_csv(name)` | Read CSV as DataFrame |
|
|
153
|
+
| `write_bytes(name, data)` | Write bytes |
|
|
154
|
+
| `write_text(name, text)` | Write string |
|
|
155
|
+
| `write_json(name, data)` | Write JSON |
|
|
156
|
+
| `write_csv(name, df)` | Write DataFrame as CSV |
|
|
157
|
+
| `namelist()` | List files in bundle |
|
|
158
|
+
|
|
159
|
+
### Nested Access (bundle.nested)
|
|
160
|
+
|
|
161
|
+
| Function | Description |
|
|
162
|
+
|----------|-------------|
|
|
163
|
+
| `nested.get_file(path)` | Get file from nested bundle |
|
|
164
|
+
| `nested.get_json(path)` | Get JSON from nested bundle |
|
|
165
|
+
| `nested.get_preview(path)` | Get preview PNG |
|
|
166
|
+
| `nested.put_file(path, data)` | Write file to nested bundle |
|
|
167
|
+
| `nested.put_json(path, data)` | Write JSON to nested bundle |
|
|
168
|
+
| `nested.list_files(path)` | List files in nested bundle |
|
|
169
|
+
| `nested.resolve(path)` | Load full nested bundle data |
|
|
170
|
+
| `nested.parse_path(path)` | Parse nested path components |
|
|
171
|
+
|
|
172
|
+
## Migration from Old API
|
|
173
|
+
|
|
174
|
+
| Old Import | New Import |
|
|
175
|
+
|------------|------------|
|
|
176
|
+
| `from scitex.io._bundle import load_bundle` | `from scitex.io.bundle import load` |
|
|
177
|
+
| `from scitex.io._bundle import save_bundle` | `from scitex.io.bundle import save` |
|
|
178
|
+
| `from scitex.io._bundle import copy_bundle` | `from scitex.io.bundle import copy` |
|
|
179
|
+
| `from scitex.io._bundle import pack_bundle` | `from scitex.io.bundle import pack` |
|
|
180
|
+
| `from scitex.io._bundle import unpack_bundle` | `from scitex.io.bundle import unpack` |
|
|
181
|
+
| `from scitex.io._bundle import validate_bundle` | `from scitex.io.bundle import validate` |
|
|
182
|
+
| `from scitex.io._bundle import BundleType` | `from scitex.io.bundle import BundleType` |
|
|
183
|
+
| `from scitex.io._bundle import BundleValidationError` | `from scitex.io.bundle import BundleValidationError` |
|
|
184
|
+
| `from scitex.io._bundle import BUNDLE_EXTENSIONS` | `from scitex.io.bundle import EXTENSIONS` |
|
|
185
|
+
| `from scitex.io._bundle import get_bundle_type` | `from scitex.io.bundle import get_type` |
|
|
186
|
+
| `from scitex.io._zip_bundle import ZipBundle` | `from scitex.io.bundle import ZipBundle` |
|
|
187
|
+
| `from scitex.io._zip_bundle import open_bundle` | `from scitex.io.bundle import open_zip` |
|
|
188
|
+
| `from scitex.io._zip_bundle import create_bundle` | `from scitex.io.bundle import create_zip` |
|
|
189
|
+
| `from scitex.io._zip_bundle import zip_directory_bundle` | `from scitex.io.bundle import zip_directory` |
|
|
190
|
+
| `from scitex.io._nested_bundle import resolve_nested_bundle` | `from scitex.io.bundle import nested; nested.resolve` |
|
|
191
|
+
| `from scitex.io._nested_bundle import get_nested_file` | `from scitex.io.bundle import nested; nested.get_file` |
|
|
192
|
+
| `from scitex.io._nested_bundle import get_nested_json` | `from scitex.io.bundle import nested; nested.get_json` |
|
|
193
|
+
| `from scitex.io._nested_bundle import get_nested_preview` | `from scitex.io.bundle import nested; nested.get_preview` |
|
|
194
|
+
| `from scitex.io._nested_bundle import put_nested_file` | `from scitex.io.bundle import nested; nested.put_file` |
|
|
195
|
+
| `from scitex.io._nested_bundle import put_nested_json` | `from scitex.io.bundle import nested; nested.put_json` |
|
|
196
|
+
| `from scitex.io._nested_bundle import list_nested_files` | `from scitex.io.bundle import nested; nested.list_files` |
|
|
197
|
+
| `from scitex.io._nested_bundle import parse_nested_path` | `from scitex.io.bundle import nested; nested.parse_path` |
|
|
198
|
+
| `from scitex.io._nested_bundle import NestedBundleNotFoundError` | `from scitex.io.bundle import NestedBundleNotFoundError` |
|
|
199
|
+
|
|
200
|
+
## Module Structure
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
scitex/io/bundle/
|
|
204
|
+
├── __init__.py # Public API exports
|
|
205
|
+
├── _types.py # BundleType, errors, constants
|
|
206
|
+
├── _core.py # load, save, copy, pack, unpack, validate
|
|
207
|
+
├── _zip.py # ZipBundle class and functions
|
|
208
|
+
├── _nested.py # Nested bundle access
|
|
209
|
+
└── README.md # This documentation
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
<!-- EOF -->
|
|
@@ -0,0 +1,110 @@
|
|
|
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/__init__.py
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
SciTeX Bundle I/O - Unified bundle handling for .figz, .pltz, .statsz formats.
|
|
8
|
+
|
|
9
|
+
This module provides a clean API for working with SciTeX bundles:
|
|
10
|
+
- .figz - Publication Figure Bundle (panels + layout)
|
|
11
|
+
- .pltz - Reproducible Plot Bundle (data + spec + exports)
|
|
12
|
+
- .statsz - Statistical Results Bundle (stats + metadata)
|
|
13
|
+
|
|
14
|
+
Each bundle can exist in two forms:
|
|
15
|
+
- ZIP archive: Figure1.figz, plot.pltz
|
|
16
|
+
- Directory: Figure1.figz.d/, plot.pltz.d/
|
|
17
|
+
|
|
18
|
+
Usage:
|
|
19
|
+
import scitex.io.bundle as bundle
|
|
20
|
+
|
|
21
|
+
# Load a bundle
|
|
22
|
+
data = bundle.load("Figure1.figz")
|
|
23
|
+
|
|
24
|
+
# Save a bundle
|
|
25
|
+
bundle.save(data, "output.pltz", as_zip=True)
|
|
26
|
+
|
|
27
|
+
# Copy a bundle
|
|
28
|
+
bundle.copy("template.pltz", "my_plot.pltz.d")
|
|
29
|
+
|
|
30
|
+
# Access ZIP bundles in-memory
|
|
31
|
+
with bundle.ZipBundle("figure.figz") as zb:
|
|
32
|
+
spec = zb.read_json("spec.json")
|
|
33
|
+
data = zb.read_csv("data.csv")
|
|
34
|
+
|
|
35
|
+
# Access nested bundles (pltz inside figz)
|
|
36
|
+
preview = bundle.nested.get_preview("Figure1.figz/A.pltz.d")
|
|
37
|
+
spec = bundle.nested.get_json("Figure1.figz/A.pltz.d/spec.json")
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
# Types and constants
|
|
41
|
+
from ._types import (
|
|
42
|
+
EXTENSIONS,
|
|
43
|
+
FIGZ,
|
|
44
|
+
PLTZ,
|
|
45
|
+
STATSZ,
|
|
46
|
+
BundleError,
|
|
47
|
+
BundleNotFoundError,
|
|
48
|
+
BundleType,
|
|
49
|
+
BundleValidationError,
|
|
50
|
+
NestedBundleNotFoundError,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
# Core operations
|
|
54
|
+
from ._core import (
|
|
55
|
+
copy,
|
|
56
|
+
dir_to_zip_path,
|
|
57
|
+
get_type,
|
|
58
|
+
is_bundle,
|
|
59
|
+
load,
|
|
60
|
+
pack,
|
|
61
|
+
save,
|
|
62
|
+
unpack,
|
|
63
|
+
validate,
|
|
64
|
+
validate_spec,
|
|
65
|
+
zip_to_dir_path,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# ZipBundle class and functions
|
|
69
|
+
from ._zip import ZipBundle
|
|
70
|
+
from ._zip import create as create_zip
|
|
71
|
+
from ._zip import open as open_zip
|
|
72
|
+
from ._zip import zip_directory
|
|
73
|
+
|
|
74
|
+
# Nested bundle access as namespace
|
|
75
|
+
from . import _nested as nested
|
|
76
|
+
|
|
77
|
+
__all__ = [
|
|
78
|
+
# Types
|
|
79
|
+
"BundleType",
|
|
80
|
+
"BundleError",
|
|
81
|
+
"BundleValidationError",
|
|
82
|
+
"BundleNotFoundError",
|
|
83
|
+
"NestedBundleNotFoundError",
|
|
84
|
+
# Constants
|
|
85
|
+
"EXTENSIONS",
|
|
86
|
+
"FIGZ",
|
|
87
|
+
"PLTZ",
|
|
88
|
+
"STATSZ",
|
|
89
|
+
# Core operations
|
|
90
|
+
"load",
|
|
91
|
+
"save",
|
|
92
|
+
"copy",
|
|
93
|
+
"pack",
|
|
94
|
+
"unpack",
|
|
95
|
+
"validate",
|
|
96
|
+
"validate_spec",
|
|
97
|
+
"is_bundle",
|
|
98
|
+
"get_type",
|
|
99
|
+
"dir_to_zip_path",
|
|
100
|
+
"zip_to_dir_path",
|
|
101
|
+
# ZipBundle
|
|
102
|
+
"ZipBundle",
|
|
103
|
+
"open_zip",
|
|
104
|
+
"create_zip",
|
|
105
|
+
"zip_directory",
|
|
106
|
+
# Nested access namespace
|
|
107
|
+
"nested",
|
|
108
|
+
]
|
|
109
|
+
|
|
110
|
+
# EOF
|