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.
Files changed (704) hide show
  1. scitex/__init__.py +53 -15
  2. scitex/__main__.py +72 -26
  3. scitex/__version__.py +1 -1
  4. scitex/_sh.py +145 -23
  5. scitex/ai/__init__.py +30 -16
  6. scitex/ai/_gen_ai/_Anthropic.py +5 -7
  7. scitex/ai/_gen_ai/_BaseGenAI.py +2 -2
  8. scitex/ai/_gen_ai/_DeepSeek.py +10 -2
  9. scitex/ai/_gen_ai/_Google.py +2 -2
  10. scitex/ai/_gen_ai/_Llama.py +2 -2
  11. scitex/ai/_gen_ai/_OpenAI.py +2 -2
  12. scitex/ai/_gen_ai/_PARAMS.py +51 -65
  13. scitex/ai/_gen_ai/_Perplexity.py +2 -2
  14. scitex/ai/_gen_ai/__init__.py +25 -14
  15. scitex/ai/_gen_ai/_format_output_func.py +4 -4
  16. scitex/ai/classification/{classifier_server.py → Classifier.py} +5 -5
  17. scitex/ai/classification/CrossValidationExperiment.py +374 -0
  18. scitex/ai/classification/__init__.py +43 -4
  19. scitex/ai/classification/reporters/_BaseClassificationReporter.py +281 -0
  20. scitex/ai/classification/reporters/_ClassificationReporter.py +773 -0
  21. scitex/ai/classification/reporters/_MultiClassificationReporter.py +406 -0
  22. scitex/ai/classification/reporters/_SingleClassificationReporter.py +1834 -0
  23. scitex/ai/classification/reporters/__init__.py +11 -0
  24. scitex/ai/classification/reporters/reporter_utils/_Plotter.py +1028 -0
  25. scitex/ai/classification/reporters/reporter_utils/__init__.py +80 -0
  26. scitex/ai/classification/reporters/reporter_utils/aggregation.py +457 -0
  27. scitex/ai/classification/reporters/reporter_utils/data_models.py +313 -0
  28. scitex/ai/classification/reporters/reporter_utils/reporting.py +1056 -0
  29. scitex/ai/classification/reporters/reporter_utils/storage.py +221 -0
  30. scitex/ai/classification/reporters/reporter_utils/validation.py +395 -0
  31. scitex/ai/classification/timeseries/_TimeSeriesBlockingSplit.py +568 -0
  32. scitex/ai/classification/timeseries/_TimeSeriesCalendarSplit.py +688 -0
  33. scitex/ai/classification/timeseries/_TimeSeriesMetadata.py +139 -0
  34. scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit.py +1716 -0
  35. scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit_v01-not-using-n_splits.py +1685 -0
  36. scitex/ai/classification/timeseries/_TimeSeriesStrategy.py +84 -0
  37. scitex/ai/classification/timeseries/_TimeSeriesStratifiedSplit.py +610 -0
  38. scitex/ai/classification/timeseries/__init__.py +39 -0
  39. scitex/ai/classification/timeseries/_normalize_timestamp.py +436 -0
  40. scitex/ai/clustering/_umap.py +2 -2
  41. scitex/ai/feature_extraction/vit.py +1 -0
  42. scitex/ai/feature_selection/__init__.py +30 -0
  43. scitex/ai/feature_selection/feature_selection.py +364 -0
  44. scitex/ai/loss/multi_task_loss.py +1 -1
  45. scitex/ai/metrics/__init__.py +51 -4
  46. scitex/ai/metrics/_calc_bacc.py +61 -0
  47. scitex/ai/metrics/_calc_bacc_from_conf_mat.py +38 -0
  48. scitex/ai/metrics/_calc_clf_report.py +78 -0
  49. scitex/ai/metrics/_calc_conf_mat.py +93 -0
  50. scitex/ai/metrics/_calc_feature_importance.py +183 -0
  51. scitex/ai/metrics/_calc_mcc.py +61 -0
  52. scitex/ai/metrics/_calc_pre_rec_auc.py +116 -0
  53. scitex/ai/metrics/_calc_roc_auc.py +110 -0
  54. scitex/ai/metrics/_calc_seizure_prediction_metrics.py +490 -0
  55. scitex/ai/metrics/{silhoute_score_block.py → _calc_silhouette_score.py} +15 -8
  56. scitex/ai/metrics/_normalize_labels.py +83 -0
  57. scitex/ai/plt/__init__.py +47 -8
  58. scitex/ai/plt/{_conf_mat.py → _plot_conf_mat.py} +158 -87
  59. scitex/ai/plt/_plot_feature_importance.py +323 -0
  60. scitex/ai/plt/_plot_learning_curve.py +345 -0
  61. scitex/ai/plt/_plot_optuna_study.py +225 -0
  62. scitex/ai/plt/_plot_pre_rec_curve.py +290 -0
  63. scitex/ai/plt/_plot_roc_curve.py +255 -0
  64. scitex/ai/training/{learning_curve_logger.py → _LearningCurveLogger.py} +197 -213
  65. scitex/ai/training/__init__.py +2 -2
  66. scitex/ai/utils/grid_search.py +3 -3
  67. scitex/benchmark/__init__.py +52 -0
  68. scitex/benchmark/benchmark.py +400 -0
  69. scitex/benchmark/monitor.py +370 -0
  70. scitex/benchmark/profiler.py +297 -0
  71. scitex/browser/__init__.py +48 -0
  72. scitex/browser/automation/CookieHandler.py +216 -0
  73. scitex/browser/automation/__init__.py +7 -0
  74. scitex/browser/collaboration/__init__.py +55 -0
  75. scitex/browser/collaboration/auth_helpers.py +94 -0
  76. scitex/browser/collaboration/collaborative_agent.py +136 -0
  77. scitex/browser/collaboration/credential_manager.py +188 -0
  78. scitex/browser/collaboration/interactive_panel.py +400 -0
  79. scitex/browser/collaboration/persistent_browser.py +170 -0
  80. scitex/browser/collaboration/shared_session.py +383 -0
  81. scitex/browser/collaboration/standard_interactions.py +246 -0
  82. scitex/browser/collaboration/visual_feedback.py +181 -0
  83. scitex/browser/core/BrowserMixin.py +326 -0
  84. scitex/browser/core/ChromeProfileManager.py +446 -0
  85. scitex/browser/core/__init__.py +9 -0
  86. scitex/browser/debugging/__init__.py +18 -0
  87. scitex/browser/debugging/_browser_logger.py +657 -0
  88. scitex/browser/debugging/_highlight_element.py +143 -0
  89. scitex/browser/debugging/_show_grid.py +154 -0
  90. scitex/browser/interaction/__init__.py +24 -0
  91. scitex/browser/interaction/click_center.py +149 -0
  92. scitex/browser/interaction/click_with_fallbacks.py +206 -0
  93. scitex/browser/interaction/close_popups.py +498 -0
  94. scitex/browser/interaction/fill_with_fallbacks.py +209 -0
  95. scitex/browser/pdf/__init__.py +14 -0
  96. scitex/browser/pdf/click_download_for_chrome_pdf_viewer.py +200 -0
  97. scitex/browser/pdf/detect_chrome_pdf_viewer.py +198 -0
  98. scitex/browser/remote/CaptchaHandler.py +434 -0
  99. scitex/browser/remote/ZenRowsAPIClient.py +347 -0
  100. scitex/browser/remote/ZenRowsBrowserManager.py +570 -0
  101. scitex/browser/remote/__init__.py +11 -0
  102. scitex/browser/stealth/HumanBehavior.py +344 -0
  103. scitex/browser/stealth/StealthManager.py +1008 -0
  104. scitex/browser/stealth/__init__.py +9 -0
  105. scitex/browser/template.py +122 -0
  106. scitex/capture/__init__.py +110 -0
  107. scitex/capture/__main__.py +25 -0
  108. scitex/capture/capture.py +848 -0
  109. scitex/capture/cli.py +233 -0
  110. scitex/capture/gif.py +344 -0
  111. scitex/capture/mcp_server.py +961 -0
  112. scitex/capture/session.py +70 -0
  113. scitex/capture/utils.py +705 -0
  114. scitex/cli/__init__.py +17 -0
  115. scitex/cli/cloud.py +447 -0
  116. scitex/cli/main.py +42 -0
  117. scitex/cli/scholar.py +280 -0
  118. scitex/context/_suppress_output.py +5 -3
  119. scitex/db/__init__.py +30 -3
  120. scitex/db/__main__.py +75 -0
  121. scitex/db/_check_health.py +381 -0
  122. scitex/db/_delete_duplicates.py +25 -386
  123. scitex/db/_inspect.py +335 -114
  124. scitex/db/_inspect_optimized.py +301 -0
  125. scitex/db/{_PostgreSQL.py → _postgresql/_PostgreSQL.py} +3 -3
  126. scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_BackupMixin.py +1 -1
  127. scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_BatchMixin.py +1 -1
  128. scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_BlobMixin.py +1 -1
  129. scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_ConnectionMixin.py +1 -1
  130. scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_MaintenanceMixin.py +1 -1
  131. scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_QueryMixin.py +1 -1
  132. scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_SchemaMixin.py +1 -1
  133. scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_TransactionMixin.py +1 -1
  134. scitex/db/_postgresql/__init__.py +6 -0
  135. scitex/db/_sqlite3/_SQLite3.py +210 -0
  136. scitex/db/_sqlite3/_SQLite3Mixins/_ArrayMixin.py +581 -0
  137. scitex/db/_sqlite3/_SQLite3Mixins/_ArrayMixin_v01-need-_hash-col.py +517 -0
  138. scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/_BatchMixin.py +1 -1
  139. scitex/db/_sqlite3/_SQLite3Mixins/_BlobMixin.py +281 -0
  140. scitex/db/_sqlite3/_SQLite3Mixins/_ColumnMixin.py +548 -0
  141. scitex/db/_sqlite3/_SQLite3Mixins/_ColumnMixin_v01-indentation-issues.py +583 -0
  142. scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/_ConnectionMixin.py +29 -13
  143. scitex/db/_sqlite3/_SQLite3Mixins/_GitMixin.py +583 -0
  144. scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/_ImportExportMixin.py +1 -1
  145. scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/_IndexMixin.py +1 -1
  146. scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/_MaintenanceMixin.py +2 -1
  147. scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/_QueryMixin.py +37 -10
  148. scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/_RowMixin.py +46 -6
  149. scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/_TableMixin.py +56 -10
  150. scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/_TransactionMixin.py +1 -1
  151. scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/__init__.py +14 -2
  152. scitex/db/_sqlite3/__init__.py +7 -0
  153. scitex/db/_sqlite3/_delete_duplicates.py +274 -0
  154. scitex/decorators/__init__.py +2 -0
  155. scitex/decorators/_cache_disk.py +13 -5
  156. scitex/decorators/_cache_disk_async.py +49 -0
  157. scitex/decorators/_deprecated.py +175 -10
  158. scitex/decorators/_timeout.py +1 -1
  159. scitex/dev/_analyze_code_flow.py +2 -2
  160. scitex/dict/_DotDict.py +73 -15
  161. scitex/dict/_DotDict_v01-not-handling-recursive-instantiations.py +442 -0
  162. scitex/dict/_DotDict_v02-not-serializing-Path-object.py +446 -0
  163. scitex/dict/__init__.py +2 -0
  164. scitex/dict/_flatten.py +27 -0
  165. scitex/dsp/_crop.py +2 -2
  166. scitex/dsp/_demo_sig.py +2 -2
  167. scitex/dsp/_detect_ripples.py +2 -2
  168. scitex/dsp/_hilbert.py +2 -2
  169. scitex/dsp/_listen.py +6 -6
  170. scitex/dsp/_modulation_index.py +2 -2
  171. scitex/dsp/_pac.py +1 -1
  172. scitex/dsp/_psd.py +2 -2
  173. scitex/dsp/_resample.py +2 -1
  174. scitex/dsp/_time.py +3 -2
  175. scitex/dsp/_wavelet.py +3 -2
  176. scitex/dsp/add_noise.py +2 -2
  177. scitex/dsp/example.py +1 -0
  178. scitex/dsp/filt.py +10 -9
  179. scitex/dsp/template.py +3 -2
  180. scitex/dsp/utils/_differential_bandpass_filters.py +1 -1
  181. scitex/dsp/utils/pac.py +2 -2
  182. scitex/dt/_normalize_timestamp.py +432 -0
  183. scitex/errors.py +572 -0
  184. scitex/gen/_DimHandler.py +2 -2
  185. scitex/gen/__init__.py +37 -7
  186. scitex/gen/_deprecated_close.py +80 -0
  187. scitex/gen/_deprecated_start.py +26 -0
  188. scitex/gen/_detect_environment.py +152 -0
  189. scitex/gen/_detect_notebook_path.py +169 -0
  190. scitex/gen/_embed.py +6 -2
  191. scitex/gen/_get_notebook_path.py +257 -0
  192. scitex/gen/_less.py +1 -1
  193. scitex/gen/_list_packages.py +2 -2
  194. scitex/gen/_norm.py +44 -9
  195. scitex/gen/_norm_cache.py +269 -0
  196. scitex/gen/_src.py +3 -5
  197. scitex/gen/_title_case.py +3 -3
  198. scitex/io/__init__.py +28 -6
  199. scitex/io/_glob.py +13 -7
  200. scitex/io/_load.py +108 -21
  201. scitex/io/_load_cache.py +303 -0
  202. scitex/io/_load_configs.py +40 -15
  203. scitex/io/{_H5Explorer.py → _load_modules/_H5Explorer.py} +80 -17
  204. scitex/io/_load_modules/_ZarrExplorer.py +114 -0
  205. scitex/io/_load_modules/_bibtex.py +207 -0
  206. scitex/io/_load_modules/_hdf5.py +53 -178
  207. scitex/io/_load_modules/_json.py +5 -3
  208. scitex/io/_load_modules/_pdf.py +871 -16
  209. scitex/io/_load_modules/_sqlite3.py +15 -0
  210. scitex/io/_load_modules/_txt.py +41 -12
  211. scitex/io/_load_modules/_yaml.py +4 -3
  212. scitex/io/_load_modules/_zarr.py +126 -0
  213. scitex/io/_save.py +429 -171
  214. scitex/io/_save_modules/__init__.py +6 -0
  215. scitex/io/_save_modules/_bibtex.py +194 -0
  216. scitex/io/_save_modules/_csv.py +8 -4
  217. scitex/io/_save_modules/_excel.py +174 -15
  218. scitex/io/_save_modules/_hdf5.py +251 -226
  219. scitex/io/_save_modules/_image.py +1 -3
  220. scitex/io/_save_modules/_json.py +49 -4
  221. scitex/io/_save_modules/_listed_dfs_as_csv.py +1 -3
  222. scitex/io/_save_modules/_listed_scalars_as_csv.py +1 -3
  223. scitex/io/_save_modules/_tex.py +277 -0
  224. scitex/io/_save_modules/_yaml.py +42 -3
  225. scitex/io/_save_modules/_zarr.py +160 -0
  226. scitex/io/utils/__init__.py +20 -0
  227. scitex/io/utils/h5_to_zarr.py +616 -0
  228. scitex/linalg/_geometric_median.py +6 -2
  229. scitex/{gen/_tee.py → logging/_Tee.py} +43 -84
  230. scitex/logging/__init__.py +122 -0
  231. scitex/logging/_config.py +158 -0
  232. scitex/logging/_context.py +103 -0
  233. scitex/logging/_formatters.py +128 -0
  234. scitex/logging/_handlers.py +64 -0
  235. scitex/logging/_levels.py +35 -0
  236. scitex/logging/_logger.py +163 -0
  237. scitex/logging/_print_capture.py +95 -0
  238. scitex/ml/__init__.py +69 -0
  239. scitex/{ai/genai/anthropic.py → ml/_gen_ai/_Anthropic.py} +13 -19
  240. scitex/{ai/genai/base_genai.py → ml/_gen_ai/_BaseGenAI.py} +5 -5
  241. scitex/{ai/genai/deepseek.py → ml/_gen_ai/_DeepSeek.py} +11 -16
  242. scitex/{ai/genai/google.py → ml/_gen_ai/_Google.py} +7 -15
  243. scitex/{ai/genai/groq.py → ml/_gen_ai/_Groq.py} +1 -8
  244. scitex/{ai/genai/llama.py → ml/_gen_ai/_Llama.py} +3 -16
  245. scitex/{ai/genai/openai.py → ml/_gen_ai/_OpenAI.py} +3 -3
  246. scitex/{ai/genai/params.py → ml/_gen_ai/_PARAMS.py} +51 -65
  247. scitex/{ai/genai/perplexity.py → ml/_gen_ai/_Perplexity.py} +3 -14
  248. scitex/ml/_gen_ai/__init__.py +43 -0
  249. scitex/{ai/genai/calc_cost.py → ml/_gen_ai/_calc_cost.py} +1 -1
  250. scitex/{ai/genai/format_output_func.py → ml/_gen_ai/_format_output_func.py} +4 -4
  251. scitex/{ai/genai/genai_factory.py → ml/_gen_ai/_genai_factory.py} +8 -8
  252. scitex/ml/activation/__init__.py +8 -0
  253. scitex/ml/activation/_define.py +11 -0
  254. scitex/{ai/classifier_server.py → ml/classification/Classifier.py} +5 -5
  255. scitex/ml/classification/CrossValidationExperiment.py +374 -0
  256. scitex/ml/classification/__init__.py +46 -0
  257. scitex/ml/classification/reporters/_BaseClassificationReporter.py +281 -0
  258. scitex/ml/classification/reporters/_ClassificationReporter.py +773 -0
  259. scitex/ml/classification/reporters/_MultiClassificationReporter.py +406 -0
  260. scitex/ml/classification/reporters/_SingleClassificationReporter.py +1834 -0
  261. scitex/ml/classification/reporters/__init__.py +11 -0
  262. scitex/ml/classification/reporters/reporter_utils/_Plotter.py +1028 -0
  263. scitex/ml/classification/reporters/reporter_utils/__init__.py +80 -0
  264. scitex/ml/classification/reporters/reporter_utils/aggregation.py +457 -0
  265. scitex/ml/classification/reporters/reporter_utils/data_models.py +313 -0
  266. scitex/ml/classification/reporters/reporter_utils/reporting.py +1056 -0
  267. scitex/ml/classification/reporters/reporter_utils/storage.py +221 -0
  268. scitex/ml/classification/reporters/reporter_utils/validation.py +395 -0
  269. scitex/ml/classification/timeseries/_TimeSeriesBlockingSplit.py +568 -0
  270. scitex/ml/classification/timeseries/_TimeSeriesCalendarSplit.py +688 -0
  271. scitex/ml/classification/timeseries/_TimeSeriesMetadata.py +139 -0
  272. scitex/ml/classification/timeseries/_TimeSeriesSlidingWindowSplit.py +1716 -0
  273. scitex/ml/classification/timeseries/_TimeSeriesSlidingWindowSplit_v01-not-using-n_splits.py +1685 -0
  274. scitex/ml/classification/timeseries/_TimeSeriesStrategy.py +84 -0
  275. scitex/ml/classification/timeseries/_TimeSeriesStratifiedSplit.py +610 -0
  276. scitex/ml/classification/timeseries/__init__.py +39 -0
  277. scitex/ml/classification/timeseries/_normalize_timestamp.py +436 -0
  278. scitex/ml/clustering/__init__.py +11 -0
  279. scitex/ml/clustering/_pca.py +115 -0
  280. scitex/ml/clustering/_umap.py +376 -0
  281. scitex/ml/feature_extraction/__init__.py +56 -0
  282. scitex/ml/feature_extraction/vit.py +149 -0
  283. scitex/ml/feature_selection/__init__.py +30 -0
  284. scitex/ml/feature_selection/feature_selection.py +364 -0
  285. scitex/ml/loss/_L1L2Losses.py +34 -0
  286. scitex/ml/loss/__init__.py +12 -0
  287. scitex/ml/loss/multi_task_loss.py +47 -0
  288. scitex/ml/metrics/__init__.py +56 -0
  289. scitex/ml/metrics/_calc_bacc.py +61 -0
  290. scitex/ml/metrics/_calc_bacc_from_conf_mat.py +38 -0
  291. scitex/ml/metrics/_calc_clf_report.py +78 -0
  292. scitex/ml/metrics/_calc_conf_mat.py +93 -0
  293. scitex/ml/metrics/_calc_feature_importance.py +183 -0
  294. scitex/ml/metrics/_calc_mcc.py +61 -0
  295. scitex/ml/metrics/_calc_pre_rec_auc.py +116 -0
  296. scitex/ml/metrics/_calc_roc_auc.py +110 -0
  297. scitex/ml/metrics/_calc_seizure_prediction_metrics.py +490 -0
  298. scitex/ml/metrics/_calc_silhouette_score.py +503 -0
  299. scitex/ml/metrics/_normalize_labels.py +83 -0
  300. scitex/ml/optim/Ranger_Deep_Learning_Optimizer/__init__.py +0 -0
  301. scitex/ml/optim/Ranger_Deep_Learning_Optimizer/ranger/__init__.py +3 -0
  302. scitex/ml/optim/Ranger_Deep_Learning_Optimizer/ranger/ranger.py +207 -0
  303. scitex/ml/optim/Ranger_Deep_Learning_Optimizer/ranger/ranger2020.py +238 -0
  304. scitex/ml/optim/Ranger_Deep_Learning_Optimizer/ranger/ranger913A.py +215 -0
  305. scitex/ml/optim/Ranger_Deep_Learning_Optimizer/ranger/rangerqh.py +184 -0
  306. scitex/ml/optim/Ranger_Deep_Learning_Optimizer/setup.py +24 -0
  307. scitex/ml/optim/__init__.py +13 -0
  308. scitex/ml/optim/_get_set.py +31 -0
  309. scitex/ml/optim/_optimizers.py +71 -0
  310. scitex/ml/plt/__init__.py +60 -0
  311. scitex/ml/plt/_plot_conf_mat.py +663 -0
  312. scitex/ml/plt/_plot_feature_importance.py +323 -0
  313. scitex/ml/plt/_plot_learning_curve.py +345 -0
  314. scitex/ml/plt/_plot_optuna_study.py +225 -0
  315. scitex/ml/plt/_plot_pre_rec_curve.py +290 -0
  316. scitex/ml/plt/_plot_roc_curve.py +255 -0
  317. scitex/ml/sk/__init__.py +11 -0
  318. scitex/ml/sk/_clf.py +58 -0
  319. scitex/ml/sk/_to_sktime.py +100 -0
  320. scitex/ml/sklearn/__init__.py +26 -0
  321. scitex/ml/sklearn/clf.py +58 -0
  322. scitex/ml/sklearn/to_sktime.py +100 -0
  323. scitex/{ai/training/early_stopping.py → ml/training/_EarlyStopping.py} +1 -2
  324. scitex/{ai → ml/training}/_LearningCurveLogger.py +198 -242
  325. scitex/ml/training/__init__.py +7 -0
  326. scitex/ml/utils/__init__.py +22 -0
  327. scitex/ml/utils/_check_params.py +50 -0
  328. scitex/ml/utils/_default_dataset.py +46 -0
  329. scitex/ml/utils/_format_samples_for_sktime.py +26 -0
  330. scitex/ml/utils/_label_encoder.py +134 -0
  331. scitex/ml/utils/_merge_labels.py +22 -0
  332. scitex/ml/utils/_sliding_window_data_augmentation.py +11 -0
  333. scitex/ml/utils/_under_sample.py +51 -0
  334. scitex/ml/utils/_verify_n_gpus.py +16 -0
  335. scitex/ml/utils/grid_search.py +148 -0
  336. scitex/nn/_BNet.py +15 -9
  337. scitex/nn/_Filters.py +2 -2
  338. scitex/nn/_ModulationIndex.py +2 -2
  339. scitex/nn/_PAC.py +1 -1
  340. scitex/nn/_Spectrogram.py +12 -3
  341. scitex/nn/__init__.py +9 -10
  342. scitex/path/__init__.py +18 -0
  343. scitex/path/_clean.py +4 -0
  344. scitex/path/_find.py +9 -4
  345. scitex/path/_symlink.py +348 -0
  346. scitex/path/_version.py +4 -3
  347. scitex/pd/__init__.py +2 -0
  348. scitex/pd/_get_unique.py +99 -0
  349. scitex/plt/__init__.py +114 -5
  350. scitex/plt/_subplots/_AxesWrapper.py +1 -3
  351. scitex/plt/_subplots/_AxisWrapper.py +7 -3
  352. scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin.py +47 -13
  353. scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin.py +160 -2
  354. scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin.py +26 -4
  355. scitex/plt/_subplots/_AxisWrapperMixins/_UnitAwareMixin.py +322 -0
  356. scitex/plt/_subplots/_AxisWrapperMixins/__init__.py +1 -0
  357. scitex/plt/_subplots/_FigWrapper.py +62 -6
  358. scitex/plt/_subplots/_export_as_csv.py +43 -27
  359. scitex/plt/_subplots/_export_as_csv_formatters/__init__.py +5 -4
  360. scitex/plt/_subplots/_export_as_csv_formatters/_format_annotate.py +81 -0
  361. scitex/plt/_subplots/_export_as_csv_formatters/_format_bar.py +1 -3
  362. scitex/plt/_subplots/_export_as_csv_formatters/_format_barh.py +20 -5
  363. scitex/plt/_subplots/_export_as_csv_formatters/_format_boxplot.py +1 -3
  364. scitex/plt/_subplots/_export_as_csv_formatters/_format_contour.py +1 -3
  365. scitex/plt/_subplots/_export_as_csv_formatters/_format_errorbar.py +35 -18
  366. scitex/plt/_subplots/_export_as_csv_formatters/_format_eventplot.py +1 -3
  367. scitex/plt/_subplots/_export_as_csv_formatters/_format_fill.py +1 -3
  368. scitex/plt/_subplots/_export_as_csv_formatters/_format_fill_between.py +1 -3
  369. scitex/plt/_subplots/_export_as_csv_formatters/_format_hist.py +1 -3
  370. scitex/plt/_subplots/_export_as_csv_formatters/_format_imshow.py +1 -3
  371. scitex/plt/_subplots/_export_as_csv_formatters/_format_imshow2d.py +1 -3
  372. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot.py +15 -3
  373. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_box.py +1 -3
  374. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_conf_mat.py +1 -3
  375. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_ecdf.py +1 -3
  376. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_fillv.py +1 -3
  377. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_heatmap.py +1 -3
  378. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_image.py +1 -3
  379. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_joyplot.py +1 -3
  380. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_kde.py +1 -3
  381. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_line.py +1 -3
  382. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_mean_ci.py +1 -3
  383. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_mean_std.py +1 -3
  384. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_median_iqr.py +1 -3
  385. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_raster.py +1 -3
  386. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_rectangle.py +1 -3
  387. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_scatter.py +35 -0
  388. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_scatter_hist.py +1 -3
  389. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_shaded_line.py +1 -3
  390. scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_violin.py +1 -3
  391. scitex/plt/_subplots/_export_as_csv_formatters/_format_scatter.py +6 -4
  392. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_barplot.py +1 -3
  393. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_boxplot.py +1 -3
  394. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_heatmap.py +1 -3
  395. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_histplot.py +1 -3
  396. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_jointplot.py +1 -3
  397. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_kdeplot.py +1 -3
  398. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_lineplot.py +1 -3
  399. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_pairplot.py +1 -3
  400. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_scatterplot.py +1 -3
  401. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_stripplot.py +1 -3
  402. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_swarmplot.py +1 -3
  403. scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_violinplot.py +1 -3
  404. scitex/plt/_subplots/_export_as_csv_formatters/_format_text.py +60 -0
  405. scitex/plt/_subplots/_export_as_csv_formatters/_format_violin.py +1 -3
  406. scitex/plt/_subplots/_export_as_csv_formatters/_format_violinplot.py +1 -3
  407. scitex/plt/_subplots/_export_as_csv_formatters/test_formatters.py +1 -3
  408. scitex/plt/_subplots/_export_as_csv_formatters.py +56 -59
  409. scitex/plt/ax/_style/_hide_spines.py +1 -3
  410. scitex/plt/ax/_style/_rotate_labels.py +180 -76
  411. scitex/plt/ax/_style/_rotate_labels_v01.py +248 -0
  412. scitex/plt/ax/_style/_set_meta.py +11 -4
  413. scitex/plt/ax/_style/_set_supxyt.py +3 -3
  414. scitex/plt/ax/_style/_set_xyt.py +3 -3
  415. scitex/plt/ax/_style/_share_axes.py +2 -2
  416. scitex/plt/color/__init__.py +4 -4
  417. scitex/plt/color/{_get_colors_from_cmap.py → _get_colors_from_conf_matap.py} +7 -7
  418. scitex/plt/utils/_configure_mpl.py +99 -86
  419. scitex/plt/utils/_histogram_utils.py +1 -3
  420. scitex/plt/utils/_is_valid_axis.py +1 -3
  421. scitex/plt/utils/_scitex_config.py +1 -0
  422. scitex/repro/__init__.py +75 -0
  423. scitex/{reproduce → repro}/_gen_ID.py +1 -1
  424. scitex/{reproduce → repro}/_gen_timestamp.py +1 -1
  425. scitex/repro_rng/_RandomStateManager.py +590 -0
  426. scitex/repro_rng/_RandomStateManager_v01-no-verbose-options.py +414 -0
  427. scitex/repro_rng/__init__.py +39 -0
  428. scitex/reproduce/__init__.py +25 -13
  429. scitex/reproduce/_hash_array.py +22 -0
  430. scitex/resource/_get_processor_usages.py +4 -4
  431. scitex/resource/_get_specs.py +2 -2
  432. scitex/resource/_log_processor_usages.py +2 -2
  433. scitex/rng/_RandomStateManager.py +590 -0
  434. scitex/rng/_RandomStateManager_v01-no-verbose-options.py +414 -0
  435. scitex/rng/__init__.py +39 -0
  436. scitex/scholar/__init__.py +309 -19
  437. scitex/scholar/__main__.py +319 -0
  438. scitex/scholar/auth/ScholarAuthManager.py +308 -0
  439. scitex/scholar/auth/__init__.py +12 -0
  440. scitex/scholar/auth/core/AuthenticationGateway.py +473 -0
  441. scitex/scholar/auth/core/BrowserAuthenticator.py +386 -0
  442. scitex/scholar/auth/core/StrategyResolver.py +309 -0
  443. scitex/scholar/auth/core/__init__.py +16 -0
  444. scitex/scholar/auth/gateway/_OpenURLLinkFinder.py +120 -0
  445. scitex/scholar/auth/gateway/_OpenURLResolver.py +209 -0
  446. scitex/scholar/auth/gateway/__init__.py +38 -0
  447. scitex/scholar/auth/gateway/_resolve_functions.py +101 -0
  448. scitex/scholar/auth/providers/BaseAuthenticator.py +166 -0
  449. scitex/scholar/auth/providers/EZProxyAuthenticator.py +484 -0
  450. scitex/scholar/auth/providers/OpenAthensAuthenticator.py +619 -0
  451. scitex/scholar/auth/providers/ShibbolethAuthenticator.py +686 -0
  452. scitex/scholar/auth/providers/__init__.py +18 -0
  453. scitex/scholar/auth/session/AuthCacheManager.py +189 -0
  454. scitex/scholar/auth/session/SessionManager.py +159 -0
  455. scitex/scholar/auth/session/__init__.py +11 -0
  456. scitex/scholar/auth/sso/BaseSSOAutomator.py +373 -0
  457. scitex/scholar/auth/sso/OpenAthensSSOAutomator.py +378 -0
  458. scitex/scholar/auth/sso/SSOAutomator.py +180 -0
  459. scitex/scholar/auth/sso/UniversityOfMelbourneSSOAutomator.py +380 -0
  460. scitex/scholar/auth/sso/__init__.py +15 -0
  461. scitex/scholar/browser/ScholarBrowserManager.py +705 -0
  462. scitex/scholar/browser/__init__.py +38 -0
  463. scitex/scholar/browser/utils/__init__.py +13 -0
  464. scitex/scholar/browser/utils/click_and_wait.py +205 -0
  465. scitex/scholar/browser/utils/close_unwanted_pages.py +140 -0
  466. scitex/scholar/browser/utils/wait_redirects.py +732 -0
  467. scitex/scholar/config/PublisherRules.py +132 -0
  468. scitex/scholar/config/ScholarConfig.py +126 -0
  469. scitex/scholar/config/__init__.py +17 -0
  470. scitex/scholar/core/Paper.py +627 -0
  471. scitex/scholar/core/Papers.py +722 -0
  472. scitex/scholar/core/Scholar.py +1975 -0
  473. scitex/scholar/core/__init__.py +9 -0
  474. scitex/scholar/impact_factor/ImpactFactorEngine.py +204 -0
  475. scitex/scholar/impact_factor/__init__.py +20 -0
  476. scitex/scholar/impact_factor/estimation/ImpactFactorEstimationEngine.py +0 -0
  477. scitex/scholar/impact_factor/estimation/__init__.py +40 -0
  478. scitex/scholar/impact_factor/estimation/build_database.py +0 -0
  479. scitex/scholar/impact_factor/estimation/core/__init__.py +28 -0
  480. scitex/scholar/impact_factor/estimation/core/cache_manager.py +523 -0
  481. scitex/scholar/impact_factor/estimation/core/calculator.py +355 -0
  482. scitex/scholar/impact_factor/estimation/core/journal_matcher.py +428 -0
  483. scitex/scholar/integration/__init__.py +59 -0
  484. scitex/scholar/integration/base.py +502 -0
  485. scitex/scholar/integration/mendeley/__init__.py +22 -0
  486. scitex/scholar/integration/mendeley/exporter.py +166 -0
  487. scitex/scholar/integration/mendeley/importer.py +236 -0
  488. scitex/scholar/integration/mendeley/linker.py +79 -0
  489. scitex/scholar/integration/mendeley/mapper.py +212 -0
  490. scitex/scholar/integration/zotero/__init__.py +27 -0
  491. scitex/scholar/integration/zotero/__main__.py +264 -0
  492. scitex/scholar/integration/zotero/exporter.py +351 -0
  493. scitex/scholar/integration/zotero/importer.py +372 -0
  494. scitex/scholar/integration/zotero/linker.py +415 -0
  495. scitex/scholar/integration/zotero/mapper.py +286 -0
  496. scitex/scholar/metadata_engines/ScholarEngine.py +588 -0
  497. scitex/scholar/metadata_engines/__init__.py +21 -0
  498. scitex/scholar/metadata_engines/individual/ArXivEngine.py +397 -0
  499. scitex/scholar/metadata_engines/individual/CrossRefEngine.py +274 -0
  500. scitex/scholar/metadata_engines/individual/CrossRefLocalEngine.py +263 -0
  501. scitex/scholar/metadata_engines/individual/OpenAlexEngine.py +350 -0
  502. scitex/scholar/metadata_engines/individual/PubMedEngine.py +329 -0
  503. scitex/scholar/metadata_engines/individual/SemanticScholarEngine.py +438 -0
  504. scitex/scholar/metadata_engines/individual/URLDOIEngine.py +410 -0
  505. scitex/scholar/metadata_engines/individual/_BaseDOIEngine.py +487 -0
  506. scitex/scholar/metadata_engines/individual/__init__.py +7 -0
  507. scitex/scholar/metadata_engines/utils/_PubMedConverter.py +469 -0
  508. scitex/scholar/metadata_engines/utils/_URLDOIExtractor.py +283 -0
  509. scitex/scholar/metadata_engines/utils/__init__.py +30 -0
  510. scitex/scholar/metadata_engines/utils/_metadata2bibtex.py +103 -0
  511. scitex/scholar/metadata_engines/utils/_standardize_metadata.py +376 -0
  512. scitex/scholar/pdf_download/ScholarPDFDownloader.py +579 -0
  513. scitex/scholar/pdf_download/__init__.py +5 -0
  514. scitex/scholar/pdf_download/strategies/__init__.py +38 -0
  515. scitex/scholar/pdf_download/strategies/chrome_pdf_viewer.py +376 -0
  516. scitex/scholar/pdf_download/strategies/direct_download.py +131 -0
  517. scitex/scholar/pdf_download/strategies/manual_download_fallback.py +167 -0
  518. scitex/scholar/pdf_download/strategies/manual_download_utils.py +996 -0
  519. scitex/scholar/pdf_download/strategies/response_body.py +207 -0
  520. scitex/scholar/pipelines/ScholarPipelineBibTeX.py +364 -0
  521. scitex/scholar/pipelines/ScholarPipelineParallel.py +478 -0
  522. scitex/scholar/pipelines/ScholarPipelineSingle.py +767 -0
  523. scitex/scholar/pipelines/__init__.py +49 -0
  524. scitex/scholar/storage/BibTeXHandler.py +1018 -0
  525. scitex/scholar/storage/PaperIO.py +468 -0
  526. scitex/scholar/storage/ScholarLibrary.py +182 -0
  527. scitex/scholar/storage/_DeduplicationManager.py +548 -0
  528. scitex/scholar/storage/_LibraryCacheManager.py +724 -0
  529. scitex/scholar/storage/_LibraryManager.py +1835 -0
  530. scitex/scholar/storage/__init__.py +28 -0
  531. scitex/scholar/url_finder/ScholarURLFinder.py +379 -0
  532. scitex/scholar/url_finder/__init__.py +7 -0
  533. scitex/scholar/url_finder/strategies/__init__.py +33 -0
  534. scitex/scholar/url_finder/strategies/find_pdf_urls_by_direct_links.py +261 -0
  535. scitex/scholar/url_finder/strategies/find_pdf_urls_by_dropdown.py +67 -0
  536. scitex/scholar/url_finder/strategies/find_pdf_urls_by_href.py +204 -0
  537. scitex/scholar/url_finder/strategies/find_pdf_urls_by_navigation.py +256 -0
  538. scitex/scholar/url_finder/strategies/find_pdf_urls_by_publisher_patterns.py +165 -0
  539. scitex/scholar/url_finder/strategies/find_pdf_urls_by_zotero_translators.py +163 -0
  540. scitex/scholar/url_finder/strategies/find_supplementary_urls_by_href.py +70 -0
  541. scitex/scholar/utils/__init__.py +22 -0
  542. scitex/scholar/utils/bibtex/__init__.py +9 -0
  543. scitex/scholar/utils/bibtex/_parse_bibtex.py +71 -0
  544. scitex/scholar/utils/cleanup/__init__.py +8 -0
  545. scitex/scholar/utils/cleanup/_cleanup_scholar_processes.py +96 -0
  546. scitex/scholar/utils/cleanup/cleanup_old_extractions.py +117 -0
  547. scitex/scholar/utils/text/_TextNormalizer.py +407 -0
  548. scitex/scholar/utils/text/__init__.py +9 -0
  549. scitex/scholar/zotero/__init__.py +38 -0
  550. scitex/session/__init__.py +51 -0
  551. scitex/session/_lifecycle.py +736 -0
  552. scitex/session/_manager.py +102 -0
  553. scitex/session/template.py +122 -0
  554. scitex/stats/__init__.py +30 -26
  555. scitex/stats/correct/__init__.py +21 -0
  556. scitex/stats/correct/_correct_bonferroni.py +551 -0
  557. scitex/stats/correct/_correct_fdr.py +634 -0
  558. scitex/stats/correct/_correct_holm.py +548 -0
  559. scitex/stats/correct/_correct_sidak.py +499 -0
  560. scitex/stats/descriptive/__init__.py +85 -0
  561. scitex/stats/descriptive/_circular.py +540 -0
  562. scitex/stats/descriptive/_describe.py +219 -0
  563. scitex/stats/descriptive/_nan.py +518 -0
  564. scitex/stats/descriptive/_real.py +189 -0
  565. scitex/stats/effect_sizes/__init__.py +41 -0
  566. scitex/stats/effect_sizes/_cliffs_delta.py +325 -0
  567. scitex/stats/effect_sizes/_cohens_d.py +342 -0
  568. scitex/stats/effect_sizes/_epsilon_squared.py +315 -0
  569. scitex/stats/effect_sizes/_eta_squared.py +302 -0
  570. scitex/stats/effect_sizes/_prob_superiority.py +296 -0
  571. scitex/stats/posthoc/__init__.py +19 -0
  572. scitex/stats/posthoc/_dunnett.py +463 -0
  573. scitex/stats/posthoc/_games_howell.py +383 -0
  574. scitex/stats/posthoc/_tukey_hsd.py +367 -0
  575. scitex/stats/power/__init__.py +19 -0
  576. scitex/stats/power/_power.py +433 -0
  577. scitex/stats/template.py +119 -0
  578. scitex/stats/utils/__init__.py +62 -0
  579. scitex/stats/utils/_effect_size.py +985 -0
  580. scitex/stats/utils/_formatters.py +270 -0
  581. scitex/stats/utils/_normalizers.py +927 -0
  582. scitex/stats/utils/_power.py +433 -0
  583. scitex/stats_v01/_EffectSizeCalculator.py +488 -0
  584. scitex/stats_v01/_StatisticalValidator.py +411 -0
  585. scitex/stats_v01/__init__.py +60 -0
  586. scitex/stats_v01/_additional_tests.py +415 -0
  587. scitex/{stats → stats_v01}/_p2stars.py +19 -5
  588. scitex/stats_v01/_two_sample_tests.py +141 -0
  589. scitex/stats_v01/desc/__init__.py +83 -0
  590. scitex/stats_v01/desc/_circular.py +540 -0
  591. scitex/stats_v01/desc/_describe.py +219 -0
  592. scitex/stats_v01/desc/_nan.py +518 -0
  593. scitex/{stats/desc/_nan.py → stats_v01/desc/_nan_v01-20250920_145731.py} +23 -12
  594. scitex/stats_v01/desc/_real.py +189 -0
  595. scitex/stats_v01/tests/__corr_test_optimized.py +221 -0
  596. scitex/stats_v01/tests/_corr_test_optimized.py +179 -0
  597. scitex/str/__init__.py +1 -3
  598. scitex/str/_clean_path.py +6 -2
  599. scitex/str/_latex_fallback.py +267 -160
  600. scitex/str/_parse.py +44 -36
  601. scitex/str/_printc.py +1 -3
  602. scitex/template/__init__.py +87 -0
  603. scitex/template/_create_project.py +267 -0
  604. scitex/template/create_pip_project.py +80 -0
  605. scitex/template/create_research.py +80 -0
  606. scitex/template/create_singularity.py +80 -0
  607. scitex/units.py +291 -0
  608. scitex/utils/_compress_hdf5.py +14 -3
  609. scitex/utils/_email.py +21 -2
  610. scitex/utils/_grid.py +6 -4
  611. scitex/utils/_notify.py +13 -10
  612. scitex/utils/_verify_scitex_format.py +589 -0
  613. scitex/utils/_verify_scitex_format_v01.py +370 -0
  614. scitex/utils/template.py +122 -0
  615. scitex/web/_search_pubmed.py +62 -16
  616. scitex-2.1.0.dist-info/LICENSE +21 -0
  617. scitex-2.1.0.dist-info/METADATA +677 -0
  618. scitex-2.1.0.dist-info/RECORD +919 -0
  619. {scitex-2.0.0.dist-info → scitex-2.1.0.dist-info}/WHEEL +1 -1
  620. scitex-2.1.0.dist-info/entry_points.txt +3 -0
  621. scitex/ai/__Classifiers.py +0 -101
  622. scitex/ai/classification/classification_reporter.py +0 -1137
  623. scitex/ai/classification/classifiers.py +0 -101
  624. scitex/ai/classification_reporter.py +0 -1161
  625. scitex/ai/genai/__init__.py +0 -277
  626. scitex/ai/genai/anthropic_provider.py +0 -320
  627. scitex/ai/genai/anthropic_refactored.py +0 -109
  628. scitex/ai/genai/auth_manager.py +0 -200
  629. scitex/ai/genai/base_provider.py +0 -291
  630. scitex/ai/genai/chat_history.py +0 -307
  631. scitex/ai/genai/cost_tracker.py +0 -276
  632. scitex/ai/genai/deepseek_provider.py +0 -251
  633. scitex/ai/genai/google_provider.py +0 -228
  634. scitex/ai/genai/groq_provider.py +0 -248
  635. scitex/ai/genai/image_processor.py +0 -250
  636. scitex/ai/genai/llama_provider.py +0 -214
  637. scitex/ai/genai/mock_provider.py +0 -127
  638. scitex/ai/genai/model_registry.py +0 -304
  639. scitex/ai/genai/openai_provider.py +0 -293
  640. scitex/ai/genai/perplexity_provider.py +0 -205
  641. scitex/ai/genai/provider_base.py +0 -302
  642. scitex/ai/genai/provider_factory.py +0 -370
  643. scitex/ai/genai/response_handler.py +0 -235
  644. scitex/ai/layer/_Pass.py +0 -21
  645. scitex/ai/layer/__init__.py +0 -10
  646. scitex/ai/layer/_switch.py +0 -8
  647. scitex/ai/metrics/_bACC.py +0 -51
  648. scitex/ai/plt/_learning_curve.py +0 -194
  649. scitex/ai/plt/_optuna_study.py +0 -111
  650. scitex/ai/plt/aucs/__init__.py +0 -2
  651. scitex/ai/plt/aucs/example.py +0 -60
  652. scitex/ai/plt/aucs/pre_rec_auc.py +0 -223
  653. scitex/ai/plt/aucs/roc_auc.py +0 -246
  654. scitex/ai/sampling/undersample.py +0 -29
  655. scitex/db/_SQLite3.py +0 -2136
  656. scitex/db/_SQLite3Mixins/_BlobMixin.py +0 -229
  657. scitex/gen/_close.py +0 -222
  658. scitex/gen/_start.py +0 -451
  659. scitex/general/__init__.py +0 -5
  660. scitex/io/_load_modules/_db.py +0 -24
  661. scitex/life/__init__.py +0 -10
  662. scitex/life/_monitor_rain.py +0 -49
  663. scitex/reproduce/_fix_seeds.py +0 -45
  664. scitex/res/__init__.py +0 -5
  665. scitex/scholar/_local_search.py +0 -454
  666. scitex/scholar/_paper.py +0 -244
  667. scitex/scholar/_pdf_downloader.py +0 -325
  668. scitex/scholar/_search.py +0 -393
  669. scitex/scholar/_vector_search.py +0 -370
  670. scitex/scholar/_web_sources.py +0 -457
  671. scitex/stats/desc/__init__.py +0 -40
  672. scitex-2.0.0.dist-info/METADATA +0 -307
  673. scitex-2.0.0.dist-info/RECORD +0 -572
  674. scitex-2.0.0.dist-info/licenses/LICENSE +0 -7
  675. /scitex/ai/{act → activation}/__init__.py +0 -0
  676. /scitex/ai/{act → activation}/_define.py +0 -0
  677. /scitex/ai/{early_stopping.py → training/_EarlyStopping.py} +0 -0
  678. /scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_ImportExportMixin.py +0 -0
  679. /scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_IndexMixin.py +0 -0
  680. /scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_RowMixin.py +0 -0
  681. /scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_TableMixin.py +0 -0
  682. /scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/__init__.py +0 -0
  683. /scitex/{stats → stats_v01}/_calc_partial_corr.py +0 -0
  684. /scitex/{stats → stats_v01}/_corr_test_multi.py +0 -0
  685. /scitex/{stats → stats_v01}/_corr_test_wrapper.py +0 -0
  686. /scitex/{stats → stats_v01}/_describe_wrapper.py +0 -0
  687. /scitex/{stats → stats_v01}/_multiple_corrections.py +0 -0
  688. /scitex/{stats → stats_v01}/_nan_stats.py +0 -0
  689. /scitex/{stats → stats_v01}/_p2stars_wrapper.py +0 -0
  690. /scitex/{stats → stats_v01}/_statistical_tests.py +0 -0
  691. /scitex/{stats/desc/_describe.py → stats_v01/desc/_describe_v01-20250920_145731.py} +0 -0
  692. /scitex/{stats/desc/_real.py → stats_v01/desc/_real_v01-20250920_145731.py} +0 -0
  693. /scitex/{stats → stats_v01}/multiple/__init__.py +0 -0
  694. /scitex/{stats → stats_v01}/multiple/_bonferroni_correction.py +0 -0
  695. /scitex/{stats → stats_v01}/multiple/_fdr_correction.py +0 -0
  696. /scitex/{stats → stats_v01}/multiple/_multicompair.py +0 -0
  697. /scitex/{stats → stats_v01}/tests/__corr_test.py +0 -0
  698. /scitex/{stats → stats_v01}/tests/__corr_test_multi.py +0 -0
  699. /scitex/{stats → stats_v01}/tests/__corr_test_single.py +0 -0
  700. /scitex/{stats → stats_v01}/tests/__init__.py +0 -0
  701. /scitex/{stats → stats_v01}/tests/_brunner_munzel_test.py +0 -0
  702. /scitex/{stats → stats_v01}/tests/_nocorrelation_test.py +0 -0
  703. /scitex/{stats → stats_v01}/tests/_smirnov_grubbs.py +0 -0
  704. {scitex-2.0.0.dist-info → scitex-2.1.0.dist-info}/top_level.txt +0 -0
scitex/io/_save.py CHANGED
@@ -1,17 +1,19 @@
1
1
  #!/usr/bin/env python3
2
2
  # -*- coding: utf-8 -*-
3
- # Timestamp: "2025-05-18 16:49:44 (ywatanabe)"
4
- # File: /ssh:sp:/home/ywatanabe/proj/scitex_repo/src/scitex/io/_save.py
3
+ # Timestamp: "2025-10-16 03:09:46 (ywatanabe)"
4
+ # File: /home/ywatanabe/proj/scitex_repo/src/scitex/io/_save.py
5
5
  # ----------------------------------------
6
+ from __future__ import annotations
6
7
  import os
7
-
8
- __FILE__ = "./src/scitex/io/_save.py"
8
+ __FILE__ = (
9
+ "./src/scitex/io/_save.py"
10
+ )
9
11
  __DIR__ = os.path.dirname(__FILE__)
10
12
  # ----------------------------------------
11
13
 
12
- import warnings
14
+ __FILE__ = __file__
13
15
 
14
- THIS_FILE = "/home/ywatanabe/proj/scitex_repo/src/scitex/io/_save.py"
16
+ import warnings
15
17
 
16
18
  """
17
19
  1. Functionality:
@@ -28,9 +30,11 @@ THIS_FILE = "/home/ywatanabe/proj/scitex_repo/src/scitex/io/_save.py"
28
30
 
29
31
  """Imports"""
30
32
  import inspect
31
- import logging
32
33
  import os as _os
33
- from typing import Any
34
+ from pathlib import Path
35
+ from typing import Any, Union
36
+
37
+ from scitex import logging
34
38
 
35
39
  from .._sh import sh
36
40
  from ..path._clean import clean
@@ -41,119 +45,123 @@ from ..str._readable_bytes import readable_bytes
41
45
 
42
46
  # Import save functions from the new modular structure
43
47
  from ._save_modules import (
48
+ save_catboost,
44
49
  save_csv,
45
50
  save_excel,
51
+ save_hdf5,
52
+ save_html,
53
+ save_image,
54
+ save_joblib,
55
+ save_json,
56
+ save_matlab,
57
+ save_mp4,
46
58
  save_npy,
47
59
  save_npz,
48
60
  save_pickle,
49
61
  save_pickle_compressed,
50
- save_joblib,
62
+ save_tex,
63
+ save_text,
51
64
  save_torch,
52
- save_json,
53
65
  save_yaml,
54
- save_hdf5,
55
- save_matlab,
56
- save_catboost,
57
- save_text,
58
- save_html,
59
- save_image,
60
- save_mp4,
61
- save_listed_dfs_as_csv,
62
- save_listed_scalars_as_csv,
63
- save_optuna_study_as_csv_and_pngs,
66
+ save_zarr,
64
67
  )
68
+ from ._save_modules._bibtex import save_bibtex
69
+
70
+ logger = logging.getLogger()
65
71
 
66
72
 
67
73
  def _get_figure_with_data(obj):
68
74
  """
69
75
  Extract figure or axes object that may contain plotting data for CSV export.
70
-
76
+
71
77
  Parameters
72
78
  ----------
73
79
  obj : various matplotlib objects
74
80
  Could be Figure, Axes, FigWrapper, AxisWrapper, or other matplotlib objects
75
-
81
+
76
82
  Returns
77
83
  -------
78
84
  object or None
79
85
  Figure or axes object that has export_as_csv methods, or None if not found
80
86
  """
81
- import matplotlib.pyplot as plt
82
- import matplotlib.figure
83
87
  import matplotlib.axes
84
-
88
+ import matplotlib.figure
89
+ import matplotlib.pyplot as plt
90
+
85
91
  # Check if object already has export methods (SciTeX wrapped objects)
86
- if hasattr(obj, 'export_as_csv'):
92
+ if hasattr(obj, "export_as_csv"):
87
93
  return obj
88
-
94
+
89
95
  # Handle matplotlib Figure objects
90
96
  if isinstance(obj, matplotlib.figure.Figure):
91
97
  # Get the current axes that might be wrapped with SciTeX functionality
92
98
  current_ax = plt.gca()
93
- if hasattr(current_ax, 'export_as_csv'):
99
+ if hasattr(current_ax, "export_as_csv"):
94
100
  return current_ax
95
-
101
+
96
102
  # Check all axes in the figure
97
103
  for ax in obj.axes:
98
- if hasattr(ax, 'export_as_csv'):
104
+ if hasattr(ax, "export_as_csv"):
99
105
  return ax
100
-
106
+
101
107
  return None
102
-
103
- # Handle matplotlib Axes objects
108
+
109
+ # Handle matplotlib Axes objects
104
110
  if isinstance(obj, matplotlib.axes.Axes):
105
- if hasattr(obj, 'export_as_csv'):
111
+ if hasattr(obj, "export_as_csv"):
106
112
  return obj
107
113
  return None
108
-
114
+
109
115
  # Handle FigWrapper or similar SciTeX objects
110
- if hasattr(obj, 'figure') and hasattr(obj.figure, 'axes'):
116
+ if hasattr(obj, "figure") and hasattr(obj.figure, "axes"):
111
117
  # Check if the wrapper itself has export methods
112
- if hasattr(obj, 'export_as_csv'):
118
+ if hasattr(obj, "export_as_csv"):
113
119
  return obj
114
-
120
+
115
121
  # Check the underlying figure's axes
116
122
  for ax in obj.figure.axes:
117
- if hasattr(ax, 'export_as_csv'):
123
+ if hasattr(ax, "export_as_csv"):
118
124
  return ax
119
-
125
+
120
126
  return None
121
-
127
+
122
128
  # Handle AxisWrapper or similar SciTeX objects
123
- if hasattr(obj, '_axis_mpl') or hasattr(obj, '_ax'):
124
- if hasattr(obj, 'export_as_csv'):
129
+ if hasattr(obj, "_axis_mpl") or hasattr(obj, "_ax"):
130
+ if hasattr(obj, "export_as_csv"):
125
131
  return obj
126
132
  return None
127
-
133
+
128
134
  # Try to get the current figure and its axes as fallback
129
135
  try:
130
136
  current_fig = plt.gcf()
131
- current_ax = plt.gca()
132
-
133
- if hasattr(current_ax, 'export_as_csv'):
137
+ current_ax = plt.gca()
138
+
139
+ if hasattr(current_ax, "export_as_csv"):
134
140
  return current_ax
135
- elif hasattr(current_fig, 'export_as_csv'):
141
+ elif hasattr(current_fig, "export_as_csv"):
136
142
  return current_fig
137
-
143
+
138
144
  # Check all axes in current figure
139
145
  for ax in current_fig.axes:
140
- if hasattr(ax, 'export_as_csv'):
146
+ if hasattr(ax, "export_as_csv"):
141
147
  return ax
142
-
148
+
143
149
  except:
144
150
  pass
145
-
151
+
146
152
  return None
147
153
 
148
154
 
149
155
  def save(
150
156
  obj: Any,
151
- specified_path: str,
157
+ specified_path: Union[str, Path],
152
158
  makedirs: bool = True,
153
159
  verbose: bool = True,
154
160
  symlink_from_cwd: bool = False,
161
+ symlink_to: Union[str, Path] = None,
155
162
  dry_run: bool = False,
156
163
  no_csv: bool = False,
164
+ use_caller_path: bool = False,
157
165
  **kwargs,
158
166
  ) -> None:
159
167
  """
@@ -163,16 +171,22 @@ def save(
163
171
  ----------
164
172
  obj : Any
165
173
  The object to be saved. Can be a NumPy array, PyTorch tensor, Pandas DataFrame, or any serializable object.
166
- specified_path : str
167
- The file name or path where the object should be saved. The file extension determines the format.
174
+ specified_path : Union[str, Path]
175
+ The file name or path where the object should be saved. Can be a string or pathlib.Path object. The file extension determines the format.
168
176
  makedirs : bool, optional
169
177
  If True, create the directory path if it does not exist. Default is True.
170
178
  verbose : bool, optional
171
179
  If True, print a message upon successful saving. Default is True.
172
180
  symlink_from_cwd : bool, optional
173
181
  If True, create a _symlink from the current working directory. Default is False.
182
+ symlink_to : Union[str, Path], optional
183
+ If specified, create a symlink at this path pointing to the saved file. Default is None.
174
184
  dry_run : bool, optional
175
185
  If True, simulate the saving process without actually writing files. Default is False.
186
+ use_caller_path : bool, optional
187
+ If True, intelligently determine the script path by skipping internal library frames.
188
+ This is useful when stx.io.save is called from within scitex library code.
189
+ Default is False.
176
190
  **kwargs
177
191
  Additional keyword arguments to pass to the underlying save function of the specific format.
178
192
 
@@ -221,6 +235,10 @@ def save(
221
235
  >>> scitex.io.save(data_dict, "data.json")
222
236
  """
223
237
  try:
238
+ # Convert Path objects to strings for consistency
239
+ if isinstance(specified_path, Path):
240
+ specified_path = str(specified_path)
241
+
224
242
  ########################################
225
243
  # DO NOT MODIFY THIS SECTION
226
244
  ########################################
@@ -230,7 +248,10 @@ def save(
230
248
  # When called in /path/to/script.py,
231
249
  # data will be saved under `/path/to/script.py_out/`
232
250
  #
233
- # On the other hand, when called in ipython environment,
251
+ # When called in a Jupyter notebook /path/to/notebook.ipynb,
252
+ # data will be saved under `/path/to/notebook_out/`
253
+ #
254
+ # When called in ipython environment,
234
255
  # data will be saved under `/tmp/{_os.getenv("USER")/`
235
256
  #
236
257
  ########################################
@@ -240,26 +261,29 @@ def save(
240
261
  if specified_path.startswith('f"') or specified_path.startswith("f'"):
241
262
  # Remove the f prefix and quotes
242
263
  path_content = specified_path[2:-1]
243
-
264
+
244
265
  # Get the caller's frame to access their local variables
245
266
  frame = inspect.currentframe().f_back
246
267
  try:
247
268
  # Use string formatting with the caller's locals and globals
248
269
  # This is much safer than eval() as it only does string substitution
249
270
  import re
271
+
250
272
  # Find all {variable} patterns
251
- variables = re.findall(r'\{([^}]+)\}', path_content)
273
+ variables = re.findall(r"\{([^}]+)\}", path_content)
252
274
  format_dict = {}
253
275
  for var in variables:
254
276
  # Only allow simple variable names, not arbitrary expressions
255
- if re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', var):
277
+ if re.match(r"^[a-zA-Z_][a-zA-Z0-9_]*$", var):
256
278
  if var in frame.f_locals:
257
279
  format_dict[var] = frame.f_locals[var]
258
280
  elif var in frame.f_globals:
259
281
  format_dict[var] = frame.f_globals[var]
260
282
  else:
261
- raise ValueError(f"Invalid variable name in f-string: {var}")
262
-
283
+ raise ValueError(
284
+ f"Invalid variable name in f-string: {var}"
285
+ )
286
+
263
287
  # Use str.format() which is safe
264
288
  specified_path = path_content.format(**format_dict)
265
289
  finally:
@@ -271,14 +295,72 @@ def save(
271
295
 
272
296
  # When relative path
273
297
  else:
274
- script_path = inspect.stack()[1].filename
275
-
276
- # Fake path if in ipython
277
- if ("ipython" in script_path) or ("<stdin>" in script_path):
278
- script_path = f'/tmp/{_os.getenv("USER")}'
279
-
280
- sdir = clean_path(_os.path.splitext(script_path)[0] + "_out")
281
- spath = _os.path.join(sdir, specified_path)
298
+ # Import here to avoid circular imports
299
+ from ..gen._detect_environment import detect_environment
300
+ from ..gen._get_notebook_path import get_notebook_info_simple
301
+
302
+ # Detect the current environment
303
+ env_type = detect_environment()
304
+
305
+ if env_type == "jupyter":
306
+ # Special handling for Jupyter notebooks
307
+ notebook_name, notebook_dir = get_notebook_info_simple()
308
+
309
+ if notebook_name:
310
+ # Remove .ipynb extension and add _out
311
+ notebook_base = _os.path.splitext(notebook_name)[0]
312
+ sdir = _os.path.join(
313
+ notebook_dir or _os.getcwd(), f"{notebook_base}_out"
314
+ )
315
+ else:
316
+ # Fallback if we can't detect notebook name
317
+ sdir = _os.path.join(_os.getcwd(), "notebook_out")
318
+
319
+ spath = _os.path.join(sdir, specified_path)
320
+
321
+ elif env_type == "script":
322
+ # Regular script handling
323
+ if use_caller_path:
324
+ # Smart path detection: skip internal scitex library frames
325
+ script_path = None
326
+ scitex_src_path = _os.path.join(
327
+ _os.path.dirname(__file__), "..", ".."
328
+ )
329
+ scitex_src_path = _os.path.abspath(scitex_src_path)
330
+
331
+ # Walk through the call stack from caller to find the first non-scitex frame
332
+ for frame_info in inspect.stack()[1:]:
333
+ frame_path = _os.path.abspath(frame_info.filename)
334
+ # Skip frames from scitex library
335
+ if not frame_path.startswith(scitex_src_path):
336
+ script_path = frame_path
337
+ break
338
+
339
+ # Fallback to stack[1] if we couldn't find a non-scitex frame
340
+ if script_path is None:
341
+ script_path = inspect.stack()[1].filename
342
+ else:
343
+ script_path = inspect.stack()[1].filename
344
+
345
+ sdir = clean_path(_os.path.splitext(script_path)[0] + "_out")
346
+ spath = _os.path.join(sdir, specified_path)
347
+
348
+ else:
349
+ # IPython console or interactive mode
350
+ script_path = inspect.stack()[1].filename
351
+
352
+ if (
353
+ ("ipython" in script_path)
354
+ or ("<stdin>" in script_path)
355
+ or env_type in ["ipython", "interactive"]
356
+ ):
357
+ script_path = f'/tmp/{_os.getenv("USER")}'
358
+ sdir = script_path
359
+ else:
360
+ # Unknown environment, use current directory
361
+ sdir = _os.path.join(_os.getcwd(), "output")
362
+
363
+ spath = _os.path.join(sdir, specified_path)
282
364
 
283
365
  # Sanitization
284
366
  spath_final = clean(spath)
@@ -291,17 +373,27 @@ def save(
291
373
  # Removes spath and spath_cwd to prevent potential circular links
292
374
  # Skip deletion for CSV files to allow caching to work
293
375
  # Also skip deletion for HDF5 files when a key is specified
294
- should_skip_deletion = (
295
- spath_final.endswith('.csv') or
296
- ((spath_final.endswith('.hdf5') or spath_final.endswith('.h5')) and 'key' in kwargs)
376
+ should_skip_deletion = spath_final.endswith(".csv") or (
377
+ (spath_final.endswith(".hdf5") or spath_final.endswith(".h5"))
378
+ and "key" in kwargs
297
379
  )
298
-
380
+
299
381
  if not should_skip_deletion:
300
382
  for path in [spath_final, spath_cwd]:
301
383
  sh(f"rm -f {path}", verbose=False)
302
384
 
303
385
  if dry_run:
304
- print(color_text(f"\n(dry run) Saved to: {spath_final}", c="yellow"))
386
+ # Get relative path from current working directory
387
+ try:
388
+ rel_path = _os.path.relpath(spath, _os.getcwd())
389
+ except ValueError:
390
+ rel_path = spath
391
+
392
+ if verbose:
393
+ print()
394
+ logger.success(
395
+ color_text(f"(dry run) Saved to: ./{rel_path}", c="yellow")
396
+ )
305
397
  return
306
398
 
307
399
  # Ensure directory exists
@@ -314,20 +406,27 @@ def save(
314
406
  spath_final,
315
407
  verbose=verbose,
316
408
  symlink_from_cwd=symlink_from_cwd,
409
+ symlink_to=symlink_to,
317
410
  dry_run=dry_run,
318
411
  no_csv=no_csv,
319
412
  **kwargs,
320
413
  )
321
414
 
322
- # Symbolic link
415
+ # Symbolic links
323
416
  _symlink(spath, spath_cwd, symlink_from_cwd, verbose)
417
+ _symlink_to(spath_final, symlink_to, verbose)
418
+ return Path(spath)
419
+ # return True
324
420
 
325
421
  except Exception as e:
326
- logging.error(
327
- f"Error occurred while saving: {str(e)}"
328
- f"Debug: Initial script_path = {inspect.stack()[1].filename}"
329
- f"Debug: Final spath = {spath}"
422
+ logger.error(
423
+ f"Error occurred while saving: {str(e)}\n"
424
+ f"Debug: Initial script_path = {inspect.stack()[1].filename}\n"
425
+ f"Debug: Final spath = {spath}\n"
426
+ f"Debug: specified_path type = {type(specified_path)}\n"
427
+ f"Debug: specified_path = {specified_path}"
330
428
  )
429
+ return False
331
430
 
332
431
 
333
432
  def _symlink(spath, spath_cwd, symlink_from_cwd, verbose):
@@ -337,7 +436,32 @@ def _symlink(spath, spath_cwd, symlink_from_cwd, verbose):
337
436
  sh(f"rm -f {spath_cwd}", verbose=False)
338
437
  sh(f"ln -sfr {spath} {spath_cwd}", verbose=False)
339
438
  if verbose:
340
- print(color_text(f"\n(Symlinked to: {spath_cwd})", "yellow"))
439
+ # Get file extension to provide more informative message
440
+ ext = _os.path.splitext(spath_cwd)[1].lower()
441
+ logger.success(color_text(f"(Symlinked to: {spath_cwd})"))
442
+
443
+
444
+ def _symlink_to(spath_final, symlink_to, verbose):
445
+ """Create a symbolic link at the specified path pointing to the saved file."""
446
+ if symlink_to:
447
+ # Convert Path objects to strings for consistency
448
+ if isinstance(symlink_to, Path):
449
+ symlink_to = str(symlink_to)
450
+
451
+ # Clean the symlink path
452
+ symlink_to = clean(symlink_to)
453
+
454
+ # Ensure the symlink directory exists
455
+ _os.makedirs(_os.path.dirname(symlink_to), exist_ok=True)
456
+
457
+ # Remove existing symlink or file
458
+ sh(f"rm -f {symlink_to}", verbose=False)
459
+
460
+ # Create the symlink using relative path for robustness
461
+ sh(f"ln -sfr {spath_final} {symlink_to}", verbose=False)
462
+
463
+ if verbose:
464
+ print(color_text(f"\n(Symlinked to: {symlink_to})", "yellow"))
341
465
 
342
466
 
343
467
  def _save(
@@ -347,18 +471,40 @@ def _save(
347
471
  symlink_from_cwd=False,
348
472
  dry_run=False,
349
473
  no_csv=False,
474
+ symlink_to=None,
350
475
  **kwargs,
351
476
  ):
477
+ # Don't use object's own save method - use consistent handlers
478
+ # This ensures all saves go through the same pipeline and get
479
+ # the yellow confirmation message
480
+
352
481
  # Get file extension
353
482
  ext = _os.path.splitext(spath)[1].lower()
354
-
483
+
355
484
  # Try dispatch dictionary first for O(1) lookup
356
485
  if ext in _FILE_HANDLERS:
357
486
  # Check if handler needs special parameters
358
- if ext in ['.png', '.jpg', '.jpeg', '.gif', '.tiff', '.tif', '.svc']:
359
- _FILE_HANDLERS[ext](obj, spath, no_csv=no_csv, symlink_from_cwd=symlink_from_cwd, dry_run=dry_run, **kwargs)
360
- elif ext in ['.hdf5', '.h5']:
361
- # HDF5 files may need special 'key' parameter
487
+ if ext in [
488
+ ".png",
489
+ ".jpg",
490
+ ".jpeg",
491
+ ".gif",
492
+ ".tiff",
493
+ ".tif",
494
+ ".svg",
495
+ ".pdf",
496
+ ]:
497
+ _FILE_HANDLERS[ext](
498
+ obj,
499
+ spath,
500
+ no_csv=no_csv,
501
+ symlink_from_cwd=symlink_from_cwd,
502
+ symlink_to=symlink_to,
503
+ dry_run=dry_run,
504
+ **kwargs,
505
+ )
506
+ elif ext in [".hdf5", ".h5", ".zarr"]:
507
+ # HDF5 and Zarr files may need special 'key' parameter
362
508
  _FILE_HANDLERS[ext](obj, spath, **kwargs)
363
509
  else:
364
510
  _FILE_HANDLERS[ext](obj, spath, **kwargs)
@@ -375,165 +521,277 @@ def _save(
375
521
  if _os.path.exists(spath):
376
522
  file_size = getsize(spath)
377
523
  file_size = readable_bytes(file_size)
378
- print(color_text(f"\nSaved to: {spath} ({file_size})", c="yellow"))
524
+ # Get relative path from current working directory
525
+ try:
526
+ rel_path = _os.path.relpath(spath, _os.getcwd())
527
+ except ValueError:
528
+ rel_path = spath
379
529
 
530
+ print()
531
+ logger.success(f"Saved to: ./{rel_path} ({file_size})")
380
532
 
381
- def _save_separate_legends(obj, spath, symlink_from_cwd=False, dry_run=False, **kwargs):
533
+
534
+ def _save_separate_legends(
535
+ obj, spath, symlink_from_cwd=False, dry_run=False, **kwargs
536
+ ):
382
537
  """Save separate legend files if ax.legend('separate') was used."""
383
- import matplotlib.pyplot as plt
538
+ if dry_run:
539
+ return
540
+
384
541
  import matplotlib.figure
385
-
542
+ import matplotlib.pyplot as plt
543
+
386
544
  # Get the matplotlib figure object
387
545
  fig = None
388
546
  if isinstance(obj, matplotlib.figure.Figure):
389
547
  fig = obj
390
- elif hasattr(obj, '_fig_mpl'):
548
+ elif hasattr(obj, "_fig_mpl"):
391
549
  fig = obj._fig_mpl
392
- elif hasattr(obj, 'figure'):
550
+ elif hasattr(obj, "figure"):
393
551
  if isinstance(obj.figure, matplotlib.figure.Figure):
394
552
  fig = obj.figure
395
- elif hasattr(obj.figure, '_fig_mpl'):
553
+ elif hasattr(obj.figure, "_fig_mpl"):
396
554
  fig = obj.figure._fig_mpl
397
-
555
+
398
556
  if fig is None:
399
557
  return
400
-
558
+
401
559
  # Check if there are separate legend parameters stored
402
- if not hasattr(fig, '_separate_legend_params'):
560
+ if not hasattr(fig, "_separate_legend_params"):
403
561
  return
404
-
562
+
405
563
  # Save each legend as a separate file
406
564
  base_path = _os.path.splitext(spath)[0]
407
565
  ext = _os.path.splitext(spath)[1]
408
-
566
+
409
567
  for legend_params in fig._separate_legend_params:
410
568
  # Create a new figure for the legend
411
- legend_fig = plt.figure(figsize=legend_params['figsize'])
569
+ legend_fig = plt.figure(figsize=legend_params["figsize"])
412
570
  legend_ax = legend_fig.add_subplot(111)
413
-
571
+
414
572
  # Create the legend
415
573
  legend = legend_ax.legend(
416
- legend_params['handles'],
417
- legend_params['labels'],
418
- loc='center',
419
- frameon=legend_params['frameon'],
420
- fancybox=legend_params['fancybox'],
421
- shadow=legend_params['shadow'],
422
- **legend_params['kwargs']
574
+ legend_params["handles"],
575
+ legend_params["labels"],
576
+ loc="center",
577
+ frameon=legend_params["frameon"],
578
+ fancybox=legend_params["fancybox"],
579
+ shadow=legend_params["shadow"],
580
+ **legend_params["kwargs"],
423
581
  )
424
-
582
+
425
583
  # Remove axes
426
- legend_ax.axis('off')
427
-
584
+ legend_ax.axis("off")
585
+
428
586
  # Adjust layout to fit the legend
429
587
  legend_fig.tight_layout()
430
-
588
+
431
589
  # Save the legend figure
432
590
  legend_filename = f"{base_path}_{legend_params['axis_id']}_legend{ext}"
433
591
  save_image(legend_fig, legend_filename, **kwargs)
434
-
592
+
435
593
  # Close the legend figure to free memory
436
594
  plt.close(legend_fig)
437
-
595
+
438
596
  if not dry_run and _os.path.exists(legend_filename):
439
597
  file_size = getsize(legend_filename)
440
598
  file_size = readable_bytes(file_size)
441
- print(color_text(f"\nSaved legend to: {legend_filename} ({file_size})", c="yellow"))
599
+ print(
600
+ color_text(
601
+ f"\nSaved legend to: {legend_filename} ({file_size})",
602
+ c="yellow",
603
+ )
604
+ )
442
605
 
443
606
 
444
- def _handle_image_with_csv(obj, spath, no_csv=False, symlink_from_cwd=False, dry_run=False, **kwargs):
607
+ def _handle_image_with_csv(
608
+ obj,
609
+ spath,
610
+ no_csv=False,
611
+ symlink_from_cwd=False,
612
+ dry_run=False,
613
+ symlink_to=None,
614
+ **kwargs,
615
+ ):
445
616
  """Handle image file saving with optional CSV export."""
617
+ if dry_run:
618
+ return
619
+
446
620
  save_image(obj, spath, **kwargs)
447
-
621
+
448
622
  # Handle separate legend saving
449
- _save_separate_legends(obj, spath, symlink_from_cwd=symlink_from_cwd, dry_run=dry_run, **kwargs)
450
-
623
+ _save_separate_legends(
624
+ obj,
625
+ spath,
626
+ symlink_from_cwd=symlink_from_cwd,
627
+ dry_run=dry_run,
628
+ **kwargs,
629
+ )
630
+
451
631
  if not no_csv:
452
632
  ext = _os.path.splitext(spath)[1].lower()
453
633
  ext_wo_dot = ext.replace(".", "")
454
-
634
+
455
635
  try:
456
636
  # Get the figure object that may contain plot data
457
637
  fig_obj = _get_figure_with_data(obj)
458
-
638
+
459
639
  if fig_obj is not None:
460
640
  # Save regular CSV if export method exists
461
- if hasattr(fig_obj, 'export_as_csv'):
641
+ if hasattr(fig_obj, "export_as_csv"):
462
642
  csv_data = fig_obj.export_as_csv()
463
643
  if csv_data is not None and not csv_data.empty:
464
- save(
644
+ # Save CSV in same directory as image with .csv extension
645
+ # Example: ./path/to/output/fig.jpg -> ./path/to/output/fig.csv
646
+ csv_path = _os.path.splitext(spath)[0] + ".csv"
647
+ # Ensure parent directory exists (should already exist from image save)
648
+ _os.makedirs(_os.path.dirname(csv_path), exist_ok=True)
649
+ # Save directly using _save to avoid path doubling
650
+ # Don't pass image-specific kwargs to CSV save
651
+ _save(
465
652
  csv_data,
466
- spath.replace(ext_wo_dot, "csv"),
467
- symlink_from_cwd=symlink_from_cwd,
653
+ csv_path,
654
+ verbose=True,
655
+ symlink_from_cwd=False, # Will handle symlink manually
468
656
  dry_run=dry_run,
469
657
  no_csv=True,
470
- **kwargs,
471
658
  )
472
-
659
+
660
+ # Create symlink_to for CSV if it was specified for the image
661
+ if symlink_to:
662
+ csv_symlink_to = (
663
+ _os.path.splitext(symlink_to)[0] + ".csv"
664
+ )
665
+ _symlink_to(csv_path, csv_symlink_to, True)
666
+
667
+ # Create symlink for CSV manually if needed
668
+ if symlink_from_cwd:
669
+ # Get the relative path from the original specified path
670
+ # This preserves the directory structure for the symlink
671
+ import inspect
672
+
673
+ frame_info = inspect.stack()
674
+ # Find the original specified_path from the parent save() call
675
+ for frame in frame_info:
676
+ if "specified_path" in frame.frame.f_locals:
677
+ original_path = frame.frame.f_locals[
678
+ "specified_path"
679
+ ]
680
+ if isinstance(original_path, str):
681
+ # Replace extension to get CSV path structure
682
+ csv_relative = original_path.replace(
683
+ _os.path.splitext(original_path)[
684
+ 1
685
+ ],
686
+ ".csv",
687
+ )
688
+ csv_cwd = _os.path.join(
689
+ _os.getcwd(), csv_relative
690
+ )
691
+ _symlink(csv_path, csv_cwd, True, True)
692
+ break
693
+ else:
694
+ # Fallback to basename if we can't find the original path
695
+ csv_cwd = (
696
+ _os.getcwd()
697
+ + "/"
698
+ + _os.path.basename(csv_path)
699
+ )
700
+ _symlink(csv_path, csv_cwd, True, True)
701
+
473
702
  # Save SigmaPlot CSV if method exists
474
- if hasattr(fig_obj, 'export_as_csv_for_sigmaplot'):
703
+ if hasattr(fig_obj, "export_as_csv_for_sigmaplot"):
475
704
  sigmaplot_data = fig_obj.export_as_csv_for_sigmaplot()
476
705
  if sigmaplot_data is not None and not sigmaplot_data.empty:
477
- save(
706
+ # For CSV files, we want them in the same directory as the image
707
+ csv_sigmaplot_path = spath.replace(
708
+ ext_wo_dot, "csv"
709
+ ).replace(".csv", "_for_sigmaplot.csv")
710
+ # Save directly using _save to avoid path doubling
711
+ # Don't pass image-specific kwargs to CSV save
712
+ _save(
478
713
  sigmaplot_data,
479
- spath.replace(ext_wo_dot, "csv").replace(".csv", "_for_sigmaplot.csv"),
480
- symlink_from_cwd=symlink_from_cwd,
714
+ csv_sigmaplot_path,
715
+ verbose=True,
716
+ symlink_from_cwd=False, # Will handle symlink manually
481
717
  dry_run=dry_run,
482
718
  no_csv=True,
483
- **kwargs,
484
719
  )
485
- except Exception:
486
- pass
720
+
721
+ # Create symlink_to for SigmaPlot CSV if it was specified for the image
722
+ if symlink_to:
723
+ csv_sigmaplot_symlink_to = (
724
+ _os.path.splitext(symlink_to)[0]
725
+ + "_for_sigmaplot.csv"
726
+ )
727
+ _symlink_to(
728
+ csv_sigmaplot_path,
729
+ csv_sigmaplot_symlink_to,
730
+ True,
731
+ )
732
+
733
+ # Create symlink for SigmaPlot CSV manually if needed
734
+ if symlink_from_cwd:
735
+ csv_cwd = (
736
+ _os.getcwd()
737
+ + "/"
738
+ + _os.path.basename(csv_sigmaplot_path)
739
+ )
740
+ _symlink(csv_sigmaplot_path, csv_cwd, True, True)
741
+ except Exception as e:
742
+ import warnings
743
+
744
+ warnings.warn(f"CSV export failed: {e}")
745
+ import traceback
746
+
747
+ traceback.print_exc()
487
748
 
488
749
 
489
750
  # Dispatch dictionary for O(1) file format lookup
490
751
  _FILE_HANDLERS = {
491
752
  # Excel formats
492
- '.xlsx': save_excel,
493
- '.xls': save_excel,
494
-
753
+ ".xlsx": save_excel,
754
+ ".xls": save_excel,
495
755
  # NumPy formats
496
- '.npy': save_npy,
497
- '.npz': save_npz,
498
-
756
+ ".npy": save_npy,
757
+ ".npz": save_npz,
499
758
  # Pickle formats
500
- '.pkl': save_pickle,
501
- '.pickle': save_pickle,
502
- '.pkl.gz': save_pickle_compressed,
503
-
759
+ ".pkl": save_pickle,
760
+ ".pickle": save_pickle,
761
+ ".pkl.gz": save_pickle_compressed,
504
762
  # Other binary formats
505
- '.joblib': save_joblib,
506
- '.pth': save_torch,
507
- '.pt': save_torch,
508
- '.mat': save_matlab,
509
- '.cbm': save_catboost,
510
-
763
+ ".joblib": save_joblib,
764
+ ".pth": save_torch,
765
+ ".pt": save_torch,
766
+ ".mat": save_matlab,
767
+ ".cbm": save_catboost,
511
768
  # Text formats
512
- '.json': save_json,
513
- '.yaml': save_yaml,
514
- '.yml': save_yaml,
515
- '.txt': save_text,
516
- '.md': save_text,
517
- '.py': save_text,
518
- '.css': save_text,
519
- '.js': save_text,
520
-
769
+ ".json": save_json,
770
+ ".yaml": save_yaml,
771
+ ".yml": save_yaml,
772
+ ".txt": save_text,
773
+ ".md": save_text,
774
+ ".py": save_text,
775
+ ".css": save_text,
776
+ ".js": save_text,
777
+ ".tex": save_tex,
778
+ # Bibliography
779
+ ".bib": save_bibtex,
521
780
  # Data formats
522
- '.html': save_html,
523
- '.hdf5': save_hdf5,
524
- '.h5': save_hdf5,
525
-
781
+ ".html": save_html,
782
+ ".hdf5": save_hdf5,
783
+ ".h5": save_hdf5,
784
+ ".zarr": save_zarr,
526
785
  # Media formats
527
- '.mp4': save_mp4,
528
- '.png': _handle_image_with_csv,
529
- '.jpg': _handle_image_with_csv,
530
- '.jpeg': _handle_image_with_csv,
531
- '.gif': _handle_image_with_csv,
532
- '.tiff': _handle_image_with_csv,
533
- '.tif': _handle_image_with_csv,
534
- '.svg': _handle_image_with_csv,
535
- '.pdf': _handle_image_with_csv,
786
+ ".mp4": save_mp4,
787
+ ".png": _handle_image_with_csv,
788
+ ".jpg": _handle_image_with_csv,
789
+ ".jpeg": _handle_image_with_csv,
790
+ ".gif": _handle_image_with_csv,
791
+ ".tiff": _handle_image_with_csv,
792
+ ".tif": _handle_image_with_csv,
793
+ ".svg": _handle_image_with_csv,
794
+ ".pdf": _handle_image_with_csv,
536
795
  }
537
796
 
538
-
539
797
  # EOF