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
scitex/cli/template.py ADDED
@@ -0,0 +1,236 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ SciTeX CLI - Template Commands (Project Scaffolding)
4
+
5
+ Provides project template cloning and management.
6
+ """
7
+
8
+ import sys
9
+ from pathlib import Path
10
+
11
+ import click
12
+
13
+
14
+ @click.group(context_settings={"help_option_names": ["-h", "--help"]})
15
+ def template():
16
+ """
17
+ Project template scaffolding
18
+
19
+ \b
20
+ Available templates:
21
+ research - Full scientific workflow structure
22
+ pip-project - Pip-installable Python package
23
+ singularity - Container-based project
24
+ paper - Academic paper writing template
25
+
26
+ \b
27
+ Examples:
28
+ scitex template list # Show available templates
29
+ scitex template clone research ./my-project # Clone research template
30
+ scitex template clone pip-project ./my-pkg # Clone package template
31
+ """
32
+ pass
33
+
34
+
35
+ @template.command(name="list")
36
+ @click.option("--json", "as_json", is_flag=True, help="Output as JSON")
37
+ def list_templates(as_json):
38
+ """
39
+ List available project templates
40
+
41
+ \b
42
+ Example:
43
+ scitex template list
44
+ scitex template list --json
45
+ """
46
+ try:
47
+ from scitex.template import get_available_templates_info
48
+
49
+ templates = get_available_templates_info()
50
+
51
+ if as_json:
52
+ import json
53
+
54
+ click.echo(json.dumps(templates, indent=2))
55
+ else:
56
+ click.secho("Available SciTeX Templates", fg="cyan", bold=True)
57
+ click.echo("=" * 60)
58
+
59
+ for tmpl in templates:
60
+ click.echo()
61
+ click.secho(f"{tmpl['name']} ({tmpl['id']})", fg="green", bold=True)
62
+ click.echo(f" {tmpl['description']}")
63
+ click.echo(f" Use case: {tmpl['use_case']}")
64
+ click.echo(f" GitHub: {tmpl['github_url']}")
65
+ if tmpl.get("features"):
66
+ click.echo(" Features:")
67
+ for feature in tmpl["features"][:3]: # Show first 3
68
+ click.echo(f" - {feature}")
69
+
70
+ except Exception as e:
71
+ click.secho(f"Error: {e}", fg="red", err=True)
72
+ sys.exit(1)
73
+
74
+
75
+ @template.command()
76
+ @click.argument(
77
+ "template_type",
78
+ type=click.Choice(["research", "pip-project", "singularity", "paper"]),
79
+ )
80
+ @click.argument("destination", type=click.Path())
81
+ @click.option(
82
+ "--git-strategy",
83
+ "-g",
84
+ type=click.Choice(["child", "parent", "origin", "none"]),
85
+ default="child",
86
+ help="Git initialization strategy (default: child)",
87
+ )
88
+ @click.option("--branch", "-b", help="Specific branch to clone")
89
+ @click.option("--tag", "-t", help="Specific tag/release to clone")
90
+ def clone(template_type, destination, git_strategy, branch, tag):
91
+ """
92
+ Clone a project template
93
+
94
+ \b
95
+ Template Types:
96
+ research - Full scientific workflow (scripts, data, docs, results)
97
+ pip-project - Python package (src, tests, docs, CI/CD)
98
+ singularity - Container-based (definition files, build scripts)
99
+ paper - Academic paper (LaTeX, BibTeX, figures)
100
+
101
+ \b
102
+ Git Strategies:
103
+ child - Create isolated git in project directory (default)
104
+ parent - Use parent git repository
105
+ origin - Preserve template's original git history
106
+ none - Disable git initialization
107
+
108
+ \b
109
+ Examples:
110
+ scitex template clone research ./my-research
111
+ scitex template clone pip-project ./my-package --git-strategy parent
112
+ scitex template clone paper ./manuscript --branch develop
113
+ """
114
+ try:
115
+ # Validate mutual exclusivity
116
+ if branch and tag:
117
+ click.echo("Error: Cannot specify both --branch and --tag", err=True)
118
+ sys.exit(1)
119
+
120
+ # Convert git_strategy 'none' to None
121
+ if git_strategy == "none":
122
+ git_strategy = None
123
+
124
+ # Map template types to clone functions
125
+ clone_funcs = {
126
+ "research": "clone_research",
127
+ "pip-project": "clone_pip_project",
128
+ "singularity": "clone_singularity",
129
+ "paper": "clone_writer_directory",
130
+ }
131
+
132
+ func_name = clone_funcs[template_type]
133
+
134
+ # Import the appropriate function
135
+ from scitex import template as tmpl_module
136
+
137
+ clone_func = getattr(tmpl_module, func_name)
138
+
139
+ click.echo(f"Cloning {template_type} template to {destination}...")
140
+
141
+ # Call clone function
142
+ kwargs = {"path": destination}
143
+ if git_strategy is not None:
144
+ kwargs["git_strategy"] = git_strategy
145
+ if branch:
146
+ kwargs["branch"] = branch
147
+ if tag:
148
+ kwargs["tag"] = tag
149
+
150
+ result = clone_func(**kwargs)
151
+
152
+ if result:
153
+ dest_path = Path(destination).absolute()
154
+ click.secho("Successfully cloned template!", fg="green")
155
+ click.echo()
156
+ click.echo(f"Location: {dest_path}")
157
+ click.echo()
158
+ click.echo("Next steps:")
159
+ click.echo(f" cd {destination}")
160
+
161
+ if template_type == "research":
162
+ click.echo(" # Start your research project")
163
+ click.echo(" # Edit scripts/, data/, docs/")
164
+ elif template_type == "pip-project":
165
+ click.echo(" # Develop your package")
166
+ click.echo(" pip install -e .")
167
+ click.echo(" pytest")
168
+ elif template_type == "singularity":
169
+ click.echo(" # Build your container")
170
+ click.echo(" singularity build container.sif Singularity.def")
171
+ elif template_type == "paper":
172
+ click.echo(" # Write your paper")
173
+ click.echo(" scitex writer compile manuscript")
174
+ else:
175
+ click.secho("Failed to clone template", fg="red", err=True)
176
+ sys.exit(1)
177
+
178
+ except Exception as e:
179
+ click.secho(f"Error: {e}", fg="red", err=True)
180
+ sys.exit(1)
181
+
182
+
183
+ @template.command()
184
+ @click.argument("template_id")
185
+ def info(template_id):
186
+ """
187
+ Show detailed information about a template
188
+
189
+ \b
190
+ Example:
191
+ scitex template info research
192
+ scitex template info pip-project
193
+ """
194
+ try:
195
+ from scitex.template import get_available_templates_info
196
+
197
+ templates = get_available_templates_info()
198
+
199
+ # Find matching template
200
+ template_info = None
201
+ for tmpl in templates:
202
+ if tmpl["id"] == template_id or tmpl["name"].lower() == template_id.lower():
203
+ template_info = tmpl
204
+ break
205
+
206
+ if not template_info:
207
+ click.secho(f"Template '{template_id}' not found", fg="red", err=True)
208
+ click.echo("Available templates:")
209
+ for tmpl in templates:
210
+ click.echo(f" - {tmpl['id']}")
211
+ sys.exit(1)
212
+
213
+ click.secho(f"Template: {template_info['name']}", fg="cyan", bold=True)
214
+ click.echo("=" * 50)
215
+ click.echo()
216
+ click.echo(f"ID: {template_info['id']}")
217
+ click.echo(f"Description: {template_info['description']}")
218
+ click.echo(f"Use case: {template_info['use_case']}")
219
+ click.echo(f"GitHub: {template_info['github_url']}")
220
+ click.echo()
221
+ click.secho("Features:", fg="yellow")
222
+ for feature in template_info.get("features", []):
223
+ click.echo(f" - {feature}")
224
+ click.echo()
225
+ click.echo("Clone with:")
226
+ click.secho(
227
+ f" scitex template clone {template_info['id']} ./my-project", fg="green"
228
+ )
229
+
230
+ except Exception as e:
231
+ click.secho(f"Error: {e}", fg="red", err=True)
232
+ sys.exit(1)
233
+
234
+
235
+ if __name__ == "__main__":
236
+ template()
scitex/cli/tex.py ADDED
@@ -0,0 +1,286 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ SciTeX CLI - TeX Commands (LaTeX Operations)
4
+
5
+ Provides LaTeX compilation and preview utilities.
6
+ """
7
+
8
+ import sys
9
+ from pathlib import Path
10
+
11
+ import click
12
+
13
+
14
+ @click.group(context_settings={"help_option_names": ["-h", "--help"]})
15
+ def tex():
16
+ """
17
+ LaTeX compilation and utilities
18
+
19
+ \b
20
+ Commands:
21
+ compile Compile LaTeX document to PDF
22
+ preview Preview LaTeX document
23
+ to-vec Convert to vector format (SVG/PDF)
24
+
25
+ \b
26
+ Examples:
27
+ scitex tex compile paper.tex
28
+ scitex tex preview paper.tex
29
+ scitex tex to-vec figure.tex --format svg
30
+ """
31
+ pass
32
+
33
+
34
+ @tex.command()
35
+ @click.argument("tex_file", type=click.Path(exists=True))
36
+ @click.option("--output", "-o", type=click.Path(), help="Output PDF path")
37
+ @click.option(
38
+ "--engine",
39
+ "-e",
40
+ type=click.Choice(["pdflatex", "xelatex", "lualatex"]),
41
+ default="pdflatex",
42
+ help="LaTeX engine (default: pdflatex)",
43
+ )
44
+ @click.option(
45
+ "--clean", "-c", is_flag=True, help="Clean auxiliary files after compilation"
46
+ )
47
+ @click.option(
48
+ "--timeout",
49
+ type=int,
50
+ default=300,
51
+ help="Compilation timeout in seconds (default: 300)",
52
+ )
53
+ @click.option("--verbose", "-v", is_flag=True, help="Show detailed compilation output")
54
+ def compile(tex_file, output, engine, clean, timeout, verbose):
55
+ """
56
+ Compile LaTeX document to PDF
57
+
58
+ \b
59
+ Examples:
60
+ scitex tex compile paper.tex
61
+ scitex tex compile paper.tex --output ./output/paper.pdf
62
+ scitex tex compile paper.tex --engine xelatex
63
+ scitex tex compile paper.tex --clean --verbose
64
+ """
65
+ try:
66
+ from scitex.tex import compile_tex
67
+
68
+ path = Path(tex_file)
69
+ click.echo(f"Compiling: {path.name}")
70
+
71
+ result = compile_tex(
72
+ tex_path=path,
73
+ output_path=output,
74
+ engine=engine,
75
+ timeout=timeout,
76
+ )
77
+
78
+ if result.success:
79
+ click.secho("Compilation successful!", fg="green")
80
+ click.echo(f"PDF: {result.output_pdf}")
81
+
82
+ if clean:
83
+ # Clean auxiliary files
84
+ aux_extensions = [
85
+ ".aux",
86
+ ".log",
87
+ ".out",
88
+ ".toc",
89
+ ".bbl",
90
+ ".blg",
91
+ ".fls",
92
+ ".fdb_latexmk",
93
+ ]
94
+ for ext in aux_extensions:
95
+ aux_file = path.with_suffix(ext)
96
+ if aux_file.exists():
97
+ aux_file.unlink()
98
+ click.echo("Auxiliary files cleaned")
99
+ else:
100
+ click.secho(
101
+ f"Compilation failed (exit code {result.exit_code})", fg="red", err=True
102
+ )
103
+ if result.errors and verbose:
104
+ click.echo("\nErrors:")
105
+ for error in result.errors[:10]:
106
+ click.echo(f" {error}")
107
+ sys.exit(result.exit_code)
108
+
109
+ except Exception as e:
110
+ click.secho(f"Error: {e}", fg="red", err=True)
111
+ sys.exit(1)
112
+
113
+
114
+ @tex.command()
115
+ @click.argument("tex_file", type=click.Path(exists=True))
116
+ @click.option("--viewer", "-v", help="PDF viewer to use (default: system default)")
117
+ def preview(tex_file, viewer):
118
+ """
119
+ Preview LaTeX document (compile and open)
120
+
121
+ \b
122
+ Examples:
123
+ scitex tex preview paper.tex
124
+ scitex tex preview paper.tex --viewer evince
125
+ """
126
+ try:
127
+ from scitex.tex import preview as tex_preview
128
+
129
+ path = Path(tex_file)
130
+ click.echo(f"Previewing: {path.name}")
131
+
132
+ tex_preview(path, viewer=viewer)
133
+
134
+ except Exception as e:
135
+ click.secho(f"Error: {e}", fg="red", err=True)
136
+ sys.exit(1)
137
+
138
+
139
+ @tex.command("to-vec")
140
+ @click.argument("tex_file", type=click.Path(exists=True))
141
+ @click.option(
142
+ "--format",
143
+ "-f",
144
+ "fmt",
145
+ type=click.Choice(["svg", "pdf", "eps"]),
146
+ default="svg",
147
+ help="Output format (default: svg)",
148
+ )
149
+ @click.option("--output", "-o", type=click.Path(), help="Output file path")
150
+ def to_vec(tex_file, fmt, output):
151
+ """
152
+ Convert LaTeX to vector format
153
+
154
+ \b
155
+ Useful for embedding equations and figures in other documents.
156
+
157
+ \b
158
+ Examples:
159
+ scitex tex to-vec equation.tex
160
+ scitex tex to-vec equation.tex --format pdf
161
+ scitex tex to-vec figure.tex --output ./vectors/fig.svg
162
+ """
163
+ try:
164
+ from scitex.tex import to_vec as convert_to_vec
165
+
166
+ path = Path(tex_file)
167
+ click.echo(f"Converting: {path.name} -> {fmt.upper()}")
168
+
169
+ if output:
170
+ output_path = Path(output)
171
+ else:
172
+ output_path = path.with_suffix(f".{fmt}")
173
+
174
+ result = convert_to_vec(path, output_path, format=fmt)
175
+
176
+ if result:
177
+ click.secho("Conversion successful!", fg="green")
178
+ click.echo(f"Output: {result}")
179
+ else:
180
+ click.secho("Conversion failed", fg="red", err=True)
181
+ sys.exit(1)
182
+
183
+ except Exception as e:
184
+ click.secho(f"Error: {e}", fg="red", err=True)
185
+ sys.exit(1)
186
+
187
+
188
+ @tex.command()
189
+ @click.argument("tex_file", type=click.Path(exists=True))
190
+ def check(tex_file):
191
+ """
192
+ Check LaTeX document for common issues
193
+
194
+ \b
195
+ Checks:
196
+ - Missing packages
197
+ - Undefined references
198
+ - Overfull/underfull boxes
199
+ - Citation warnings
200
+
201
+ \b
202
+ Example:
203
+ scitex tex check paper.tex
204
+ """
205
+ try:
206
+ import subprocess
207
+ from pathlib import Path
208
+
209
+ path = Path(tex_file)
210
+ click.echo(f"Checking: {path.name}")
211
+
212
+ # Run LaTeX in draft mode to check
213
+ result = subprocess.run(
214
+ ["pdflatex", "-draftmode", "-interaction=nonstopmode", str(path)],
215
+ capture_output=True,
216
+ text=True,
217
+ cwd=path.parent,
218
+ timeout=60,
219
+ )
220
+
221
+ # Parse log for issues
222
+ log_file = path.with_suffix(".log")
223
+ issues = {
224
+ "warnings": [],
225
+ "errors": [],
226
+ "overfull": [],
227
+ "undefined": [],
228
+ }
229
+
230
+ if log_file.exists():
231
+ with open(log_file) as f:
232
+ for line in f:
233
+ if "Warning:" in line:
234
+ issues["warnings"].append(line.strip())
235
+ elif "Error:" in line or "!" in line[:2]:
236
+ issues["errors"].append(line.strip())
237
+ elif "Overfull" in line or "Underfull" in line:
238
+ issues["overfull"].append(line.strip())
239
+ elif "undefined" in line.lower():
240
+ issues["undefined"].append(line.strip())
241
+
242
+ # Report
243
+ total_issues = sum(len(v) for v in issues.values())
244
+
245
+ if total_issues == 0:
246
+ click.secho("No issues found!", fg="green")
247
+ else:
248
+ click.secho(f"Found {total_issues} issue(s):", fg="yellow")
249
+
250
+ if issues["errors"]:
251
+ click.secho(f"\nErrors ({len(issues['errors'])}):", fg="red")
252
+ for err in issues["errors"][:5]:
253
+ click.echo(f" {err}")
254
+
255
+ if issues["undefined"]:
256
+ click.secho(
257
+ f"\nUndefined References ({len(issues['undefined'])}):", fg="yellow"
258
+ )
259
+ for ref in issues["undefined"][:5]:
260
+ click.echo(f" {ref}")
261
+
262
+ if issues["overfull"]:
263
+ click.secho(
264
+ f"\nOverfull/Underfull Boxes ({len(issues['overfull'])}):",
265
+ fg="yellow",
266
+ )
267
+ for box in issues["overfull"][:5]:
268
+ click.echo(f" {box}")
269
+
270
+ if issues["warnings"]:
271
+ click.secho(f"\nWarnings ({len(issues['warnings'])}):", fg="yellow")
272
+ for warn in issues["warnings"][:5]:
273
+ click.echo(f" {warn}")
274
+
275
+ except subprocess.TimeoutExpired:
276
+ click.secho("Check timed out", fg="yellow")
277
+ except FileNotFoundError:
278
+ click.secho("Error: pdflatex not found. Install TeX Live.", fg="red", err=True)
279
+ sys.exit(1)
280
+ except Exception as e:
281
+ click.secho(f"Error: {e}", fg="red", err=True)
282
+ sys.exit(1)
283
+
284
+
285
+ if __name__ == "__main__":
286
+ tex()
scitex/cli/web.py CHANGED
@@ -1,20 +1,18 @@
1
1
  #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
2
  """
4
3
  SciTeX CLI - Web Scraping Commands
5
4
  """
6
5
 
7
- import os
6
+ import subprocess
8
7
  import sys
9
- import click
8
+ from datetime import datetime
10
9
  from pathlib import Path
11
10
 
12
- from scitex.web import get_urls, download_images, get_image_urls
13
- from scitex.web._scraping import _get_default_download_dir
11
+ import click
12
+
14
13
  from scitex.logging import getLogger
15
- import subprocess
16
- import json
17
- from datetime import datetime
14
+ from scitex.web import download_images, get_image_urls, get_urls
15
+ from scitex.web.download_images import _get_default_download_dir
18
16
 
19
17
  logger = getLogger(__name__)
20
18
 
@@ -34,7 +32,7 @@ def web():
34
32
  \b
35
33
  Examples:
36
34
  scitex web get-urls https://example.com
37
- scitex web get-urls https://example.com --pattern "\.pdf$"
35
+ scitex web get-urls https://example.com --pattern "\\.pdf$"
38
36
  scitex web get-image-urls https://example.com
39
37
  scitex web download-images https://example.com --output ./downloads
40
38
  scitex web download-images https://example.com --min-size 100x100
@@ -195,7 +193,7 @@ def download_images_cmd(url, output, pattern, min_size, same_domain, max_workers
195
193
  min_size_tuple = (width, height)
196
194
  except ValueError:
197
195
  click.secho(
198
- f"ERROR: Invalid min-size format. Use WIDTHxHEIGHT (e.g., '100x100')",
196
+ "ERROR: Invalid min-size format. Use WIDTHxHEIGHT (e.g., '100x100')",
199
197
  fg="red",
200
198
  err=True,
201
199
  )
@@ -301,6 +299,7 @@ def take_screenshot_cmd(url, output, message, quality, full_page):
301
299
  try:
302
300
  # For now, we'll use a simpler approach with playwright directly
303
301
  import asyncio
302
+
304
303
  from playwright.async_api import async_playwright
305
304
 
306
305
  async def capture():
@@ -322,7 +321,7 @@ def take_screenshot_cmd(url, output, message, quality, full_page):
322
321
  asyncio.run(capture())
323
322
 
324
323
  if output_file.exists():
325
- click.secho(f"Screenshot saved successfully", fg="green")
324
+ click.secho("Screenshot saved successfully", fg="green")
326
325
  click.echo(f"Location: {output_file}")
327
326
  sys.exit(0)
328
327
  else:
@@ -340,7 +339,7 @@ def take_screenshot_cmd(url, output, message, quality, full_page):
340
339
  )
341
340
 
342
341
  if result.returncode == 0 and output_file.exists():
343
- click.secho(f"Screenshot saved successfully", fg="green")
342
+ click.secho("Screenshot saved successfully", fg="green")
344
343
  click.echo(f"Location: {output_file}")
345
344
  sys.exit(0)
346
345
  else:
scitex/dev/__init__.py CHANGED
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env python3
2
2
  """Scitex dev module."""
3
3
 
4
+ # Pyproject utilities (lazy import to avoid tomlkit dependency)
5
+ from . import _pyproject as pyproject
4
6
  from ._analyze_code_flow import CodeFlowAnalyzer, analyze_code_flow, main, parse_args
5
7
  from ._reload import reload, reload_auto, reload_stop
6
8
 
@@ -12,4 +14,5 @@ __all__ = [
12
14
  "reload",
13
15
  "reload_auto",
14
16
  "reload_stop",
17
+ "pyproject",
15
18
  ]