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
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Timestamp: 2025-12-20
|
|
3
|
+
# File: /home/ywatanabe/proj/scitex-code/src/scitex/fsb/_tables/_latex/_validator.py
|
|
4
|
+
|
|
5
|
+
"""LaTeX validation for error detection and suggestions."""
|
|
6
|
+
|
|
7
|
+
import re
|
|
8
|
+
import subprocess
|
|
9
|
+
import tempfile
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from enum import Enum
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import List, Optional, Tuple
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ErrorSeverity(Enum):
|
|
17
|
+
"""Error severity levels."""
|
|
18
|
+
|
|
19
|
+
ERROR = "error"
|
|
20
|
+
WARNING = "warning"
|
|
21
|
+
INFO = "info"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class LaTeXError:
|
|
26
|
+
"""A LaTeX validation error.
|
|
27
|
+
|
|
28
|
+
Attributes:
|
|
29
|
+
line: Line number (1-indexed)
|
|
30
|
+
column: Column number (1-indexed)
|
|
31
|
+
message: Error description
|
|
32
|
+
severity: Error severity
|
|
33
|
+
code: Error code (e.g., E001, W001)
|
|
34
|
+
suggestion: Fix suggestion
|
|
35
|
+
context: Line content for context
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
line: int
|
|
39
|
+
column: int
|
|
40
|
+
message: str
|
|
41
|
+
severity: ErrorSeverity
|
|
42
|
+
code: str
|
|
43
|
+
suggestion: Optional[str] = None
|
|
44
|
+
context: Optional[str] = None
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@dataclass
|
|
48
|
+
class ValidationResult:
|
|
49
|
+
"""Result of LaTeX validation.
|
|
50
|
+
|
|
51
|
+
Attributes:
|
|
52
|
+
is_valid: Whether the LaTeX is valid (no errors)
|
|
53
|
+
errors: List of errors
|
|
54
|
+
warnings: List of warnings
|
|
55
|
+
info: List of info messages
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
is_valid: bool = True
|
|
59
|
+
errors: List[LaTeXError] = field(default_factory=list)
|
|
60
|
+
warnings: List[LaTeXError] = field(default_factory=list)
|
|
61
|
+
info: List[LaTeXError] = field(default_factory=list)
|
|
62
|
+
|
|
63
|
+
def add_error(self, error: LaTeXError) -> None:
|
|
64
|
+
"""Add an error to the appropriate list."""
|
|
65
|
+
if error.severity == ErrorSeverity.ERROR:
|
|
66
|
+
self.errors.append(error)
|
|
67
|
+
self.is_valid = False
|
|
68
|
+
elif error.severity == ErrorSeverity.WARNING:
|
|
69
|
+
self.warnings.append(error)
|
|
70
|
+
else:
|
|
71
|
+
self.info.append(error)
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def all_issues(self) -> List[LaTeXError]:
|
|
75
|
+
"""Get all issues sorted by line number."""
|
|
76
|
+
return sorted(
|
|
77
|
+
self.errors + self.warnings + self.info,
|
|
78
|
+
key=lambda e: (e.line, e.column),
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def validate_latex(
|
|
83
|
+
latex_code: str,
|
|
84
|
+
level: str = "syntax",
|
|
85
|
+
) -> ValidationResult:
|
|
86
|
+
"""Validate LaTeX code.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
latex_code: LaTeX source code
|
|
90
|
+
level: Validation level ("syntax", "semantic", "compile")
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
ValidationResult with errors and warnings
|
|
94
|
+
"""
|
|
95
|
+
result = ValidationResult()
|
|
96
|
+
lines = latex_code.split("\n")
|
|
97
|
+
|
|
98
|
+
# Always do syntax validation
|
|
99
|
+
_validate_syntax(lines, result)
|
|
100
|
+
|
|
101
|
+
# Semantic validation
|
|
102
|
+
if level in ("semantic", "compile"):
|
|
103
|
+
_validate_semantic(lines, result)
|
|
104
|
+
|
|
105
|
+
# Compilation validation (optional, requires pdflatex)
|
|
106
|
+
if level == "compile":
|
|
107
|
+
_validate_compilation(latex_code, result)
|
|
108
|
+
|
|
109
|
+
return result
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _validate_syntax(lines: List[str], result: ValidationResult) -> None:
|
|
113
|
+
"""Check for syntax errors.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
lines: Source lines
|
|
117
|
+
result: ValidationResult to populate
|
|
118
|
+
"""
|
|
119
|
+
# Track brace balance
|
|
120
|
+
brace_stack = [] # List of (line, col, char)
|
|
121
|
+
env_stack = [] # List of (line, env_name)
|
|
122
|
+
|
|
123
|
+
for line_num, line in enumerate(lines, 1):
|
|
124
|
+
# Skip comments
|
|
125
|
+
line_no_comment = line.split("%")[0] if "%" in line and "\\%" not in line.split("%")[0] else line
|
|
126
|
+
|
|
127
|
+
# Check brace balance
|
|
128
|
+
for col, char in enumerate(line_no_comment, 1):
|
|
129
|
+
if char == "{":
|
|
130
|
+
# Check if escaped
|
|
131
|
+
if col > 1 and line_no_comment[col - 2] == "\\":
|
|
132
|
+
continue
|
|
133
|
+
brace_stack.append((line_num, col, char))
|
|
134
|
+
elif char == "}":
|
|
135
|
+
if col > 1 and line_no_comment[col - 2] == "\\":
|
|
136
|
+
continue
|
|
137
|
+
if brace_stack:
|
|
138
|
+
brace_stack.pop()
|
|
139
|
+
else:
|
|
140
|
+
result.add_error(
|
|
141
|
+
LaTeXError(
|
|
142
|
+
line=line_num,
|
|
143
|
+
column=col,
|
|
144
|
+
message="Unmatched closing brace '}'",
|
|
145
|
+
severity=ErrorSeverity.ERROR,
|
|
146
|
+
code="E001",
|
|
147
|
+
suggestion="Remove the extra '}' or add a matching '{'",
|
|
148
|
+
context=line,
|
|
149
|
+
)
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
# Check environment matching
|
|
153
|
+
begin_match = re.search(r"\\begin\{(\w+)\}", line_no_comment)
|
|
154
|
+
if begin_match:
|
|
155
|
+
env_name = begin_match.group(1)
|
|
156
|
+
env_stack.append((line_num, env_name))
|
|
157
|
+
|
|
158
|
+
end_match = re.search(r"\\end\{(\w+)\}", line_no_comment)
|
|
159
|
+
if end_match:
|
|
160
|
+
env_name = end_match.group(1)
|
|
161
|
+
if env_stack:
|
|
162
|
+
_, expected_env = env_stack[-1]
|
|
163
|
+
if env_name == expected_env:
|
|
164
|
+
env_stack.pop()
|
|
165
|
+
else:
|
|
166
|
+
result.add_error(
|
|
167
|
+
LaTeXError(
|
|
168
|
+
line=line_num,
|
|
169
|
+
column=end_match.start() + 1,
|
|
170
|
+
message=f"Environment mismatch: expected \\end{{{expected_env}}}, got \\end{{{env_name}}}",
|
|
171
|
+
severity=ErrorSeverity.ERROR,
|
|
172
|
+
code="E002",
|
|
173
|
+
suggestion=f"Change to \\end{{{expected_env}}} or fix the \\begin command",
|
|
174
|
+
context=line,
|
|
175
|
+
)
|
|
176
|
+
)
|
|
177
|
+
else:
|
|
178
|
+
result.add_error(
|
|
179
|
+
LaTeXError(
|
|
180
|
+
line=line_num,
|
|
181
|
+
column=end_match.start() + 1,
|
|
182
|
+
message=f"\\end{{{env_name}}} without matching \\begin{{{env_name}}}",
|
|
183
|
+
severity=ErrorSeverity.ERROR,
|
|
184
|
+
code="E003",
|
|
185
|
+
suggestion=f"Add \\begin{{{env_name}}} before this or remove the \\end command",
|
|
186
|
+
context=line,
|
|
187
|
+
)
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
# Check for common typos
|
|
191
|
+
_check_common_typos(line_num, line, result)
|
|
192
|
+
|
|
193
|
+
# Report unclosed braces
|
|
194
|
+
for line_num, col, _ in brace_stack:
|
|
195
|
+
result.add_error(
|
|
196
|
+
LaTeXError(
|
|
197
|
+
line=line_num,
|
|
198
|
+
column=col,
|
|
199
|
+
message="Unclosed brace '{'",
|
|
200
|
+
severity=ErrorSeverity.ERROR,
|
|
201
|
+
code="E004",
|
|
202
|
+
suggestion="Add a matching '}'",
|
|
203
|
+
context=lines[line_num - 1] if line_num <= len(lines) else "",
|
|
204
|
+
)
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
# Report unclosed environments
|
|
208
|
+
for line_num, env_name in env_stack:
|
|
209
|
+
result.add_error(
|
|
210
|
+
LaTeXError(
|
|
211
|
+
line=line_num,
|
|
212
|
+
column=1,
|
|
213
|
+
message=f"Unclosed environment: \\begin{{{env_name}}} without \\end{{{env_name}}}",
|
|
214
|
+
severity=ErrorSeverity.ERROR,
|
|
215
|
+
code="E005",
|
|
216
|
+
suggestion=f"Add \\end{{{env_name}}} at the end",
|
|
217
|
+
context=lines[line_num - 1] if line_num <= len(lines) else "",
|
|
218
|
+
)
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def _check_common_typos(line_num: int, line: str, result: ValidationResult) -> None:
|
|
223
|
+
"""Check for common LaTeX typos.
|
|
224
|
+
|
|
225
|
+
Args:
|
|
226
|
+
line_num: Line number
|
|
227
|
+
line: Line content
|
|
228
|
+
result: ValidationResult to populate
|
|
229
|
+
"""
|
|
230
|
+
typos = [
|
|
231
|
+
(r"\\beign\{", "\\begin{", "W001"),
|
|
232
|
+
(r"\\beigin\{", "\\begin{", "W001"),
|
|
233
|
+
(r"\\ened\{", "\\end{", "W002"),
|
|
234
|
+
(r"\\ceneter", "\\centering", "W003"),
|
|
235
|
+
(r"\\includegraphcis", "\\includegraphics", "W004"),
|
|
236
|
+
(r"\\captoin", "\\caption", "W005"),
|
|
237
|
+
(r"\\lable\{", "\\label{", "W006"),
|
|
238
|
+
(r"\\toperule", "\\toprule", "W007"),
|
|
239
|
+
(r"\\bottomrul", "\\bottomrule", "W008"),
|
|
240
|
+
(r"\\midruel", "\\midrule", "W009"),
|
|
241
|
+
]
|
|
242
|
+
|
|
243
|
+
for pattern, correct, code in typos:
|
|
244
|
+
match = re.search(pattern, line, re.IGNORECASE)
|
|
245
|
+
if match:
|
|
246
|
+
result.add_error(
|
|
247
|
+
LaTeXError(
|
|
248
|
+
line=line_num,
|
|
249
|
+
column=match.start() + 1,
|
|
250
|
+
message=f"Possible typo: '{match.group()}' should be '{correct}'",
|
|
251
|
+
severity=ErrorSeverity.WARNING,
|
|
252
|
+
code=code,
|
|
253
|
+
suggestion=f"Replace with '{correct}'",
|
|
254
|
+
context=line,
|
|
255
|
+
)
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def _validate_semantic(lines: List[str], result: ValidationResult) -> None:
|
|
260
|
+
"""Check for semantic issues.
|
|
261
|
+
|
|
262
|
+
Args:
|
|
263
|
+
lines: Source lines
|
|
264
|
+
result: ValidationResult to populate
|
|
265
|
+
"""
|
|
266
|
+
labels = set()
|
|
267
|
+
refs = set()
|
|
268
|
+
has_caption = False
|
|
269
|
+
in_float = False
|
|
270
|
+
|
|
271
|
+
for line_num, line in enumerate(lines, 1):
|
|
272
|
+
# Track float environments
|
|
273
|
+
if re.search(r"\\begin\{(figure|table)\}", line):
|
|
274
|
+
in_float = True
|
|
275
|
+
has_caption = False
|
|
276
|
+
|
|
277
|
+
if re.search(r"\\end\{(figure|table)\}", line):
|
|
278
|
+
if in_float and not has_caption:
|
|
279
|
+
result.add_error(
|
|
280
|
+
LaTeXError(
|
|
281
|
+
line=line_num,
|
|
282
|
+
column=1,
|
|
283
|
+
message="Float environment without caption",
|
|
284
|
+
severity=ErrorSeverity.WARNING,
|
|
285
|
+
code="W010",
|
|
286
|
+
suggestion="Add \\caption{...} to the figure/table",
|
|
287
|
+
context=line,
|
|
288
|
+
)
|
|
289
|
+
)
|
|
290
|
+
in_float = False
|
|
291
|
+
|
|
292
|
+
# Track captions
|
|
293
|
+
if "\\caption" in line:
|
|
294
|
+
has_caption = True
|
|
295
|
+
|
|
296
|
+
# Collect labels
|
|
297
|
+
label_match = re.search(r"\\label\{([^}]+)\}", line)
|
|
298
|
+
if label_match:
|
|
299
|
+
label = label_match.group(1)
|
|
300
|
+
if label in labels:
|
|
301
|
+
result.add_error(
|
|
302
|
+
LaTeXError(
|
|
303
|
+
line=line_num,
|
|
304
|
+
column=label_match.start() + 1,
|
|
305
|
+
message=f"Duplicate label: '{label}'",
|
|
306
|
+
severity=ErrorSeverity.WARNING,
|
|
307
|
+
code="W011",
|
|
308
|
+
suggestion="Use a unique label",
|
|
309
|
+
context=line,
|
|
310
|
+
)
|
|
311
|
+
)
|
|
312
|
+
labels.add(label)
|
|
313
|
+
|
|
314
|
+
# Collect refs
|
|
315
|
+
for ref_match in re.finditer(r"\\ref\{([^}]+)\}", line):
|
|
316
|
+
refs.add(ref_match.group(1))
|
|
317
|
+
|
|
318
|
+
# Check for undefined refs (only warning since refs might be in other files)
|
|
319
|
+
# for ref in refs - labels:
|
|
320
|
+
# result.add_error(...)
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def _validate_compilation(latex_code: str, result: ValidationResult) -> None:
|
|
324
|
+
"""Attempt to compile LaTeX and capture errors.
|
|
325
|
+
|
|
326
|
+
Args:
|
|
327
|
+
latex_code: LaTeX source code
|
|
328
|
+
result: ValidationResult to populate
|
|
329
|
+
"""
|
|
330
|
+
# Create a minimal document if needed
|
|
331
|
+
if "\\documentclass" not in latex_code:
|
|
332
|
+
latex_code = _wrap_in_document(latex_code)
|
|
333
|
+
|
|
334
|
+
try:
|
|
335
|
+
with tempfile.TemporaryDirectory() as tmpdir:
|
|
336
|
+
tex_path = Path(tmpdir) / "test.tex"
|
|
337
|
+
tex_path.write_text(latex_code, encoding="utf-8")
|
|
338
|
+
|
|
339
|
+
proc = subprocess.run(
|
|
340
|
+
["pdflatex", "-interaction=nonstopmode", "-halt-on-error", str(tex_path)],
|
|
341
|
+
cwd=tmpdir,
|
|
342
|
+
capture_output=True,
|
|
343
|
+
text=True,
|
|
344
|
+
timeout=30,
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
if proc.returncode != 0:
|
|
348
|
+
# Parse pdflatex output for errors
|
|
349
|
+
_parse_pdflatex_output(proc.stdout, result)
|
|
350
|
+
|
|
351
|
+
except FileNotFoundError:
|
|
352
|
+
result.add_error(
|
|
353
|
+
LaTeXError(
|
|
354
|
+
line=0,
|
|
355
|
+
column=0,
|
|
356
|
+
message="pdflatex not found - compilation check skipped",
|
|
357
|
+
severity=ErrorSeverity.INFO,
|
|
358
|
+
code="I001",
|
|
359
|
+
suggestion="Install TeX Live or MiKTeX for compilation validation",
|
|
360
|
+
)
|
|
361
|
+
)
|
|
362
|
+
except subprocess.TimeoutExpired:
|
|
363
|
+
result.add_error(
|
|
364
|
+
LaTeXError(
|
|
365
|
+
line=0,
|
|
366
|
+
column=0,
|
|
367
|
+
message="Compilation timed out",
|
|
368
|
+
severity=ErrorSeverity.WARNING,
|
|
369
|
+
code="W012",
|
|
370
|
+
suggestion="Check for infinite loops in macros",
|
|
371
|
+
)
|
|
372
|
+
)
|
|
373
|
+
except Exception as e:
|
|
374
|
+
result.add_error(
|
|
375
|
+
LaTeXError(
|
|
376
|
+
line=0,
|
|
377
|
+
column=0,
|
|
378
|
+
message=f"Compilation error: {str(e)}",
|
|
379
|
+
severity=ErrorSeverity.INFO,
|
|
380
|
+
code="I002",
|
|
381
|
+
)
|
|
382
|
+
)
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
def _wrap_in_document(content: str) -> str:
|
|
386
|
+
"""Wrap content in a minimal LaTeX document.
|
|
387
|
+
|
|
388
|
+
Args:
|
|
389
|
+
content: LaTeX content
|
|
390
|
+
|
|
391
|
+
Returns:
|
|
392
|
+
Complete document string
|
|
393
|
+
"""
|
|
394
|
+
return f"""\\documentclass{{article}}
|
|
395
|
+
\\usepackage{{graphicx}}
|
|
396
|
+
\\usepackage{{booktabs}}
|
|
397
|
+
\\usepackage{{amsmath}}
|
|
398
|
+
\\begin{{document}}
|
|
399
|
+
{content}
|
|
400
|
+
\\end{{document}}
|
|
401
|
+
"""
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
def _parse_pdflatex_output(output: str, result: ValidationResult) -> None:
|
|
405
|
+
"""Parse pdflatex output for errors.
|
|
406
|
+
|
|
407
|
+
Args:
|
|
408
|
+
output: pdflatex stdout
|
|
409
|
+
result: ValidationResult to populate
|
|
410
|
+
"""
|
|
411
|
+
# Look for error lines
|
|
412
|
+
error_pattern = re.compile(r"^! (.+)$", re.MULTILINE)
|
|
413
|
+
line_pattern = re.compile(r"^l\.(\d+) (.*)$", re.MULTILINE)
|
|
414
|
+
|
|
415
|
+
for match in error_pattern.finditer(output):
|
|
416
|
+
error_msg = match.group(1)
|
|
417
|
+
|
|
418
|
+
# Try to find line number
|
|
419
|
+
line_num = 0
|
|
420
|
+
context = ""
|
|
421
|
+
line_match = line_pattern.search(output, match.end())
|
|
422
|
+
if line_match:
|
|
423
|
+
line_num = int(line_match.group(1))
|
|
424
|
+
context = line_match.group(2)
|
|
425
|
+
|
|
426
|
+
result.add_error(
|
|
427
|
+
LaTeXError(
|
|
428
|
+
line=line_num,
|
|
429
|
+
column=1,
|
|
430
|
+
message=error_msg,
|
|
431
|
+
severity=ErrorSeverity.ERROR,
|
|
432
|
+
code="C001",
|
|
433
|
+
context=context,
|
|
434
|
+
)
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
__all__ = [
|
|
439
|
+
"ErrorSeverity",
|
|
440
|
+
"LaTeXError",
|
|
441
|
+
"ValidationResult",
|
|
442
|
+
"validate_latex",
|
|
443
|
+
]
|
|
444
|
+
|
|
445
|
+
# EOF
|
scitex/gen/__init__.py
CHANGED
|
@@ -1,15 +1,32 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""Scitex gen module."""
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
# Optional: DimHandler requires torch
|
|
5
|
+
try:
|
|
6
|
+
from ._DimHandler import DimHandler
|
|
7
|
+
except ImportError:
|
|
8
|
+
DimHandler = None
|
|
6
9
|
from ._alternate_kwarg import alternate_kwarg
|
|
7
10
|
from ._cache import cache
|
|
8
11
|
from ._check_host import check_host, is_host, verify_host
|
|
9
12
|
from ._ci import ci
|
|
13
|
+
from ._deprecated_close import (
|
|
14
|
+
close as _deprecated_close,
|
|
15
|
+
)
|
|
16
|
+
from ._deprecated_close import (
|
|
17
|
+
running2finished as _deprecated_running2finished,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
# _start.py moved to old/ directory - functionality now in scitex.session
|
|
21
|
+
# BACKWARD COMPATIBILITY: Import deprecated wrappers
|
|
22
|
+
from ._deprecated_start import start as _deprecated_start
|
|
10
23
|
|
|
11
24
|
# _close.py moved to old/ directory - functionality now in scitex.session
|
|
12
|
-
|
|
25
|
+
# Optional: _embed requires torch
|
|
26
|
+
try:
|
|
27
|
+
from ._embed import embed
|
|
28
|
+
except ImportError:
|
|
29
|
+
embed = None
|
|
13
30
|
from ._inspect_module import inspect_module
|
|
14
31
|
from ._is_ipython import is_ipython, is_script
|
|
15
32
|
from ._less import less
|
|
@@ -23,47 +40,69 @@ from ._mat2py import (
|
|
|
23
40
|
public_keys,
|
|
24
41
|
save_npa,
|
|
25
42
|
)
|
|
26
|
-
|
|
43
|
+
|
|
44
|
+
# Optional: _norm requires torch
|
|
45
|
+
try:
|
|
46
|
+
from ._norm import clip_perc, to_01, to_nan01, to_nanz, to_z, unbias
|
|
47
|
+
except ImportError:
|
|
48
|
+
clip_perc = None
|
|
49
|
+
to_01 = None
|
|
50
|
+
to_nan01 = None
|
|
51
|
+
to_nanz = None
|
|
52
|
+
to_z = None
|
|
53
|
+
unbias = None
|
|
27
54
|
from ._paste import paste
|
|
28
55
|
from ._print_config import print_config, print_config_main
|
|
29
56
|
from ._shell import run_shellcommand, run_shellscript
|
|
30
57
|
from ._src import src
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
# BACKWARD COMPATIBILITY: Import deprecated wrappers
|
|
34
|
-
from ._deprecated_start import start as _deprecated_start
|
|
35
|
-
from ._deprecated_close import (
|
|
36
|
-
close as _deprecated_close,
|
|
37
|
-
running2finished as _deprecated_running2finished,
|
|
38
|
-
)
|
|
58
|
+
from ._TimeStamper import TimeStamper
|
|
39
59
|
|
|
40
60
|
# Override the imported functions with deprecated wrappers
|
|
41
61
|
start = _deprecated_start
|
|
42
62
|
close = _deprecated_close
|
|
43
63
|
running2finished = _deprecated_running2finished
|
|
44
64
|
|
|
65
|
+
from ._detect_environment import (
|
|
66
|
+
detect_environment,
|
|
67
|
+
get_output_directory,
|
|
68
|
+
is_notebook,
|
|
69
|
+
)
|
|
70
|
+
from ._get_notebook_path import (
|
|
71
|
+
get_notebook_directory,
|
|
72
|
+
get_notebook_name,
|
|
73
|
+
get_notebook_path,
|
|
74
|
+
)
|
|
45
75
|
from ._symlink import symlink
|
|
46
76
|
from ._symlog import symlog
|
|
47
77
|
from ._title2path import title2path
|
|
48
78
|
from ._title_case import main, title_case
|
|
49
79
|
from ._to_even import to_even
|
|
50
80
|
from ._to_odd import to_odd
|
|
51
|
-
|
|
81
|
+
|
|
82
|
+
# Optional: _to_rank requires torch
|
|
83
|
+
try:
|
|
84
|
+
from ._to_rank import to_rank
|
|
85
|
+
except ImportError:
|
|
86
|
+
to_rank = None
|
|
52
87
|
from ._transpose import transpose
|
|
53
|
-
|
|
54
|
-
|
|
88
|
+
|
|
89
|
+
# Optional: _type and _var_info require torch
|
|
90
|
+
try:
|
|
91
|
+
from ._type import ArrayLike, var_info
|
|
92
|
+
except ImportError:
|
|
93
|
+
ArrayLike = None
|
|
94
|
+
var_info = None
|
|
95
|
+
|
|
96
|
+
try:
|
|
97
|
+
from ._var_info import ArrayLike, var_info
|
|
98
|
+
except ImportError:
|
|
99
|
+
pass # Already set to None above
|
|
55
100
|
from ._wrap import wrap
|
|
56
101
|
from ._xml2dict import XmlDictConfig, XmlListConfig, xml2dict
|
|
57
|
-
from .
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
)
|
|
62
|
-
from ._get_notebook_path import (
|
|
63
|
-
get_notebook_path,
|
|
64
|
-
get_notebook_name,
|
|
65
|
-
get_notebook_directory,
|
|
66
|
-
)
|
|
102
|
+
from .misc import float_linspace
|
|
103
|
+
|
|
104
|
+
# Import from misc module
|
|
105
|
+
from .misc import connect_nums
|
|
67
106
|
|
|
68
107
|
__all__ = [
|
|
69
108
|
"ArrayLike",
|
|
@@ -79,8 +118,10 @@ __all__ = [
|
|
|
79
118
|
"ci",
|
|
80
119
|
"clip_perc",
|
|
81
120
|
"close",
|
|
121
|
+
"connect_nums",
|
|
82
122
|
"dir2npy",
|
|
83
123
|
"embed",
|
|
124
|
+
"float_linspace",
|
|
84
125
|
"inspect_module",
|
|
85
126
|
"is_host",
|
|
86
127
|
"is_ipython",
|
scitex/gen/misc.py
CHANGED
|
@@ -423,6 +423,34 @@ def partial_at(func, index, value):
|
|
|
423
423
|
return result
|
|
424
424
|
|
|
425
425
|
|
|
426
|
+
def connect_nums(nums):
|
|
427
|
+
"""Connect multiple numbers/values with hyphens.
|
|
428
|
+
|
|
429
|
+
This function takes an iterable of numbers or values and joins them
|
|
430
|
+
with hyphens to create a single string representation.
|
|
431
|
+
|
|
432
|
+
Parameters
|
|
433
|
+
----------
|
|
434
|
+
nums : iterable
|
|
435
|
+
An iterable of numbers or values to be connected.
|
|
436
|
+
|
|
437
|
+
Returns
|
|
438
|
+
-------
|
|
439
|
+
str
|
|
440
|
+
A string with the values joined by hyphens.
|
|
441
|
+
|
|
442
|
+
Example
|
|
443
|
+
-------
|
|
444
|
+
>>> connect_nums((0, 0))
|
|
445
|
+
'0-0'
|
|
446
|
+
>>> connect_nums((1, 2, 3))
|
|
447
|
+
'1-2-3'
|
|
448
|
+
>>> connect_nums(('a', 'b'))
|
|
449
|
+
'a-b'
|
|
450
|
+
"""
|
|
451
|
+
return "-".join(str(num) for num in nums)
|
|
452
|
+
|
|
453
|
+
|
|
426
454
|
# def describe(df, method="mean", round_factor=1, axis=0):
|
|
427
455
|
# assert method in ["mean_std", "mean_ci", "median_iqr"]
|
|
428
456
|
# df = pd.DataFrame(df)
|