scitex 2.0.0__py2.py3-none-any.whl → 2.1.0__py2.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 +53 -15
- scitex/__main__.py +72 -26
- scitex/__version__.py +1 -1
- scitex/_sh.py +145 -23
- scitex/ai/__init__.py +30 -16
- scitex/ai/_gen_ai/_Anthropic.py +5 -7
- scitex/ai/_gen_ai/_BaseGenAI.py +2 -2
- scitex/ai/_gen_ai/_DeepSeek.py +10 -2
- scitex/ai/_gen_ai/_Google.py +2 -2
- scitex/ai/_gen_ai/_Llama.py +2 -2
- scitex/ai/_gen_ai/_OpenAI.py +2 -2
- scitex/ai/_gen_ai/_PARAMS.py +51 -65
- scitex/ai/_gen_ai/_Perplexity.py +2 -2
- scitex/ai/_gen_ai/__init__.py +25 -14
- scitex/ai/_gen_ai/_format_output_func.py +4 -4
- scitex/ai/classification/{classifier_server.py → Classifier.py} +5 -5
- scitex/ai/classification/CrossValidationExperiment.py +374 -0
- scitex/ai/classification/__init__.py +43 -4
- scitex/ai/classification/reporters/_BaseClassificationReporter.py +281 -0
- scitex/ai/classification/reporters/_ClassificationReporter.py +773 -0
- scitex/ai/classification/reporters/_MultiClassificationReporter.py +406 -0
- scitex/ai/classification/reporters/_SingleClassificationReporter.py +1834 -0
- scitex/ai/classification/reporters/__init__.py +11 -0
- scitex/ai/classification/reporters/reporter_utils/_Plotter.py +1028 -0
- scitex/ai/classification/reporters/reporter_utils/__init__.py +80 -0
- scitex/ai/classification/reporters/reporter_utils/aggregation.py +457 -0
- scitex/ai/classification/reporters/reporter_utils/data_models.py +313 -0
- scitex/ai/classification/reporters/reporter_utils/reporting.py +1056 -0
- scitex/ai/classification/reporters/reporter_utils/storage.py +221 -0
- scitex/ai/classification/reporters/reporter_utils/validation.py +395 -0
- scitex/ai/classification/timeseries/_TimeSeriesBlockingSplit.py +568 -0
- scitex/ai/classification/timeseries/_TimeSeriesCalendarSplit.py +688 -0
- scitex/ai/classification/timeseries/_TimeSeriesMetadata.py +139 -0
- scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit.py +1716 -0
- scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit_v01-not-using-n_splits.py +1685 -0
- scitex/ai/classification/timeseries/_TimeSeriesStrategy.py +84 -0
- scitex/ai/classification/timeseries/_TimeSeriesStratifiedSplit.py +610 -0
- scitex/ai/classification/timeseries/__init__.py +39 -0
- scitex/ai/classification/timeseries/_normalize_timestamp.py +436 -0
- scitex/ai/clustering/_umap.py +2 -2
- scitex/ai/feature_extraction/vit.py +1 -0
- scitex/ai/feature_selection/__init__.py +30 -0
- scitex/ai/feature_selection/feature_selection.py +364 -0
- scitex/ai/loss/multi_task_loss.py +1 -1
- scitex/ai/metrics/__init__.py +51 -4
- scitex/ai/metrics/_calc_bacc.py +61 -0
- scitex/ai/metrics/_calc_bacc_from_conf_mat.py +38 -0
- scitex/ai/metrics/_calc_clf_report.py +78 -0
- scitex/ai/metrics/_calc_conf_mat.py +93 -0
- scitex/ai/metrics/_calc_feature_importance.py +183 -0
- scitex/ai/metrics/_calc_mcc.py +61 -0
- scitex/ai/metrics/_calc_pre_rec_auc.py +116 -0
- scitex/ai/metrics/_calc_roc_auc.py +110 -0
- scitex/ai/metrics/_calc_seizure_prediction_metrics.py +490 -0
- scitex/ai/metrics/{silhoute_score_block.py → _calc_silhouette_score.py} +15 -8
- scitex/ai/metrics/_normalize_labels.py +83 -0
- scitex/ai/plt/__init__.py +47 -8
- scitex/ai/plt/{_conf_mat.py → _plot_conf_mat.py} +158 -87
- scitex/ai/plt/_plot_feature_importance.py +323 -0
- scitex/ai/plt/_plot_learning_curve.py +345 -0
- scitex/ai/plt/_plot_optuna_study.py +225 -0
- scitex/ai/plt/_plot_pre_rec_curve.py +290 -0
- scitex/ai/plt/_plot_roc_curve.py +255 -0
- scitex/ai/training/{learning_curve_logger.py → _LearningCurveLogger.py} +197 -213
- scitex/ai/training/__init__.py +2 -2
- scitex/ai/utils/grid_search.py +3 -3
- scitex/benchmark/__init__.py +52 -0
- scitex/benchmark/benchmark.py +400 -0
- scitex/benchmark/monitor.py +370 -0
- scitex/benchmark/profiler.py +297 -0
- scitex/browser/__init__.py +48 -0
- scitex/browser/automation/CookieHandler.py +216 -0
- scitex/browser/automation/__init__.py +7 -0
- scitex/browser/collaboration/__init__.py +55 -0
- scitex/browser/collaboration/auth_helpers.py +94 -0
- scitex/browser/collaboration/collaborative_agent.py +136 -0
- scitex/browser/collaboration/credential_manager.py +188 -0
- scitex/browser/collaboration/interactive_panel.py +400 -0
- scitex/browser/collaboration/persistent_browser.py +170 -0
- scitex/browser/collaboration/shared_session.py +383 -0
- scitex/browser/collaboration/standard_interactions.py +246 -0
- scitex/browser/collaboration/visual_feedback.py +181 -0
- scitex/browser/core/BrowserMixin.py +326 -0
- scitex/browser/core/ChromeProfileManager.py +446 -0
- scitex/browser/core/__init__.py +9 -0
- scitex/browser/debugging/__init__.py +18 -0
- scitex/browser/debugging/_browser_logger.py +657 -0
- scitex/browser/debugging/_highlight_element.py +143 -0
- scitex/browser/debugging/_show_grid.py +154 -0
- scitex/browser/interaction/__init__.py +24 -0
- scitex/browser/interaction/click_center.py +149 -0
- scitex/browser/interaction/click_with_fallbacks.py +206 -0
- scitex/browser/interaction/close_popups.py +498 -0
- scitex/browser/interaction/fill_with_fallbacks.py +209 -0
- scitex/browser/pdf/__init__.py +14 -0
- scitex/browser/pdf/click_download_for_chrome_pdf_viewer.py +200 -0
- scitex/browser/pdf/detect_chrome_pdf_viewer.py +198 -0
- scitex/browser/remote/CaptchaHandler.py +434 -0
- scitex/browser/remote/ZenRowsAPIClient.py +347 -0
- scitex/browser/remote/ZenRowsBrowserManager.py +570 -0
- scitex/browser/remote/__init__.py +11 -0
- scitex/browser/stealth/HumanBehavior.py +344 -0
- scitex/browser/stealth/StealthManager.py +1008 -0
- scitex/browser/stealth/__init__.py +9 -0
- scitex/browser/template.py +122 -0
- scitex/capture/__init__.py +110 -0
- scitex/capture/__main__.py +25 -0
- scitex/capture/capture.py +848 -0
- scitex/capture/cli.py +233 -0
- scitex/capture/gif.py +344 -0
- scitex/capture/mcp_server.py +961 -0
- scitex/capture/session.py +70 -0
- scitex/capture/utils.py +705 -0
- scitex/cli/__init__.py +17 -0
- scitex/cli/cloud.py +447 -0
- scitex/cli/main.py +42 -0
- scitex/cli/scholar.py +280 -0
- scitex/context/_suppress_output.py +5 -3
- scitex/db/__init__.py +30 -3
- scitex/db/__main__.py +75 -0
- scitex/db/_check_health.py +381 -0
- scitex/db/_delete_duplicates.py +25 -386
- scitex/db/_inspect.py +335 -114
- scitex/db/_inspect_optimized.py +301 -0
- scitex/db/{_PostgreSQL.py → _postgresql/_PostgreSQL.py} +3 -3
- scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_BackupMixin.py +1 -1
- scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_BatchMixin.py +1 -1
- scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_BlobMixin.py +1 -1
- scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_ConnectionMixin.py +1 -1
- scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_MaintenanceMixin.py +1 -1
- scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_QueryMixin.py +1 -1
- scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_SchemaMixin.py +1 -1
- scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_TransactionMixin.py +1 -1
- scitex/db/_postgresql/__init__.py +6 -0
- scitex/db/_sqlite3/_SQLite3.py +210 -0
- scitex/db/_sqlite3/_SQLite3Mixins/_ArrayMixin.py +581 -0
- scitex/db/_sqlite3/_SQLite3Mixins/_ArrayMixin_v01-need-_hash-col.py +517 -0
- scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/_BatchMixin.py +1 -1
- scitex/db/_sqlite3/_SQLite3Mixins/_BlobMixin.py +281 -0
- scitex/db/_sqlite3/_SQLite3Mixins/_ColumnMixin.py +548 -0
- scitex/db/_sqlite3/_SQLite3Mixins/_ColumnMixin_v01-indentation-issues.py +583 -0
- scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/_ConnectionMixin.py +29 -13
- scitex/db/_sqlite3/_SQLite3Mixins/_GitMixin.py +583 -0
- scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/_ImportExportMixin.py +1 -1
- scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/_IndexMixin.py +1 -1
- scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/_MaintenanceMixin.py +2 -1
- scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/_QueryMixin.py +37 -10
- scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/_RowMixin.py +46 -6
- scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/_TableMixin.py +56 -10
- scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/_TransactionMixin.py +1 -1
- scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/__init__.py +14 -2
- scitex/db/_sqlite3/__init__.py +7 -0
- scitex/db/_sqlite3/_delete_duplicates.py +274 -0
- scitex/decorators/__init__.py +2 -0
- scitex/decorators/_cache_disk.py +13 -5
- scitex/decorators/_cache_disk_async.py +49 -0
- scitex/decorators/_deprecated.py +175 -10
- scitex/decorators/_timeout.py +1 -1
- scitex/dev/_analyze_code_flow.py +2 -2
- scitex/dict/_DotDict.py +73 -15
- scitex/dict/_DotDict_v01-not-handling-recursive-instantiations.py +442 -0
- scitex/dict/_DotDict_v02-not-serializing-Path-object.py +446 -0
- scitex/dict/__init__.py +2 -0
- scitex/dict/_flatten.py +27 -0
- scitex/dsp/_crop.py +2 -2
- scitex/dsp/_demo_sig.py +2 -2
- scitex/dsp/_detect_ripples.py +2 -2
- scitex/dsp/_hilbert.py +2 -2
- scitex/dsp/_listen.py +6 -6
- scitex/dsp/_modulation_index.py +2 -2
- scitex/dsp/_pac.py +1 -1
- scitex/dsp/_psd.py +2 -2
- scitex/dsp/_resample.py +2 -1
- scitex/dsp/_time.py +3 -2
- scitex/dsp/_wavelet.py +3 -2
- scitex/dsp/add_noise.py +2 -2
- scitex/dsp/example.py +1 -0
- scitex/dsp/filt.py +10 -9
- scitex/dsp/template.py +3 -2
- scitex/dsp/utils/_differential_bandpass_filters.py +1 -1
- scitex/dsp/utils/pac.py +2 -2
- scitex/dt/_normalize_timestamp.py +432 -0
- scitex/errors.py +572 -0
- scitex/gen/_DimHandler.py +2 -2
- scitex/gen/__init__.py +37 -7
- scitex/gen/_deprecated_close.py +80 -0
- scitex/gen/_deprecated_start.py +26 -0
- scitex/gen/_detect_environment.py +152 -0
- scitex/gen/_detect_notebook_path.py +169 -0
- scitex/gen/_embed.py +6 -2
- scitex/gen/_get_notebook_path.py +257 -0
- scitex/gen/_less.py +1 -1
- scitex/gen/_list_packages.py +2 -2
- scitex/gen/_norm.py +44 -9
- scitex/gen/_norm_cache.py +269 -0
- scitex/gen/_src.py +3 -5
- scitex/gen/_title_case.py +3 -3
- scitex/io/__init__.py +28 -6
- scitex/io/_glob.py +13 -7
- scitex/io/_load.py +108 -21
- scitex/io/_load_cache.py +303 -0
- scitex/io/_load_configs.py +40 -15
- scitex/io/{_H5Explorer.py → _load_modules/_H5Explorer.py} +80 -17
- scitex/io/_load_modules/_ZarrExplorer.py +114 -0
- scitex/io/_load_modules/_bibtex.py +207 -0
- scitex/io/_load_modules/_hdf5.py +53 -178
- scitex/io/_load_modules/_json.py +5 -3
- scitex/io/_load_modules/_pdf.py +871 -16
- scitex/io/_load_modules/_sqlite3.py +15 -0
- scitex/io/_load_modules/_txt.py +41 -12
- scitex/io/_load_modules/_yaml.py +4 -3
- scitex/io/_load_modules/_zarr.py +126 -0
- scitex/io/_save.py +429 -171
- scitex/io/_save_modules/__init__.py +6 -0
- scitex/io/_save_modules/_bibtex.py +194 -0
- scitex/io/_save_modules/_csv.py +8 -4
- scitex/io/_save_modules/_excel.py +174 -15
- scitex/io/_save_modules/_hdf5.py +251 -226
- scitex/io/_save_modules/_image.py +1 -3
- scitex/io/_save_modules/_json.py +49 -4
- scitex/io/_save_modules/_listed_dfs_as_csv.py +1 -3
- scitex/io/_save_modules/_listed_scalars_as_csv.py +1 -3
- scitex/io/_save_modules/_tex.py +277 -0
- scitex/io/_save_modules/_yaml.py +42 -3
- scitex/io/_save_modules/_zarr.py +160 -0
- scitex/io/utils/__init__.py +20 -0
- scitex/io/utils/h5_to_zarr.py +616 -0
- scitex/linalg/_geometric_median.py +6 -2
- scitex/{gen/_tee.py → logging/_Tee.py} +43 -84
- scitex/logging/__init__.py +122 -0
- scitex/logging/_config.py +158 -0
- scitex/logging/_context.py +103 -0
- scitex/logging/_formatters.py +128 -0
- scitex/logging/_handlers.py +64 -0
- scitex/logging/_levels.py +35 -0
- scitex/logging/_logger.py +163 -0
- scitex/logging/_print_capture.py +95 -0
- scitex/ml/__init__.py +69 -0
- scitex/{ai/genai/anthropic.py → ml/_gen_ai/_Anthropic.py} +13 -19
- scitex/{ai/genai/base_genai.py → ml/_gen_ai/_BaseGenAI.py} +5 -5
- scitex/{ai/genai/deepseek.py → ml/_gen_ai/_DeepSeek.py} +11 -16
- scitex/{ai/genai/google.py → ml/_gen_ai/_Google.py} +7 -15
- scitex/{ai/genai/groq.py → ml/_gen_ai/_Groq.py} +1 -8
- scitex/{ai/genai/llama.py → ml/_gen_ai/_Llama.py} +3 -16
- scitex/{ai/genai/openai.py → ml/_gen_ai/_OpenAI.py} +3 -3
- scitex/{ai/genai/params.py → ml/_gen_ai/_PARAMS.py} +51 -65
- scitex/{ai/genai/perplexity.py → ml/_gen_ai/_Perplexity.py} +3 -14
- scitex/ml/_gen_ai/__init__.py +43 -0
- scitex/{ai/genai/calc_cost.py → ml/_gen_ai/_calc_cost.py} +1 -1
- scitex/{ai/genai/format_output_func.py → ml/_gen_ai/_format_output_func.py} +4 -4
- scitex/{ai/genai/genai_factory.py → ml/_gen_ai/_genai_factory.py} +8 -8
- scitex/ml/activation/__init__.py +8 -0
- scitex/ml/activation/_define.py +11 -0
- scitex/{ai/classifier_server.py → ml/classification/Classifier.py} +5 -5
- scitex/ml/classification/CrossValidationExperiment.py +374 -0
- scitex/ml/classification/__init__.py +46 -0
- scitex/ml/classification/reporters/_BaseClassificationReporter.py +281 -0
- scitex/ml/classification/reporters/_ClassificationReporter.py +773 -0
- scitex/ml/classification/reporters/_MultiClassificationReporter.py +406 -0
- scitex/ml/classification/reporters/_SingleClassificationReporter.py +1834 -0
- scitex/ml/classification/reporters/__init__.py +11 -0
- scitex/ml/classification/reporters/reporter_utils/_Plotter.py +1028 -0
- scitex/ml/classification/reporters/reporter_utils/__init__.py +80 -0
- scitex/ml/classification/reporters/reporter_utils/aggregation.py +457 -0
- scitex/ml/classification/reporters/reporter_utils/data_models.py +313 -0
- scitex/ml/classification/reporters/reporter_utils/reporting.py +1056 -0
- scitex/ml/classification/reporters/reporter_utils/storage.py +221 -0
- scitex/ml/classification/reporters/reporter_utils/validation.py +395 -0
- scitex/ml/classification/timeseries/_TimeSeriesBlockingSplit.py +568 -0
- scitex/ml/classification/timeseries/_TimeSeriesCalendarSplit.py +688 -0
- scitex/ml/classification/timeseries/_TimeSeriesMetadata.py +139 -0
- scitex/ml/classification/timeseries/_TimeSeriesSlidingWindowSplit.py +1716 -0
- scitex/ml/classification/timeseries/_TimeSeriesSlidingWindowSplit_v01-not-using-n_splits.py +1685 -0
- scitex/ml/classification/timeseries/_TimeSeriesStrategy.py +84 -0
- scitex/ml/classification/timeseries/_TimeSeriesStratifiedSplit.py +610 -0
- scitex/ml/classification/timeseries/__init__.py +39 -0
- scitex/ml/classification/timeseries/_normalize_timestamp.py +436 -0
- scitex/ml/clustering/__init__.py +11 -0
- scitex/ml/clustering/_pca.py +115 -0
- scitex/ml/clustering/_umap.py +376 -0
- scitex/ml/feature_extraction/__init__.py +56 -0
- scitex/ml/feature_extraction/vit.py +149 -0
- scitex/ml/feature_selection/__init__.py +30 -0
- scitex/ml/feature_selection/feature_selection.py +364 -0
- scitex/ml/loss/_L1L2Losses.py +34 -0
- scitex/ml/loss/__init__.py +12 -0
- scitex/ml/loss/multi_task_loss.py +47 -0
- scitex/ml/metrics/__init__.py +56 -0
- scitex/ml/metrics/_calc_bacc.py +61 -0
- scitex/ml/metrics/_calc_bacc_from_conf_mat.py +38 -0
- scitex/ml/metrics/_calc_clf_report.py +78 -0
- scitex/ml/metrics/_calc_conf_mat.py +93 -0
- scitex/ml/metrics/_calc_feature_importance.py +183 -0
- scitex/ml/metrics/_calc_mcc.py +61 -0
- scitex/ml/metrics/_calc_pre_rec_auc.py +116 -0
- scitex/ml/metrics/_calc_roc_auc.py +110 -0
- scitex/ml/metrics/_calc_seizure_prediction_metrics.py +490 -0
- scitex/ml/metrics/_calc_silhouette_score.py +503 -0
- scitex/ml/metrics/_normalize_labels.py +83 -0
- scitex/ml/optim/Ranger_Deep_Learning_Optimizer/__init__.py +0 -0
- scitex/ml/optim/Ranger_Deep_Learning_Optimizer/ranger/__init__.py +3 -0
- scitex/ml/optim/Ranger_Deep_Learning_Optimizer/ranger/ranger.py +207 -0
- scitex/ml/optim/Ranger_Deep_Learning_Optimizer/ranger/ranger2020.py +238 -0
- scitex/ml/optim/Ranger_Deep_Learning_Optimizer/ranger/ranger913A.py +215 -0
- scitex/ml/optim/Ranger_Deep_Learning_Optimizer/ranger/rangerqh.py +184 -0
- scitex/ml/optim/Ranger_Deep_Learning_Optimizer/setup.py +24 -0
- scitex/ml/optim/__init__.py +13 -0
- scitex/ml/optim/_get_set.py +31 -0
- scitex/ml/optim/_optimizers.py +71 -0
- scitex/ml/plt/__init__.py +60 -0
- scitex/ml/plt/_plot_conf_mat.py +663 -0
- scitex/ml/plt/_plot_feature_importance.py +323 -0
- scitex/ml/plt/_plot_learning_curve.py +345 -0
- scitex/ml/plt/_plot_optuna_study.py +225 -0
- scitex/ml/plt/_plot_pre_rec_curve.py +290 -0
- scitex/ml/plt/_plot_roc_curve.py +255 -0
- scitex/ml/sk/__init__.py +11 -0
- scitex/ml/sk/_clf.py +58 -0
- scitex/ml/sk/_to_sktime.py +100 -0
- scitex/ml/sklearn/__init__.py +26 -0
- scitex/ml/sklearn/clf.py +58 -0
- scitex/ml/sklearn/to_sktime.py +100 -0
- scitex/{ai/training/early_stopping.py → ml/training/_EarlyStopping.py} +1 -2
- scitex/{ai → ml/training}/_LearningCurveLogger.py +198 -242
- scitex/ml/training/__init__.py +7 -0
- scitex/ml/utils/__init__.py +22 -0
- scitex/ml/utils/_check_params.py +50 -0
- scitex/ml/utils/_default_dataset.py +46 -0
- scitex/ml/utils/_format_samples_for_sktime.py +26 -0
- scitex/ml/utils/_label_encoder.py +134 -0
- scitex/ml/utils/_merge_labels.py +22 -0
- scitex/ml/utils/_sliding_window_data_augmentation.py +11 -0
- scitex/ml/utils/_under_sample.py +51 -0
- scitex/ml/utils/_verify_n_gpus.py +16 -0
- scitex/ml/utils/grid_search.py +148 -0
- scitex/nn/_BNet.py +15 -9
- scitex/nn/_Filters.py +2 -2
- scitex/nn/_ModulationIndex.py +2 -2
- scitex/nn/_PAC.py +1 -1
- scitex/nn/_Spectrogram.py +12 -3
- scitex/nn/__init__.py +9 -10
- scitex/path/__init__.py +18 -0
- scitex/path/_clean.py +4 -0
- scitex/path/_find.py +9 -4
- scitex/path/_symlink.py +348 -0
- scitex/path/_version.py +4 -3
- scitex/pd/__init__.py +2 -0
- scitex/pd/_get_unique.py +99 -0
- scitex/plt/__init__.py +114 -5
- scitex/plt/_subplots/_AxesWrapper.py +1 -3
- scitex/plt/_subplots/_AxisWrapper.py +7 -3
- scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin.py +47 -13
- scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin.py +160 -2
- scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin.py +26 -4
- scitex/plt/_subplots/_AxisWrapperMixins/_UnitAwareMixin.py +322 -0
- scitex/plt/_subplots/_AxisWrapperMixins/__init__.py +1 -0
- scitex/plt/_subplots/_FigWrapper.py +62 -6
- scitex/plt/_subplots/_export_as_csv.py +43 -27
- scitex/plt/_subplots/_export_as_csv_formatters/__init__.py +5 -4
- scitex/plt/_subplots/_export_as_csv_formatters/_format_annotate.py +81 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_bar.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_barh.py +20 -5
- scitex/plt/_subplots/_export_as_csv_formatters/_format_boxplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_contour.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_errorbar.py +35 -18
- scitex/plt/_subplots/_export_as_csv_formatters/_format_eventplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_fill.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_fill_between.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_hist.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_imshow.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_imshow2d.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot.py +15 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_box.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_conf_mat.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_ecdf.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_fillv.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_heatmap.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_image.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_joyplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_kde.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_line.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_mean_ci.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_mean_std.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_median_iqr.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_raster.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_rectangle.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_scatter.py +35 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_scatter_hist.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_shaded_line.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_violin.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_scatter.py +6 -4
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_barplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_boxplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_heatmap.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_histplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_jointplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_kdeplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_lineplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_pairplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_scatterplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_stripplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_swarmplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_violinplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_text.py +60 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_violin.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_violinplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/test_formatters.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters.py +56 -59
- scitex/plt/ax/_style/_hide_spines.py +1 -3
- scitex/plt/ax/_style/_rotate_labels.py +180 -76
- scitex/plt/ax/_style/_rotate_labels_v01.py +248 -0
- scitex/plt/ax/_style/_set_meta.py +11 -4
- scitex/plt/ax/_style/_set_supxyt.py +3 -3
- scitex/plt/ax/_style/_set_xyt.py +3 -3
- scitex/plt/ax/_style/_share_axes.py +2 -2
- scitex/plt/color/__init__.py +4 -4
- scitex/plt/color/{_get_colors_from_cmap.py → _get_colors_from_conf_matap.py} +7 -7
- scitex/plt/utils/_configure_mpl.py +99 -86
- scitex/plt/utils/_histogram_utils.py +1 -3
- scitex/plt/utils/_is_valid_axis.py +1 -3
- scitex/plt/utils/_scitex_config.py +1 -0
- scitex/repro/__init__.py +75 -0
- scitex/{reproduce → repro}/_gen_ID.py +1 -1
- scitex/{reproduce → repro}/_gen_timestamp.py +1 -1
- scitex/repro_rng/_RandomStateManager.py +590 -0
- scitex/repro_rng/_RandomStateManager_v01-no-verbose-options.py +414 -0
- scitex/repro_rng/__init__.py +39 -0
- scitex/reproduce/__init__.py +25 -13
- scitex/reproduce/_hash_array.py +22 -0
- scitex/resource/_get_processor_usages.py +4 -4
- scitex/resource/_get_specs.py +2 -2
- scitex/resource/_log_processor_usages.py +2 -2
- scitex/rng/_RandomStateManager.py +590 -0
- scitex/rng/_RandomStateManager_v01-no-verbose-options.py +414 -0
- scitex/rng/__init__.py +39 -0
- scitex/scholar/__init__.py +309 -19
- scitex/scholar/__main__.py +319 -0
- scitex/scholar/auth/ScholarAuthManager.py +308 -0
- scitex/scholar/auth/__init__.py +12 -0
- scitex/scholar/auth/core/AuthenticationGateway.py +473 -0
- scitex/scholar/auth/core/BrowserAuthenticator.py +386 -0
- scitex/scholar/auth/core/StrategyResolver.py +309 -0
- scitex/scholar/auth/core/__init__.py +16 -0
- scitex/scholar/auth/gateway/_OpenURLLinkFinder.py +120 -0
- scitex/scholar/auth/gateway/_OpenURLResolver.py +209 -0
- scitex/scholar/auth/gateway/__init__.py +38 -0
- scitex/scholar/auth/gateway/_resolve_functions.py +101 -0
- scitex/scholar/auth/providers/BaseAuthenticator.py +166 -0
- scitex/scholar/auth/providers/EZProxyAuthenticator.py +484 -0
- scitex/scholar/auth/providers/OpenAthensAuthenticator.py +619 -0
- scitex/scholar/auth/providers/ShibbolethAuthenticator.py +686 -0
- scitex/scholar/auth/providers/__init__.py +18 -0
- scitex/scholar/auth/session/AuthCacheManager.py +189 -0
- scitex/scholar/auth/session/SessionManager.py +159 -0
- scitex/scholar/auth/session/__init__.py +11 -0
- scitex/scholar/auth/sso/BaseSSOAutomator.py +373 -0
- scitex/scholar/auth/sso/OpenAthensSSOAutomator.py +378 -0
- scitex/scholar/auth/sso/SSOAutomator.py +180 -0
- scitex/scholar/auth/sso/UniversityOfMelbourneSSOAutomator.py +380 -0
- scitex/scholar/auth/sso/__init__.py +15 -0
- scitex/scholar/browser/ScholarBrowserManager.py +705 -0
- scitex/scholar/browser/__init__.py +38 -0
- scitex/scholar/browser/utils/__init__.py +13 -0
- scitex/scholar/browser/utils/click_and_wait.py +205 -0
- scitex/scholar/browser/utils/close_unwanted_pages.py +140 -0
- scitex/scholar/browser/utils/wait_redirects.py +732 -0
- scitex/scholar/config/PublisherRules.py +132 -0
- scitex/scholar/config/ScholarConfig.py +126 -0
- scitex/scholar/config/__init__.py +17 -0
- scitex/scholar/core/Paper.py +627 -0
- scitex/scholar/core/Papers.py +722 -0
- scitex/scholar/core/Scholar.py +1975 -0
- scitex/scholar/core/__init__.py +9 -0
- scitex/scholar/impact_factor/ImpactFactorEngine.py +204 -0
- scitex/scholar/impact_factor/__init__.py +20 -0
- scitex/scholar/impact_factor/estimation/ImpactFactorEstimationEngine.py +0 -0
- scitex/scholar/impact_factor/estimation/__init__.py +40 -0
- scitex/scholar/impact_factor/estimation/build_database.py +0 -0
- scitex/scholar/impact_factor/estimation/core/__init__.py +28 -0
- scitex/scholar/impact_factor/estimation/core/cache_manager.py +523 -0
- scitex/scholar/impact_factor/estimation/core/calculator.py +355 -0
- scitex/scholar/impact_factor/estimation/core/journal_matcher.py +428 -0
- scitex/scholar/integration/__init__.py +59 -0
- scitex/scholar/integration/base.py +502 -0
- scitex/scholar/integration/mendeley/__init__.py +22 -0
- scitex/scholar/integration/mendeley/exporter.py +166 -0
- scitex/scholar/integration/mendeley/importer.py +236 -0
- scitex/scholar/integration/mendeley/linker.py +79 -0
- scitex/scholar/integration/mendeley/mapper.py +212 -0
- scitex/scholar/integration/zotero/__init__.py +27 -0
- scitex/scholar/integration/zotero/__main__.py +264 -0
- scitex/scholar/integration/zotero/exporter.py +351 -0
- scitex/scholar/integration/zotero/importer.py +372 -0
- scitex/scholar/integration/zotero/linker.py +415 -0
- scitex/scholar/integration/zotero/mapper.py +286 -0
- scitex/scholar/metadata_engines/ScholarEngine.py +588 -0
- scitex/scholar/metadata_engines/__init__.py +21 -0
- scitex/scholar/metadata_engines/individual/ArXivEngine.py +397 -0
- scitex/scholar/metadata_engines/individual/CrossRefEngine.py +274 -0
- scitex/scholar/metadata_engines/individual/CrossRefLocalEngine.py +263 -0
- scitex/scholar/metadata_engines/individual/OpenAlexEngine.py +350 -0
- scitex/scholar/metadata_engines/individual/PubMedEngine.py +329 -0
- scitex/scholar/metadata_engines/individual/SemanticScholarEngine.py +438 -0
- scitex/scholar/metadata_engines/individual/URLDOIEngine.py +410 -0
- scitex/scholar/metadata_engines/individual/_BaseDOIEngine.py +487 -0
- scitex/scholar/metadata_engines/individual/__init__.py +7 -0
- scitex/scholar/metadata_engines/utils/_PubMedConverter.py +469 -0
- scitex/scholar/metadata_engines/utils/_URLDOIExtractor.py +283 -0
- scitex/scholar/metadata_engines/utils/__init__.py +30 -0
- scitex/scholar/metadata_engines/utils/_metadata2bibtex.py +103 -0
- scitex/scholar/metadata_engines/utils/_standardize_metadata.py +376 -0
- scitex/scholar/pdf_download/ScholarPDFDownloader.py +579 -0
- scitex/scholar/pdf_download/__init__.py +5 -0
- scitex/scholar/pdf_download/strategies/__init__.py +38 -0
- scitex/scholar/pdf_download/strategies/chrome_pdf_viewer.py +376 -0
- scitex/scholar/pdf_download/strategies/direct_download.py +131 -0
- scitex/scholar/pdf_download/strategies/manual_download_fallback.py +167 -0
- scitex/scholar/pdf_download/strategies/manual_download_utils.py +996 -0
- scitex/scholar/pdf_download/strategies/response_body.py +207 -0
- scitex/scholar/pipelines/ScholarPipelineBibTeX.py +364 -0
- scitex/scholar/pipelines/ScholarPipelineParallel.py +478 -0
- scitex/scholar/pipelines/ScholarPipelineSingle.py +767 -0
- scitex/scholar/pipelines/__init__.py +49 -0
- scitex/scholar/storage/BibTeXHandler.py +1018 -0
- scitex/scholar/storage/PaperIO.py +468 -0
- scitex/scholar/storage/ScholarLibrary.py +182 -0
- scitex/scholar/storage/_DeduplicationManager.py +548 -0
- scitex/scholar/storage/_LibraryCacheManager.py +724 -0
- scitex/scholar/storage/_LibraryManager.py +1835 -0
- scitex/scholar/storage/__init__.py +28 -0
- scitex/scholar/url_finder/ScholarURLFinder.py +379 -0
- scitex/scholar/url_finder/__init__.py +7 -0
- scitex/scholar/url_finder/strategies/__init__.py +33 -0
- scitex/scholar/url_finder/strategies/find_pdf_urls_by_direct_links.py +261 -0
- scitex/scholar/url_finder/strategies/find_pdf_urls_by_dropdown.py +67 -0
- scitex/scholar/url_finder/strategies/find_pdf_urls_by_href.py +204 -0
- scitex/scholar/url_finder/strategies/find_pdf_urls_by_navigation.py +256 -0
- scitex/scholar/url_finder/strategies/find_pdf_urls_by_publisher_patterns.py +165 -0
- scitex/scholar/url_finder/strategies/find_pdf_urls_by_zotero_translators.py +163 -0
- scitex/scholar/url_finder/strategies/find_supplementary_urls_by_href.py +70 -0
- scitex/scholar/utils/__init__.py +22 -0
- scitex/scholar/utils/bibtex/__init__.py +9 -0
- scitex/scholar/utils/bibtex/_parse_bibtex.py +71 -0
- scitex/scholar/utils/cleanup/__init__.py +8 -0
- scitex/scholar/utils/cleanup/_cleanup_scholar_processes.py +96 -0
- scitex/scholar/utils/cleanup/cleanup_old_extractions.py +117 -0
- scitex/scholar/utils/text/_TextNormalizer.py +407 -0
- scitex/scholar/utils/text/__init__.py +9 -0
- scitex/scholar/zotero/__init__.py +38 -0
- scitex/session/__init__.py +51 -0
- scitex/session/_lifecycle.py +736 -0
- scitex/session/_manager.py +102 -0
- scitex/session/template.py +122 -0
- scitex/stats/__init__.py +30 -26
- scitex/stats/correct/__init__.py +21 -0
- scitex/stats/correct/_correct_bonferroni.py +551 -0
- scitex/stats/correct/_correct_fdr.py +634 -0
- scitex/stats/correct/_correct_holm.py +548 -0
- scitex/stats/correct/_correct_sidak.py +499 -0
- scitex/stats/descriptive/__init__.py +85 -0
- scitex/stats/descriptive/_circular.py +540 -0
- scitex/stats/descriptive/_describe.py +219 -0
- scitex/stats/descriptive/_nan.py +518 -0
- scitex/stats/descriptive/_real.py +189 -0
- scitex/stats/effect_sizes/__init__.py +41 -0
- scitex/stats/effect_sizes/_cliffs_delta.py +325 -0
- scitex/stats/effect_sizes/_cohens_d.py +342 -0
- scitex/stats/effect_sizes/_epsilon_squared.py +315 -0
- scitex/stats/effect_sizes/_eta_squared.py +302 -0
- scitex/stats/effect_sizes/_prob_superiority.py +296 -0
- scitex/stats/posthoc/__init__.py +19 -0
- scitex/stats/posthoc/_dunnett.py +463 -0
- scitex/stats/posthoc/_games_howell.py +383 -0
- scitex/stats/posthoc/_tukey_hsd.py +367 -0
- scitex/stats/power/__init__.py +19 -0
- scitex/stats/power/_power.py +433 -0
- scitex/stats/template.py +119 -0
- scitex/stats/utils/__init__.py +62 -0
- scitex/stats/utils/_effect_size.py +985 -0
- scitex/stats/utils/_formatters.py +270 -0
- scitex/stats/utils/_normalizers.py +927 -0
- scitex/stats/utils/_power.py +433 -0
- scitex/stats_v01/_EffectSizeCalculator.py +488 -0
- scitex/stats_v01/_StatisticalValidator.py +411 -0
- scitex/stats_v01/__init__.py +60 -0
- scitex/stats_v01/_additional_tests.py +415 -0
- scitex/{stats → stats_v01}/_p2stars.py +19 -5
- scitex/stats_v01/_two_sample_tests.py +141 -0
- scitex/stats_v01/desc/__init__.py +83 -0
- scitex/stats_v01/desc/_circular.py +540 -0
- scitex/stats_v01/desc/_describe.py +219 -0
- scitex/stats_v01/desc/_nan.py +518 -0
- scitex/{stats/desc/_nan.py → stats_v01/desc/_nan_v01-20250920_145731.py} +23 -12
- scitex/stats_v01/desc/_real.py +189 -0
- scitex/stats_v01/tests/__corr_test_optimized.py +221 -0
- scitex/stats_v01/tests/_corr_test_optimized.py +179 -0
- scitex/str/__init__.py +1 -3
- scitex/str/_clean_path.py +6 -2
- scitex/str/_latex_fallback.py +267 -160
- scitex/str/_parse.py +44 -36
- scitex/str/_printc.py +1 -3
- scitex/template/__init__.py +87 -0
- scitex/template/_create_project.py +267 -0
- scitex/template/create_pip_project.py +80 -0
- scitex/template/create_research.py +80 -0
- scitex/template/create_singularity.py +80 -0
- scitex/units.py +291 -0
- scitex/utils/_compress_hdf5.py +14 -3
- scitex/utils/_email.py +21 -2
- scitex/utils/_grid.py +6 -4
- scitex/utils/_notify.py +13 -10
- scitex/utils/_verify_scitex_format.py +589 -0
- scitex/utils/_verify_scitex_format_v01.py +370 -0
- scitex/utils/template.py +122 -0
- scitex/web/_search_pubmed.py +62 -16
- scitex-2.1.0.dist-info/LICENSE +21 -0
- scitex-2.1.0.dist-info/METADATA +677 -0
- scitex-2.1.0.dist-info/RECORD +919 -0
- {scitex-2.0.0.dist-info → scitex-2.1.0.dist-info}/WHEEL +1 -1
- scitex-2.1.0.dist-info/entry_points.txt +3 -0
- scitex/ai/__Classifiers.py +0 -101
- scitex/ai/classification/classification_reporter.py +0 -1137
- scitex/ai/classification/classifiers.py +0 -101
- scitex/ai/classification_reporter.py +0 -1161
- scitex/ai/genai/__init__.py +0 -277
- scitex/ai/genai/anthropic_provider.py +0 -320
- scitex/ai/genai/anthropic_refactored.py +0 -109
- scitex/ai/genai/auth_manager.py +0 -200
- scitex/ai/genai/base_provider.py +0 -291
- scitex/ai/genai/chat_history.py +0 -307
- scitex/ai/genai/cost_tracker.py +0 -276
- scitex/ai/genai/deepseek_provider.py +0 -251
- scitex/ai/genai/google_provider.py +0 -228
- scitex/ai/genai/groq_provider.py +0 -248
- scitex/ai/genai/image_processor.py +0 -250
- scitex/ai/genai/llama_provider.py +0 -214
- scitex/ai/genai/mock_provider.py +0 -127
- scitex/ai/genai/model_registry.py +0 -304
- scitex/ai/genai/openai_provider.py +0 -293
- scitex/ai/genai/perplexity_provider.py +0 -205
- scitex/ai/genai/provider_base.py +0 -302
- scitex/ai/genai/provider_factory.py +0 -370
- scitex/ai/genai/response_handler.py +0 -235
- scitex/ai/layer/_Pass.py +0 -21
- scitex/ai/layer/__init__.py +0 -10
- scitex/ai/layer/_switch.py +0 -8
- scitex/ai/metrics/_bACC.py +0 -51
- scitex/ai/plt/_learning_curve.py +0 -194
- scitex/ai/plt/_optuna_study.py +0 -111
- scitex/ai/plt/aucs/__init__.py +0 -2
- scitex/ai/plt/aucs/example.py +0 -60
- scitex/ai/plt/aucs/pre_rec_auc.py +0 -223
- scitex/ai/plt/aucs/roc_auc.py +0 -246
- scitex/ai/sampling/undersample.py +0 -29
- scitex/db/_SQLite3.py +0 -2136
- scitex/db/_SQLite3Mixins/_BlobMixin.py +0 -229
- scitex/gen/_close.py +0 -222
- scitex/gen/_start.py +0 -451
- scitex/general/__init__.py +0 -5
- scitex/io/_load_modules/_db.py +0 -24
- scitex/life/__init__.py +0 -10
- scitex/life/_monitor_rain.py +0 -49
- scitex/reproduce/_fix_seeds.py +0 -45
- scitex/res/__init__.py +0 -5
- scitex/scholar/_local_search.py +0 -454
- scitex/scholar/_paper.py +0 -244
- scitex/scholar/_pdf_downloader.py +0 -325
- scitex/scholar/_search.py +0 -393
- scitex/scholar/_vector_search.py +0 -370
- scitex/scholar/_web_sources.py +0 -457
- scitex/stats/desc/__init__.py +0 -40
- scitex-2.0.0.dist-info/METADATA +0 -307
- scitex-2.0.0.dist-info/RECORD +0 -572
- scitex-2.0.0.dist-info/licenses/LICENSE +0 -7
- /scitex/ai/{act → activation}/__init__.py +0 -0
- /scitex/ai/{act → activation}/_define.py +0 -0
- /scitex/ai/{early_stopping.py → training/_EarlyStopping.py} +0 -0
- /scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_ImportExportMixin.py +0 -0
- /scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_IndexMixin.py +0 -0
- /scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_RowMixin.py +0 -0
- /scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_TableMixin.py +0 -0
- /scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/__init__.py +0 -0
- /scitex/{stats → stats_v01}/_calc_partial_corr.py +0 -0
- /scitex/{stats → stats_v01}/_corr_test_multi.py +0 -0
- /scitex/{stats → stats_v01}/_corr_test_wrapper.py +0 -0
- /scitex/{stats → stats_v01}/_describe_wrapper.py +0 -0
- /scitex/{stats → stats_v01}/_multiple_corrections.py +0 -0
- /scitex/{stats → stats_v01}/_nan_stats.py +0 -0
- /scitex/{stats → stats_v01}/_p2stars_wrapper.py +0 -0
- /scitex/{stats → stats_v01}/_statistical_tests.py +0 -0
- /scitex/{stats/desc/_describe.py → stats_v01/desc/_describe_v01-20250920_145731.py} +0 -0
- /scitex/{stats/desc/_real.py → stats_v01/desc/_real_v01-20250920_145731.py} +0 -0
- /scitex/{stats → stats_v01}/multiple/__init__.py +0 -0
- /scitex/{stats → stats_v01}/multiple/_bonferroni_correction.py +0 -0
- /scitex/{stats → stats_v01}/multiple/_fdr_correction.py +0 -0
- /scitex/{stats → stats_v01}/multiple/_multicompair.py +0 -0
- /scitex/{stats → stats_v01}/tests/__corr_test.py +0 -0
- /scitex/{stats → stats_v01}/tests/__corr_test_multi.py +0 -0
- /scitex/{stats → stats_v01}/tests/__corr_test_single.py +0 -0
- /scitex/{stats → stats_v01}/tests/__init__.py +0 -0
- /scitex/{stats → stats_v01}/tests/_brunner_munzel_test.py +0 -0
- /scitex/{stats → stats_v01}/tests/_nocorrelation_test.py +0 -0
- /scitex/{stats → stats_v01}/tests/_smirnov_grubbs.py +0 -0
- {scitex-2.0.0.dist-info → scitex-2.1.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,583 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Timestamp: "2025-09-08 06:55:13 (ywatanabe)"
|
|
4
|
+
# File: /ssh:sp:/home/ywatanabe/proj/scitex_repo/src/scitex/db/_sqlite3/_SQLite3Mixins/_GitMixin.py
|
|
5
|
+
# ----------------------------------------
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
import os
|
|
8
|
+
__FILE__ = __file__
|
|
9
|
+
__DIR__ = os.path.dirname(__FILE__)
|
|
10
|
+
# ----------------------------------------
|
|
11
|
+
|
|
12
|
+
import hashlib
|
|
13
|
+
import json
|
|
14
|
+
import pickle
|
|
15
|
+
import time
|
|
16
|
+
import zlib
|
|
17
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class _GitMixin:
|
|
21
|
+
"""Git-like version control for SQLite databases using diff-based tracking."""
|
|
22
|
+
|
|
23
|
+
def git_init(self, force: bool = False) -> None:
|
|
24
|
+
"""Initialize version control tables.
|
|
25
|
+
|
|
26
|
+
Parameters
|
|
27
|
+
----------
|
|
28
|
+
force : bool
|
|
29
|
+
If True, reinitialize even if tables exist
|
|
30
|
+
"""
|
|
31
|
+
if force:
|
|
32
|
+
self.execute("DROP TABLE IF EXISTS _git_commits")
|
|
33
|
+
self.execute("DROP TABLE IF EXISTS _git_refs")
|
|
34
|
+
self.execute("DROP TABLE IF EXISTS _git_changes")
|
|
35
|
+
|
|
36
|
+
# Store commit metadata
|
|
37
|
+
self.execute(
|
|
38
|
+
"""
|
|
39
|
+
CREATE TABLE IF NOT EXISTS _git_commits (
|
|
40
|
+
hash TEXT PRIMARY KEY,
|
|
41
|
+
parent_hash TEXT,
|
|
42
|
+
message TEXT,
|
|
43
|
+
author TEXT,
|
|
44
|
+
timestamp REAL,
|
|
45
|
+
tree_hash TEXT
|
|
46
|
+
)
|
|
47
|
+
"""
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
# Store references (branches, HEAD)
|
|
51
|
+
self.execute(
|
|
52
|
+
"""
|
|
53
|
+
CREATE TABLE IF NOT EXISTS _git_refs (
|
|
54
|
+
name TEXT PRIMARY KEY,
|
|
55
|
+
commit_hash TEXT,
|
|
56
|
+
type TEXT -- 'branch', 'tag', 'HEAD'
|
|
57
|
+
)
|
|
58
|
+
"""
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# Store actual changes per commit
|
|
62
|
+
self.execute(
|
|
63
|
+
"""
|
|
64
|
+
CREATE TABLE IF NOT EXISTS _git_changes (
|
|
65
|
+
commit_hash TEXT,
|
|
66
|
+
table_name TEXT,
|
|
67
|
+
operation TEXT, -- INSERT, UPDATE, DELETE
|
|
68
|
+
row_id INTEGER,
|
|
69
|
+
old_data BLOB,
|
|
70
|
+
new_data BLOB,
|
|
71
|
+
PRIMARY KEY (commit_hash, table_name, operation, row_id)
|
|
72
|
+
)
|
|
73
|
+
"""
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
# Initialize HEAD if not exists
|
|
77
|
+
if not self.execute(
|
|
78
|
+
"SELECT 1 FROM _git_refs WHERE name='HEAD'"
|
|
79
|
+
).fetchone():
|
|
80
|
+
self.execute("INSERT INTO _git_refs VALUES ('HEAD', NULL, 'HEAD')")
|
|
81
|
+
self.execute(
|
|
82
|
+
"INSERT INTO _git_refs VALUES ('main', NULL, 'branch')"
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
def git_commit(self, message: str = "", author: str = "unknown") -> str:
|
|
86
|
+
"""Create a new commit with current database state.
|
|
87
|
+
|
|
88
|
+
Parameters
|
|
89
|
+
----------
|
|
90
|
+
message : str
|
|
91
|
+
Commit message
|
|
92
|
+
author : str
|
|
93
|
+
Author name
|
|
94
|
+
|
|
95
|
+
Returns
|
|
96
|
+
-------
|
|
97
|
+
str
|
|
98
|
+
Commit hash (first 8 characters)
|
|
99
|
+
"""
|
|
100
|
+
# Get current HEAD
|
|
101
|
+
parent_hash = self._git_get_head()
|
|
102
|
+
|
|
103
|
+
# Calculate changes since parent
|
|
104
|
+
changes = self._git_calculate_changes(parent_hash)
|
|
105
|
+
|
|
106
|
+
if not changes and parent_hash:
|
|
107
|
+
print("No changes to commit")
|
|
108
|
+
return parent_hash
|
|
109
|
+
|
|
110
|
+
# Generate commit hash
|
|
111
|
+
tree_hash = self._git_calculate_tree_hash(changes)
|
|
112
|
+
commit_data = (
|
|
113
|
+
f"{parent_hash}:{message}:{author}:{time.time()}:{tree_hash}"
|
|
114
|
+
)
|
|
115
|
+
commit_hash = hashlib.sha256(commit_data.encode()).hexdigest()[:8]
|
|
116
|
+
|
|
117
|
+
# Store commit
|
|
118
|
+
self.execute(
|
|
119
|
+
"""
|
|
120
|
+
INSERT INTO _git_commits VALUES (?, ?, ?, ?, ?, ?)
|
|
121
|
+
""",
|
|
122
|
+
(
|
|
123
|
+
commit_hash,
|
|
124
|
+
parent_hash,
|
|
125
|
+
message,
|
|
126
|
+
author,
|
|
127
|
+
time.time(),
|
|
128
|
+
tree_hash,
|
|
129
|
+
),
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# Store changes
|
|
133
|
+
for change in changes:
|
|
134
|
+
self.execute(
|
|
135
|
+
"""
|
|
136
|
+
INSERT INTO _git_changes VALUES (?, ?, ?, ?, ?, ?)
|
|
137
|
+
""",
|
|
138
|
+
(
|
|
139
|
+
commit_hash,
|
|
140
|
+
change["table"],
|
|
141
|
+
change["operation"],
|
|
142
|
+
change["row_id"],
|
|
143
|
+
change["old_data"],
|
|
144
|
+
change["new_data"],
|
|
145
|
+
),
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
# Update HEAD and current branch
|
|
149
|
+
current_branch = self._git_get_current_branch()
|
|
150
|
+
self.execute(
|
|
151
|
+
"UPDATE _git_refs SET commit_hash = ? WHERE name = 'HEAD'",
|
|
152
|
+
(commit_hash,),
|
|
153
|
+
)
|
|
154
|
+
if current_branch:
|
|
155
|
+
self.execute(
|
|
156
|
+
"UPDATE _git_refs SET commit_hash = ? WHERE name = ?",
|
|
157
|
+
(commit_hash, current_branch),
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
self.commit() # SQL commit
|
|
161
|
+
return commit_hash
|
|
162
|
+
|
|
163
|
+
def git_checkout(self, ref: str) -> None:
|
|
164
|
+
"""Switch to a different commit or branch.
|
|
165
|
+
|
|
166
|
+
Parameters
|
|
167
|
+
----------
|
|
168
|
+
ref : str
|
|
169
|
+
Commit hash or branch name
|
|
170
|
+
"""
|
|
171
|
+
# Resolve ref to commit hash
|
|
172
|
+
target_hash = self._git_resolve_ref(ref)
|
|
173
|
+
if not target_hash:
|
|
174
|
+
raise ValueError(f"Reference '{ref}' not found")
|
|
175
|
+
|
|
176
|
+
current_hash = self._git_get_head()
|
|
177
|
+
|
|
178
|
+
if target_hash == current_hash:
|
|
179
|
+
return # Already there
|
|
180
|
+
|
|
181
|
+
# Find path between commits
|
|
182
|
+
path = self._git_find_path(current_hash, target_hash)
|
|
183
|
+
|
|
184
|
+
# Apply changes along path
|
|
185
|
+
for i in range(len(path) - 1):
|
|
186
|
+
from_commit = path[i]
|
|
187
|
+
to_commit = path[i + 1]
|
|
188
|
+
|
|
189
|
+
if self._git_is_ancestor(from_commit, to_commit):
|
|
190
|
+
# Moving forward - apply changes
|
|
191
|
+
self._git_apply_changes(to_commit, reverse=False)
|
|
192
|
+
else:
|
|
193
|
+
# Moving backward - reverse changes
|
|
194
|
+
self._git_apply_changes(from_commit, reverse=True)
|
|
195
|
+
|
|
196
|
+
# Update HEAD
|
|
197
|
+
self.execute(
|
|
198
|
+
"UPDATE _git_refs SET commit_hash = ? WHERE name = 'HEAD'",
|
|
199
|
+
(target_hash,),
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
# If ref is a branch, update current branch tracking
|
|
203
|
+
if self.execute(
|
|
204
|
+
"SELECT 1 FROM _git_refs WHERE name = ? AND type = 'branch'",
|
|
205
|
+
(ref,),
|
|
206
|
+
).fetchone():
|
|
207
|
+
self.execute(
|
|
208
|
+
"UPDATE _git_refs SET commit_hash = ? WHERE name = ?",
|
|
209
|
+
(target_hash, ref),
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
self.commit() # SQL commit
|
|
213
|
+
|
|
214
|
+
def git_branch(
|
|
215
|
+
self, name: Optional[str] = None, delete: bool = False
|
|
216
|
+
) -> List[Tuple[str, str]]:
|
|
217
|
+
"""Create, list, or delete branches.
|
|
218
|
+
|
|
219
|
+
Parameters
|
|
220
|
+
----------
|
|
221
|
+
name : str, optional
|
|
222
|
+
Branch name to create
|
|
223
|
+
delete : bool
|
|
224
|
+
If True, delete the branch
|
|
225
|
+
|
|
226
|
+
Returns
|
|
227
|
+
-------
|
|
228
|
+
list
|
|
229
|
+
List of (branch_name, commit_hash) tuples if listing
|
|
230
|
+
"""
|
|
231
|
+
if delete and name:
|
|
232
|
+
self.execute(
|
|
233
|
+
"DELETE FROM _git_refs WHERE name = ? AND type = 'branch'",
|
|
234
|
+
(name,),
|
|
235
|
+
)
|
|
236
|
+
return []
|
|
237
|
+
elif name:
|
|
238
|
+
# Create new branch at current commit
|
|
239
|
+
current_hash = self._git_get_head()
|
|
240
|
+
self.execute(
|
|
241
|
+
"INSERT OR REPLACE INTO _git_refs VALUES (?, ?, 'branch')",
|
|
242
|
+
(name, current_hash),
|
|
243
|
+
)
|
|
244
|
+
return []
|
|
245
|
+
else:
|
|
246
|
+
# List branches
|
|
247
|
+
return self.execute(
|
|
248
|
+
"""
|
|
249
|
+
SELECT name, commit_hash
|
|
250
|
+
FROM _git_refs
|
|
251
|
+
WHERE type = 'branch'
|
|
252
|
+
ORDER BY name
|
|
253
|
+
"""
|
|
254
|
+
).fetchall()
|
|
255
|
+
|
|
256
|
+
def git_log(
|
|
257
|
+
self, limit: int = 10, oneline: bool = False
|
|
258
|
+
) -> List[Dict[str, Any]]:
|
|
259
|
+
"""Show commit history.
|
|
260
|
+
|
|
261
|
+
Parameters
|
|
262
|
+
----------
|
|
263
|
+
limit : int
|
|
264
|
+
Maximum number of commits to show
|
|
265
|
+
oneline : bool
|
|
266
|
+
If True, return condensed format
|
|
267
|
+
|
|
268
|
+
Returns
|
|
269
|
+
-------
|
|
270
|
+
list
|
|
271
|
+
List of commit information dictionaries
|
|
272
|
+
"""
|
|
273
|
+
current = self._git_get_head()
|
|
274
|
+
history = []
|
|
275
|
+
visited = set()
|
|
276
|
+
|
|
277
|
+
while current and len(history) < limit:
|
|
278
|
+
if current in visited:
|
|
279
|
+
break
|
|
280
|
+
visited.add(current)
|
|
281
|
+
|
|
282
|
+
commit_info = self.execute(
|
|
283
|
+
"""
|
|
284
|
+
SELECT hash, parent_hash, message, author, timestamp
|
|
285
|
+
FROM _git_commits
|
|
286
|
+
WHERE hash = ?
|
|
287
|
+
""",
|
|
288
|
+
(current,),
|
|
289
|
+
).fetchone()
|
|
290
|
+
|
|
291
|
+
if commit_info:
|
|
292
|
+
if oneline:
|
|
293
|
+
history.append(
|
|
294
|
+
{
|
|
295
|
+
"hash": commit_info[0],
|
|
296
|
+
"message": commit_info[2][:50],
|
|
297
|
+
}
|
|
298
|
+
)
|
|
299
|
+
else:
|
|
300
|
+
history.append(
|
|
301
|
+
{
|
|
302
|
+
"hash": commit_info[0],
|
|
303
|
+
"parent": commit_info[1],
|
|
304
|
+
"message": commit_info[2],
|
|
305
|
+
"author": commit_info[3],
|
|
306
|
+
"date": time.strftime(
|
|
307
|
+
"%Y-%m-%d %H:%M:%S",
|
|
308
|
+
time.localtime(commit_info[4]),
|
|
309
|
+
),
|
|
310
|
+
}
|
|
311
|
+
)
|
|
312
|
+
current = commit_info[1] # Move to parent
|
|
313
|
+
else:
|
|
314
|
+
break
|
|
315
|
+
|
|
316
|
+
return history
|
|
317
|
+
|
|
318
|
+
def git_diff(
|
|
319
|
+
self, from_ref: Optional[str] = None, to_ref: Optional[str] = None
|
|
320
|
+
) -> Dict[str, List]:
|
|
321
|
+
"""Show differences between commits.
|
|
322
|
+
|
|
323
|
+
Parameters
|
|
324
|
+
----------
|
|
325
|
+
from_ref : str, optional
|
|
326
|
+
Starting commit (default: parent of HEAD)
|
|
327
|
+
to_ref : str, optional
|
|
328
|
+
Ending commit (default: HEAD)
|
|
329
|
+
|
|
330
|
+
Returns
|
|
331
|
+
-------
|
|
332
|
+
dict
|
|
333
|
+
Dictionary of changes by table
|
|
334
|
+
"""
|
|
335
|
+
if not to_ref:
|
|
336
|
+
to_ref = self._git_get_head()
|
|
337
|
+
if not from_ref:
|
|
338
|
+
# Get parent of to_ref
|
|
339
|
+
parent = self.execute(
|
|
340
|
+
"SELECT parent_hash FROM _git_commits WHERE hash = ?",
|
|
341
|
+
(to_ref,),
|
|
342
|
+
).fetchone()
|
|
343
|
+
from_ref = parent[0] if parent else None
|
|
344
|
+
|
|
345
|
+
if not from_ref:
|
|
346
|
+
# No parent, show all changes in to_ref
|
|
347
|
+
changes = self.execute(
|
|
348
|
+
"""
|
|
349
|
+
SELECT table_name, operation, row_id, old_data, new_data
|
|
350
|
+
FROM _git_changes
|
|
351
|
+
WHERE commit_hash = ?
|
|
352
|
+
""",
|
|
353
|
+
(to_ref,),
|
|
354
|
+
).fetchall()
|
|
355
|
+
else:
|
|
356
|
+
# This is simplified - real implementation would compute actual diff
|
|
357
|
+
changes = self.execute(
|
|
358
|
+
"""
|
|
359
|
+
SELECT table_name, operation, row_id, old_data, new_data
|
|
360
|
+
FROM _git_changes
|
|
361
|
+
WHERE commit_hash = ?
|
|
362
|
+
""",
|
|
363
|
+
(to_ref,),
|
|
364
|
+
).fetchall()
|
|
365
|
+
|
|
366
|
+
# Group by table
|
|
367
|
+
diff = {}
|
|
368
|
+
for table, op, row_id, old_data, new_data in changes:
|
|
369
|
+
if table not in diff:
|
|
370
|
+
diff[table] = []
|
|
371
|
+
diff[table].append(
|
|
372
|
+
{
|
|
373
|
+
"operation": op,
|
|
374
|
+
"row_id": row_id,
|
|
375
|
+
"old": pickle.loads(old_data) if old_data else None,
|
|
376
|
+
"new": pickle.loads(new_data) if new_data else None,
|
|
377
|
+
}
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
return diff
|
|
381
|
+
|
|
382
|
+
def git_status(self) -> Dict[str, Any]:
|
|
383
|
+
"""Show working tree status.
|
|
384
|
+
|
|
385
|
+
Returns
|
|
386
|
+
-------
|
|
387
|
+
dict
|
|
388
|
+
Status information including current branch and uncommitted changes
|
|
389
|
+
"""
|
|
390
|
+
current_branch = self._git_get_current_branch()
|
|
391
|
+
current_commit = self._git_get_head()
|
|
392
|
+
uncommitted = self._git_calculate_changes(current_commit)
|
|
393
|
+
|
|
394
|
+
return {
|
|
395
|
+
"branch": current_branch or "detached HEAD",
|
|
396
|
+
"commit": current_commit,
|
|
397
|
+
"uncommitted_changes": len(uncommitted),
|
|
398
|
+
"changes_summary": self._summarize_changes(uncommitted),
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
def git_reset(self, ref: str, mode: str = "mixed") -> None:
|
|
402
|
+
"""Reset current HEAD to specified state.
|
|
403
|
+
|
|
404
|
+
Parameters
|
|
405
|
+
----------
|
|
406
|
+
ref : str
|
|
407
|
+
Target commit
|
|
408
|
+
mode : str
|
|
409
|
+
'soft' (move HEAD only), 'mixed' (move HEAD + index),
|
|
410
|
+
'hard' (move HEAD + working tree)
|
|
411
|
+
"""
|
|
412
|
+
target_hash = self._git_resolve_ref(ref)
|
|
413
|
+
|
|
414
|
+
if mode == "soft":
|
|
415
|
+
# Just move HEAD
|
|
416
|
+
self.execute(
|
|
417
|
+
"UPDATE _git_refs SET commit_hash = ? WHERE name = 'HEAD'",
|
|
418
|
+
(target_hash,),
|
|
419
|
+
)
|
|
420
|
+
elif mode == "hard":
|
|
421
|
+
# Move HEAD and restore working tree
|
|
422
|
+
self.git_checkout(ref)
|
|
423
|
+
# 'mixed' would update index if we had one
|
|
424
|
+
|
|
425
|
+
# Private helper methods
|
|
426
|
+
|
|
427
|
+
def _git_get_head(self) -> Optional[str]:
|
|
428
|
+
"""Get current HEAD commit hash."""
|
|
429
|
+
result = self.execute(
|
|
430
|
+
"SELECT commit_hash FROM _git_refs WHERE name = 'HEAD'"
|
|
431
|
+
).fetchone()
|
|
432
|
+
return result[0] if result else None
|
|
433
|
+
|
|
434
|
+
def _git_get_current_branch(self) -> Optional[str]:
|
|
435
|
+
"""Get current branch name."""
|
|
436
|
+
head = self._git_get_head()
|
|
437
|
+
if not head:
|
|
438
|
+
return None
|
|
439
|
+
|
|
440
|
+
result = self.execute(
|
|
441
|
+
"""
|
|
442
|
+
SELECT name FROM _git_refs
|
|
443
|
+
WHERE commit_hash = ? AND type = 'branch'
|
|
444
|
+
LIMIT 1
|
|
445
|
+
""",
|
|
446
|
+
(head,),
|
|
447
|
+
).fetchone()
|
|
448
|
+
return result[0] if result else None
|
|
449
|
+
|
|
450
|
+
def _git_resolve_ref(self, ref: str) -> Optional[str]:
|
|
451
|
+
"""Resolve a reference to a commit hash."""
|
|
452
|
+
# Check if it's already a commit hash
|
|
453
|
+
if self.execute(
|
|
454
|
+
"SELECT 1 FROM _git_commits WHERE hash = ?", (ref,)
|
|
455
|
+
).fetchone():
|
|
456
|
+
return ref
|
|
457
|
+
|
|
458
|
+
# Check if it's a branch or tag
|
|
459
|
+
result = self.execute(
|
|
460
|
+
"SELECT commit_hash FROM _git_refs WHERE name = ?", (ref,)
|
|
461
|
+
).fetchone()
|
|
462
|
+
return result[0] if result else None
|
|
463
|
+
|
|
464
|
+
def _git_calculate_changes(
|
|
465
|
+
self, since_commit: Optional[str]
|
|
466
|
+
) -> List[Dict]:
|
|
467
|
+
"""Calculate changes since a commit."""
|
|
468
|
+
changes = []
|
|
469
|
+
|
|
470
|
+
# Get all tracked tables (exclude git tables)
|
|
471
|
+
tables = [
|
|
472
|
+
t for t in self.get_table_names() if not t.startswith("_git_")
|
|
473
|
+
]
|
|
474
|
+
|
|
475
|
+
for table in tables:
|
|
476
|
+
# This is simplified - real implementation would track actual changes
|
|
477
|
+
# For now, we'll snapshot current state
|
|
478
|
+
current_data = self.execute(
|
|
479
|
+
f"SELECT rowid, * FROM {table}"
|
|
480
|
+
).fetchall()
|
|
481
|
+
|
|
482
|
+
for row in current_data[:10]: # Limit for demo
|
|
483
|
+
changes.append(
|
|
484
|
+
{
|
|
485
|
+
"table": table,
|
|
486
|
+
"operation": "UPDATE", # Simplified
|
|
487
|
+
"row_id": row[0],
|
|
488
|
+
"old_data": None, # Would need to track this
|
|
489
|
+
"new_data": pickle.dumps(row[1:]),
|
|
490
|
+
}
|
|
491
|
+
)
|
|
492
|
+
|
|
493
|
+
return changes
|
|
494
|
+
|
|
495
|
+
def _git_calculate_tree_hash(self, changes: List[Dict]) -> str:
|
|
496
|
+
"""Calculate hash of current tree state."""
|
|
497
|
+
tree_data = json.dumps(changes, sort_keys=True, default=str)
|
|
498
|
+
return hashlib.sha256(tree_data.encode()).hexdigest()[:8]
|
|
499
|
+
|
|
500
|
+
def _git_find_path(
|
|
501
|
+
self, from_hash: Optional[str], to_hash: str
|
|
502
|
+
) -> List[str]:
|
|
503
|
+
"""Find path between two commits."""
|
|
504
|
+
if not from_hash:
|
|
505
|
+
return [to_hash]
|
|
506
|
+
|
|
507
|
+
# Build commit graph
|
|
508
|
+
commits = {}
|
|
509
|
+
for hash, parent in self.execute(
|
|
510
|
+
"SELECT hash, parent_hash FROM _git_commits"
|
|
511
|
+
):
|
|
512
|
+
commits[hash] = parent
|
|
513
|
+
|
|
514
|
+
# Find common ancestor and build path
|
|
515
|
+
# Simplified - just return direct path
|
|
516
|
+
return [from_hash, to_hash]
|
|
517
|
+
|
|
518
|
+
def _git_is_ancestor(self, commit1: str, commit2: str) -> bool:
|
|
519
|
+
"""Check if commit1 is an ancestor of commit2."""
|
|
520
|
+
current = commit2
|
|
521
|
+
while current:
|
|
522
|
+
if current == commit1:
|
|
523
|
+
return True
|
|
524
|
+
result = self.execute(
|
|
525
|
+
"SELECT parent_hash FROM _git_commits WHERE hash = ?",
|
|
526
|
+
(current,),
|
|
527
|
+
).fetchone()
|
|
528
|
+
current = result[0] if result else None
|
|
529
|
+
return False
|
|
530
|
+
|
|
531
|
+
def _git_apply_changes(
|
|
532
|
+
self, commit_hash: str, reverse: bool = False
|
|
533
|
+
) -> None:
|
|
534
|
+
"""Apply or reverse changes from a commit."""
|
|
535
|
+
changes = self.execute(
|
|
536
|
+
"""
|
|
537
|
+
SELECT table_name, operation, row_id, old_data, new_data
|
|
538
|
+
FROM _git_changes
|
|
539
|
+
WHERE commit_hash = ?
|
|
540
|
+
""",
|
|
541
|
+
(commit_hash,),
|
|
542
|
+
).fetchall()
|
|
543
|
+
|
|
544
|
+
for table, op, row_id, old_data, new_data in changes:
|
|
545
|
+
if reverse:
|
|
546
|
+
# Reverse the operation
|
|
547
|
+
if op == "INSERT":
|
|
548
|
+
self.execute(
|
|
549
|
+
f"DELETE FROM {table} WHERE rowid = ?", (row_id,)
|
|
550
|
+
)
|
|
551
|
+
elif op == "DELETE" and old_data:
|
|
552
|
+
# Re-insert deleted data
|
|
553
|
+
data = pickle.loads(old_data)
|
|
554
|
+
placeholders = ",".join(["?" for _ in data])
|
|
555
|
+
self.execute(
|
|
556
|
+
f"INSERT INTO {table} VALUES ({placeholders})", data
|
|
557
|
+
)
|
|
558
|
+
elif op == "UPDATE" and old_data:
|
|
559
|
+
# Restore old data
|
|
560
|
+
data = pickle.loads(old_data)
|
|
561
|
+
# Simplified - would need proper column mapping
|
|
562
|
+
else:
|
|
563
|
+
# Apply forward changes
|
|
564
|
+
if op == "INSERT" and new_data:
|
|
565
|
+
data = pickle.loads(new_data)
|
|
566
|
+
placeholders = ",".join(["?" for _ in data])
|
|
567
|
+
self.execute(
|
|
568
|
+
f"INSERT INTO {table} VALUES ({placeholders})", data
|
|
569
|
+
)
|
|
570
|
+
elif op == "DELETE":
|
|
571
|
+
self.execute(
|
|
572
|
+
f"DELETE FROM {table} WHERE rowid = ?", (row_id,)
|
|
573
|
+
)
|
|
574
|
+
# UPDATE handling would go here
|
|
575
|
+
|
|
576
|
+
def _summarize_changes(self, changes: List[Dict]) -> Dict[str, int]:
|
|
577
|
+
"""Summarize changes by operation type."""
|
|
578
|
+
summary = {"INSERT": 0, "UPDATE": 0, "DELETE": 0}
|
|
579
|
+
for change in changes:
|
|
580
|
+
summary[change["operation"]] += 1
|
|
581
|
+
return summary
|
|
582
|
+
|
|
583
|
+
# EOF
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
THIS_FILE = "/home/ywatanabe/proj/scitex_repo/src/scitex/db/_SQLite3Mixins/_IndexMixin.py"
|
|
7
7
|
|
|
8
8
|
from typing import List
|
|
9
|
-
from
|
|
9
|
+
from ..._BaseMixins._BaseIndexMixin import _BaseIndexMixin
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class _IndexMixin:
|
|
@@ -8,12 +8,13 @@ THIS_FILE = (
|
|
|
8
8
|
)
|
|
9
9
|
|
|
10
10
|
import contextlib
|
|
11
|
+
import os
|
|
11
12
|
import sqlite3
|
|
12
13
|
from typing import Callable
|
|
13
14
|
from typing import ContextManager, Dict, List, Optional
|
|
14
15
|
import pandas as pd
|
|
15
16
|
|
|
16
|
-
from
|
|
17
|
+
from ..._BaseMixins._BaseMaintenanceMixin import _BaseMaintenanceMixin
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
class _MaintenanceMixin:
|