scitex 2.16.0__py3-none-any.whl → 2.16.2__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/scholar/url_finder/.tmp/open_url/KNOWN_RESOLVERS.py +462 -0
- scitex/scholar/url_finder/.tmp/open_url/README.md +223 -0
- scitex/scholar/url_finder/.tmp/open_url/_DOIToURLResolver.py +694 -0
- scitex/scholar/url_finder/.tmp/open_url/_OpenURLResolver.py +1160 -0
- scitex/scholar/url_finder/.tmp/open_url/_ResolverLinkFinder.py +344 -0
- scitex/scholar/url_finder/.tmp/open_url/__init__.py +24 -0
- 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.2.dist-info}/METADATA +6 -1
- {scitex-2.16.0.dist-info → scitex-2.16.2.dist-info}/RECORD +21 -93
- scitex/dev/plt/data/mpl/PLOTTING_FUNCTIONS.yaml +0 -90
- scitex/dev/plt/data/mpl/PLOTTING_SIGNATURES.yaml +0 -1571
- scitex/dev/plt/data/mpl/PLOTTING_SIGNATURES_DETAILED.yaml +0 -6262
- scitex/dev/plt/data/mpl/SIGNATURES_FLATTENED.yaml +0 -1274
- scitex/dev/plt/data/mpl/dir_ax.txt +0 -459
- scitex/scholar/data/.gitkeep +0 -0
- scitex/scholar/data/README.md +0 -44
- scitex/scholar/data/bib_files/bibliography.bib +0 -1952
- scitex/scholar/data/bib_files/neurovista.bib +0 -277
- scitex/scholar/data/bib_files/neurovista_enriched.bib +0 -441
- scitex/scholar/data/bib_files/neurovista_enriched_enriched.bib +0 -441
- scitex/scholar/data/bib_files/neurovista_processed.bib +0 -338
- scitex/scholar/data/bib_files/openaccess.bib +0 -89
- scitex/scholar/data/bib_files/pac-seizure_prediction_enriched.bib +0 -2178
- scitex/scholar/data/bib_files/pac.bib +0 -698
- scitex/scholar/data/bib_files/pac_enriched.bib +0 -1061
- scitex/scholar/data/bib_files/pac_processed.bib +0 -0
- scitex/scholar/data/bib_files/pac_titles.txt +0 -75
- scitex/scholar/data/bib_files/paywalled.bib +0 -98
- scitex/scholar/data/bib_files/related-papers-by-coauthors.bib +0 -58
- scitex/scholar/data/bib_files/related-papers-by-coauthors_enriched.bib +0 -87
- scitex/scholar/data/bib_files/seizure_prediction.bib +0 -694
- scitex/scholar/data/bib_files/seizure_prediction_processed.bib +0 -0
- scitex/scholar/data/bib_files/test_complete_enriched.bib +0 -437
- scitex/scholar/data/bib_files/test_final_enriched.bib +0 -437
- scitex/scholar/data/bib_files/test_seizure.bib +0 -46
- scitex/scholar/data/impact_factor/JCR_IF_2022.xlsx +0 -0
- scitex/scholar/data/impact_factor/JCR_IF_2024.db +0 -0
- scitex/scholar/data/impact_factor/JCR_IF_2024.xlsx +0 -0
- scitex/scholar/data/impact_factor/JCR_IF_2024_v01.db +0 -0
- scitex/scholar/data/impact_factor.db +0 -0
- 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.2.dist-info}/WHEEL +0 -0
- {scitex-2.16.0.dist-info → scitex-2.16.2.dist-info}/entry_points.txt +0 -0
- {scitex-2.16.0.dist-info → scitex-2.16.2.dist-info}/licenses/LICENSE +0 -0
scitex/writer/README.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
<!-- ---
|
|
2
|
-
!-- Timestamp: 2025-10-29 17:33:34
|
|
3
|
-
!-- Author: ywatanabe
|
|
4
|
-
!-- File: /home/ywatanabe/proj/scitex-python/src/scitex/writer/README.md
|
|
5
|
-
!-- --- -->
|
|
6
|
-
|
|
7
1
|
# SciTeX Writer
|
|
8
2
|
|
|
9
|
-
|
|
3
|
+
Thin wrapper delegating to [scitex-writer](https://github.com/ywatanabe1989/scitex-writer) package.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install scitex-writer
|
|
9
|
+
```
|
|
10
10
|
|
|
11
11
|
## Usage
|
|
12
12
|
|
|
@@ -14,422 +14,38 @@ Python interface for LaTeX manuscript compilation.
|
|
|
14
14
|
from scitex.writer import Writer
|
|
15
15
|
from pathlib import Path
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
# Create or attach to a writer project
|
|
18
18
|
writer = Writer(Path("my_paper"))
|
|
19
19
|
|
|
20
|
-
#
|
|
21
|
-
# writer = Writer(Path("my_project/scitex/writer"), git_strategy='parent')
|
|
22
|
-
#
|
|
23
|
-
# # Clone specific branch of template
|
|
24
|
-
# writer = Writer(Path("my_paper"), branch="develop")
|
|
25
|
-
#
|
|
26
|
-
# # No git (temporary work)
|
|
27
|
-
# writer = Writer(Path("temp_work"), git_strategy=None)
|
|
28
|
-
|
|
29
|
-
# Document operations (git-based version control)
|
|
30
|
-
intro = writer.manuscript.contents.introduction
|
|
31
|
-
lines = intro.read() # Read file (uses scitex.io or fallback to plain text)
|
|
32
|
-
intro.write(lines + ["# New"]) # Write file
|
|
33
|
-
|
|
34
|
-
intro.commit("Update intro") # Commit to git with message
|
|
35
|
-
# intro.save() is not an alias - use commit() instead
|
|
36
|
-
|
|
37
|
-
intro.history() # Show git log (returns list of commit messages)
|
|
38
|
-
intro.diff() # Show uncommitted changes vs HEAD (returns diff string)
|
|
39
|
-
intro.diff(ref="HEAD~1") # Show uncommitted changes vs previous commit
|
|
40
|
-
intro.diff(ref="main") # Show uncommitted changes vs main branch
|
|
41
|
-
|
|
42
|
-
intro.checkout("HEAD~1") # Restore from previous version
|
|
43
|
-
intro.checkout("HEAD") # Restore from HEAD (returns bool: success)
|
|
44
|
-
|
|
45
|
-
# Compilation
|
|
20
|
+
# Compile manuscript
|
|
46
21
|
result = writer.compile_manuscript()
|
|
47
22
|
if result.success:
|
|
48
|
-
print(f"PDF: {result.output_pdf}")
|
|
49
|
-
|
|
50
|
-
# Utilities
|
|
51
|
-
pdf = writer.get_pdf()
|
|
52
|
-
writer.watch()
|
|
53
|
-
writer.delete()
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
**Git Strategies:**
|
|
57
|
-
- **`'child'` (default)**: Isolated git repository in project directory
|
|
58
|
-
- Self-contained version history
|
|
59
|
-
- Can use git directly in project directory
|
|
60
|
-
- **`'parent'`**: Use existing parent git repository
|
|
61
|
-
- Manuscript tracked in project's git repo
|
|
62
|
-
- Better for code + paper reproducibility
|
|
63
|
-
- **`None`**: Disable git (for temporary work)
|
|
64
|
-
|
|
65
|
-
## API Reference
|
|
66
|
-
|
|
67
|
-
### Writer Class
|
|
68
|
-
|
|
69
|
-
```python
|
|
70
|
-
Writer(project_dir, name=None, git_strategy='child', branch=None)
|
|
71
|
-
|
|
72
|
-
# Parameters:
|
|
73
|
-
# - project_dir: Path to project directory
|
|
74
|
-
# - name: Project name (optional, defaults to directory name)
|
|
75
|
-
# - git_strategy: 'child' (default), 'parent', 'origin', or None
|
|
76
|
-
# - branch: Specific branch of template to clone (optional)
|
|
77
|
-
|
|
78
|
-
# Attributes:
|
|
79
|
-
writer.project_dir # Path to project
|
|
80
|
-
writer.project_name # Project name
|
|
81
|
-
writer.git_root # Git repository root (if using git)
|
|
82
|
-
|
|
83
|
-
# Document trees:
|
|
84
|
-
writer.manuscript # ManuscriptTree with contents and sections
|
|
85
|
-
writer.supplementary # SupplementaryTree
|
|
86
|
-
writer.revision # RevisionTree
|
|
87
|
-
writer.scripts # ScriptsTree with compilation and utility scripts
|
|
88
|
-
|
|
89
|
-
# Methods:
|
|
90
|
-
writer.compile_manuscript(timeout=300) # → CompilationResult
|
|
91
|
-
writer.compile_supplementary(timeout=300) # → CompilationResult
|
|
92
|
-
writer.compile_revision(track_changes=False) # → CompilationResult
|
|
93
|
-
writer.watch(on_compile=None) # Auto-recompile on changes
|
|
94
|
-
writer.get_pdf(doc_type='manuscript') # → Path or None
|
|
95
|
-
writer.delete() # → bool
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
### DocumentSection Class
|
|
99
|
-
|
|
100
|
-
All manuscript/supplementary/revision sections are DocumentSection instances:
|
|
101
|
-
|
|
102
|
-
```python
|
|
103
|
-
section = writer.manuscript.contents.introduction # Example
|
|
104
|
-
|
|
105
|
-
# Methods:
|
|
106
|
-
section.read() # → content (str or list)
|
|
107
|
-
section.write(content) # → bool
|
|
108
|
-
section.commit(message) # → bool (git add + commit)
|
|
109
|
-
section.history() # → List[str] (git log messages)
|
|
110
|
-
section.diff(ref="HEAD") # → str (uncommitted changes vs ref, "" if none)
|
|
111
|
-
section.diff_between(ref1, ref2) # → str (compare any two git states)
|
|
112
|
-
section.checkout(ref="HEAD") # → bool (restore from git reference)
|
|
113
|
-
|
|
114
|
-
# Attributes:
|
|
115
|
-
section.path # → Path to file
|
|
116
|
-
section.git_root # → Path to git root (if available)
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
### Available Sections
|
|
120
|
-
|
|
121
|
-
**Manuscript Contents** (`writer.manuscript.contents.*`):
|
|
122
|
-
- Core: abstract, introduction, methods, results, discussion
|
|
123
|
-
- Metadata: title, authors, keywords, journal_name
|
|
124
|
-
- Optional: graphical_abstract, highlights, data_availability, additional_info, wordcount
|
|
125
|
-
- References: bibliography
|
|
126
|
-
- Directories: figures/, tables/, latex_styles/
|
|
127
|
-
|
|
128
|
-
**Supplementary & Revision**: Similar structure, customize as needed
|
|
129
|
-
|
|
130
|
-
## Usage Examples
|
|
131
|
-
|
|
132
|
-
### Basic Read/Write/Commit Workflow
|
|
133
|
-
|
|
134
|
-
```python
|
|
135
|
-
intro = writer.manuscript.contents.introduction
|
|
136
|
-
|
|
137
|
-
# 1. Read current content
|
|
138
|
-
lines = intro.read()
|
|
139
|
-
|
|
140
|
-
# 2. Modify and write
|
|
141
|
-
lines.append("New paragraph...")
|
|
142
|
-
intro.write(lines)
|
|
143
|
-
|
|
144
|
-
# 3. Check what changed (returns "" if no changes, diff string if changed)
|
|
145
|
-
changes = intro.diff()
|
|
146
|
-
if changes:
|
|
147
|
-
print("Changes detected:")
|
|
148
|
-
print(changes)
|
|
149
|
-
|
|
150
|
-
# 4. Commit when satisfied
|
|
151
|
-
intro.commit("Added new paragraph")
|
|
152
|
-
else:
|
|
153
|
-
print("No changes to commit")
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
### Working with Git History
|
|
157
|
-
|
|
158
|
-
```python
|
|
159
|
-
# View full version history
|
|
160
|
-
history = intro.history()
|
|
161
|
-
for commit in history:
|
|
162
|
-
print(commit) # Output: "abc1234 Commit message"
|
|
163
|
-
|
|
164
|
-
# Compare uncommitted changes against different versions
|
|
165
|
-
diff_prev = intro.diff(ref="HEAD~1") # Uncommitted changes vs last commit
|
|
166
|
-
diff_main = intro.diff(ref="main") # Uncommitted changes vs main branch
|
|
167
|
-
diff_tag = intro.diff(ref="v1.0") # Uncommitted changes vs tag
|
|
168
|
-
|
|
169
|
-
# Compare two arbitrary versions (no uncommitted changes needed)
|
|
170
|
-
diff = intro.diff_between("v1.0", "v2.0") # Between tags
|
|
171
|
-
diff = intro.diff_between("HEAD~2", "HEAD") # Between commits
|
|
172
|
-
diff = intro.diff_between("main", "develop") # Between branches
|
|
173
|
-
|
|
174
|
-
# Time-based comparisons with human-readable timestamps
|
|
175
|
-
diff = intro.diff_between("1 week ago", "now") # Last week's changes
|
|
176
|
-
diff = intro.diff_between("2 days ago", "HEAD") # Last 2 days
|
|
177
|
-
diff = intro.diff_between("2025-10-20", "2025-10-28") # Between dates
|
|
178
|
-
|
|
179
|
-
# Restore previous version
|
|
180
|
-
intro.checkout("HEAD~1") # Restore to last commit
|
|
181
|
-
intro.checkout("main") # Restore to main branch
|
|
182
|
-
|
|
183
|
-
# After restore, commit if needed
|
|
184
|
-
intro.commit("Reverted to previous version")
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
### Working with Scripts
|
|
188
|
-
|
|
189
|
-
```python
|
|
190
|
-
# Access compilation scripts
|
|
191
|
-
scripts = writer.scripts
|
|
192
|
-
|
|
193
|
-
# View script paths
|
|
194
|
-
compile_script = scripts.compile_manuscript.path
|
|
195
|
-
watch_script = scripts.watch_compile.path
|
|
196
|
-
|
|
197
|
-
# Read script content
|
|
198
|
-
content = scripts.compile_manuscript.read()
|
|
199
|
-
|
|
200
|
-
# Modify scripts (with git tracking)
|
|
201
|
-
new_content = scripts.compile_manuscript.read()
|
|
202
|
-
# ... modify content ...
|
|
203
|
-
scripts.compile_manuscript.write(new_content)
|
|
204
|
-
scripts.compile_manuscript.commit("Update compilation script")
|
|
205
|
-
|
|
206
|
-
# View script history
|
|
207
|
-
history = scripts.compile_manuscript.history()
|
|
208
|
-
diff = scripts.compile_manuscript.diff()
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
### Typical Edit Workflow
|
|
212
|
-
|
|
213
|
-
```python
|
|
214
|
-
# 1. Read current content
|
|
215
|
-
content = intro.read()
|
|
216
|
-
|
|
217
|
-
# 2. Make edits
|
|
218
|
-
updated = content + "\n\nNew section..."
|
|
219
|
-
intro.write(updated)
|
|
220
|
-
|
|
221
|
-
# 3. Review changes
|
|
222
|
-
print(intro.diff())
|
|
223
|
-
|
|
224
|
-
# 4. Commit when satisfied
|
|
225
|
-
if intro.diff():
|
|
226
|
-
intro.commit("Add new section")
|
|
227
|
-
else:
|
|
228
|
-
print("No changes to commit")
|
|
229
|
-
|
|
230
|
-
# 5. View history
|
|
231
|
-
print(intro.history())
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
## CompilationResult
|
|
235
|
-
|
|
236
|
-
```python
|
|
237
|
-
result.success # bool
|
|
238
|
-
result.exit_code # int
|
|
239
|
-
result.output_pdf # Path
|
|
240
|
-
result.duration # float (seconds)
|
|
241
|
-
result.errors # List[str]
|
|
242
|
-
result.warnings # List[str]
|
|
243
|
-
result.stdout # str
|
|
244
|
-
result.stderr # str
|
|
245
|
-
result.log_file # Path
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
## Project Structure
|
|
249
|
-
|
|
250
|
-
Writer creates and manages the following directory structure:
|
|
251
|
-
|
|
252
|
-
```
|
|
253
|
-
project_dir/
|
|
254
|
-
├── 01_manuscript/ # Main manuscript
|
|
255
|
-
│ ├── abstract.tex
|
|
256
|
-
│ ├── introduction.tex
|
|
257
|
-
│ ├── methods.tex
|
|
258
|
-
│ ├── results.tex
|
|
259
|
-
│ ├── discussion.tex
|
|
260
|
-
│ └── main.tex
|
|
261
|
-
├── 02_supplementary/ # Supplementary materials
|
|
262
|
-
│ ├── figures/
|
|
263
|
-
│ └── tables/
|
|
264
|
-
├── 03_revision/ # Revision/response documents
|
|
265
|
-
└── .git/ # Git repository (if using 'child' or 'parent' strategy)
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
## Error Handling
|
|
269
|
-
|
|
270
|
-
Writer handles errors gracefully with clear logging:
|
|
271
|
-
|
|
272
|
-
```python
|
|
273
|
-
try:
|
|
274
|
-
writer = Writer("/path/to/project")
|
|
275
|
-
except RuntimeError as e:
|
|
276
|
-
# Missing required directories (01_manuscript, 02_supplementary, 03_revision)
|
|
277
|
-
print(f"Invalid project structure: {e}")
|
|
278
|
-
|
|
279
|
-
try:
|
|
280
|
-
result = writer.compile_manuscript()
|
|
281
|
-
if not result.success:
|
|
282
|
-
print(f"Compilation failed: {result.errors}")
|
|
283
|
-
except Exception as e:
|
|
284
|
-
print(f"Compilation error: {e}")
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
**Common Issues:**
|
|
288
|
-
- Invalid project structure: Ensure all 3 required directories exist
|
|
289
|
-
- Git initialization failure: Check git installation and permissions
|
|
290
|
-
- LaTeX compilation error: Check .tex files syntax and LaTeX installation
|
|
23
|
+
print(f"PDF created: {result.output_pdf}")
|
|
291
24
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
Run the comprehensive test suite:
|
|
295
|
-
|
|
296
|
-
```bash
|
|
297
|
-
# Run all Writer tests
|
|
298
|
-
python -m pytest src/scitex/writer/tests/test_writer_integration.py -v
|
|
25
|
+
# Compile supplementary
|
|
26
|
+
result = writer.compile_supplementary()
|
|
299
27
|
|
|
300
|
-
#
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
# Run with coverage
|
|
304
|
-
python -m pytest src/scitex/writer/tests/test_writer_integration.py --cov=scitex.writer
|
|
28
|
+
# Compile revision with change tracking
|
|
29
|
+
result = writer.compile_revision(track_changes=True)
|
|
305
30
|
```
|
|
306
31
|
|
|
307
|
-
|
|
308
|
-
- Project attachment and creation
|
|
309
|
-
- Structure validation
|
|
310
|
-
- Git strategy handling (child, parent, None)
|
|
311
|
-
- Project name handling
|
|
312
|
-
- Child git cleanup for parent strategy
|
|
32
|
+
## Source of Truth
|
|
313
33
|
|
|
314
|
-
|
|
34
|
+
The implementation lives in the `scitex-writer` package. This module (`scitex.writer`) simply re-exports from `scitex_writer`:
|
|
315
35
|
|
|
316
|
-
|
|
36
|
+
- `Writer` - Main class for manuscript compilation
|
|
37
|
+
- `CompilationResult` - Compilation result dataclass
|
|
38
|
+
- `ManuscriptTree`, `SupplementaryTree`, `RevisionTree` - Document tree structures
|
|
39
|
+
- `bib`, `compile`, `figures`, `guidelines`, `project`, `prompts`, `tables` - Submodules
|
|
317
40
|
|
|
318
|
-
|
|
319
|
-
- **Real-time output**: View LaTeX compilation output as it happens, not buffered until completion
|
|
320
|
-
- **ANSI color preservation**: Color-coded messages (INFO, SUCC, ERRO, WARNING) display correctly
|
|
321
|
-
- **Progress visibility**: Know exactly which step is running and how long it takes
|
|
322
|
-
- **Immediate error detection**: Errors appear instantly instead of after full compilation
|
|
323
|
-
- **Stdbuf integration**: Forces line-buffered output for shell scripts
|
|
41
|
+
## Direct Import
|
|
324
42
|
|
|
325
|
-
|
|
326
|
-
- **Configurable timeouts**: Default 300s (5 minutes), customizable per compilation
|
|
327
|
-
- **Graceful termination**: Process killed cleanly on timeout
|
|
328
|
-
- **Clear timeout messages**: Explicit notification when compilation exceeds time limit
|
|
329
|
-
- **Works with streaming**: Timeout checks happen during execution, not after
|
|
43
|
+
You can also import directly from scitex-writer:
|
|
330
44
|
|
|
331
|
-
**Enhanced Compilation**:
|
|
332
45
|
```python
|
|
333
|
-
|
|
334
|
-
result = writer.compile_manuscript()
|
|
335
|
-
|
|
336
|
-
# Custom timeout
|
|
337
|
-
result = writer.compile_manuscript(timeout=600) # 10 minutes
|
|
338
|
-
|
|
339
|
-
# Watch real-time output with color coding:
|
|
340
|
-
# INFO: Running compilation...
|
|
341
|
-
# SUCC: All required tools available
|
|
342
|
-
# INFO: Pass 1/3: Initial (3s)
|
|
343
|
-
# SUCC: PDF ready (828K)
|
|
344
|
-
```
|
|
345
|
-
|
|
346
|
-
**Implementation Details**:
|
|
347
|
-
- Non-blocking I/O with `fcntl` for true streaming
|
|
348
|
-
- Unbuffered subprocess execution (`bufsize=0`)
|
|
349
|
-
- Environment variable propagation (`PYTHONUNBUFFERED=1`)
|
|
350
|
-
- Progressive output reading without blocking
|
|
351
|
-
- Separate stdout/stderr handling with immediate display
|
|
352
|
-
|
|
353
|
-
**Test Coverage** - 64 comprehensive tests:
|
|
354
|
-
- Real-time behavior verification (timing-based proofs)
|
|
355
|
-
- ANSI color code preservation tests
|
|
356
|
-
- Timeout during execution tests
|
|
357
|
-
- Large output handling (100+ lines)
|
|
358
|
-
- Stdbuf wrapper integration tests
|
|
359
|
-
- Streaming vs buffered consistency tests
|
|
360
|
-
|
|
361
|
-
**Benefits**:
|
|
362
|
-
- 🔍 **Visibility**: See what's happening during long compilations (161s in example)
|
|
363
|
-
- ⚡ **Responsiveness**: Decide to wait or interrupt based on live progress
|
|
364
|
-
- 🎨 **Clarity**: Color-coded output for easy scanning
|
|
365
|
-
- ⏱️ **Control**: Prevent runaway compilations with timeouts
|
|
366
|
-
- 🐛 **Debugging**: Errors visible immediately with full context
|
|
367
|
-
|
|
368
|
-
### 2025-10-28: Enhanced Git Integration & Temporal Queries
|
|
369
|
-
|
|
370
|
-
**Bug Fixes**:
|
|
371
|
-
- Fixed incomplete initialization that left `git_root` uninitialized
|
|
372
|
-
- Removed blocking debug code (`ipdb.set_trace()`)
|
|
373
|
-
- Fixed return type annotation in `_attach_or_create_project()`
|
|
374
|
-
- Improved error handling with proper logging throughout
|
|
375
|
-
|
|
376
|
-
**New Features**:
|
|
377
|
-
- **Structure Validation**: Automatically verifies project has required directories (01_manuscript, 02_supplementary, 03_revision) when attaching
|
|
378
|
-
- **Child Git Cleanup**: Automatically removes project's `.git/` when using `'parent'` strategy and parent repo is found, preventing nested git issues
|
|
379
|
-
|
|
380
|
-
**Enhanced Logging**:
|
|
381
|
-
- Detailed initialization logs with project name, directory, and git strategy
|
|
382
|
-
- Clear strategy selection and progression messages
|
|
383
|
-
- Explicit error messages with full context
|
|
384
|
-
- Success confirmations for key operations
|
|
385
|
-
|
|
386
|
-
**Enhanced diff() Capability**:
|
|
387
|
-
- **New `diff_between()` method** for comparing any two arbitrary git states
|
|
388
|
-
- Compare commits: `diff_between("HEAD~2", "HEAD")`
|
|
389
|
-
- Compare releases: `diff_between("v1.0", "v2.0")`
|
|
390
|
-
- Compare branches: `diff_between("main", "develop")`
|
|
391
|
-
- **Time-aware ref resolution**: `diff_between("1 week ago", "now")`
|
|
392
|
-
- **Timestamp-based queries**: `diff_between("2025-10-20", "2025-10-28")`
|
|
393
|
-
- Supports human-readable specifications without breaking git functionality
|
|
394
|
-
- **Reference resolution** (`_resolve_ref()`) handles:
|
|
395
|
-
- Standard git refs (HEAD, branches, tags, commit hashes)
|
|
396
|
-
- Relative time: "2 days ago", "1 week ago", "24 hours ago"
|
|
397
|
-
- Absolute dates: "2025-10-28", "2025-10-28 14:30"
|
|
398
|
-
- Timestamp-based commit finding with `git log --before`
|
|
399
|
-
- 15 new tests for diff_between functionality (all passing)
|
|
400
|
-
|
|
401
|
-
**Comprehensive Testing**:
|
|
402
|
-
- 99 tests covering all Writer and DocumentSection functionality
|
|
403
|
-
- DocumentSection operations fully tested (read/write/commit/history/diff/diff_between/checkout)
|
|
404
|
-
- End-to-end workflow testing (project creation → document editing → git operations)
|
|
405
|
-
- Temporal queries and reference resolution tested
|
|
406
|
-
- Error handling and edge cases covered
|
|
407
|
-
- All tests passing ✅
|
|
408
|
-
|
|
409
|
-
**Test Coverage**:
|
|
410
|
-
- Writer initialization and configuration
|
|
411
|
-
- Project creation and attachment
|
|
412
|
-
- Git strategy handling (child, parent, None)
|
|
413
|
-
- Document section operations (read, write, commit)
|
|
414
|
-
- Git operations (history, diff, checkout)
|
|
415
|
-
- Tree structure verification
|
|
416
|
-
- Error handling
|
|
417
|
-
- Live streaming infrastructure
|
|
418
|
-
- Timeout handling
|
|
419
|
-
|
|
420
|
-
**Run tests**:
|
|
421
|
-
```bash
|
|
422
|
-
# Writer module tests
|
|
423
|
-
pytest src/scitex/writer/tests/ -v
|
|
424
|
-
|
|
425
|
-
# Shell/streaming infrastructure tests
|
|
426
|
-
pytest tests/scitex/sh/ -v
|
|
46
|
+
from scitex_writer import Writer, CompilationResult
|
|
427
47
|
```
|
|
428
48
|
|
|
429
|
-
##
|
|
430
|
-
|
|
431
|
-
- Python 3.8+
|
|
432
|
-
- LaTeX distribution
|
|
433
|
-
- Git (for version control)
|
|
49
|
+
## Documentation
|
|
434
50
|
|
|
435
|
-
|
|
51
|
+
See [scitex-writer documentation](https://github.com/ywatanabe1989/scitex-writer) for full API reference.
|
scitex/writer/__init__.py
CHANGED
|
@@ -1,22 +1,62 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
# Timestamp: 2026-01-30
|
|
3
|
+
# File: src/scitex/writer/__init__.py
|
|
4
|
+
|
|
5
|
+
"""SciTeX Writer - LaTeX manuscript compilation system.
|
|
6
|
+
|
|
7
|
+
This module provides a thin wrapper around scitex-writer, the core manuscript
|
|
8
|
+
compilation package. It uses scitex branding and environment variable prefixes.
|
|
9
|
+
|
|
10
|
+
Features
|
|
11
|
+
--------
|
|
12
|
+
- LaTeX manuscript compilation
|
|
13
|
+
- Supplementary materials compilation
|
|
14
|
+
- Revision response compilation with change tracking
|
|
15
|
+
- BibTeX management
|
|
16
|
+
- Figure/table management
|
|
17
|
+
- Writing guidelines
|
|
18
|
+
|
|
19
|
+
Usage
|
|
20
|
+
-----
|
|
21
|
+
import scitex as stx
|
|
4
22
|
|
|
5
|
-
|
|
6
|
-
|
|
23
|
+
# Create or attach to a project
|
|
24
|
+
writer = stx.writer.Writer("my_paper")
|
|
7
25
|
|
|
8
|
-
|
|
26
|
+
# Compile manuscript
|
|
27
|
+
result = writer.compile_manuscript()
|
|
28
|
+
if result.success:
|
|
29
|
+
print(f"PDF created: {result.output_pdf}")
|
|
30
|
+
|
|
31
|
+
# Compile supplementary
|
|
32
|
+
result = writer.compile_supplementary()
|
|
33
|
+
|
|
34
|
+
# Compile revision with change tracking
|
|
35
|
+
result = writer.compile_revision(track_changes=True)
|
|
36
|
+
|
|
37
|
+
See Also
|
|
38
|
+
--------
|
|
39
|
+
- scitex-writer: https://github.com/ywatanabe1989/scitex-writer
|
|
40
|
+
- scitex: https://scitex.ai
|
|
9
41
|
"""
|
|
10
42
|
|
|
11
43
|
import os as _os
|
|
12
44
|
|
|
13
|
-
# Set branding
|
|
45
|
+
# Set branding BEFORE importing scitex-writer
|
|
14
46
|
_os.environ.setdefault("SCITEX_WRITER_BRAND", "scitex.writer")
|
|
15
47
|
_os.environ.setdefault("SCITEX_WRITER_ALIAS", "sw")
|
|
16
48
|
|
|
17
|
-
#
|
|
49
|
+
# Check scitex-writer availability
|
|
18
50
|
try:
|
|
19
|
-
|
|
51
|
+
# Re-export main class and dataclasses
|
|
52
|
+
from scitex_writer import (
|
|
53
|
+
CompilationResult,
|
|
54
|
+
ManuscriptTree,
|
|
55
|
+
RevisionTree,
|
|
56
|
+
SupplementaryTree,
|
|
57
|
+
Writer,
|
|
58
|
+
)
|
|
59
|
+
from scitex_writer import __version__ as _writer_version
|
|
20
60
|
from scitex_writer import (
|
|
21
61
|
bib,
|
|
22
62
|
compile,
|
|
@@ -27,11 +67,34 @@ try:
|
|
|
27
67
|
tables,
|
|
28
68
|
)
|
|
29
69
|
|
|
30
|
-
|
|
70
|
+
WRITER_AVAILABLE = True
|
|
71
|
+
__writer_version__ = _writer_version
|
|
31
72
|
|
|
32
73
|
except ImportError:
|
|
33
|
-
|
|
34
|
-
|
|
74
|
+
WRITER_AVAILABLE = False
|
|
75
|
+
__writer_version__ = None
|
|
76
|
+
|
|
77
|
+
# Provide helpful error on access
|
|
78
|
+
class _WriterNotAvailable:
|
|
79
|
+
"""Placeholder when scitex-writer is not installed."""
|
|
80
|
+
|
|
81
|
+
def __init__(self, *args, **kwargs):
|
|
82
|
+
raise ImportError(
|
|
83
|
+
"scitex-writer is required for scitex.writer. "
|
|
84
|
+
"Install with: pip install scitex-writer"
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
def __getattr__(self, name):
|
|
88
|
+
raise ImportError(
|
|
89
|
+
"scitex-writer is required for scitex.writer. "
|
|
90
|
+
"Install with: pip install scitex-writer"
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
Writer = _WriterNotAvailable
|
|
94
|
+
CompilationResult = _WriterNotAvailable
|
|
95
|
+
ManuscriptTree = _WriterNotAvailable
|
|
96
|
+
SupplementaryTree = _WriterNotAvailable
|
|
97
|
+
RevisionTree = _WriterNotAvailable
|
|
35
98
|
bib = None
|
|
36
99
|
compile = None
|
|
37
100
|
figures = None
|
|
@@ -40,9 +103,31 @@ except ImportError:
|
|
|
40
103
|
prompts = None
|
|
41
104
|
tables = None
|
|
42
105
|
|
|
106
|
+
|
|
107
|
+
def has_writer() -> bool:
|
|
108
|
+
"""Check if scitex-writer is available.
|
|
109
|
+
|
|
110
|
+
Returns
|
|
111
|
+
-------
|
|
112
|
+
bool
|
|
113
|
+
True if scitex-writer is installed and importable.
|
|
114
|
+
"""
|
|
115
|
+
return WRITER_AVAILABLE
|
|
116
|
+
|
|
117
|
+
|
|
43
118
|
__all__ = [
|
|
44
|
-
|
|
45
|
-
"
|
|
119
|
+
# Availability check
|
|
120
|
+
"WRITER_AVAILABLE",
|
|
121
|
+
"has_writer",
|
|
122
|
+
"__writer_version__",
|
|
123
|
+
# Main class
|
|
124
|
+
"Writer",
|
|
125
|
+
# Dataclasses
|
|
126
|
+
"CompilationResult",
|
|
127
|
+
"ManuscriptTree",
|
|
128
|
+
"SupplementaryTree",
|
|
129
|
+
"RevisionTree",
|
|
130
|
+
# Modules
|
|
46
131
|
"bib",
|
|
47
132
|
"compile",
|
|
48
133
|
"figures",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scitex
|
|
3
|
-
Version: 2.16.
|
|
3
|
+
Version: 2.16.2
|
|
4
4
|
Summary: A comprehensive Python library for scientific computing and data analysis
|
|
5
5
|
Project-URL: Homepage, https://github.com/ywatanabe1989/scitex-python
|
|
6
6
|
Project-URL: Documentation, https://scitex.readthedocs.io
|
|
@@ -62,6 +62,7 @@ Requires-Dist: catboost; extra == 'all'
|
|
|
62
62
|
Requires-Dist: celery; extra == 'all'
|
|
63
63
|
Requires-Dist: click; extra == 'all'
|
|
64
64
|
Requires-Dist: crawl4ai; extra == 'all'
|
|
65
|
+
Requires-Dist: crossref-local; extra == 'all'
|
|
65
66
|
Requires-Dist: csv2latex; extra == 'all'
|
|
66
67
|
Requires-Dist: dearpygui; extra == 'all'
|
|
67
68
|
Requires-Dist: einops; extra == 'all'
|
|
@@ -102,6 +103,7 @@ Requires-Dist: nest-asyncio; extra == 'all'
|
|
|
102
103
|
Requires-Dist: numcodecs; extra == 'all'
|
|
103
104
|
Requires-Dist: obspy; extra == 'all'
|
|
104
105
|
Requires-Dist: openai; extra == 'all'
|
|
106
|
+
Requires-Dist: openalex-local; extra == 'all'
|
|
105
107
|
Requires-Dist: opencv-python; extra == 'all'
|
|
106
108
|
Requires-Dist: openpyxl; extra == 'all'
|
|
107
109
|
Requires-Dist: optuna; extra == 'all'
|
|
@@ -140,6 +142,7 @@ Requires-Dist: scholarly; extra == 'all'
|
|
|
140
142
|
Requires-Dist: scikit-image; extra == 'all'
|
|
141
143
|
Requires-Dist: scikit-learn; extra == 'all'
|
|
142
144
|
Requires-Dist: scipy; extra == 'all'
|
|
145
|
+
Requires-Dist: scitex-writer; extra == 'all'
|
|
143
146
|
Requires-Dist: seaborn; extra == 'all'
|
|
144
147
|
Requires-Dist: selenium; extra == 'all'
|
|
145
148
|
Requires-Dist: sktime; extra == 'all'
|
|
@@ -382,12 +385,14 @@ Requires-Dist: aiohttp; extra == 'scholar'
|
|
|
382
385
|
Requires-Dist: beautifulsoup4; extra == 'scholar'
|
|
383
386
|
Requires-Dist: bibtexparser; extra == 'scholar'
|
|
384
387
|
Requires-Dist: crawl4ai; extra == 'scholar'
|
|
388
|
+
Requires-Dist: crossref-local; extra == 'scholar'
|
|
385
389
|
Requires-Dist: feedparser; extra == 'scholar'
|
|
386
390
|
Requires-Dist: html2text; extra == 'scholar'
|
|
387
391
|
Requires-Dist: httpx; extra == 'scholar'
|
|
388
392
|
Requires-Dist: matplotlib; extra == 'scholar'
|
|
389
393
|
Requires-Dist: natsort; extra == 'scholar'
|
|
390
394
|
Requires-Dist: nest-asyncio; extra == 'scholar'
|
|
395
|
+
Requires-Dist: openalex-local; extra == 'scholar'
|
|
391
396
|
Requires-Dist: openpyxl; extra == 'scholar'
|
|
392
397
|
Requires-Dist: pdfplumber; extra == 'scholar'
|
|
393
398
|
Requires-Dist: pillow; extra == 'scholar'
|