rxiv-maker 1.16.4__py3-none-any.whl → 1.16.6__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.
- rxiv_maker/__version__.py +1 -1
- rxiv_maker/cli/commands/upgrade.py +25 -3
- rxiv_maker/cli/framework/utility_commands.py +5 -2
- rxiv_maker/engines/operations/generate_figures.py +146 -18
- rxiv_maker/templates/registry.py +53 -29
- rxiv_maker/validators/syntax_validator.py +13 -4
- {rxiv_maker-1.16.4.dist-info → rxiv_maker-1.16.6.dist-info}/METADATA +1 -1
- {rxiv_maker-1.16.4.dist-info → rxiv_maker-1.16.6.dist-info}/RECORD +11 -11
- {rxiv_maker-1.16.4.dist-info → rxiv_maker-1.16.6.dist-info}/WHEEL +0 -0
- {rxiv_maker-1.16.4.dist-info → rxiv_maker-1.16.6.dist-info}/entry_points.txt +0 -0
- {rxiv_maker-1.16.4.dist-info → rxiv_maker-1.16.6.dist-info}/licenses/LICENSE +0 -0
rxiv_maker/__version__.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"""Upgrade command for rxiv-maker CLI."""
|
|
2
2
|
|
|
3
|
+
import subprocess # nosec B404 - needed for executing upgrade commands
|
|
3
4
|
import sys
|
|
4
5
|
|
|
5
6
|
import click
|
|
6
|
-
from henriqueslab_updater import
|
|
7
|
+
from henriqueslab_updater import force_update_check
|
|
7
8
|
from rich.console import Console
|
|
8
9
|
|
|
9
10
|
from ... import __version__
|
|
@@ -119,11 +120,32 @@ def upgrade(ctx: click.Context, yes: bool, check_only: bool) -> None:
|
|
|
119
120
|
console.print("❌ Upgrade cancelled", style="yellow")
|
|
120
121
|
sys.exit(0)
|
|
121
122
|
|
|
122
|
-
# Execute upgrade command
|
|
123
|
+
# Execute upgrade command directly
|
|
123
124
|
console.print("\n🚀 Upgrading rxiv-maker...", style="blue")
|
|
124
125
|
console.print(f" Running: {upgrade_cmd}", style="dim")
|
|
125
126
|
|
|
126
|
-
|
|
127
|
+
try:
|
|
128
|
+
# Split command for safer execution without shell=True
|
|
129
|
+
import shlex
|
|
130
|
+
|
|
131
|
+
cmd_parts = shlex.split(upgrade_cmd)
|
|
132
|
+
result = subprocess.run(
|
|
133
|
+
cmd_parts,
|
|
134
|
+
check=True,
|
|
135
|
+
capture_output=False,
|
|
136
|
+
timeout=300,
|
|
137
|
+
) # nosec B603 - upgrade_cmd comes from trusted install_detector module
|
|
138
|
+
success = result.returncode == 0
|
|
139
|
+
error = None
|
|
140
|
+
except subprocess.CalledProcessError as e:
|
|
141
|
+
success = False
|
|
142
|
+
error = f"Command failed with exit code {e.returncode}"
|
|
143
|
+
except subprocess.TimeoutExpired:
|
|
144
|
+
success = False
|
|
145
|
+
error = "Upgrade timed out after 5 minutes"
|
|
146
|
+
except Exception as e:
|
|
147
|
+
success = False
|
|
148
|
+
error = str(e)
|
|
127
149
|
|
|
128
150
|
if success:
|
|
129
151
|
console.print("\n✅ Upgrade completed successfully!", style="green")
|
|
@@ -187,13 +187,16 @@ class CheckInstallationCommand(BaseCommand):
|
|
|
187
187
|
"""Show next steps after dependency check."""
|
|
188
188
|
if not missing_results:
|
|
189
189
|
self.console.print("\n🚀 Next steps:", style="blue")
|
|
190
|
-
self.console.print(" •
|
|
190
|
+
self.console.print(" • Get example manuscript: rxiv get-rxiv-preprint")
|
|
191
|
+
self.console.print(" • Navigate to manuscript: cd manuscript-rxiv-maker/MANUSCRIPT")
|
|
192
|
+
self.console.print(" • Generate PDF: rxiv pdf")
|
|
191
193
|
return
|
|
192
194
|
|
|
193
195
|
self.console.print("\n🔧 Next steps:", style="blue")
|
|
194
196
|
self.console.print(" • Install missing dependencies shown above")
|
|
195
197
|
self.console.print(" • Re-run: rxiv check-installation")
|
|
196
|
-
self.console.print(" •
|
|
198
|
+
self.console.print(" • Get example manuscript: rxiv get-rxiv-preprint")
|
|
199
|
+
self.console.print(" • Generate PDF: cd manuscript-rxiv-maker/MANUSCRIPT && rxiv pdf")
|
|
197
200
|
|
|
198
201
|
def _show_basic_results(self, results: dict) -> None:
|
|
199
202
|
"""Show basic installation results."""
|
|
@@ -250,31 +250,95 @@ class FigureGenerator:
|
|
|
250
250
|
response = get_with_retry(mermaid_url, max_attempts=5, timeout=30)
|
|
251
251
|
else:
|
|
252
252
|
response = requests.get(mermaid_url, timeout=30)
|
|
253
|
-
except
|
|
254
|
-
#
|
|
255
|
-
return self._create_fallback_mermaid_diagram(
|
|
253
|
+
except requests.Timeout:
|
|
254
|
+
# Timeout - likely diagram too complex or service slow
|
|
255
|
+
return self._create_fallback_mermaid_diagram(
|
|
256
|
+
input_file, output_file, reason="timeout", details="30s timeout exceeded"
|
|
257
|
+
)
|
|
258
|
+
except requests.HTTPError as e:
|
|
259
|
+
# HTTP error (400, 503, etc.) - extract status code
|
|
260
|
+
status_code = e.response.status_code if hasattr(e, "response") else "unknown"
|
|
261
|
+
if status_code == 400:
|
|
262
|
+
details = "syntax error or diagram too complex"
|
|
263
|
+
elif status_code == 503:
|
|
264
|
+
details = "service timeout (diagram too complex)"
|
|
265
|
+
else:
|
|
266
|
+
details = f"HTTP {status_code}"
|
|
267
|
+
return self._create_fallback_mermaid_diagram(
|
|
268
|
+
input_file, output_file, reason="http_error", details=details
|
|
269
|
+
)
|
|
270
|
+
except Exception as e:
|
|
271
|
+
# Network or other error during request
|
|
272
|
+
error_msg = str(e)
|
|
273
|
+
# Try to extract status code from error message if it's there
|
|
274
|
+
if "400" in error_msg:
|
|
275
|
+
details = "syntax error or diagram too complex"
|
|
276
|
+
elif "503" in error_msg:
|
|
277
|
+
details = "service timeout (diagram too complex)"
|
|
278
|
+
elif "429" in error_msg:
|
|
279
|
+
details = "rate limit exceeded"
|
|
280
|
+
else:
|
|
281
|
+
details = "connection error"
|
|
282
|
+
return self._create_fallback_mermaid_diagram(
|
|
283
|
+
input_file, output_file, reason="network_error", details=details
|
|
284
|
+
)
|
|
256
285
|
|
|
257
286
|
if response.status_code == 200:
|
|
258
287
|
with open(output_file, "wb") as f:
|
|
259
288
|
f.write(response.content)
|
|
260
289
|
return True
|
|
261
290
|
else:
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
291
|
+
# Determine failure reason from status code
|
|
292
|
+
if response.status_code == 400:
|
|
293
|
+
reason_msg = "syntax error or diagram too complex"
|
|
294
|
+
elif response.status_code == 429:
|
|
295
|
+
reason_msg = "rate limit exceeded"
|
|
296
|
+
elif response.status_code == 503:
|
|
297
|
+
reason_msg = "service timeout (diagram too complex)"
|
|
298
|
+
elif response.status_code >= 500:
|
|
299
|
+
reason_msg = "service unavailable"
|
|
300
|
+
else:
|
|
301
|
+
reason_msg = f"HTTP {response.status_code}"
|
|
302
|
+
|
|
303
|
+
return self._create_fallback_mermaid_diagram(
|
|
304
|
+
input_file, output_file, reason="http_error", details=reason_msg
|
|
265
305
|
)
|
|
266
|
-
return self._create_fallback_mermaid_diagram(input_file, output_file)
|
|
267
306
|
else:
|
|
268
|
-
|
|
269
|
-
|
|
307
|
+
return self._create_fallback_mermaid_diagram(
|
|
308
|
+
input_file, output_file, reason="no_requests_lib", details="requests library not available"
|
|
309
|
+
)
|
|
270
310
|
|
|
271
311
|
except Exception as e:
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
312
|
+
return self._create_fallback_mermaid_diagram(
|
|
313
|
+
input_file, output_file, reason="unexpected_error", details=str(e)
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
def _create_fallback_mermaid_diagram(
|
|
317
|
+
self, input_file: Path, output_file: Path, reason: str = "unknown", details: str = "service unavailable"
|
|
318
|
+
) -> bool:
|
|
319
|
+
"""Create a fallback placeholder diagram when Mermaid service is unavailable.
|
|
320
|
+
|
|
321
|
+
Args:
|
|
322
|
+
input_file: Source mermaid file
|
|
323
|
+
output_file: Output file path
|
|
324
|
+
reason: Failure reason category (timeout, http_error, network_error, etc.)
|
|
325
|
+
details: Detailed error message
|
|
326
|
+
|
|
327
|
+
Returns:
|
|
328
|
+
True if placeholder was created successfully
|
|
329
|
+
"""
|
|
330
|
+
# Generate user-friendly warning message based on failure reason
|
|
331
|
+
if reason == "timeout":
|
|
332
|
+
warning_msg = f"diagram rendering timed out ({details})"
|
|
333
|
+
elif reason == "http_error":
|
|
334
|
+
warning_msg = f"{details}"
|
|
335
|
+
elif reason == "network_error":
|
|
336
|
+
warning_msg = f"network error: {details}"
|
|
337
|
+
elif reason == "no_requests_lib":
|
|
338
|
+
warning_msg = "requests library not available"
|
|
339
|
+
else:
|
|
340
|
+
warning_msg = f"{details}"
|
|
275
341
|
|
|
276
|
-
def _create_fallback_mermaid_diagram(self, input_file: Path, output_file: Path) -> bool:
|
|
277
|
-
"""Create a fallback placeholder diagram when Mermaid service is unavailable."""
|
|
278
342
|
try:
|
|
279
343
|
if self.output_format.lower() == "svg":
|
|
280
344
|
# Create SVG placeholder
|
|
@@ -294,6 +358,7 @@ class FigureGenerator:
|
|
|
294
358
|
</svg>"""
|
|
295
359
|
with open(output_file, "w", encoding="utf-8") as f:
|
|
296
360
|
f.write(svg_content)
|
|
361
|
+
print(f"⚠️ Created placeholder SVG for {input_file.name} ({warning_msg})")
|
|
297
362
|
return True
|
|
298
363
|
elif self.output_format.lower() == "png":
|
|
299
364
|
# Create minimal PNG placeholder (1x1 white pixel)
|
|
@@ -303,7 +368,7 @@ class FigureGenerator:
|
|
|
303
368
|
)
|
|
304
369
|
with open(output_file, "wb") as f:
|
|
305
370
|
f.write(png_data)
|
|
306
|
-
print(f"⚠️ Created placeholder PNG for {input_file.name} (
|
|
371
|
+
print(f"⚠️ Created placeholder PNG for {input_file.name} ({warning_msg})")
|
|
307
372
|
return True
|
|
308
373
|
elif self.output_format.lower() == "pdf":
|
|
309
374
|
# Create minimal PDF placeholder
|
|
@@ -374,20 +439,83 @@ startxref
|
|
|
374
439
|
"""
|
|
375
440
|
with open(output_file, "w", encoding="utf-8") as f:
|
|
376
441
|
f.write(pdf_content)
|
|
377
|
-
print(f"⚠️ Created placeholder PDF for {input_file.name} (
|
|
442
|
+
print(f"⚠️ Created placeholder PDF for {input_file.name} ({warning_msg})")
|
|
378
443
|
return True
|
|
379
444
|
else:
|
|
380
445
|
# Fallback for other formats - create text file with warning
|
|
381
446
|
with open(output_file.with_suffix(".txt"), "w", encoding="utf-8") as f:
|
|
382
447
|
f.write(f"Mermaid diagram placeholder for {input_file.name}\n")
|
|
383
|
-
f.write("
|
|
448
|
+
f.write(f"Reason: {warning_msg}\n")
|
|
384
449
|
f.write("\n💡 Tip: Check your Mermaid diagram syntax at https://www.mermaidchart.com/\n")
|
|
385
|
-
print(f"⚠️ Created text placeholder for {input_file.name} (
|
|
450
|
+
print(f"⚠️ Created text placeholder for {input_file.name} ({warning_msg})")
|
|
386
451
|
return True
|
|
387
452
|
except Exception as e:
|
|
388
453
|
print(f"Failed to create fallback diagram: {e}")
|
|
389
454
|
return False
|
|
390
455
|
|
|
456
|
+
def validate_mermaid_diagram(self, mmd_file: Path) -> tuple[bool, str, dict]:
|
|
457
|
+
"""Validate a Mermaid diagram for mermaid.ink compatibility.
|
|
458
|
+
|
|
459
|
+
Args:
|
|
460
|
+
mmd_file: Path to .mmd file
|
|
461
|
+
|
|
462
|
+
Returns:
|
|
463
|
+
Tuple of (is_valid, message, details_dict)
|
|
464
|
+
- is_valid: True if diagram will render successfully
|
|
465
|
+
- message: Human-readable validation result
|
|
466
|
+
- details_dict: Dict with complexity metrics and suggestions
|
|
467
|
+
"""
|
|
468
|
+
if not requests:
|
|
469
|
+
return False, "requests library not available for validation", {}
|
|
470
|
+
|
|
471
|
+
try:
|
|
472
|
+
# Read and analyze the diagram
|
|
473
|
+
with open(mmd_file, "r", encoding="utf-8") as f:
|
|
474
|
+
content = f.read().strip()
|
|
475
|
+
|
|
476
|
+
# Analyze complexity
|
|
477
|
+
details = {
|
|
478
|
+
"file_size": len(content),
|
|
479
|
+
"line_count": content.count("\n") + 1,
|
|
480
|
+
"subgraph_count": content.count("subgraph"),
|
|
481
|
+
"node_count": len(re.findall(r"\w+\[", content)),
|
|
482
|
+
"class_def_count": content.count("classDef"),
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
# Check for known problematic patterns
|
|
486
|
+
warnings = []
|
|
487
|
+
if details["file_size"] > 2500:
|
|
488
|
+
warnings.append(f"Large diagram ({details['file_size']} chars, limit ~2500)")
|
|
489
|
+
if details["subgraph_count"] > 5:
|
|
490
|
+
warnings.append(f"Many subgraphs ({details['subgraph_count']}, limit ~5)")
|
|
491
|
+
if details["class_def_count"] > 6:
|
|
492
|
+
warnings.append(f"Heavy styling ({details['class_def_count']} classes, limit ~6)")
|
|
493
|
+
|
|
494
|
+
# Test with mermaid.ink
|
|
495
|
+
encoded = base64.b64encode(content.encode("utf-8")).decode("ascii")
|
|
496
|
+
test_url = f"https://mermaid.ink/svg/{encoded}" # Use SVG for faster testing
|
|
497
|
+
|
|
498
|
+
try:
|
|
499
|
+
response = requests.get(test_url, timeout=10)
|
|
500
|
+
if response.status_code == 200:
|
|
501
|
+
if warnings:
|
|
502
|
+
msg = f"✓ Valid (but complex: {', '.join(warnings)})"
|
|
503
|
+
return True, msg, details
|
|
504
|
+
return True, "✓ Valid and will render successfully", details
|
|
505
|
+
elif response.status_code == 400:
|
|
506
|
+
return False, "✗ Syntax error or too complex for mermaid.ink", details
|
|
507
|
+
elif response.status_code == 503:
|
|
508
|
+
return False, "✗ Diagram too complex (service timeout)", details
|
|
509
|
+
else:
|
|
510
|
+
return False, f"✗ HTTP {response.status_code}", details
|
|
511
|
+
except requests.Timeout:
|
|
512
|
+
return False, "✗ Validation timeout (diagram likely too complex)", details
|
|
513
|
+
except Exception as e:
|
|
514
|
+
return False, f"✗ Network error: {str(e)[:50]}", details
|
|
515
|
+
|
|
516
|
+
except Exception as e:
|
|
517
|
+
return False, f"✗ Error reading diagram: {str(e)[:50]}", {}
|
|
518
|
+
|
|
391
519
|
def _execute_python_files(self, progress=None, task_id=None, use_rich: bool = True):
|
|
392
520
|
"""Execute Python scripts to generate figures using local Python."""
|
|
393
521
|
py_files = list(self.figures_dir.glob("*.py"))
|
rxiv_maker/templates/registry.py
CHANGED
|
@@ -163,38 +163,36 @@ citation_style: "numbered"
|
|
|
163
163
|
"""Get default main manuscript template."""
|
|
164
164
|
return """## Abstract
|
|
165
165
|
|
|
166
|
-
Your manuscript abstract goes here. Provide a comprehensive summary of your work,
|
|
167
|
-
key findings, and significance to the field.
|
|
166
|
+
Your manuscript abstract goes here. Provide a comprehensive summary of your work, including the main problem you are addressing, your approach, key findings, and the significance of your results to the field. The abstract should be self-contained and provide readers with a clear understanding of your contribution. Aim for 150-300 words that capture the essence of your research.
|
|
168
167
|
|
|
169
168
|
## Introduction
|
|
170
169
|
|
|
171
|
-
Introduce your topic
|
|
170
|
+
Introduce your research topic by providing essential background context and motivation. Start with the broader significance of your field, then narrow down to the specific problem your work addresses. Clearly state your research objectives and how your approach differs from or builds upon existing work in the literature [@smith2023]. Explain why this research is important and what gap in knowledge it fills.
|
|
172
171
|
|
|
173
172
|
## Methods
|
|
174
173
|
|
|
175
|
-
Describe your
|
|
176
|
-
(For reviews, you can remove this section or describe your literature search strategy)
|
|
174
|
+
Describe your experimental design, data collection procedures, and analytical techniques in sufficient detail to allow replication of your work. For computational studies, specify software versions, parameters, and algorithms used. For experimental work, detail protocols, sample preparation, and measurement procedures [@johnson2022]. Include information about statistical methods and data validation approaches. If you are writing a review article, you may remove this section or describe your literature search and selection strategy.
|
|
177
175
|
|
|
178
176
|
## Results
|
|
179
177
|
|
|
180
|
-
Present your findings
|
|
181
|
-
(For reviews, you can remove this section or rename it to organize your discussion)
|
|
178
|
+
Present your findings in a logical sequence, using figures and tables to support your narrative. Start with an overview of the key results, then provide detailed analyses.
|
|
182
179
|
|
|
183
|
-

|
|
184
|
-
{{#fig:example}} **Example
|
|
180
|
+

|
|
181
|
+
{{#fig:example}} **Example workflow diagram.** This Mermaid diagram illustrates a typical data processing pipeline, automatically converted to PDF during manuscript compilation. The diagram shows three stages: data input (gray), processing and analysis (red), and results output (green).
|
|
182
|
+
|
|
183
|
+
Our analysis demonstrates that the methodology produces consistent results across different datasets. The workflow presented in @fig:example provides a schematic overview of the processing pipeline. These findings build upon previous work [@smith2023; @johnson2022] while introducing novel approaches to data analysis.
|
|
185
184
|
|
|
186
185
|
## Discussion
|
|
187
186
|
|
|
188
|
-
Interpret your findings
|
|
187
|
+
Interpret your results in the context of existing literature and theory. Discuss how your findings support or challenge current understanding in the field. Address the implications of your work for theory, practice, or policy. Acknowledge limitations of your study, such as sample size constraints, methodological limitations, or scope boundaries. Suggest directions for future research that build upon your findings.
|
|
189
188
|
|
|
190
189
|
## Conclusions
|
|
191
190
|
|
|
192
|
-
Summarize your key
|
|
191
|
+
Summarize your key findings and their significance. Reinforce the main contributions of your work and their broader impact on the field. Keep this section concise but impactful, leaving readers with a clear understanding of what your research has accomplished and why it matters.
|
|
193
192
|
|
|
194
193
|
## References
|
|
195
194
|
|
|
196
|
-
Citations
|
|
197
|
-
reference them in your text: [@smith2023; @johnson2022]
|
|
195
|
+
Citations are automatically formatted from 03_REFERENCES.bib. Reference works using citation keys like [@smith2023] for single citations or [@smith2023; @johnson2022] for multiple citations.
|
|
198
196
|
"""
|
|
199
197
|
|
|
200
198
|
def _get_default_supplementary_template(self) -> str:
|
|
@@ -225,34 +223,60 @@ Information about code repositories, data availability, and reproducibility reso
|
|
|
225
223
|
def _get_default_bibliography_template(self) -> str:
|
|
226
224
|
"""Get default bibliography template."""
|
|
227
225
|
return """@article{{smith2023,
|
|
228
|
-
title = {{
|
|
229
|
-
author = {{Smith, John and Doe, Jane}},
|
|
230
|
-
journal = {{Nature}},
|
|
231
|
-
volume = {{
|
|
232
|
-
|
|
226
|
+
title = {{Advances in computational biology: methods and applications}},
|
|
227
|
+
author = {{Smith, John A. and Doe, Jane M. and Williams, Robert L.}},
|
|
228
|
+
journal = {{Nature Methods}},
|
|
229
|
+
volume = {{20}},
|
|
230
|
+
number = {{8}},
|
|
231
|
+
pages = {{1234--1245}},
|
|
233
232
|
year = {{2023}},
|
|
234
|
-
|
|
233
|
+
publisher = {{Springer Nature}},
|
|
234
|
+
doi = {{10.1038/s41592-023-01234-5}}
|
|
235
235
|
}}
|
|
236
236
|
|
|
237
237
|
@article{{johnson2022,
|
|
238
|
-
title = {{
|
|
239
|
-
author = {{Johnson, Alice and Brown,
|
|
238
|
+
title = {{Machine learning approaches for biological data analysis}},
|
|
239
|
+
author = {{Johnson, Alice B. and Brown, Robert C. and Davis, Sarah K.}},
|
|
240
240
|
journal = {{Cell}},
|
|
241
241
|
volume = {{185}},
|
|
242
|
-
|
|
242
|
+
number = {{12}},
|
|
243
|
+
pages = {{2156--2170}},
|
|
243
244
|
year = {{2022}},
|
|
244
|
-
|
|
245
|
+
publisher = {{Elsevier}},
|
|
246
|
+
doi = {{10.1016/j.cell.2022.05.015}}
|
|
247
|
+
}}
|
|
248
|
+
|
|
249
|
+
@article{{wilson2024,
|
|
250
|
+
title = {{Reproducible research practices in modern science}},
|
|
251
|
+
author = {{Wilson, Greg and Jones, Emily R.}},
|
|
252
|
+
journal = {{PLOS Computational Biology}},
|
|
253
|
+
volume = {{20}},
|
|
254
|
+
number = {{3}},
|
|
255
|
+
pages = {{e1011234}},
|
|
256
|
+
year = {{2024}},
|
|
257
|
+
publisher = {{Public Library of Science}},
|
|
258
|
+
doi = {{10.1371/journal.pcbi.1011234}}
|
|
245
259
|
}}
|
|
246
260
|
"""
|
|
247
261
|
|
|
248
262
|
def _get_default_figure_template(self) -> str:
|
|
249
263
|
"""Get default figure template (Mermaid diagram)."""
|
|
250
|
-
return """
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
264
|
+
return """---
|
|
265
|
+
config:
|
|
266
|
+
look: neo
|
|
267
|
+
theme: neo
|
|
268
|
+
---
|
|
269
|
+
flowchart LR
|
|
270
|
+
A["<b>DATA</b><br/>Input"] --> B["<b>PROCESSING</b><br/>Analysis"]
|
|
271
|
+
B --> C["<b>RESULTS</b><br/>Output"]
|
|
272
|
+
|
|
273
|
+
classDef inputStyle fill:#1f2937,stroke:#374151,stroke-width:3px,color:#ffffff
|
|
274
|
+
classDef processStyle fill:#dc2626,stroke:#991b1b,stroke-width:3px,color:#ffffff
|
|
275
|
+
classDef outputStyle fill:#059669,stroke:#047857,stroke-width:3px,color:#ffffff
|
|
276
|
+
|
|
277
|
+
class A inputStyle
|
|
278
|
+
class B processStyle
|
|
279
|
+
class C outputStyle
|
|
256
280
|
"""
|
|
257
281
|
|
|
258
282
|
def _get_default_gitignore_template(self) -> str:
|
|
@@ -854,8 +854,17 @@ class SyntaxValidator(BaseValidator):
|
|
|
854
854
|
heading_texts = {}
|
|
855
855
|
previous_level = 0
|
|
856
856
|
|
|
857
|
-
|
|
858
|
-
|
|
857
|
+
# Protect code blocks (including {{py:exec}}) from being treated as headings
|
|
858
|
+
content = "\n".join(lines)
|
|
859
|
+
protected_content = self._protect_validation_sensitive_content(content)
|
|
860
|
+
protected_lines = protected_content.split("\n")
|
|
861
|
+
|
|
862
|
+
for line_num, (original_line, protected_line) in enumerate(zip(lines, protected_lines, strict=False), 1):
|
|
863
|
+
# Skip protected code blocks (they might contain # comments)
|
|
864
|
+
if "XXPROTECTEDCODEXX" in protected_line:
|
|
865
|
+
continue
|
|
866
|
+
|
|
867
|
+
match = heading_pattern.match(protected_line)
|
|
859
868
|
if match:
|
|
860
869
|
hashes = match.group(1)
|
|
861
870
|
heading_text = match.group(2).strip()
|
|
@@ -904,7 +913,7 @@ class SyntaxValidator(BaseValidator):
|
|
|
904
913
|
f"Heading hierarchy skips levels: {previous_level} → {level}",
|
|
905
914
|
file_path=file_path,
|
|
906
915
|
line_number=line_num,
|
|
907
|
-
context=
|
|
916
|
+
context=original_line.strip(),
|
|
908
917
|
suggestion=(
|
|
909
918
|
f"Consider using {'#' * (previous_level + 1)} instead of {'#' * level}.\n"
|
|
910
919
|
f" Skipping heading levels (e.g., ## to ####) makes document structure unclear."
|
|
@@ -927,7 +936,7 @@ class SyntaxValidator(BaseValidator):
|
|
|
927
936
|
f"Standard section '{heading_text}' using level 1 heading (#)",
|
|
928
937
|
file_path=file_path,
|
|
929
938
|
line_number=line_num,
|
|
930
|
-
context=
|
|
939
|
+
context=original_line.strip(),
|
|
931
940
|
suggestion=(
|
|
932
941
|
f"Change to level 2 heading: ## {heading_text}\n"
|
|
933
942
|
f" Level 1 (#) should only be used for the document title.\n"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rxiv-maker
|
|
3
|
-
Version: 1.16.
|
|
3
|
+
Version: 1.16.6
|
|
4
4
|
Summary: Write scientific preprints in Markdown. Generate publication-ready PDFs efficiently.
|
|
5
5
|
Project-URL: Homepage, https://github.com/HenriquesLab/rxiv-maker
|
|
6
6
|
Project-URL: Documentation, https://github.com/HenriquesLab/rxiv-maker#readme
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
rxiv_maker/__init__.py,sha256=p04JYC5ZhP6dLXkoWVlKNyiRvsDE1a4C88f9q4xO3tA,3268
|
|
2
|
-
rxiv_maker/__version__.py,sha256=
|
|
2
|
+
rxiv_maker/__version__.py,sha256=qf0GMhAIH5L_wI59eHcfpHtgoZxaqziVuvj0M1daj0g,51
|
|
3
3
|
rxiv_maker/rxiv_maker_cli.py,sha256=9Lu_mhFPXwx5jzAR6StCNxwCm_fkmP5qiOYdNuh_AwI,120
|
|
4
4
|
rxiv_maker/validate.py,sha256=AIzgP59KbCQJqC9WIGfUdVv0xI6ud9g1fFznQkaGz5Q,9373
|
|
5
5
|
rxiv_maker/cli/__init__.py,sha256=Jw0DTFUSofN-02xpVrt1UUzRcgH5NNd-GPNidhmNwpU,77
|
|
@@ -29,7 +29,7 @@ rxiv_maker/cli/commands/repos.py,sha256=SQ9nuhSkyHKFPYn_TrOxyQoGdDRI-OBOgUSGJpRu
|
|
|
29
29
|
rxiv_maker/cli/commands/repos_search.py,sha256=6sUMvyHlHEX1p88hPtu0_Hf8z6JpOinJ53l9ZI-rirc,7743
|
|
30
30
|
rxiv_maker/cli/commands/setup.py,sha256=9ue4bDETpSPGVkWFDfpuTDsysax5-QKGxmt42Gb7oeU,2294
|
|
31
31
|
rxiv_maker/cli/commands/track_changes.py,sha256=omf_77A7htRSa8naUEPTTtUTxrSwMpzHFOuU0j1xAJw,1163
|
|
32
|
-
rxiv_maker/cli/commands/upgrade.py,sha256=
|
|
32
|
+
rxiv_maker/cli/commands/upgrade.py,sha256=VJ1snYyLGrb5-snF4olfsMwfQsuKkAbXEr8aQ88WYYE,6349
|
|
33
33
|
rxiv_maker/cli/commands/validate.py,sha256=3JghFQevJvQDQII4p_QWbQXMEUyDpM-t9-WxtaT4edo,1629
|
|
34
34
|
rxiv_maker/cli/commands/version.py,sha256=VMlfSxxsrZH02d24MXLUDZfHBW39yZRpWxUpMhQ-X0Y,2737
|
|
35
35
|
rxiv_maker/cli/framework/__init__.py,sha256=4FPXdP8J6v4eeEn46mwY0VtnwxjR1jnW_kTrXykQlQs,2704
|
|
@@ -38,7 +38,7 @@ rxiv_maker/cli/framework/cache_commands.py,sha256=J91UYLTsLTRoNdzuhAbNL2bJJovYYf
|
|
|
38
38
|
rxiv_maker/cli/framework/config_commands.py,sha256=a1uOQkCCw3d4qlro3OwHIorcoNg03T_R4-HbfVb-hmQ,19336
|
|
39
39
|
rxiv_maker/cli/framework/content_commands.py,sha256=RilxKeG2c1m2fu0CtWAvP3cGh11DGx9P-nh2kIewAg4,22596
|
|
40
40
|
rxiv_maker/cli/framework/decorators.py,sha256=fh085e3k1CaLSMoZevt8hvgnEuejrf-mcNS-dwXoY_A,10365
|
|
41
|
-
rxiv_maker/cli/framework/utility_commands.py,sha256=
|
|
41
|
+
rxiv_maker/cli/framework/utility_commands.py,sha256=drIAc1TAYpne76gj7SZeZhPozVAY5uL9GFPVT_Ez0-E,26437
|
|
42
42
|
rxiv_maker/cli/framework/workflow_commands.py,sha256=CFa3c5oJMmy9cUZxTAU97eKC6YrOljzerSAMrywjbKw,29684
|
|
43
43
|
rxiv_maker/config/defaults.py,sha256=vHyLGVxe5-z9TLxu5f6NhquPvqQkER_KZv_j1I4_dHQ,3055
|
|
44
44
|
rxiv_maker/config/validator.py,sha256=9XDPfo_YgasGt6NLkl6HIhaGh1fr6XsFNiXU2DSsivw,38299
|
|
@@ -96,7 +96,7 @@ rxiv_maker/engines/operations/build_manager.py,sha256=TAX4-r8HjraAzzvQuIt0CNlvWL
|
|
|
96
96
|
rxiv_maker/engines/operations/cleanup.py,sha256=RfbXif0neEVMlprFIHWyvQh6kwghalcesY3t-69Iwsw,18095
|
|
97
97
|
rxiv_maker/engines/operations/fix_bibliography.py,sha256=ZD8uO4YCxDCMWH4WtBSDc4TOMgM383fcLgsCCW0yK60,22428
|
|
98
98
|
rxiv_maker/engines/operations/generate_docs.py,sha256=8d_oVYUuRRqTuYN1KnJKqM5Ydp4_yt52ntBv8gUoRVk,11223
|
|
99
|
-
rxiv_maker/engines/operations/generate_figures.py,sha256=
|
|
99
|
+
rxiv_maker/engines/operations/generate_figures.py,sha256=YeKzH6qVsuPGjtCsvWugLJoys6y73xTyO7Y5g30KM20,38730
|
|
100
100
|
rxiv_maker/engines/operations/generate_preprint.py,sha256=wpKDAu2RLJ4amSdhX5GZ7hU-iTsTRt4etcEA7AZYp04,2662
|
|
101
101
|
rxiv_maker/engines/operations/prepare_arxiv.py,sha256=cd0JN5IO-Wy9T8ab75eibyaA8_K8Gpwrz2F-95OMnx4,21551
|
|
102
102
|
rxiv_maker/engines/operations/setup_environment.py,sha256=gERuThHTldH0YqgXn85995deHBP6csY1ZhCNgU6-vFg,12691
|
|
@@ -141,7 +141,7 @@ rxiv_maker/services/publication_service.py,sha256=0p8yQ1jrY3RHwCkzTEl_sAbWYTafRk
|
|
|
141
141
|
rxiv_maker/services/validation_service.py,sha256=eWg14NqJu6LzyJBgeXkTaVZAlX4wYFX8ZEvSR5hMx7U,14619
|
|
142
142
|
rxiv_maker/templates/__init__.py,sha256=UTet1pYPkPdgvrLw-wwaY-PAgdjGJasAi_hdyIh0J8s,562
|
|
143
143
|
rxiv_maker/templates/manager.py,sha256=HlI7Qb52866Okf4k1aRh0fUy9heOSNGjMQJtrCdL3Xk,6131
|
|
144
|
-
rxiv_maker/templates/registry.py,sha256=
|
|
144
|
+
rxiv_maker/templates/registry.py,sha256=mRKUhuNg1VWzryEV-l6tD2pmdQG6b_JDh3_jtrR_K48,16200
|
|
145
145
|
rxiv_maker/tex/python_execution_section.tex,sha256=pHz6NGfZN4ViBo6rInUO5FAuk81sV_Ppqszrvl00w_4,2218
|
|
146
146
|
rxiv_maker/utils/__init__.py,sha256=4ya5VR8jqRqUChlnUeMeeetOuWV-gIvjPwcE1u_1OnI,1540
|
|
147
147
|
rxiv_maker/utils/author_name_formatter.py,sha256=UjvarbyQm89EUIYqckygx3g37o-EcNyvipBtY8GJDxs,10222
|
|
@@ -180,15 +180,15 @@ rxiv_maker/validators/latex_error_parser.py,sha256=crk3NAniLBp2iABP4lxts7gvCEg6K
|
|
|
180
180
|
rxiv_maker/validators/math_validator.py,sha256=LcRIGAv47OsPfOg4E48l2vKN1Q7lHAeduNN5MFMLQGE,27669
|
|
181
181
|
rxiv_maker/validators/pdf_validator.py,sha256=YU4WRPeTEOtvBlquFEtZrG9p_WjlN5nnCByTSRAvWyw,21530
|
|
182
182
|
rxiv_maker/validators/reference_validator.py,sha256=UqvsEa3kVOBkbGMo24fXpFVUtpN1feIf9MfDQIraQZs,15868
|
|
183
|
-
rxiv_maker/validators/syntax_validator.py,sha256=
|
|
183
|
+
rxiv_maker/validators/syntax_validator.py,sha256=hHpKVKky3UiA1ZylA6jJVP3DN47LgaSSJCK2PPA-8BA,43599
|
|
184
184
|
rxiv_maker/validators/doi/__init__.py,sha256=NqATXseuS0zVNns56RvFe8TdqgvueY0Rbw2Pjozlajc,494
|
|
185
185
|
rxiv_maker/validators/doi/api_clients.py,sha256=tqdYUq8LFgRIO0tWfcenwmy2uO-IB1-GMvBfF3lP7-0,21763
|
|
186
186
|
rxiv_maker/validators/doi/metadata_comparator.py,sha256=euqHhKP5sHQAdZbdoAahUn6YqJqOfXIOobNgAqFHlN8,11533
|
|
187
187
|
rxiv_maker/tex/template.tex,sha256=zrJ3aFfu8j9zkg1l375eE9w-j42P3rz16wMD3dSgi1I,1354
|
|
188
188
|
rxiv_maker/tex/style/rxiv_maker_style.bst,sha256=jbVqrJgAm6F88cow5vtZuPBwwmlcYykclTm8RvZIo6Y,24281
|
|
189
189
|
rxiv_maker/tex/style/rxiv_maker_style.cls,sha256=F2qtnS9mI6SwOIaVH76egXZkB2_GzbH4gCTG_ZcfCDQ,24253
|
|
190
|
-
rxiv_maker-1.16.
|
|
191
|
-
rxiv_maker-1.16.
|
|
192
|
-
rxiv_maker-1.16.
|
|
193
|
-
rxiv_maker-1.16.
|
|
194
|
-
rxiv_maker-1.16.
|
|
190
|
+
rxiv_maker-1.16.6.dist-info/METADATA,sha256=7_r-ZEzlmKCVaCu_a-Z8tg8pr4kzfI3tDbvfCbc1dCw,17950
|
|
191
|
+
rxiv_maker-1.16.6.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
192
|
+
rxiv_maker-1.16.6.dist-info/entry_points.txt,sha256=ghCN0hI9A1GlG7QY5F6E-xYPflA8CyS4B6bTQ1YLop0,97
|
|
193
|
+
rxiv_maker-1.16.6.dist-info/licenses/LICENSE,sha256=GSZFoPIhWDNJEtSHTQ5dnELN38zFwRiQO2antBezGQk,1093
|
|
194
|
+
rxiv_maker-1.16.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|