scitex 2.11.0__py3-none-any.whl → 2.13.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. scitex/__main__.py +24 -5
  2. scitex/__version__.py +1 -1
  3. scitex/_optional_deps.py +33 -0
  4. scitex/ai/classification/reporters/_ClassificationReporter.py +1 -1
  5. scitex/ai/classification/timeseries/_TimeSeriesBlockingSplit.py +2 -2
  6. scitex/ai/classification/timeseries/_TimeSeriesCalendarSplit.py +2 -2
  7. scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit.py +2 -2
  8. scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit_v01-not-using-n_splits.py +2 -2
  9. scitex/ai/classification/timeseries/_TimeSeriesStratifiedSplit.py +2 -2
  10. scitex/ai/classification/timeseries/_normalize_timestamp.py +1 -1
  11. scitex/ai/metrics/_calc_seizure_prediction_metrics.py +1 -1
  12. scitex/ai/plt/_plot_feature_importance.py +1 -1
  13. scitex/ai/plt/_plot_learning_curve.py +1 -1
  14. scitex/ai/plt/_plot_optuna_study.py +1 -1
  15. scitex/ai/plt/_plot_pre_rec_curve.py +1 -1
  16. scitex/ai/plt/_plot_roc_curve.py +1 -1
  17. scitex/ai/plt/_stx_conf_mat.py +1 -1
  18. scitex/ai/training/_LearningCurveLogger.py +1 -1
  19. scitex/audio/mcp_server.py +38 -8
  20. scitex/browser/automation/CookieHandler.py +1 -1
  21. scitex/browser/core/BrowserMixin.py +1 -1
  22. scitex/browser/core/ChromeProfileManager.py +1 -1
  23. scitex/browser/debugging/_browser_logger.py +1 -1
  24. scitex/browser/debugging/_highlight_element.py +1 -1
  25. scitex/browser/debugging/_show_grid.py +1 -1
  26. scitex/browser/interaction/click_center.py +1 -1
  27. scitex/browser/interaction/click_with_fallbacks.py +1 -1
  28. scitex/browser/interaction/close_popups.py +1 -1
  29. scitex/browser/interaction/fill_with_fallbacks.py +1 -1
  30. scitex/browser/pdf/click_download_for_chrome_pdf_viewer.py +1 -1
  31. scitex/browser/pdf/detect_chrome_pdf_viewer.py +1 -1
  32. scitex/browser/stealth/HumanBehavior.py +1 -1
  33. scitex/browser/stealth/StealthManager.py +1 -1
  34. scitex/canvas/_mcp_handlers.py +372 -0
  35. scitex/canvas/_mcp_tool_schemas.py +219 -0
  36. scitex/canvas/mcp_server.py +151 -0
  37. scitex/capture/mcp_server.py +41 -12
  38. scitex/cli/audio.py +233 -0
  39. scitex/cli/capture.py +307 -0
  40. scitex/cli/main.py +27 -4
  41. scitex/cli/repro.py +233 -0
  42. scitex/cli/resource.py +240 -0
  43. scitex/cli/stats.py +325 -0
  44. scitex/cli/template.py +236 -0
  45. scitex/cli/tex.py +286 -0
  46. scitex/cli/web.py +11 -12
  47. scitex/dev/__init__.py +3 -0
  48. scitex/dev/_pyproject.py +405 -0
  49. scitex/dev/plt/__init__.py +2 -2
  50. scitex/dev/plt/mpl/get_dir_ax.py +1 -1
  51. scitex/dev/plt/mpl/get_signatures.py +1 -1
  52. scitex/dev/plt/mpl/get_signatures_details.py +1 -1
  53. scitex/diagram/_mcp_handlers.py +400 -0
  54. scitex/diagram/_mcp_tool_schemas.py +157 -0
  55. scitex/diagram/mcp_server.py +151 -0
  56. scitex/dsp/_demo_sig.py +51 -5
  57. scitex/dsp/_mne.py +13 -2
  58. scitex/dsp/_modulation_index.py +15 -3
  59. scitex/dsp/_pac.py +23 -5
  60. scitex/dsp/_psd.py +16 -4
  61. scitex/dsp/_resample.py +24 -4
  62. scitex/dsp/_transform.py +16 -3
  63. scitex/dsp/add_noise.py +15 -1
  64. scitex/dsp/norm.py +17 -2
  65. scitex/dsp/reference.py +17 -1
  66. scitex/dsp/utils/_differential_bandpass_filters.py +20 -2
  67. scitex/dsp/utils/_zero_pad.py +18 -4
  68. scitex/dt/_normalize_timestamp.py +1 -1
  69. scitex/git/_session.py +1 -1
  70. scitex/io/_load_modules/_con.py +12 -1
  71. scitex/io/_load_modules/_eeg.py +12 -1
  72. scitex/io/_load_modules/_optuna.py +21 -63
  73. scitex/io/_load_modules/_torch.py +11 -3
  74. scitex/io/_save_modules/_optuna_study_as_csv_and_pngs.py +13 -2
  75. scitex/io/_save_modules/_torch.py +11 -3
  76. scitex/mcp_server.py +159 -0
  77. scitex/plt/_mcp_handlers.py +361 -0
  78. scitex/plt/_mcp_tool_schemas.py +169 -0
  79. scitex/plt/mcp_server.py +205 -0
  80. scitex/repro/README_RandomStateManager.md +3 -3
  81. scitex/repro/_RandomStateManager.py +14 -14
  82. scitex/repro/_gen_ID.py +1 -1
  83. scitex/repro/_gen_timestamp.py +1 -1
  84. scitex/repro/_hash_array.py +4 -4
  85. scitex/scholar/__main__.py +24 -2
  86. scitex/scholar/_mcp_handlers.py +685 -0
  87. scitex/scholar/_mcp_tool_schemas.py +339 -0
  88. scitex/scholar/docs/template.py +1 -1
  89. scitex/scholar/examples/07_storage_integration.py +1 -1
  90. scitex/scholar/impact_factor/jcr/ImpactFactorJCREngine.py +1 -1
  91. scitex/scholar/impact_factor/jcr/build_database.py +1 -1
  92. scitex/scholar/mcp_server.py +315 -0
  93. scitex/scholar/pdf_download/ScholarPDFDownloader.py +1 -1
  94. scitex/scholar/pipelines/ScholarPipelineBibTeX.py +1 -1
  95. scitex/scholar/pipelines/ScholarPipelineParallel.py +1 -1
  96. scitex/scholar/pipelines/ScholarPipelineSingle.py +1 -1
  97. scitex/scholar/storage/PaperIO.py +1 -1
  98. scitex/session/README.md +4 -4
  99. scitex/session/__init__.py +1 -1
  100. scitex/session/_decorator.py +9 -9
  101. scitex/session/_lifecycle.py +5 -5
  102. scitex/session/template.py +1 -1
  103. scitex/stats/__main__.py +281 -0
  104. scitex/stats/_mcp_handlers.py +1191 -0
  105. scitex/stats/_mcp_tool_schemas.py +384 -0
  106. scitex/stats/correct/_correct_bonferroni.py +1 -1
  107. scitex/stats/correct/_correct_fdr.py +1 -1
  108. scitex/stats/correct/_correct_fdr_.py +1 -1
  109. scitex/stats/correct/_correct_holm.py +1 -1
  110. scitex/stats/correct/_correct_sidak.py +1 -1
  111. scitex/stats/effect_sizes/_cliffs_delta.py +1 -1
  112. scitex/stats/effect_sizes/_cohens_d.py +1 -1
  113. scitex/stats/effect_sizes/_epsilon_squared.py +1 -1
  114. scitex/stats/effect_sizes/_eta_squared.py +1 -1
  115. scitex/stats/effect_sizes/_prob_superiority.py +1 -1
  116. scitex/stats/mcp_server.py +405 -0
  117. scitex/stats/posthoc/_dunnett.py +1 -1
  118. scitex/stats/posthoc/_games_howell.py +1 -1
  119. scitex/stats/posthoc/_tukey_hsd.py +1 -1
  120. scitex/stats/power/_power.py +1 -1
  121. scitex/stats/utils/_effect_size.py +1 -1
  122. scitex/stats/utils/_formatters.py +1 -1
  123. scitex/stats/utils/_power.py +1 -1
  124. scitex/template/_mcp_handlers.py +259 -0
  125. scitex/template/_mcp_tool_schemas.py +112 -0
  126. scitex/template/mcp_server.py +186 -0
  127. scitex/utils/_verify_scitex_format.py +2 -2
  128. scitex/utils/template.py +1 -1
  129. scitex/web/__init__.py +12 -11
  130. scitex/web/_scraping.py +26 -265
  131. scitex/web/download_images.py +316 -0
  132. scitex/writer/Writer.py +1 -1
  133. scitex/writer/_clone_writer_project.py +1 -1
  134. scitex/writer/_validate_tree_structures.py +1 -1
  135. scitex/writer/dataclasses/config/_WriterConfig.py +1 -1
  136. scitex/writer/dataclasses/contents/_ManuscriptContents.py +1 -1
  137. scitex/writer/dataclasses/core/_Document.py +1 -1
  138. scitex/writer/dataclasses/core/_DocumentSection.py +1 -1
  139. scitex/writer/dataclasses/results/_CompilationResult.py +1 -1
  140. scitex/writer/dataclasses/results/_LaTeXIssue.py +1 -1
  141. scitex/writer/utils/.legacy_git_retry.py +7 -5
  142. scitex/writer/utils/_parse_latex_logs.py +1 -1
  143. {scitex-2.11.0.dist-info → scitex-2.13.0.dist-info}/METADATA +431 -269
  144. {scitex-2.11.0.dist-info → scitex-2.13.0.dist-info}/RECORD +147 -118
  145. scitex-2.13.0.dist-info/entry_points.txt +11 -0
  146. scitex-2.11.0.dist-info/entry_points.txt +0 -2
  147. {scitex-2.11.0.dist-info → scitex-2.13.0.dist-info}/WHEEL +0 -0
  148. {scitex-2.11.0.dist-info → scitex-2.13.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,405 @@
1
+ #!/usr/bin/env python3
2
+ # Timestamp: 2025-01-08
3
+ # File: /home/ywatanabe/proj/scitex-code/src/scitex/dev/_pyproject.py
4
+
5
+ """
6
+ Utility for programmatically managing pyproject.toml dependencies.
7
+
8
+ Usage:
9
+ from scitex.dev import pyproject
10
+
11
+ # Load and inspect
12
+ pp = pyproject.load()
13
+ extras = pyproject.get_extras(pp)
14
+
15
+ # Audit dependencies
16
+ pyproject.print_report()
17
+ pyproject.validate_heavy_sync()
18
+
19
+ # Find issues
20
+ duplicates = pyproject.find_duplicates()
21
+ missing = pyproject.find_missing_heavy_deps()
22
+ """
23
+
24
+ import re
25
+ from collections import defaultdict
26
+ from pathlib import Path
27
+ from typing import Dict, List, Optional, Set
28
+
29
+ try:
30
+ import tomlkit
31
+
32
+ TOMLKIT_AVAILABLE = True
33
+ except ImportError:
34
+ TOMLKIT_AVAILABLE = False
35
+ tomlkit = None
36
+
37
+
38
+ def _get_default_path() -> Path:
39
+ """Get default pyproject.toml path (project root)."""
40
+ # Navigate from this file to project root
41
+ current = Path(__file__).resolve()
42
+ # src/scitex/dev/_pyproject.py -> project root
43
+ for _ in range(4):
44
+ current = current.parent
45
+ return current / "pyproject.toml"
46
+
47
+
48
+ def load(path: Optional[Path] = None) -> dict:
49
+ """
50
+ Load pyproject.toml preserving comments and formatting.
51
+
52
+ Parameters
53
+ ----------
54
+ path : Path, optional
55
+ Path to pyproject.toml. Defaults to project root.
56
+
57
+ Returns
58
+ -------
59
+ dict
60
+ Parsed TOML document (tomlkit.TOMLDocument)
61
+ """
62
+ if not TOMLKIT_AVAILABLE:
63
+ raise ImportError(
64
+ "tomlkit is required for pyproject utilities. "
65
+ "Install with: pip install tomlkit"
66
+ )
67
+
68
+ path = path or _get_default_path()
69
+ with open(path) as f:
70
+ return tomlkit.load(f)
71
+
72
+
73
+ def save(doc: dict, path: Optional[Path] = None) -> None:
74
+ """
75
+ Save pyproject.toml preserving comments and formatting.
76
+
77
+ Parameters
78
+ ----------
79
+ doc : dict
80
+ TOML document to save
81
+ path : Path, optional
82
+ Path to pyproject.toml. Defaults to project root.
83
+ """
84
+ if not TOMLKIT_AVAILABLE:
85
+ raise ImportError("tomlkit is required")
86
+
87
+ path = path or _get_default_path()
88
+ with open(path, "w") as f:
89
+ tomlkit.dump(doc, f)
90
+
91
+
92
+ def get_extras(doc: Optional[dict] = None) -> Dict[str, List[str]]:
93
+ """
94
+ Get all optional dependency extras.
95
+
96
+ Returns
97
+ -------
98
+ dict
99
+ Mapping of extra name to list of dependencies
100
+ """
101
+ doc = doc or load()
102
+ return dict(doc.get("project", {}).get("optional-dependencies", {}))
103
+
104
+
105
+ def get_core_deps(doc: Optional[dict] = None) -> List[str]:
106
+ """Get core dependencies."""
107
+ doc = doc or load()
108
+ return list(doc.get("project", {}).get("dependencies", []))
109
+
110
+
111
+ def get_heavy_deps(doc: Optional[dict] = None) -> Set[str]:
112
+ """Get dependencies in the [heavy] extra."""
113
+ extras = get_extras(doc)
114
+ return set(extras.get("heavy", []))
115
+
116
+
117
+ def parse_commented_deps(path: Optional[Path] = None) -> Dict[str, List[str]]:
118
+ """
119
+ Parse commented-out dependencies from pyproject.toml.
120
+
121
+ Looks for patterns like:
122
+ # "torch",
123
+ # "mne",
124
+
125
+ Returns
126
+ -------
127
+ dict
128
+ Mapping of extra name to list of commented dependencies
129
+ """
130
+ path = path or _get_default_path()
131
+
132
+ commented_deps = defaultdict(list)
133
+ current_extra = None
134
+
135
+ with open(path) as f:
136
+ for line in f:
137
+ # Detect extra section
138
+ match = re.match(r"^(\w+)\s*=\s*\[", line)
139
+ if match:
140
+ current_extra = match.group(1)
141
+ continue
142
+
143
+ # Detect end of section
144
+ if line.strip() == "]":
145
+ current_extra = None
146
+ continue
147
+
148
+ # Detect commented dependency
149
+ if current_extra:
150
+ match = re.match(r'^\s*#\s*"([^"]+)"', line)
151
+ if match:
152
+ dep = match.group(1)
153
+ commented_deps[current_extra].append(dep)
154
+
155
+ return dict(commented_deps)
156
+
157
+
158
+ def find_duplicates(doc: Optional[dict] = None) -> Dict[str, List[str]]:
159
+ """
160
+ Find dependencies that appear in multiple extras.
161
+
162
+ Returns
163
+ -------
164
+ dict
165
+ Mapping of dependency to list of extras containing it
166
+ """
167
+ extras = get_extras(doc)
168
+ dep_locations = defaultdict(list)
169
+
170
+ for extra_name, deps in extras.items():
171
+ if extra_name in ("all", "dev", "heavy"):
172
+ continue # Skip meta-extras
173
+ for dep in deps:
174
+ # Normalize dep name (strip version specifiers)
175
+ dep_name = re.split(r"[<>=\[]", dep)[0].strip().lower()
176
+ dep_locations[dep_name].append(extra_name)
177
+
178
+ # Return only duplicates
179
+ return {dep: extras for dep, extras in dep_locations.items() if len(extras) > 1}
180
+
181
+
182
+ def find_missing_heavy_deps(path: Optional[Path] = None) -> List[str]:
183
+ """
184
+ Find commented deps that are NOT in [heavy] extra.
185
+
186
+ Returns
187
+ -------
188
+ list
189
+ Dependencies that should be added to [heavy]
190
+ """
191
+ doc = load(path)
192
+ heavy_deps = get_heavy_deps(doc)
193
+ commented = parse_commented_deps(path)
194
+
195
+ # Normalize heavy deps
196
+ heavy_normalized = {re.split(r"[<>=\[]", d)[0].strip().lower() for d in heavy_deps}
197
+
198
+ missing = set()
199
+ for extra, deps in commented.items():
200
+ for dep in deps:
201
+ dep_normalized = re.split(r"[<>=\[]", dep)[0].strip().lower()
202
+ if dep_normalized not in heavy_normalized:
203
+ missing.add(dep)
204
+
205
+ return sorted(missing)
206
+
207
+
208
+ def validate_heavy_sync(path: Optional[Path] = None, verbose: bool = True) -> bool:
209
+ """
210
+ Validate that all commented deps are in [heavy] extra.
211
+
212
+ Parameters
213
+ ----------
214
+ path : Path, optional
215
+ Path to pyproject.toml
216
+ verbose : bool
217
+ Print validation results
218
+
219
+ Returns
220
+ -------
221
+ bool
222
+ True if all commented deps are in [heavy]
223
+ """
224
+ missing = find_missing_heavy_deps(path)
225
+
226
+ if verbose:
227
+ if missing:
228
+ print(f"Missing from [heavy] extra ({len(missing)}):")
229
+ for dep in missing:
230
+ print(f" - {dep}")
231
+ else:
232
+ print("All commented deps are in [heavy] extra")
233
+
234
+ return len(missing) == 0
235
+
236
+
237
+ def get_extra_stats(doc: Optional[dict] = None) -> Dict[str, dict]:
238
+ """
239
+ Get statistics for each extra.
240
+
241
+ Returns
242
+ -------
243
+ dict
244
+ Mapping of extra name to stats dict
245
+ """
246
+ extras = get_extras(doc)
247
+ stats = {}
248
+
249
+ for name, deps in extras.items():
250
+ stats[name] = {
251
+ "count": len(deps),
252
+ "deps": deps,
253
+ }
254
+
255
+ return stats
256
+
257
+
258
+ def print_report(path: Optional[Path] = None) -> None:
259
+ """Print a comprehensive dependency report."""
260
+ doc = load(path)
261
+ extras = get_extras(doc)
262
+ core = get_core_deps(doc)
263
+ commented = parse_commented_deps(path)
264
+ duplicates = find_duplicates(doc)
265
+ missing = find_missing_heavy_deps(path)
266
+
267
+ print("=" * 60)
268
+ print("PYPROJECT.TOML DEPENDENCY REPORT")
269
+ print("=" * 60)
270
+
271
+ # Core deps
272
+ print(f"\nCore dependencies: {len(core)}")
273
+ for dep in core:
274
+ print(f" - {dep}")
275
+
276
+ # Extras summary
277
+ print(f"\nExtras ({len(extras)}):")
278
+ for name, deps in sorted(extras.items()):
279
+ commented_count = len(commented.get(name, []))
280
+ suffix = f" (+{commented_count} commented)" if commented_count else ""
281
+ print(f" {name}: {len(deps)} deps{suffix}")
282
+
283
+ # Duplicates
284
+ if duplicates:
285
+ print(f"\nDuplicates ({len(duplicates)}):")
286
+ for dep, locations in sorted(duplicates.items()):
287
+ print(f" {dep}: {', '.join(locations)}")
288
+ else:
289
+ print("\nNo duplicates found")
290
+
291
+ # Heavy sync status
292
+ print("\nHeavy sync: ", end="")
293
+ if missing:
294
+ print(f"MISSING {len(missing)} deps")
295
+ for dep in missing:
296
+ print(f" - {dep}")
297
+ else:
298
+ print("OK")
299
+
300
+ print("=" * 60)
301
+
302
+
303
+ def add_to_extra(
304
+ extra_name: str,
305
+ deps: List[str],
306
+ path: Optional[Path] = None,
307
+ save_file: bool = False,
308
+ ) -> dict:
309
+ """
310
+ Add dependencies to an extra.
311
+
312
+ Parameters
313
+ ----------
314
+ extra_name : str
315
+ Name of the extra
316
+ deps : list
317
+ Dependencies to add
318
+ path : Path, optional
319
+ Path to pyproject.toml
320
+ save_file : bool
321
+ If True, save changes to file
322
+
323
+ Returns
324
+ -------
325
+ dict
326
+ Updated document
327
+ """
328
+ doc = load(path)
329
+ extras = doc["project"]["optional-dependencies"]
330
+
331
+ if extra_name not in extras:
332
+ extras[extra_name] = []
333
+
334
+ existing = set(extras[extra_name])
335
+ for dep in deps:
336
+ if dep not in existing:
337
+ extras[extra_name].append(dep)
338
+
339
+ if save_file:
340
+ save(doc, path)
341
+
342
+ return doc
343
+
344
+
345
+ def remove_from_extra(
346
+ extra_name: str,
347
+ deps: List[str],
348
+ path: Optional[Path] = None,
349
+ save_file: bool = False,
350
+ ) -> dict:
351
+ """
352
+ Remove dependencies from an extra.
353
+
354
+ Parameters
355
+ ----------
356
+ extra_name : str
357
+ Name of the extra
358
+ deps : list
359
+ Dependencies to remove
360
+ path : Path, optional
361
+ Path to pyproject.toml
362
+ save_file : bool
363
+ If True, save changes to file
364
+
365
+ Returns
366
+ -------
367
+ dict
368
+ Updated document
369
+ """
370
+ doc = load(path)
371
+ extras = doc["project"]["optional-dependencies"]
372
+
373
+ if extra_name in extras:
374
+ deps_set = set(deps)
375
+ extras[extra_name] = [d for d in extras[extra_name] if d not in deps_set]
376
+
377
+ if save_file:
378
+ save(doc, path)
379
+
380
+ return doc
381
+
382
+
383
+ # CLI interface
384
+ if __name__ == "__main__":
385
+ import sys
386
+
387
+ if len(sys.argv) > 1:
388
+ cmd = sys.argv[1]
389
+ if cmd == "report":
390
+ print_report()
391
+ elif cmd == "validate":
392
+ valid = validate_heavy_sync()
393
+ sys.exit(0 if valid else 1)
394
+ elif cmd == "duplicates":
395
+ dups = find_duplicates()
396
+ for dep, extras in sorted(dups.items()):
397
+ print(f"{dep}: {', '.join(extras)}")
398
+ else:
399
+ print(f"Unknown command: {cmd}")
400
+ print("Commands: report, validate, duplicates")
401
+ else:
402
+ print_report()
403
+
404
+
405
+ # EOF
@@ -16,8 +16,8 @@ Usage:
16
16
  from scitex.dev.plt import PLOTTERS_STX, PLOTTERS_SNS, PLOTTERS_MPL
17
17
 
18
18
  @stx.session
19
- def main(plt=stx.INJECTED, rng_manager=stx.INJECTED):
20
- rng = rng_manager("demo")
19
+ def main(plt=stx.INJECTED, rng=stx.INJECTED):
20
+ rng = rng("demo")
21
21
 
22
22
  # stx_* API (ArrayLike)
23
23
  for name, plotter in PLOTTERS_STX.items():
@@ -21,7 +21,7 @@ def main(
21
21
  CONFIG=stx.INJECTED,
22
22
  plt=stx.INJECTED,
23
23
  COLORS=stx.INJECTED,
24
- rng_manager=stx.INJECTED,
24
+ rng=stx.INJECTED,
25
25
  logger=stx.INJECTED,
26
26
  ):
27
27
  """Help message for `$ python __file__ --help`"""
@@ -146,7 +146,7 @@ def main(
146
146
  CONFIG=stx.INJECTED,
147
147
  plt=stx.INJECTED,
148
148
  COLORS=stx.INJECTED,
149
- rng_manager=stx.INJECTED,
149
+ rng=stx.INJECTED,
150
150
  logger=stx.INJECTED,
151
151
  ):
152
152
  """Inspect and display matplotlib plotting function signatures."""
@@ -492,7 +492,7 @@ def main(
492
492
  CONFIG=stx.INJECTED,
493
493
  plt=stx.INJECTED,
494
494
  COLORS=stx.INJECTED,
495
- rng_manager=stx.INJECTED,
495
+ rng=stx.INJECTED,
496
496
  logger=stx.INJECTED,
497
497
  ):
498
498
  """Extract signatures with flattened *args/**kwargs."""