scitex 2.16.0__py3-none-any.whl → 2.16.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- scitex/_mcp_tools/audio.py +11 -65
- scitex/audio/README.md +40 -12
- scitex/audio/__init__.py +27 -235
- scitex/audio/_audio_check.py +93 -0
- scitex/audio/_mcp/speak_handlers.py +56 -8
- scitex/audio/_speak.py +295 -0
- scitex/audio/mcp_server.py +98 -73
- scitex/social/__init__.py +1 -24
- scitex/writer/README.md +25 -409
- scitex/writer/__init__.py +98 -13
- {scitex-2.16.0.dist-info → scitex-2.16.1.dist-info}/METADATA +6 -1
- {scitex-2.16.0.dist-info → scitex-2.16.1.dist-info}/RECORD +15 -62
- scitex/writer/Writer.py +0 -487
- scitex/writer/_clone_writer_project.py +0 -160
- scitex/writer/_compile/__init__.py +0 -41
- scitex/writer/_compile/_compile_async.py +0 -130
- scitex/writer/_compile/_compile_unified.py +0 -148
- scitex/writer/_compile/_parser.py +0 -63
- scitex/writer/_compile/_runner.py +0 -457
- scitex/writer/_compile/_validator.py +0 -46
- scitex/writer/_compile/manuscript.py +0 -110
- scitex/writer/_compile/revision.py +0 -82
- scitex/writer/_compile/supplementary.py +0 -100
- scitex/writer/_dataclasses/__init__.py +0 -44
- scitex/writer/_dataclasses/config/_CONSTANTS.py +0 -46
- scitex/writer/_dataclasses/config/_WriterConfig.py +0 -175
- scitex/writer/_dataclasses/config/__init__.py +0 -9
- scitex/writer/_dataclasses/contents/_ManuscriptContents.py +0 -236
- scitex/writer/_dataclasses/contents/_RevisionContents.py +0 -136
- scitex/writer/_dataclasses/contents/_SupplementaryContents.py +0 -114
- scitex/writer/_dataclasses/contents/__init__.py +0 -9
- scitex/writer/_dataclasses/core/_Document.py +0 -146
- scitex/writer/_dataclasses/core/_DocumentSection.py +0 -546
- scitex/writer/_dataclasses/core/__init__.py +0 -7
- scitex/writer/_dataclasses/results/_CompilationResult.py +0 -165
- scitex/writer/_dataclasses/results/_LaTeXIssue.py +0 -102
- scitex/writer/_dataclasses/results/_SaveSectionsResponse.py +0 -118
- scitex/writer/_dataclasses/results/_SectionReadResponse.py +0 -131
- scitex/writer/_dataclasses/results/__init__.py +0 -11
- scitex/writer/_dataclasses/tree/MINIMUM_FILES.md +0 -121
- scitex/writer/_dataclasses/tree/_ConfigTree.py +0 -86
- scitex/writer/_dataclasses/tree/_ManuscriptTree.py +0 -84
- scitex/writer/_dataclasses/tree/_RevisionTree.py +0 -97
- scitex/writer/_dataclasses/tree/_ScriptsTree.py +0 -118
- scitex/writer/_dataclasses/tree/_SharedTree.py +0 -100
- scitex/writer/_dataclasses/tree/_SupplementaryTree.py +0 -101
- scitex/writer/_dataclasses/tree/__init__.py +0 -23
- scitex/writer/_mcp/__init__.py +0 -4
- scitex/writer/_mcp/handlers.py +0 -32
- scitex/writer/_mcp/tool_schemas.py +0 -33
- scitex/writer/_project/__init__.py +0 -29
- scitex/writer/_project/_create.py +0 -89
- scitex/writer/_project/_trees.py +0 -63
- scitex/writer/_project/_validate.py +0 -61
- scitex/writer/utils/.legacy_git_retry.py +0 -164
- scitex/writer/utils/__init__.py +0 -24
- scitex/writer/utils/_converters.py +0 -635
- scitex/writer/utils/_parse_latex_logs.py +0 -138
- scitex/writer/utils/_parse_script_args.py +0 -156
- scitex/writer/utils/_verify_tree_structure.py +0 -205
- scitex/writer/utils/_watch.py +0 -96
- {scitex-2.16.0.dist-info → scitex-2.16.1.dist-info}/WHEEL +0 -0
- {scitex-2.16.0.dist-info → scitex-2.16.1.dist-info}/entry_points.txt +0 -0
- {scitex-2.16.0.dist-info → scitex-2.16.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,457 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
# Timestamp: "2025-10-29 (ywatanabe)"
|
|
4
|
-
# File: /home/ywatanabe/proj/scitex-code/src/scitex/writer/_compile/_runner.py
|
|
5
|
-
# ----------------------------------------
|
|
6
|
-
from __future__ import annotations
|
|
7
|
-
import os
|
|
8
|
-
|
|
9
|
-
__FILE__ = "./src/scitex/writer/_compile/_runner.py"
|
|
10
|
-
__DIR__ = os.path.dirname(__FILE__)
|
|
11
|
-
# ----------------------------------------
|
|
12
|
-
|
|
13
|
-
"""
|
|
14
|
-
Compilation script execution.
|
|
15
|
-
|
|
16
|
-
Executes LaTeX compilation scripts and captures results.
|
|
17
|
-
"""
|
|
18
|
-
|
|
19
|
-
from pathlib import Path
|
|
20
|
-
from datetime import datetime
|
|
21
|
-
from typing import Optional, Callable
|
|
22
|
-
import subprocess
|
|
23
|
-
import time
|
|
24
|
-
import fcntl
|
|
25
|
-
|
|
26
|
-
from scitex.logging import getLogger
|
|
27
|
-
from scitex.sh import sh
|
|
28
|
-
from scitex.writer._dataclasses.config import DOC_TYPE_DIRS
|
|
29
|
-
from scitex.writer._dataclasses import CompilationResult
|
|
30
|
-
from ._validator import validate_before_compile
|
|
31
|
-
from ._parser import parse_output
|
|
32
|
-
|
|
33
|
-
logger = getLogger(__name__)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def _get_compile_script(project_dir: Path, doc_type: str) -> Path:
|
|
37
|
-
"""
|
|
38
|
-
Get compile script path for document type.
|
|
39
|
-
|
|
40
|
-
Parameters
|
|
41
|
-
----------
|
|
42
|
-
project_dir : Path
|
|
43
|
-
Path to project directory
|
|
44
|
-
doc_type : str
|
|
45
|
-
Document type ('manuscript', 'supplementary', 'revision')
|
|
46
|
-
|
|
47
|
-
Returns
|
|
48
|
-
-------
|
|
49
|
-
Path
|
|
50
|
-
Path to compilation script
|
|
51
|
-
"""
|
|
52
|
-
script_map = {
|
|
53
|
-
"manuscript": project_dir / "scripts" / "shell" / "compile_manuscript.sh",
|
|
54
|
-
"supplementary": project_dir / "scripts" / "shell" / "compile_supplementary.sh",
|
|
55
|
-
"revision": project_dir / "scripts" / "shell" / "compile_revision.sh",
|
|
56
|
-
}
|
|
57
|
-
return script_map.get(doc_type)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
def _find_output_files(
|
|
61
|
-
project_dir: Path,
|
|
62
|
-
doc_type: str,
|
|
63
|
-
) -> tuple:
|
|
64
|
-
"""
|
|
65
|
-
Find generated output files after compilation.
|
|
66
|
-
|
|
67
|
-
Parameters
|
|
68
|
-
----------
|
|
69
|
-
project_dir : Path
|
|
70
|
-
Path to project directory
|
|
71
|
-
doc_type : str
|
|
72
|
-
Document type
|
|
73
|
-
|
|
74
|
-
Returns
|
|
75
|
-
-------
|
|
76
|
-
tuple
|
|
77
|
-
(output_pdf, diff_pdf, log_file)
|
|
78
|
-
"""
|
|
79
|
-
doc_dir = project_dir / DOC_TYPE_DIRS[doc_type]
|
|
80
|
-
|
|
81
|
-
# Find generated PDF
|
|
82
|
-
pdf_name = f"{doc_type}.pdf"
|
|
83
|
-
potential_pdf = doc_dir / pdf_name
|
|
84
|
-
output_pdf = potential_pdf if potential_pdf.exists() else None
|
|
85
|
-
|
|
86
|
-
# Check for diff PDF
|
|
87
|
-
diff_name = f"{doc_type}_diff.pdf"
|
|
88
|
-
potential_diff = doc_dir / diff_name
|
|
89
|
-
diff_pdf = potential_diff if potential_diff.exists() else None
|
|
90
|
-
|
|
91
|
-
# Find log file
|
|
92
|
-
log_dir = doc_dir / "logs"
|
|
93
|
-
log_file = None
|
|
94
|
-
if log_dir.exists():
|
|
95
|
-
log_files = list(log_dir.glob("*.log"))
|
|
96
|
-
if log_files:
|
|
97
|
-
log_file = max(log_files, key=lambda p: p.stat().st_mtime)
|
|
98
|
-
|
|
99
|
-
return output_pdf, diff_pdf, log_file
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
def _execute_with_callbacks(
|
|
103
|
-
command: list,
|
|
104
|
-
cwd: Path,
|
|
105
|
-
timeout: int,
|
|
106
|
-
log_callback: Optional[Callable[[str], None]] = None,
|
|
107
|
-
) -> dict:
|
|
108
|
-
"""
|
|
109
|
-
Execute command with line-by-line output capture and callbacks.
|
|
110
|
-
|
|
111
|
-
Parameters
|
|
112
|
-
----------
|
|
113
|
-
command : list
|
|
114
|
-
Command to execute as list
|
|
115
|
-
cwd : Path
|
|
116
|
-
Working directory
|
|
117
|
-
timeout : int
|
|
118
|
-
Timeout in seconds
|
|
119
|
-
log_callback : Optional[Callable[[str], None]]
|
|
120
|
-
Called with each output line
|
|
121
|
-
|
|
122
|
-
Returns
|
|
123
|
-
-------
|
|
124
|
-
dict
|
|
125
|
-
Dict with stdout, stderr, exit_code, success
|
|
126
|
-
"""
|
|
127
|
-
# Set environment for unbuffered output
|
|
128
|
-
env = os.environ.copy()
|
|
129
|
-
env["PYTHONUNBUFFERED"] = "1"
|
|
130
|
-
|
|
131
|
-
process = subprocess.Popen(
|
|
132
|
-
command,
|
|
133
|
-
shell=False,
|
|
134
|
-
stdout=subprocess.PIPE,
|
|
135
|
-
stderr=subprocess.PIPE,
|
|
136
|
-
bufsize=0, # Unbuffered
|
|
137
|
-
cwd=str(cwd),
|
|
138
|
-
env=env,
|
|
139
|
-
)
|
|
140
|
-
|
|
141
|
-
stdout_lines = []
|
|
142
|
-
stderr_lines = []
|
|
143
|
-
start_time = time.time()
|
|
144
|
-
|
|
145
|
-
# Make file descriptors non-blocking
|
|
146
|
-
def make_non_blocking(fd):
|
|
147
|
-
flags = fcntl.fcntl(fd, fcntl.F_GETFL)
|
|
148
|
-
fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
|
|
149
|
-
|
|
150
|
-
make_non_blocking(process.stdout)
|
|
151
|
-
make_non_blocking(process.stderr)
|
|
152
|
-
|
|
153
|
-
stdout_buffer = b""
|
|
154
|
-
stderr_buffer = b""
|
|
155
|
-
|
|
156
|
-
try:
|
|
157
|
-
while True:
|
|
158
|
-
# Check timeout
|
|
159
|
-
if timeout and (time.time() - start_time) > timeout:
|
|
160
|
-
process.kill()
|
|
161
|
-
timeout_msg = f"[ERROR] Command timed out after {timeout} seconds"
|
|
162
|
-
if log_callback:
|
|
163
|
-
log_callback(timeout_msg)
|
|
164
|
-
stderr_lines.append(timeout_msg)
|
|
165
|
-
break
|
|
166
|
-
|
|
167
|
-
# Check if process has finished
|
|
168
|
-
poll_result = process.poll()
|
|
169
|
-
|
|
170
|
-
# Read from stdout
|
|
171
|
-
try:
|
|
172
|
-
chunk = process.stdout.read()
|
|
173
|
-
if chunk:
|
|
174
|
-
stdout_buffer += chunk
|
|
175
|
-
# Process complete lines
|
|
176
|
-
while b"\n" in stdout_buffer:
|
|
177
|
-
line, stdout_buffer = stdout_buffer.split(b"\n", 1)
|
|
178
|
-
line_str = line.decode("utf-8", errors="replace")
|
|
179
|
-
stdout_lines.append(line_str)
|
|
180
|
-
if log_callback:
|
|
181
|
-
log_callback(line_str)
|
|
182
|
-
except (IOError, BlockingIOError):
|
|
183
|
-
pass
|
|
184
|
-
|
|
185
|
-
# Read from stderr
|
|
186
|
-
try:
|
|
187
|
-
chunk = process.stderr.read()
|
|
188
|
-
if chunk:
|
|
189
|
-
stderr_buffer += chunk
|
|
190
|
-
# Process complete lines
|
|
191
|
-
while b"\n" in stderr_buffer:
|
|
192
|
-
line, stderr_buffer = stderr_buffer.split(b"\n", 1)
|
|
193
|
-
line_str = line.decode("utf-8", errors="replace")
|
|
194
|
-
stderr_lines.append(line_str)
|
|
195
|
-
if log_callback:
|
|
196
|
-
log_callback(f"[STDERR] {line_str}")
|
|
197
|
-
except (IOError, BlockingIOError):
|
|
198
|
-
pass
|
|
199
|
-
|
|
200
|
-
# If process finished, do final read and break
|
|
201
|
-
if poll_result is not None:
|
|
202
|
-
# Process remaining buffer content
|
|
203
|
-
if stdout_buffer:
|
|
204
|
-
line_str = stdout_buffer.decode("utf-8", errors="replace")
|
|
205
|
-
stdout_lines.append(line_str)
|
|
206
|
-
if log_callback:
|
|
207
|
-
log_callback(line_str)
|
|
208
|
-
|
|
209
|
-
if stderr_buffer:
|
|
210
|
-
line_str = stderr_buffer.decode("utf-8", errors="replace")
|
|
211
|
-
stderr_lines.append(line_str)
|
|
212
|
-
if log_callback:
|
|
213
|
-
log_callback(f"[STDERR] {line_str}")
|
|
214
|
-
|
|
215
|
-
break
|
|
216
|
-
|
|
217
|
-
# Small sleep to prevent CPU spinning
|
|
218
|
-
time.sleep(0.05)
|
|
219
|
-
|
|
220
|
-
except Exception as e:
|
|
221
|
-
process.kill()
|
|
222
|
-
raise
|
|
223
|
-
|
|
224
|
-
return {
|
|
225
|
-
"stdout": "\n".join(stdout_lines),
|
|
226
|
-
"stderr": "\n".join(stderr_lines),
|
|
227
|
-
"exit_code": process.returncode,
|
|
228
|
-
"success": process.returncode == 0,
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
def run_compile(
|
|
233
|
-
doc_type: str,
|
|
234
|
-
project_dir: Path,
|
|
235
|
-
timeout: int = 300,
|
|
236
|
-
track_changes: bool = False,
|
|
237
|
-
no_figs: bool = False,
|
|
238
|
-
ppt2tif: bool = False,
|
|
239
|
-
crop_tif: bool = False,
|
|
240
|
-
quiet: bool = False,
|
|
241
|
-
verbose: bool = False,
|
|
242
|
-
force: bool = False,
|
|
243
|
-
log_callback: Optional[Callable[[str], None]] = None,
|
|
244
|
-
progress_callback: Optional[Callable[[int, str], None]] = None,
|
|
245
|
-
) -> CompilationResult:
|
|
246
|
-
"""
|
|
247
|
-
Run compilation script and parse results with optional callbacks.
|
|
248
|
-
|
|
249
|
-
Parameters
|
|
250
|
-
----------
|
|
251
|
-
doc_type : str
|
|
252
|
-
Document type ('manuscript', 'supplementary', 'revision')
|
|
253
|
-
project_dir : Path
|
|
254
|
-
Path to project directory (containing 01_manuscript/, etc.)
|
|
255
|
-
timeout : int
|
|
256
|
-
Timeout in seconds
|
|
257
|
-
track_changes : bool
|
|
258
|
-
Enable change tracking (revision only)
|
|
259
|
-
no_figs : bool
|
|
260
|
-
Exclude figures for quick compilation (manuscript only)
|
|
261
|
-
ppt2tif : bool
|
|
262
|
-
Convert PowerPoint to TIF on WSL
|
|
263
|
-
crop_tif : bool
|
|
264
|
-
Crop TIF images to remove excess whitespace
|
|
265
|
-
quiet : bool
|
|
266
|
-
Suppress detailed logs for LaTeX compilation
|
|
267
|
-
verbose : bool
|
|
268
|
-
Show detailed logs for LaTeX compilation
|
|
269
|
-
force : bool
|
|
270
|
-
Force full recompilation, ignore cache (manuscript only)
|
|
271
|
-
log_callback : Optional[Callable[[str], None]]
|
|
272
|
-
Called with each log line
|
|
273
|
-
progress_callback : Optional[Callable[[int, str], None]]
|
|
274
|
-
Called with progress updates (percent, step)
|
|
275
|
-
|
|
276
|
-
Returns
|
|
277
|
-
-------
|
|
278
|
-
CompilationResult
|
|
279
|
-
Compilation status and outputs
|
|
280
|
-
"""
|
|
281
|
-
start_time = datetime.now()
|
|
282
|
-
project_dir = Path(project_dir).absolute()
|
|
283
|
-
|
|
284
|
-
# Helper for progress tracking
|
|
285
|
-
def progress(percent: int, step: str):
|
|
286
|
-
if progress_callback:
|
|
287
|
-
progress_callback(percent, step)
|
|
288
|
-
logger.info(f"Progress: {percent}% - {step}")
|
|
289
|
-
|
|
290
|
-
# Helper for logging
|
|
291
|
-
def log(message: str):
|
|
292
|
-
if log_callback:
|
|
293
|
-
log_callback(message)
|
|
294
|
-
logger.info(message)
|
|
295
|
-
|
|
296
|
-
# Progress: Starting
|
|
297
|
-
progress(0, "Starting compilation...")
|
|
298
|
-
log("[INFO] Starting LaTeX compilation...")
|
|
299
|
-
|
|
300
|
-
# Validate project structure before compilation
|
|
301
|
-
try:
|
|
302
|
-
progress(5, "Validating project structure...")
|
|
303
|
-
validate_before_compile(project_dir)
|
|
304
|
-
log("[INFO] Project structure validated")
|
|
305
|
-
except Exception as e:
|
|
306
|
-
error_msg = f"[ERROR] Validation failed: {e}"
|
|
307
|
-
log(error_msg)
|
|
308
|
-
return CompilationResult(
|
|
309
|
-
success=False,
|
|
310
|
-
exit_code=1,
|
|
311
|
-
stdout="",
|
|
312
|
-
stderr=str(e),
|
|
313
|
-
duration=0.0,
|
|
314
|
-
)
|
|
315
|
-
|
|
316
|
-
# Get compile script
|
|
317
|
-
compile_script = _get_compile_script(project_dir, doc_type)
|
|
318
|
-
if not compile_script or not compile_script.exists():
|
|
319
|
-
error_msg = f"[ERROR] Compilation script not found: {compile_script}"
|
|
320
|
-
log(error_msg)
|
|
321
|
-
return CompilationResult(
|
|
322
|
-
success=False,
|
|
323
|
-
exit_code=127,
|
|
324
|
-
stdout="",
|
|
325
|
-
stderr=error_msg,
|
|
326
|
-
duration=0.0,
|
|
327
|
-
)
|
|
328
|
-
|
|
329
|
-
# Build command
|
|
330
|
-
progress(10, "Preparing compilation command...")
|
|
331
|
-
script_path = compile_script.absolute()
|
|
332
|
-
cmd = [str(script_path)]
|
|
333
|
-
|
|
334
|
-
# Add document-specific options
|
|
335
|
-
if doc_type == "revision":
|
|
336
|
-
if track_changes:
|
|
337
|
-
cmd.append("--track-changes")
|
|
338
|
-
|
|
339
|
-
elif doc_type == "manuscript":
|
|
340
|
-
if no_figs:
|
|
341
|
-
cmd.append("--no_figs")
|
|
342
|
-
if ppt2tif:
|
|
343
|
-
cmd.append("--ppt2tif")
|
|
344
|
-
if crop_tif:
|
|
345
|
-
cmd.append("--crop_tif")
|
|
346
|
-
if quiet:
|
|
347
|
-
cmd.append("--quiet")
|
|
348
|
-
elif verbose:
|
|
349
|
-
cmd.append("--verbose")
|
|
350
|
-
if force:
|
|
351
|
-
cmd.append("--force")
|
|
352
|
-
|
|
353
|
-
elif doc_type == "supplementary":
|
|
354
|
-
if not no_figs: # For supplementary, --figs means include figures (default)
|
|
355
|
-
cmd.append("--figs")
|
|
356
|
-
if ppt2tif:
|
|
357
|
-
cmd.append("--ppt2tif")
|
|
358
|
-
if crop_tif:
|
|
359
|
-
cmd.append("--crop_tif")
|
|
360
|
-
if quiet:
|
|
361
|
-
cmd.append("--quiet")
|
|
362
|
-
|
|
363
|
-
log(f"[INFO] Running: {' '.join(cmd)}")
|
|
364
|
-
log(f"[INFO] Working directory: {project_dir}")
|
|
365
|
-
|
|
366
|
-
try:
|
|
367
|
-
cwd_original = Path.cwd()
|
|
368
|
-
os.chdir(project_dir)
|
|
369
|
-
|
|
370
|
-
try:
|
|
371
|
-
progress(15, "Executing LaTeX compilation...")
|
|
372
|
-
|
|
373
|
-
# Use callbacks version if callbacks provided
|
|
374
|
-
if log_callback:
|
|
375
|
-
result_dict = _execute_with_callbacks(
|
|
376
|
-
command=cmd,
|
|
377
|
-
cwd=project_dir,
|
|
378
|
-
timeout=timeout,
|
|
379
|
-
log_callback=log_callback,
|
|
380
|
-
)
|
|
381
|
-
else:
|
|
382
|
-
# Fallback to original sh() implementation
|
|
383
|
-
result_dict = sh(
|
|
384
|
-
cmd,
|
|
385
|
-
verbose=True,
|
|
386
|
-
return_as="dict",
|
|
387
|
-
timeout=timeout,
|
|
388
|
-
stream_output=True,
|
|
389
|
-
)
|
|
390
|
-
|
|
391
|
-
result = type(
|
|
392
|
-
"Result",
|
|
393
|
-
(),
|
|
394
|
-
{
|
|
395
|
-
"returncode": result_dict["exit_code"],
|
|
396
|
-
"stdout": result_dict["stdout"],
|
|
397
|
-
"stderr": result_dict["stderr"],
|
|
398
|
-
},
|
|
399
|
-
)()
|
|
400
|
-
|
|
401
|
-
duration = (datetime.now() - start_time).total_seconds()
|
|
402
|
-
finally:
|
|
403
|
-
os.chdir(cwd_original)
|
|
404
|
-
|
|
405
|
-
# Find output files
|
|
406
|
-
if result.returncode == 0:
|
|
407
|
-
progress(90, "Compilation successful, locating output files...")
|
|
408
|
-
log("[INFO] Compilation succeeded, checking output files...")
|
|
409
|
-
output_pdf, diff_pdf, log_file = _find_output_files(project_dir, doc_type)
|
|
410
|
-
if output_pdf:
|
|
411
|
-
log(f"[SUCCESS] PDF generated: {output_pdf}")
|
|
412
|
-
else:
|
|
413
|
-
output_pdf, diff_pdf, log_file = None, None, None
|
|
414
|
-
log(f"[ERROR] Compilation failed with exit code {result.returncode}")
|
|
415
|
-
|
|
416
|
-
# Parse errors and warnings
|
|
417
|
-
progress(95, "Parsing compilation logs...")
|
|
418
|
-
errors, warnings = parse_output(result.stdout, result.stderr, log_file=log_file)
|
|
419
|
-
|
|
420
|
-
compilation_result = CompilationResult(
|
|
421
|
-
success=(result.returncode == 0),
|
|
422
|
-
exit_code=result.returncode,
|
|
423
|
-
stdout=result.stdout,
|
|
424
|
-
stderr=result.stderr,
|
|
425
|
-
output_pdf=output_pdf,
|
|
426
|
-
diff_pdf=diff_pdf,
|
|
427
|
-
log_file=log_file,
|
|
428
|
-
duration=duration,
|
|
429
|
-
errors=errors,
|
|
430
|
-
warnings=warnings,
|
|
431
|
-
)
|
|
432
|
-
|
|
433
|
-
if compilation_result.success:
|
|
434
|
-
progress(100, "Complete!")
|
|
435
|
-
log(f"[SUCCESS] Compilation succeeded in {duration:.2f}s")
|
|
436
|
-
else:
|
|
437
|
-
progress(100, "Compilation failed")
|
|
438
|
-
if errors:
|
|
439
|
-
log(f"[ERROR] Found {len(errors)} errors")
|
|
440
|
-
|
|
441
|
-
return compilation_result
|
|
442
|
-
|
|
443
|
-
except Exception as e:
|
|
444
|
-
duration = (datetime.now() - start_time).total_seconds()
|
|
445
|
-
logger.error(f"Compilation error: {e}")
|
|
446
|
-
return CompilationResult(
|
|
447
|
-
success=False,
|
|
448
|
-
exit_code=1,
|
|
449
|
-
stdout="",
|
|
450
|
-
stderr=str(e),
|
|
451
|
-
duration=duration,
|
|
452
|
-
)
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
__all__ = ["run_compile"]
|
|
456
|
-
|
|
457
|
-
# EOF
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# Timestamp: "2025-10-29 (ywatanabe)"
|
|
3
|
-
# File: /home/ywatanabe/proj/scitex-code/src/scitex/writer/_compile/_validator.py
|
|
4
|
-
# ----------------------------------------
|
|
5
|
-
from __future__ import annotations
|
|
6
|
-
|
|
7
|
-
import os
|
|
8
|
-
|
|
9
|
-
__FILE__ = "./src/scitex/writer/_compile/_validator.py"
|
|
10
|
-
__DIR__ = os.path.dirname(__FILE__)
|
|
11
|
-
# ----------------------------------------
|
|
12
|
-
|
|
13
|
-
"""
|
|
14
|
-
Pre-compile validation for writer projects.
|
|
15
|
-
|
|
16
|
-
Validates project structure before attempting compilation.
|
|
17
|
-
"""
|
|
18
|
-
|
|
19
|
-
from pathlib import Path
|
|
20
|
-
|
|
21
|
-
from scitex.logging import getLogger
|
|
22
|
-
from scitex.writer.utils._verify_tree_structure import verify_tree_structure
|
|
23
|
-
|
|
24
|
-
logger = getLogger(__name__)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def validate_before_compile(project_dir: Path) -> None:
|
|
28
|
-
"""
|
|
29
|
-
Validate project structure before compilation.
|
|
30
|
-
|
|
31
|
-
Parameters
|
|
32
|
-
----------
|
|
33
|
-
project_dir : Path
|
|
34
|
-
Path to project directory
|
|
35
|
-
|
|
36
|
-
Raises
|
|
37
|
-
------
|
|
38
|
-
RuntimeError
|
|
39
|
-
If validation fails
|
|
40
|
-
"""
|
|
41
|
-
verify_tree_structure(project_dir)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
__all__ = ["validate_before_compile"]
|
|
45
|
-
|
|
46
|
-
# EOF
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
# Timestamp: "2025-11-08 (ywatanabe)"
|
|
4
|
-
# File: /home/ywatanabe/proj/scitex-code/src/scitex/writer/_compile/manuscript.py
|
|
5
|
-
# ----------------------------------------
|
|
6
|
-
from __future__ import annotations
|
|
7
|
-
import os
|
|
8
|
-
|
|
9
|
-
__FILE__ = "./src/scitex/writer/_compile/manuscript.py"
|
|
10
|
-
__DIR__ = os.path.dirname(__FILE__)
|
|
11
|
-
# ----------------------------------------
|
|
12
|
-
|
|
13
|
-
"""
|
|
14
|
-
Manuscript compilation function.
|
|
15
|
-
|
|
16
|
-
Provides manuscript-specific compilation with options for:
|
|
17
|
-
- Figure exclusion for quick compilation
|
|
18
|
-
- PowerPoint to TIF conversion
|
|
19
|
-
- TIF cropping
|
|
20
|
-
- Verbose/quiet modes
|
|
21
|
-
- Force recompilation
|
|
22
|
-
"""
|
|
23
|
-
|
|
24
|
-
from pathlib import Path
|
|
25
|
-
from typing import Optional, Callable
|
|
26
|
-
from ._runner import run_compile
|
|
27
|
-
from .._dataclasses import CompilationResult
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def compile_manuscript(
|
|
31
|
-
project_dir: Path,
|
|
32
|
-
timeout: int = 300,
|
|
33
|
-
no_figs: bool = False,
|
|
34
|
-
ppt2tif: bool = False,
|
|
35
|
-
crop_tif: bool = False,
|
|
36
|
-
quiet: bool = False,
|
|
37
|
-
verbose: bool = False,
|
|
38
|
-
force: bool = False,
|
|
39
|
-
log_callback: Optional[Callable[[str], None]] = None,
|
|
40
|
-
progress_callback: Optional[Callable[[int, str], None]] = None,
|
|
41
|
-
) -> CompilationResult:
|
|
42
|
-
"""
|
|
43
|
-
Compile manuscript document with optional callbacks.
|
|
44
|
-
|
|
45
|
-
Parameters
|
|
46
|
-
----------
|
|
47
|
-
project_dir : Path
|
|
48
|
-
Path to writer project directory
|
|
49
|
-
timeout : int
|
|
50
|
-
Timeout in seconds
|
|
51
|
-
no_figs : bool
|
|
52
|
-
Exclude figures for quick compilation
|
|
53
|
-
ppt2tif : bool
|
|
54
|
-
Convert PowerPoint to TIF on WSL
|
|
55
|
-
crop_tif : bool
|
|
56
|
-
Crop TIF images to remove excess whitespace
|
|
57
|
-
quiet : bool
|
|
58
|
-
Suppress detailed logs for LaTeX compilation
|
|
59
|
-
verbose : bool
|
|
60
|
-
Show detailed logs for LaTeX compilation
|
|
61
|
-
force : bool
|
|
62
|
-
Force full recompilation, ignore cache
|
|
63
|
-
log_callback : Optional[Callable[[str], None]]
|
|
64
|
-
Called with each log line
|
|
65
|
-
progress_callback : Optional[Callable[[int, str], None]]
|
|
66
|
-
Called with progress updates (percent, step)
|
|
67
|
-
|
|
68
|
-
Returns
|
|
69
|
-
-------
|
|
70
|
-
CompilationResult
|
|
71
|
-
Compilation status and outputs
|
|
72
|
-
|
|
73
|
-
Examples
|
|
74
|
-
--------
|
|
75
|
-
>>> from pathlib import Path
|
|
76
|
-
>>> from scitex.writer._compile import compile_manuscript
|
|
77
|
-
>>>
|
|
78
|
-
>>> # Quick compilation without figures
|
|
79
|
-
>>> result = compile_manuscript(
|
|
80
|
-
... project_dir=Path("~/my-paper"),
|
|
81
|
-
... no_figs=True,
|
|
82
|
-
... quiet=True
|
|
83
|
-
... )
|
|
84
|
-
>>>
|
|
85
|
-
>>> # Full compilation with PowerPoint conversion
|
|
86
|
-
>>> result = compile_manuscript(
|
|
87
|
-
... project_dir=Path("~/my-paper"),
|
|
88
|
-
... ppt2tif=True,
|
|
89
|
-
... crop_tif=True,
|
|
90
|
-
... verbose=True
|
|
91
|
-
... )
|
|
92
|
-
"""
|
|
93
|
-
return run_compile(
|
|
94
|
-
"manuscript",
|
|
95
|
-
project_dir,
|
|
96
|
-
timeout=timeout,
|
|
97
|
-
no_figs=no_figs,
|
|
98
|
-
ppt2tif=ppt2tif,
|
|
99
|
-
crop_tif=crop_tif,
|
|
100
|
-
quiet=quiet,
|
|
101
|
-
verbose=verbose,
|
|
102
|
-
force=force,
|
|
103
|
-
log_callback=log_callback,
|
|
104
|
-
progress_callback=progress_callback,
|
|
105
|
-
)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
__all__ = ["compile_manuscript"]
|
|
109
|
-
|
|
110
|
-
# EOF
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
# Timestamp: "2025-11-08 (ywatanabe)"
|
|
4
|
-
# File: /home/ywatanabe/proj/scitex-code/src/scitex/writer/_compile/revision.py
|
|
5
|
-
# ----------------------------------------
|
|
6
|
-
from __future__ import annotations
|
|
7
|
-
import os
|
|
8
|
-
|
|
9
|
-
__FILE__ = "./src/scitex/writer/_compile/revision.py"
|
|
10
|
-
__DIR__ = os.path.dirname(__FILE__)
|
|
11
|
-
# ----------------------------------------
|
|
12
|
-
|
|
13
|
-
"""
|
|
14
|
-
Revision response compilation function.
|
|
15
|
-
|
|
16
|
-
Provides revision-specific compilation with options for:
|
|
17
|
-
- Change tracking (diff highlighting)
|
|
18
|
-
"""
|
|
19
|
-
|
|
20
|
-
from pathlib import Path
|
|
21
|
-
from typing import Optional, Callable
|
|
22
|
-
from ._runner import run_compile
|
|
23
|
-
from .._dataclasses import CompilationResult
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def compile_revision(
|
|
27
|
-
project_dir: Path,
|
|
28
|
-
track_changes: bool = False,
|
|
29
|
-
timeout: int = 300,
|
|
30
|
-
log_callback: Optional[Callable[[str], None]] = None,
|
|
31
|
-
progress_callback: Optional[Callable[[int, str], None]] = None,
|
|
32
|
-
) -> CompilationResult:
|
|
33
|
-
"""
|
|
34
|
-
Compile revision responses with optional callbacks.
|
|
35
|
-
|
|
36
|
-
Parameters
|
|
37
|
-
----------
|
|
38
|
-
project_dir : Path
|
|
39
|
-
Path to writer project directory
|
|
40
|
-
track_changes : bool
|
|
41
|
-
Whether to enable change tracking (diff highlighting)
|
|
42
|
-
timeout : int
|
|
43
|
-
Timeout in seconds
|
|
44
|
-
log_callback : Optional[Callable[[str], None]]
|
|
45
|
-
Called with each log line
|
|
46
|
-
progress_callback : Optional[Callable[[int, str], None]]
|
|
47
|
-
Called with progress updates (percent, step)
|
|
48
|
-
|
|
49
|
-
Returns
|
|
50
|
-
-------
|
|
51
|
-
CompilationResult
|
|
52
|
-
Compilation status and outputs
|
|
53
|
-
|
|
54
|
-
Examples
|
|
55
|
-
--------
|
|
56
|
-
>>> from pathlib import Path
|
|
57
|
-
>>> from scitex.writer._compile import compile_revision
|
|
58
|
-
>>>
|
|
59
|
-
>>> # Standard revision compilation
|
|
60
|
-
>>> result = compile_revision(
|
|
61
|
-
... project_dir=Path("~/my-paper")
|
|
62
|
-
... )
|
|
63
|
-
>>>
|
|
64
|
-
>>> # Compilation with change tracking
|
|
65
|
-
>>> result = compile_revision(
|
|
66
|
-
... project_dir=Path("~/my-paper"),
|
|
67
|
-
... track_changes=True
|
|
68
|
-
... )
|
|
69
|
-
"""
|
|
70
|
-
return run_compile(
|
|
71
|
-
"revision",
|
|
72
|
-
project_dir,
|
|
73
|
-
timeout=timeout,
|
|
74
|
-
track_changes=track_changes,
|
|
75
|
-
log_callback=log_callback,
|
|
76
|
-
progress_callback=progress_callback,
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
__all__ = ["compile_revision"]
|
|
81
|
-
|
|
82
|
-
# EOF
|