rxiv-maker 1.16.6__py3-none-any.whl → 1.16.8__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/docx.py +74 -0
- rxiv_maker/cli/commands/upgrade.py +22 -134
- rxiv_maker/core/managers/dependency_manager.py +12 -0
- rxiv_maker/exporters/docx_exporter.py +100 -3
- rxiv_maker/exporters/docx_writer.py +38 -3
- rxiv_maker/utils/bst_generator.py +27 -7
- rxiv_maker/utils/docx_helpers.py +23 -2
- rxiv_maker/utils/rich_upgrade_notifier.py +162 -0
- {rxiv_maker-1.16.6.dist-info → rxiv_maker-1.16.8.dist-info}/METADATA +10 -5
- {rxiv_maker-1.16.6.dist-info → rxiv_maker-1.16.8.dist-info}/RECORD +14 -13
- {rxiv_maker-1.16.6.dist-info → rxiv_maker-1.16.8.dist-info}/WHEEL +0 -0
- {rxiv_maker-1.16.6.dist-info → rxiv_maker-1.16.8.dist-info}/entry_points.txt +0 -0
- {rxiv_maker-1.16.6.dist-info → rxiv_maker-1.16.8.dist-info}/licenses/LICENSE +0 -0
rxiv_maker/__version__.py
CHANGED
rxiv_maker/cli/commands/docx.py
CHANGED
|
@@ -1,15 +1,86 @@
|
|
|
1
1
|
"""DOCX export command for rxiv-maker CLI."""
|
|
2
2
|
|
|
3
|
+
import platform
|
|
4
|
+
import shutil
|
|
5
|
+
import subprocess
|
|
6
|
+
|
|
3
7
|
import rich_click as click
|
|
4
8
|
from rich.console import Console
|
|
5
9
|
|
|
6
10
|
from ...core.logging_config import get_logger
|
|
11
|
+
from ...core.managers.dependency_manager import DependencyStatus, get_dependency_manager
|
|
7
12
|
from ...exporters.docx_exporter import DocxExporter
|
|
8
13
|
|
|
9
14
|
logger = get_logger()
|
|
10
15
|
console = Console()
|
|
11
16
|
|
|
12
17
|
|
|
18
|
+
def _check_and_offer_poppler_installation(console: Console, quiet: bool, verbose: bool) -> None:
|
|
19
|
+
"""Check poppler availability and offer automatic installation via brew.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
console: Rich console for output
|
|
23
|
+
quiet: Whether to suppress output
|
|
24
|
+
verbose: Whether verbose mode is enabled
|
|
25
|
+
"""
|
|
26
|
+
# Check if poppler is installed
|
|
27
|
+
manager = get_dependency_manager()
|
|
28
|
+
result = manager.check_dependency("pdftoppm")
|
|
29
|
+
|
|
30
|
+
if result.status == DependencyStatus.AVAILABLE:
|
|
31
|
+
if verbose:
|
|
32
|
+
console.print("[dim]✓ Poppler utilities available[/dim]")
|
|
33
|
+
return
|
|
34
|
+
|
|
35
|
+
# Poppler is missing - offer to install
|
|
36
|
+
system = platform.system()
|
|
37
|
+
|
|
38
|
+
if system == "Darwin" and shutil.which("brew"):
|
|
39
|
+
# macOS with Homebrew
|
|
40
|
+
if not quiet:
|
|
41
|
+
console.print("[yellow]⚠️ Poppler not found[/yellow]")
|
|
42
|
+
console.print(" Poppler is needed to embed PDF figures in DOCX files.")
|
|
43
|
+
console.print(" Without it, PDF figures will appear as placeholders.")
|
|
44
|
+
console.print()
|
|
45
|
+
|
|
46
|
+
if click.confirm(" Would you like to install poppler now via Homebrew?", default=True):
|
|
47
|
+
console.print("[cyan]Installing poppler...[/cyan]")
|
|
48
|
+
try:
|
|
49
|
+
result = subprocess.run(
|
|
50
|
+
["brew", "install", "poppler"],
|
|
51
|
+
capture_output=True,
|
|
52
|
+
text=True,
|
|
53
|
+
timeout=300,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
if result.returncode == 0:
|
|
57
|
+
console.print("[green]✅ Poppler installed successfully![/green]")
|
|
58
|
+
# Clear dependency cache so it gets re-checked
|
|
59
|
+
manager.clear_cache()
|
|
60
|
+
else:
|
|
61
|
+
console.print(f"[red]❌ Installation failed:[/red] {result.stderr}")
|
|
62
|
+
console.print(" You can install manually with: brew install poppler")
|
|
63
|
+
except subprocess.TimeoutExpired:
|
|
64
|
+
console.print("[red]❌ Installation timed out[/red]")
|
|
65
|
+
except Exception as e:
|
|
66
|
+
console.print(f"[red]❌ Installation error:[/red] {e}")
|
|
67
|
+
else:
|
|
68
|
+
console.print(" [dim]Skipping poppler installation. PDF figures will show as placeholders.[/dim]")
|
|
69
|
+
|
|
70
|
+
elif system == "Linux":
|
|
71
|
+
# Linux
|
|
72
|
+
if not quiet:
|
|
73
|
+
console.print("[yellow]⚠️ Poppler not found[/yellow]")
|
|
74
|
+
console.print(" Install with: sudo apt install poppler-utils")
|
|
75
|
+
console.print()
|
|
76
|
+
else:
|
|
77
|
+
# Other platforms or brew not available
|
|
78
|
+
if not quiet:
|
|
79
|
+
console.print("[yellow]⚠️ Poppler not found[/yellow]")
|
|
80
|
+
console.print(f" Install instructions: {result.resolution_hint}")
|
|
81
|
+
console.print()
|
|
82
|
+
|
|
83
|
+
|
|
13
84
|
@click.command(context_settings={"help_option_names": ["-h", "--help"]})
|
|
14
85
|
@click.argument(
|
|
15
86
|
"manuscript_path",
|
|
@@ -86,6 +157,9 @@ def docx(
|
|
|
86
157
|
include_footnotes=not no_footnotes,
|
|
87
158
|
)
|
|
88
159
|
|
|
160
|
+
# Pre-flight check for poppler (if manuscript contains PDF figures)
|
|
161
|
+
_check_and_offer_poppler_installation(console, quiet, verbose)
|
|
162
|
+
|
|
89
163
|
# Perform export
|
|
90
164
|
docx_path = exporter.export()
|
|
91
165
|
|
|
@@ -1,68 +1,18 @@
|
|
|
1
1
|
"""Upgrade command for rxiv-maker CLI."""
|
|
2
2
|
|
|
3
|
-
import subprocess # nosec B404 - needed for executing upgrade commands
|
|
4
3
|
import sys
|
|
5
4
|
|
|
6
5
|
import click
|
|
7
|
-
from henriqueslab_updater import
|
|
6
|
+
from henriqueslab_updater import handle_upgrade_workflow
|
|
8
7
|
from rich.console import Console
|
|
9
8
|
|
|
10
9
|
from ... import __version__
|
|
11
|
-
from ...utils.
|
|
12
|
-
from ...utils.
|
|
13
|
-
from ..interactive import prompt_confirm
|
|
10
|
+
from ...utils.install_detector import detect_install_method
|
|
11
|
+
from ...utils.rich_upgrade_notifier import RxivUpgradeNotifier
|
|
14
12
|
|
|
15
13
|
console = Console()
|
|
16
14
|
|
|
17
15
|
|
|
18
|
-
def _display_changelog(console: Console, current_version: str, latest_version: str) -> None:
|
|
19
|
-
"""Display changelog summary for version range.
|
|
20
|
-
|
|
21
|
-
Args:
|
|
22
|
-
console: Rich console for output
|
|
23
|
-
current_version: Current installed version
|
|
24
|
-
latest_version: Latest available version
|
|
25
|
-
"""
|
|
26
|
-
console.print("\n📋 What's changing:", style="bold blue")
|
|
27
|
-
|
|
28
|
-
# Fetch changelog summary
|
|
29
|
-
summary, error = fetch_and_format_changelog(
|
|
30
|
-
current_version=current_version,
|
|
31
|
-
latest_version=latest_version,
|
|
32
|
-
highlights_per_version=3,
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
if error:
|
|
36
|
-
console.print(" Unable to fetch changelog details", style="dim yellow")
|
|
37
|
-
console.print(
|
|
38
|
-
f" View online: https://github.com/henriqueslab/rxiv-maker/releases/tag/v{latest_version}",
|
|
39
|
-
style="dim blue",
|
|
40
|
-
)
|
|
41
|
-
return
|
|
42
|
-
|
|
43
|
-
if summary:
|
|
44
|
-
# Display the changelog with proper formatting
|
|
45
|
-
for line in summary.split("\n"):
|
|
46
|
-
if line.startswith("⚠️"):
|
|
47
|
-
# Highlight breaking changes prominently
|
|
48
|
-
console.print(line, style="bold red")
|
|
49
|
-
elif line.startswith("What's New:"):
|
|
50
|
-
console.print(line, style="bold cyan")
|
|
51
|
-
elif line.startswith(" v"):
|
|
52
|
-
# Version headers
|
|
53
|
-
console.print(line, style="bold yellow")
|
|
54
|
-
elif line.strip().startswith(("✨", "🔄", "🐛", "🗑️", "🔒", "📝")):
|
|
55
|
-
# Change items
|
|
56
|
-
console.print(f" {line.strip()}", style="white")
|
|
57
|
-
elif line.strip().startswith("•"):
|
|
58
|
-
# Breaking change items
|
|
59
|
-
console.print(f" {line.strip()}", style="yellow")
|
|
60
|
-
elif line.strip():
|
|
61
|
-
console.print(f" {line}", style="dim")
|
|
62
|
-
else:
|
|
63
|
-
console.print(" No detailed changelog available", style="dim")
|
|
64
|
-
|
|
65
|
-
|
|
66
16
|
@click.command()
|
|
67
17
|
@click.option("--yes", "-y", is_flag=True, help="Skip confirmation prompt")
|
|
68
18
|
@click.option("--check-only", "-c", is_flag=True, help="Only check for updates, don't upgrade")
|
|
@@ -72,93 +22,31 @@ def upgrade(ctx: click.Context, yes: bool, check_only: bool) -> None:
|
|
|
72
22
|
|
|
73
23
|
This command automatically detects how rxiv-maker was installed
|
|
74
24
|
(Homebrew, pip, uv, pipx, etc.) and runs the appropriate upgrade command.
|
|
25
|
+
|
|
26
|
+
Examples:
|
|
27
|
+
rxiv upgrade # Check and upgrade with confirmation
|
|
28
|
+
rxiv upgrade --yes # Upgrade without confirmation
|
|
29
|
+
rxiv upgrade --check-only # Only check for updates
|
|
75
30
|
"""
|
|
76
|
-
#
|
|
31
|
+
# Handle development installations specially
|
|
77
32
|
install_method = detect_install_method()
|
|
78
|
-
install_name = get_friendly_install_name(install_method)
|
|
79
|
-
|
|
80
|
-
console.print(f"🔍 Detected installation method: {install_name}", style="blue")
|
|
81
|
-
|
|
82
|
-
# Handle development installations
|
|
83
33
|
if install_method == "dev":
|
|
84
34
|
console.print("⚠️ Development installation detected", style="yellow")
|
|
85
35
|
console.print(" To update, pull the latest changes from git:", style="yellow")
|
|
86
|
-
console.print(" cd <repo> && git pull && uv sync", style="yellow")
|
|
36
|
+
console.print(" [cyan]cd <repo> && git pull && uv sync[/cyan]", style="yellow")
|
|
87
37
|
sys.exit(0)
|
|
88
38
|
|
|
89
|
-
#
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
# Fetch and display changelog
|
|
101
|
-
_display_changelog(console, __version__, latest_version)
|
|
102
|
-
|
|
103
|
-
if check_only:
|
|
104
|
-
upgrade_cmd = get_upgrade_command(install_method)
|
|
105
|
-
console.print(f"\n Run: {upgrade_cmd}", style="blue")
|
|
106
|
-
sys.exit(0)
|
|
107
|
-
|
|
108
|
-
except Exception as e:
|
|
109
|
-
console.print(f"⚠️ Could not check for updates: {e}", style="yellow")
|
|
110
|
-
console.print(" Proceeding with upgrade attempt...", style="yellow")
|
|
111
|
-
latest_version = "latest"
|
|
112
|
-
|
|
113
|
-
# Get upgrade command
|
|
114
|
-
upgrade_cmd = get_upgrade_command(install_method)
|
|
115
|
-
|
|
116
|
-
# Show confirmation
|
|
117
|
-
if not yes:
|
|
118
|
-
console.print(f"\n📦 About to run: {upgrade_cmd}", style="blue")
|
|
119
|
-
if not prompt_confirm("Do you want to continue?", default=True):
|
|
120
|
-
console.print("❌ Upgrade cancelled", style="yellow")
|
|
121
|
-
sys.exit(0)
|
|
122
|
-
|
|
123
|
-
# Execute upgrade command directly
|
|
124
|
-
console.print("\n🚀 Upgrading rxiv-maker...", style="blue")
|
|
125
|
-
console.print(f" Running: {upgrade_cmd}", style="dim")
|
|
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)
|
|
149
|
-
|
|
150
|
-
if success:
|
|
151
|
-
console.print("\n✅ Upgrade completed successfully!", style="green")
|
|
152
|
-
console.print(" Run 'rxiv --version' to verify the installation", style="blue")
|
|
39
|
+
# Use centralized upgrade workflow
|
|
40
|
+
notifier = RxivUpgradeNotifier(console)
|
|
41
|
+
success, error = handle_upgrade_workflow(
|
|
42
|
+
package_name="rxiv-maker",
|
|
43
|
+
current_version=__version__,
|
|
44
|
+
check_only=check_only,
|
|
45
|
+
skip_confirmation=yes,
|
|
46
|
+
notifier=notifier,
|
|
47
|
+
github_org="HenriquesLab",
|
|
48
|
+
github_repo="rxiv-maker",
|
|
49
|
+
)
|
|
153
50
|
|
|
154
|
-
|
|
155
|
-
if latest_version != "latest":
|
|
156
|
-
console.print(f"\n🎉 What's new in v{latest_version}:", style="bold green")
|
|
157
|
-
console.print(
|
|
158
|
-
f" View full changelog: https://github.com/henriqueslab/rxiv-maker/releases/tag/v{latest_version}",
|
|
159
|
-
style="blue",
|
|
160
|
-
)
|
|
161
|
-
else:
|
|
162
|
-
console.print(f"\n❌ Upgrade failed: {error}", style="red")
|
|
163
|
-
console.print(f" Try running manually: {upgrade_cmd}", style="yellow")
|
|
51
|
+
if not success and error:
|
|
164
52
|
sys.exit(1)
|
|
@@ -487,6 +487,18 @@ class DependencyManager:
|
|
|
487
487
|
)
|
|
488
488
|
)
|
|
489
489
|
|
|
490
|
+
# Poppler utilities for PDF to image conversion (DOCX export)
|
|
491
|
+
self.register_dependency(
|
|
492
|
+
DependencySpec(
|
|
493
|
+
name="pdftoppm",
|
|
494
|
+
type=DependencyType.SYSTEM_BINARY,
|
|
495
|
+
required=False, # Only needed for DOCX export with PDF figures
|
|
496
|
+
alternatives=["pdfinfo"],
|
|
497
|
+
contexts={"docx", "export"},
|
|
498
|
+
install_hint="macOS: brew install poppler | Linux: sudo apt install poppler-utils",
|
|
499
|
+
)
|
|
500
|
+
)
|
|
501
|
+
|
|
490
502
|
def register_dependency(self, spec: DependencySpec) -> None:
|
|
491
503
|
"""Register a dependency specification.
|
|
492
504
|
|
|
@@ -318,9 +318,13 @@ class DocxExporter:
|
|
|
318
318
|
# Get DOI from entry
|
|
319
319
|
doi = entry.fields.get("doi")
|
|
320
320
|
|
|
321
|
-
#
|
|
322
|
-
|
|
323
|
-
|
|
321
|
+
# Attempt DOI resolution if requested and DOI missing
|
|
322
|
+
if self.resolve_dois and not doi:
|
|
323
|
+
doi = self._resolve_doi_from_metadata(entry)
|
|
324
|
+
if doi:
|
|
325
|
+
# Store in entry for this export
|
|
326
|
+
entry.fields["doi"] = doi
|
|
327
|
+
logger.info(f"Resolved DOI for {key}: {doi}")
|
|
324
328
|
|
|
325
329
|
# Format entry (full format for DOCX bibliography)
|
|
326
330
|
formatted = format_bibliography_entry(entry, doi, slim=False, author_format=self.author_format)
|
|
@@ -332,6 +336,99 @@ class DocxExporter:
|
|
|
332
336
|
|
|
333
337
|
return bibliography
|
|
334
338
|
|
|
339
|
+
def _resolve_doi_from_metadata(self, entry) -> str | None:
|
|
340
|
+
"""Resolve DOI from entry metadata using CrossRef API.
|
|
341
|
+
|
|
342
|
+
Args:
|
|
343
|
+
entry: Bibliography entry to resolve DOI for
|
|
344
|
+
|
|
345
|
+
Returns:
|
|
346
|
+
Resolved DOI if found, None otherwise
|
|
347
|
+
"""
|
|
348
|
+
import requests
|
|
349
|
+
|
|
350
|
+
# Try to construct a search query from available fields
|
|
351
|
+
title = entry.fields.get("title", "").strip()
|
|
352
|
+
year = entry.fields.get("year", "").strip()
|
|
353
|
+
|
|
354
|
+
if not title:
|
|
355
|
+
logger.debug(f"Cannot resolve DOI for {entry.key}: no title")
|
|
356
|
+
return None
|
|
357
|
+
|
|
358
|
+
# Clean title for search (remove LaTeX commands, braces, etc.)
|
|
359
|
+
search_title = self._clean_title_for_search(title)
|
|
360
|
+
|
|
361
|
+
# Try CrossRef search API
|
|
362
|
+
try:
|
|
363
|
+
url = "https://api.crossref.org/works"
|
|
364
|
+
params = {
|
|
365
|
+
"query.title": search_title,
|
|
366
|
+
"rows": 5, # Get top 5 results
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
response = requests.get(url, params=params, timeout=10)
|
|
370
|
+
|
|
371
|
+
if response.status_code == 200:
|
|
372
|
+
data = response.json()
|
|
373
|
+
items = data.get("message", {}).get("items", [])
|
|
374
|
+
|
|
375
|
+
# Find best match
|
|
376
|
+
for item in items:
|
|
377
|
+
item_title = item.get("title", [""])[0].lower()
|
|
378
|
+
search_title_lower = search_title.lower()
|
|
379
|
+
|
|
380
|
+
# Simple similarity check - titles should be very similar
|
|
381
|
+
if item_title and (search_title_lower in item_title or item_title in search_title_lower):
|
|
382
|
+
# Verify year matches if available
|
|
383
|
+
if year:
|
|
384
|
+
item_year = item.get("published", {}).get("date-parts", [[None]])[0][0]
|
|
385
|
+
if item_year and str(item_year) != year:
|
|
386
|
+
continue
|
|
387
|
+
|
|
388
|
+
doi = item.get("DOI")
|
|
389
|
+
if doi:
|
|
390
|
+
logger.info(f"Resolved DOI for {entry.key}: {doi}")
|
|
391
|
+
return doi
|
|
392
|
+
|
|
393
|
+
logger.debug(f"Could not resolve DOI for {entry.key} via CrossRef")
|
|
394
|
+
return None
|
|
395
|
+
|
|
396
|
+
except requests.exceptions.Timeout:
|
|
397
|
+
logger.debug(f"CrossRef API timeout resolving DOI for {entry.key}")
|
|
398
|
+
return None
|
|
399
|
+
except requests.exceptions.ConnectionError:
|
|
400
|
+
logger.debug(f"CrossRef API connection error for {entry.key}")
|
|
401
|
+
return None
|
|
402
|
+
except Exception as e:
|
|
403
|
+
logger.debug(f"Error resolving DOI for {entry.key}: {e}")
|
|
404
|
+
return None
|
|
405
|
+
|
|
406
|
+
def _clean_title_for_search(self, title: str) -> str:
|
|
407
|
+
"""Clean title for CrossRef search by removing LaTeX commands.
|
|
408
|
+
|
|
409
|
+
Args:
|
|
410
|
+
title: Raw title from BibTeX entry
|
|
411
|
+
|
|
412
|
+
Returns:
|
|
413
|
+
Cleaned title suitable for search
|
|
414
|
+
"""
|
|
415
|
+
import re
|
|
416
|
+
|
|
417
|
+
# Remove LaTeX commands
|
|
418
|
+
title = re.sub(r"\\[a-zA-Z]+\{([^}]*)\}", r"\1", title) # \textit{foo} -> foo
|
|
419
|
+
title = re.sub(r"\\[a-zA-Z]+", "", title) # \LaTeX -> LaTeX
|
|
420
|
+
|
|
421
|
+
# Remove braces
|
|
422
|
+
title = title.replace("{", "").replace("}", "")
|
|
423
|
+
|
|
424
|
+
# Remove special characters
|
|
425
|
+
title = re.sub(r"[^a-zA-Z0-9\s\-]", " ", title)
|
|
426
|
+
|
|
427
|
+
# Normalize whitespace
|
|
428
|
+
title = " ".join(title.split())
|
|
429
|
+
|
|
430
|
+
return title.strip()
|
|
431
|
+
|
|
335
432
|
def _get_metadata(self) -> Dict[str, Any]:
|
|
336
433
|
"""Extract metadata for title page.
|
|
337
434
|
|
|
@@ -404,6 +404,19 @@ class DocxWriter:
|
|
|
404
404
|
paragraph_format = paragraph.paragraph_format
|
|
405
405
|
paragraph_format.left_indent = Pt(36) # Indent code blocks
|
|
406
406
|
|
|
407
|
+
def _check_poppler_availability(self) -> bool:
|
|
408
|
+
"""Check if poppler is available for PDF conversion.
|
|
409
|
+
|
|
410
|
+
Returns:
|
|
411
|
+
True if poppler is available, False otherwise
|
|
412
|
+
"""
|
|
413
|
+
from ..core.managers.dependency_manager import DependencyStatus, get_dependency_manager
|
|
414
|
+
|
|
415
|
+
manager = get_dependency_manager()
|
|
416
|
+
result = manager.check_dependency("pdftoppm")
|
|
417
|
+
|
|
418
|
+
return result.status == DependencyStatus.AVAILABLE
|
|
419
|
+
|
|
407
420
|
def _add_figure(self, doc: Document, section: Dict[str, Any], figure_number: int = None):
|
|
408
421
|
"""Add figure to document with caption.
|
|
409
422
|
|
|
@@ -425,9 +438,31 @@ class DocxWriter:
|
|
|
425
438
|
if not figure_path.exists():
|
|
426
439
|
logger.warning(f"Figure file not found: {figure_path}")
|
|
427
440
|
elif figure_path.suffix.lower() == ".pdf":
|
|
428
|
-
#
|
|
429
|
-
|
|
430
|
-
|
|
441
|
+
# Check poppler availability first (cached after first check)
|
|
442
|
+
if not hasattr(self, "_poppler_checked"):
|
|
443
|
+
self._poppler_available = self._check_poppler_availability()
|
|
444
|
+
self._poppler_checked = True
|
|
445
|
+
|
|
446
|
+
if not self._poppler_available:
|
|
447
|
+
logger.warning(
|
|
448
|
+
"Poppler not installed - PDF figures will be shown as placeholders. "
|
|
449
|
+
"Install with: brew install poppler (macOS) or sudo apt install poppler-utils (Linux)"
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
if self._poppler_available:
|
|
453
|
+
# Convert PDF to image
|
|
454
|
+
try:
|
|
455
|
+
from pdf2image.exceptions import PDFInfoNotInstalledError, PopplerNotInstalledError
|
|
456
|
+
|
|
457
|
+
img_source = convert_pdf_to_image(figure_path)
|
|
458
|
+
logger.debug(f" PDF converted: {img_source is not None}")
|
|
459
|
+
except (PopplerNotInstalledError, PDFInfoNotInstalledError) as e:
|
|
460
|
+
logger.error(f"Poppler utilities not found: {e}")
|
|
461
|
+
img_source = None
|
|
462
|
+
# Update our cached status
|
|
463
|
+
self._poppler_available = False
|
|
464
|
+
else:
|
|
465
|
+
img_source = None
|
|
431
466
|
elif figure_path.suffix.lower() in [".png", ".jpg", ".jpeg", ".gif", ".bmp"]:
|
|
432
467
|
# Use image file directly
|
|
433
468
|
img_source = str(figure_path)
|
|
@@ -81,21 +81,41 @@ def generate_bst_file(format_type: str, output_dir: Path) -> Path:
|
|
|
81
81
|
except IOError as e:
|
|
82
82
|
raise IOError(f"Failed to read template .bst file: {e}") from e
|
|
83
83
|
|
|
84
|
-
# Replace the format string
|
|
84
|
+
# Replace the format string in the format.names function (line ~222)
|
|
85
85
|
# The line looks like: s nameptr "{ff~}{vv~}{ll}{, jj}" format.name$ 't :=
|
|
86
|
-
# We need to replace
|
|
87
|
-
|
|
86
|
+
# We need to replace ONLY in format.names, NOT in format.full.names
|
|
87
|
+
#
|
|
88
|
+
# Strategy: Match the FUNCTION {format.names} block specifically
|
|
89
|
+
# This ensures we don't modify format.full.names which is used for citation labels
|
|
90
|
+
#
|
|
91
|
+
# Pattern explanation:
|
|
92
|
+
# 1. Match "FUNCTION {format.names}" to find the start of the function
|
|
93
|
+
# 2. Use non-greedy match (.*?) to capture until we find our target line
|
|
94
|
+
# 3. Match and capture the format string in quotes
|
|
95
|
+
# 4. This avoids matching format.full.names which appears later in the file
|
|
96
|
+
pattern = r'(FUNCTION\s+\{format\.names\}.*?s\s+nameptr\s+")([^"]+)("\s+format\.name\$)'
|
|
88
97
|
replacement = rf"\1{format_string}\3"
|
|
89
98
|
|
|
90
|
-
modified_content, num_subs = re.subn(pattern, replacement, bst_content)
|
|
99
|
+
modified_content, num_subs = re.subn(pattern, replacement, bst_content, flags=re.DOTALL)
|
|
91
100
|
|
|
92
101
|
if num_subs == 0:
|
|
93
|
-
logger.warning(
|
|
102
|
+
logger.warning(
|
|
103
|
+
"No format string pattern found in format.names function. "
|
|
104
|
+
"The .bst file structure may have changed. "
|
|
105
|
+
"Citation formatting may not work as expected."
|
|
106
|
+
)
|
|
94
107
|
# Still write the file but log a warning
|
|
95
108
|
elif num_subs > 1:
|
|
96
|
-
|
|
97
|
-
|
|
109
|
+
# This should never happen with the new pattern, but keep the check
|
|
110
|
+
logger.error(
|
|
111
|
+
f"Found {num_subs} matches in .bst file. Expected exactly 1. "
|
|
112
|
+
"This indicates an unexpected .bst file structure. "
|
|
113
|
+
"Please report this issue."
|
|
98
114
|
)
|
|
115
|
+
raise ValueError(f"Unexpected .bst file structure: found {num_subs} matches for format.names, expected 1")
|
|
116
|
+
else:
|
|
117
|
+
# Success - exactly one match
|
|
118
|
+
logger.debug(f"Successfully updated format.names function with format '{format_type}'")
|
|
99
119
|
|
|
100
120
|
# Create output directory if it doesn't exist
|
|
101
121
|
output_dir = Path(output_dir)
|
rxiv_maker/utils/docx_helpers.py
CHANGED
|
@@ -8,6 +8,7 @@ This module provides utility functions for DOCX generation including:
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
import io
|
|
11
|
+
import logging
|
|
11
12
|
import re
|
|
12
13
|
from pathlib import Path
|
|
13
14
|
from typing import Optional
|
|
@@ -18,6 +19,8 @@ from rxiv_maker.utils.author_name_formatter import format_author_list
|
|
|
18
19
|
|
|
19
20
|
from ..utils.bibliography_parser import BibEntry
|
|
20
21
|
|
|
22
|
+
logger = logging.getLogger(__name__)
|
|
23
|
+
|
|
21
24
|
|
|
22
25
|
def remove_yaml_header(content: str) -> str:
|
|
23
26
|
r"""Remove YAML frontmatter from markdown content.
|
|
@@ -395,6 +398,12 @@ def convert_pdf_to_image(pdf_path: Path, dpi: int = 150, max_width: int = 6) ->
|
|
|
395
398
|
"""
|
|
396
399
|
try:
|
|
397
400
|
from pdf2image import convert_from_path
|
|
401
|
+
from pdf2image.exceptions import (
|
|
402
|
+
PDFInfoNotInstalledError,
|
|
403
|
+
PDFPageCountError,
|
|
404
|
+
PDFSyntaxError,
|
|
405
|
+
PopplerNotInstalledError,
|
|
406
|
+
)
|
|
398
407
|
|
|
399
408
|
# Convert first page of PDF to image
|
|
400
409
|
images = convert_from_path(
|
|
@@ -427,7 +436,19 @@ def convert_pdf_to_image(pdf_path: Path, dpi: int = 150, max_width: int = 6) ->
|
|
|
427
436
|
|
|
428
437
|
return img_bytes
|
|
429
438
|
|
|
439
|
+
except (PopplerNotInstalledError, PDFInfoNotInstalledError):
|
|
440
|
+
# Re-raise poppler errors so caller can handle them appropriately
|
|
441
|
+
# (e.g., CLI can offer to install poppler)
|
|
442
|
+
raise
|
|
443
|
+
except PDFSyntaxError as e:
|
|
444
|
+
# PDF file is malformed/corrupted
|
|
445
|
+
logger.warning(f"PDF file appears to be corrupted: {pdf_path.name} - {e}")
|
|
446
|
+
return None
|
|
447
|
+
except PDFPageCountError as e:
|
|
448
|
+
# Issue getting page count
|
|
449
|
+
logger.warning(f"Could not determine PDF page count for {pdf_path.name}: {e}")
|
|
450
|
+
return None
|
|
430
451
|
except Exception as e:
|
|
431
|
-
#
|
|
432
|
-
|
|
452
|
+
# Other unexpected errors
|
|
453
|
+
logger.warning(f"Failed to convert {pdf_path.name} to image: {e}")
|
|
433
454
|
return None
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"""Rich console adapter for upgrade notifications in rxiv-maker."""
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
from rich.console import Console
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class RxivUpgradeNotifier:
|
|
8
|
+
"""Adapt Rich console to UpgradeNotifier protocol for rxiv-maker.
|
|
9
|
+
|
|
10
|
+
Integrates with rxiv-maker's changelog parser to show rich change summaries.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __init__(self, console: Console):
|
|
14
|
+
"""Initialize with Rich console instance.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
console: Rich Console instance for styled output
|
|
18
|
+
"""
|
|
19
|
+
self.console = console
|
|
20
|
+
|
|
21
|
+
def show_checking(self) -> None:
|
|
22
|
+
"""Show 'checking for updates' message."""
|
|
23
|
+
self.console.print("🔍 Checking for updates...", style="blue")
|
|
24
|
+
|
|
25
|
+
def show_version_check(self, current: str, latest: str, available: bool) -> None:
|
|
26
|
+
"""Show version check results.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
current: Current installed version
|
|
30
|
+
latest: Latest available version
|
|
31
|
+
available: Whether an update is available
|
|
32
|
+
"""
|
|
33
|
+
if available:
|
|
34
|
+
self.console.print(
|
|
35
|
+
f"📦 Update available: [cyan]v{current}[/cyan] → [green bold]v{latest}[/green bold]",
|
|
36
|
+
style="yellow",
|
|
37
|
+
)
|
|
38
|
+
else:
|
|
39
|
+
self.console.print(
|
|
40
|
+
f"✅ You already have the latest version ([cyan]v{current}[/cyan])",
|
|
41
|
+
style="green",
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
def show_update_info(self, current: str, latest: str, release_url: str) -> None:
|
|
45
|
+
"""Show update available information with changelog integration.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
current: Current version
|
|
49
|
+
latest: Latest version
|
|
50
|
+
release_url: URL to release notes
|
|
51
|
+
"""
|
|
52
|
+
# Import here to avoid circular dependencies
|
|
53
|
+
from .changelog_parser import fetch_and_format_changelog
|
|
54
|
+
|
|
55
|
+
# Fetch and display changelog
|
|
56
|
+
summary, error = fetch_and_format_changelog(
|
|
57
|
+
current_version=current,
|
|
58
|
+
latest_version=latest,
|
|
59
|
+
highlights_per_version=3,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
if summary and not error:
|
|
63
|
+
self.console.print("\n📋 What's changing:", style="bold blue")
|
|
64
|
+
# Display changelog - format_summary returns rich-formatted text
|
|
65
|
+
# Parse and display with proper styling
|
|
66
|
+
for line in summary.split("\n"):
|
|
67
|
+
if line.startswith("⚠️"):
|
|
68
|
+
# Highlight breaking changes prominently
|
|
69
|
+
self.console.print(line, style="bold red")
|
|
70
|
+
elif "What's New:" in line or "What's changing:" in line:
|
|
71
|
+
self.console.print(line, style="bold cyan")
|
|
72
|
+
elif line.strip().startswith("v"):
|
|
73
|
+
# Version headers
|
|
74
|
+
self.console.print(line, style="bold yellow")
|
|
75
|
+
elif line.strip().startswith(("✨", "🔄", "🐛", "🗑️", "🔒", "📝")):
|
|
76
|
+
# Change items with emojis
|
|
77
|
+
self.console.print(f" {line.strip()}", style="white")
|
|
78
|
+
elif line.strip().startswith("•"):
|
|
79
|
+
# Breaking change items
|
|
80
|
+
self.console.print(f" {line.strip()}", style="yellow")
|
|
81
|
+
elif line.strip():
|
|
82
|
+
self.console.print(f" {line}", style="dim")
|
|
83
|
+
else:
|
|
84
|
+
# Fallback if changelog unavailable
|
|
85
|
+
self.console.print(
|
|
86
|
+
f"\nView release notes: [link]{release_url}[/link]",
|
|
87
|
+
style="blue",
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
def show_installer_info(self, friendly_name: str, command: str) -> None:
|
|
91
|
+
"""Show detected installer information.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
friendly_name: Human-readable installer name
|
|
95
|
+
command: The upgrade command that will be executed
|
|
96
|
+
"""
|
|
97
|
+
self.console.print()
|
|
98
|
+
self.console.print(
|
|
99
|
+
f"🔍 Detected installation method: [bold]{friendly_name}[/bold]",
|
|
100
|
+
style="blue",
|
|
101
|
+
)
|
|
102
|
+
self.console.print(f"📦 Running: [yellow]{command}[/yellow]")
|
|
103
|
+
|
|
104
|
+
def show_success(self, version: str) -> None:
|
|
105
|
+
"""Show successful upgrade message.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
version: Version that was successfully installed
|
|
109
|
+
"""
|
|
110
|
+
self.console.print()
|
|
111
|
+
self.console.print("✅ Upgrade completed successfully!", style="green bold")
|
|
112
|
+
self.console.print(f" Now running: [green]v{version}[/green]")
|
|
113
|
+
self.console.print()
|
|
114
|
+
self.console.print(" Run [blue]'rxiv --version'[/blue] to verify the installation", style="dim")
|
|
115
|
+
|
|
116
|
+
def show_error(self, error: str | None) -> None:
|
|
117
|
+
"""Show upgrade error message.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
error: Error message or None
|
|
121
|
+
"""
|
|
122
|
+
self.console.print()
|
|
123
|
+
self.console.print("❌ Upgrade failed", style="red bold")
|
|
124
|
+
if error:
|
|
125
|
+
self.console.print(f" {error}", style="red")
|
|
126
|
+
|
|
127
|
+
def show_manual_instructions(self, install_method: str) -> None:
|
|
128
|
+
"""Show manual upgrade instructions.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
install_method: The detected installation method
|
|
132
|
+
"""
|
|
133
|
+
self.console.print("\n💡 Try running manually:", style="yellow bold")
|
|
134
|
+
|
|
135
|
+
if install_method == "homebrew":
|
|
136
|
+
self.console.print(" [cyan]brew update && brew upgrade rxiv-maker[/cyan]")
|
|
137
|
+
elif install_method == "pipx":
|
|
138
|
+
self.console.print(" [cyan]pipx upgrade rxiv-maker[/cyan]")
|
|
139
|
+
elif install_method == "uv":
|
|
140
|
+
self.console.print(" [cyan]uv tool upgrade rxiv-maker[/cyan]")
|
|
141
|
+
elif install_method == "dev":
|
|
142
|
+
self.console.print(" [cyan]cd <repo> && git pull && uv sync[/cyan]", style="dim")
|
|
143
|
+
else:
|
|
144
|
+
self.console.print(" [cyan]pip install --upgrade rxiv-maker[/cyan]")
|
|
145
|
+
self.console.print(" [dim]# Or with --user flag:[/dim]")
|
|
146
|
+
self.console.print(" [cyan]pip install --upgrade --user rxiv-maker[/cyan]")
|
|
147
|
+
|
|
148
|
+
def confirm_upgrade(self, version: str) -> bool:
|
|
149
|
+
"""Prompt user for confirmation using click.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
version: Version to upgrade to
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
True if user confirms, False otherwise
|
|
156
|
+
"""
|
|
157
|
+
try:
|
|
158
|
+
self.console.print()
|
|
159
|
+
return click.confirm(f"Upgrade rxiv-maker to v{version}?", default=True)
|
|
160
|
+
except (KeyboardInterrupt, EOFError):
|
|
161
|
+
self.console.print("\n⚠️ Upgrade cancelled.", style="yellow")
|
|
162
|
+
return False
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rxiv-maker
|
|
3
|
-
Version: 1.16.
|
|
3
|
+
Version: 1.16.8
|
|
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
|
|
@@ -27,7 +27,7 @@ Requires-Python: >=3.10
|
|
|
27
27
|
Requires-Dist: click>=8.0.0
|
|
28
28
|
Requires-Dist: crossref-commons>=0.0.7
|
|
29
29
|
Requires-Dist: gitpython>=3.1.0
|
|
30
|
-
Requires-Dist: henriqueslab-updater>=1.
|
|
30
|
+
Requires-Dist: henriqueslab-updater>=1.2.0
|
|
31
31
|
Requires-Dist: latex2mathml>=3.78.0
|
|
32
32
|
Requires-Dist: matplotlib>=3.7.0
|
|
33
33
|
Requires-Dist: numpy>=1.24.0
|
|
@@ -358,9 +358,14 @@ rxiv config --non-interactive # Show current settings
|
|
|
358
358
|
|
|
359
359
|
### Maintenance
|
|
360
360
|
```bash
|
|
361
|
-
|
|
362
|
-
rxiv
|
|
363
|
-
rxiv
|
|
361
|
+
# Upgrade commands (auto-detects Homebrew, pip, uv, pipx)
|
|
362
|
+
rxiv upgrade # Interactive upgrade with confirmation
|
|
363
|
+
rxiv upgrade --yes # Upgrade without confirmation
|
|
364
|
+
rxiv upgrade --check-only # Check for updates only
|
|
365
|
+
|
|
366
|
+
# Changelog and version information
|
|
367
|
+
rxiv changelog # View changelog and release notes
|
|
368
|
+
rxiv changelog --recent 5 # View last 5 versions
|
|
364
369
|
```
|
|
365
370
|
|
|
366
371
|
> **💡 CI/Automation Note:** All interactive commands support non-interactive mode or configuration files for use in CI/CD pipelines and automated workflows. Use `--non-interactive` flag or configure via `~/.rxiv-maker/config` for non-TTY environments.
|
|
@@ -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=FDIQKkG-uf-zpYYZrGmwOD83CED6k3EcIvKFr382p-g,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
|
|
@@ -19,7 +19,7 @@ rxiv_maker/cli/commands/clean.py,sha256=8yQVbhHLQX0xIM7MD-0sG_agX7xVxzl1AkqPzZRR
|
|
|
19
19
|
rxiv_maker/cli/commands/completion.py,sha256=TKc6QPEFVN8qQsu2LbPEZvsSZr_CBvyekkfTItTDI6A,789
|
|
20
20
|
rxiv_maker/cli/commands/config.py,sha256=adN4ci_EB-NZsNXNY9FlFxE6CLVxblunX1dobrjNef0,33761
|
|
21
21
|
rxiv_maker/cli/commands/create_repo.py,sha256=jWPwT1Ai7XBhFAi9JmSAobdFYXPlSgQCD-gx_ZUNwEo,9947
|
|
22
|
-
rxiv_maker/cli/commands/docx.py,sha256=
|
|
22
|
+
rxiv_maker/cli/commands/docx.py,sha256=memJ5SeSQ8rD_wwOH9gUs1TgJUpP25_gIKEu8lKn5nQ,5896
|
|
23
23
|
rxiv_maker/cli/commands/figures.py,sha256=WraC0BjwxKImzCwt1A3vWs8_T4w2misP1eeW6aznpCw,3250
|
|
24
24
|
rxiv_maker/cli/commands/get_rxiv_preprint.py,sha256=nSPuFpS5xZ9VaUrmwnFZ5RCAAjj0ORAj8x_EJmH0Xtg,8543
|
|
25
25
|
rxiv_maker/cli/commands/init.py,sha256=2UiXtk7a5bklqwevWwhbL9lU1ASBxUwzm7JdrINHcGA,1797
|
|
@@ -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=UpdqEQwbNYmDMbSrYGv_pVd-7u8PPT3US5RVENhKK4w,1852
|
|
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
|
|
@@ -80,7 +80,7 @@ rxiv_maker/core/cache/secure_cache_utils.py,sha256=EejPWvxw_mUPqO0TRBHYYTsLXWZEU
|
|
|
80
80
|
rxiv_maker/core/managers/__init__.py,sha256=sh4ZuZH4YrAu4XTiN9ky1-tQQASKiSTY0udJJAzDRcU,950
|
|
81
81
|
rxiv_maker/core/managers/cache_manager.py,sha256=8btUaRDYPOrUynHWBMz7RVeS9xcpUoyhemFNUi8NqpQ,21893
|
|
82
82
|
rxiv_maker/core/managers/config_manager.py,sha256=DdM-3_mfrjHFkPQ2vOmpQnXaoSJU-ianVwUvCEIwZss,18829
|
|
83
|
-
rxiv_maker/core/managers/dependency_manager.py,sha256=
|
|
83
|
+
rxiv_maker/core/managers/dependency_manager.py,sha256=qtUR4sQD2x1zv4Fi77d6ThwPx9eHZ9_ZyNy0hRpIKKQ,26308
|
|
84
84
|
rxiv_maker/core/managers/execution_manager.py,sha256=cEDS0KyWBHf_N74Fc8MC4VRXxmEcaz_DJtyWO5-o628,29585
|
|
85
85
|
rxiv_maker/core/managers/file_manager.py,sha256=SVRnP1JQoGCAms3E7iSpOp_RG60P36Qk9HGAmJDaFvE,18641
|
|
86
86
|
rxiv_maker/core/managers/install_manager.py,sha256=8HChOfbm5-uXsksKMDqmgrYNMJJtyDoL2RDNpbFwhwc,15533
|
|
@@ -106,8 +106,8 @@ rxiv_maker/engines/operations/validate_pdf.py,sha256=qyrtL752Uap3i6ntQheY570soVj
|
|
|
106
106
|
rxiv_maker/exporters/__init__.py,sha256=NcTD1SDb8tTgsHhCS1A7TVEZncyWbDRTa6sJIdLqcsE,350
|
|
107
107
|
rxiv_maker/exporters/docx_citation_mapper.py,sha256=Qp3IEqrR6lQGQPQ4JeGdOCWeg97XBbVCKdX1gtX9XfY,4584
|
|
108
108
|
rxiv_maker/exporters/docx_content_processor.py,sha256=3srXfq4lC_FJpTAfu-WB930WheSm6rCy-vNUtFlsflY,23878
|
|
109
|
-
rxiv_maker/exporters/docx_exporter.py,sha256=
|
|
110
|
-
rxiv_maker/exporters/docx_writer.py,sha256=
|
|
109
|
+
rxiv_maker/exporters/docx_exporter.py,sha256=Q18TuZCbx6fzAs1f9G2A9h5N2Gw5qhCrL7a2NKXizg8,18672
|
|
110
|
+
rxiv_maker/exporters/docx_writer.py,sha256=CW2Xu9-vpuEct9344bM8ofGkCiWlAYijoXVzZ7MQZ6g,43460
|
|
111
111
|
rxiv_maker/install/__init__.py,sha256=kAB6P-12IKg_K1MQ-uzeC5IR11O2cNxj0t_2JMhooZs,590
|
|
112
112
|
rxiv_maker/install/dependency_handlers/__init__.py,sha256=NN9dP1usXpYgLpSw0uEnJ6ugX2zefihVjdyDdm1k-cE,231
|
|
113
113
|
rxiv_maker/install/dependency_handlers/latex.py,sha256=xopSJxYkg3D63rH7RoVLN-Ykl87AZqhlUrrG3m6LoWo,3304
|
|
@@ -147,11 +147,11 @@ rxiv_maker/utils/__init__.py,sha256=4ya5VR8jqRqUChlnUeMeeetOuWV-gIvjPwcE1u_1OnI,
|
|
|
147
147
|
rxiv_maker/utils/author_name_formatter.py,sha256=UjvarbyQm89EUIYqckygx3g37o-EcNyvipBtY8GJDxs,10222
|
|
148
148
|
rxiv_maker/utils/bibliography_checksum.py,sha256=Jh4VILSpGQ5KJ9UBCUb7oFy6lZ9_ncXD87vEXxw5jbY,10270
|
|
149
149
|
rxiv_maker/utils/bibliography_parser.py,sha256=WZIQoEpVwdbLmbkw9FdkVgoLE5GX7itqnzPnEEb_fFU,6846
|
|
150
|
-
rxiv_maker/utils/bst_generator.py,sha256=
|
|
150
|
+
rxiv_maker/utils/bst_generator.py,sha256=m69JWMIvf9eRiHcaWB-8D3DQCDO8flVIYbOBMuzV-F0,6097
|
|
151
151
|
rxiv_maker/utils/changelog_parser.py,sha256=WCDp9Iy6H6_3nC6FB7RLt6i00zuCyvU17sCU4e3pqCY,11954
|
|
152
152
|
rxiv_maker/utils/citation_utils.py,sha256=spIgVxPAN6jPvoG-eOE00rVX_buUGKnUjP1Fhz31sl4,5134
|
|
153
153
|
rxiv_maker/utils/dependency_checker.py,sha256=EdyIvk-W_bhC1DJCpFw5ePhjEU74C9j7RYMm06unBMA,14366
|
|
154
|
-
rxiv_maker/utils/docx_helpers.py,sha256=
|
|
154
|
+
rxiv_maker/utils/docx_helpers.py,sha256=rNNnz3mhXymrTgQR4bZDnGwpUFylWVpfpJnY0bWnl30,13635
|
|
155
155
|
rxiv_maker/utils/doi_resolver.py,sha256=8_oy5cTtklm1GCKXpn509yqYsu4P5gYbMjtfQ8dRgFA,10253
|
|
156
156
|
rxiv_maker/utils/email_encoder.py,sha256=QMD5JbGNu68gD8SBdGHfNY8uCgbMzEcmzE1TCYDMgWY,5139
|
|
157
157
|
rxiv_maker/utils/figure_checksum.py,sha256=PWgh2QAErNnnQCV-t-COACQXKICUaggAAIxhgHLCGNM,10748
|
|
@@ -165,6 +165,7 @@ rxiv_maker/utils/performance.py,sha256=EBDVNshSaeG7Nu-GCZtRAzTunGn4z_Bb2jEck045b
|
|
|
165
165
|
rxiv_maker/utils/platform.py,sha256=DCD3gvm7_DBcT67gGIXhTDV5mPrBjWrL7R2JdsmIgng,17773
|
|
166
166
|
rxiv_maker/utils/python_execution_reporter.py,sha256=l3hqLXtGAg_wKUlkikK1oaHPeBpoCkj3iR6i1fc11ys,10606
|
|
167
167
|
rxiv_maker/utils/retry.py,sha256=aNsuc7HuxMwG4yubgX0GxIEZ0iF6_4lACusVMc0ZSXA,11026
|
|
168
|
+
rxiv_maker/utils/rich_upgrade_notifier.py,sha256=aMqkx9l_2KtEiwVFdhOU4oqsAgdWQ86LuqWN4k_cTA0,6365
|
|
168
169
|
rxiv_maker/utils/text_utils.py,sha256=ntovIx7qXB0LWO9OmCu7-rqTSfyEvthrTjYEJTbmZ_U,1972
|
|
169
170
|
rxiv_maker/utils/tips.py,sha256=XHgbJkyFjYt5Pz-Rdz_yCjnRLguxIsHwdFmNSg323NA,8078
|
|
170
171
|
rxiv_maker/utils/title_sync.py,sha256=C7NT80DgBJrS70mil6b7ghcZyKR2n5_MNlC6Yli_dXM,15094
|
|
@@ -187,8 +188,8 @@ rxiv_maker/validators/doi/metadata_comparator.py,sha256=euqHhKP5sHQAdZbdoAahUn6Y
|
|
|
187
188
|
rxiv_maker/tex/template.tex,sha256=zrJ3aFfu8j9zkg1l375eE9w-j42P3rz16wMD3dSgi1I,1354
|
|
188
189
|
rxiv_maker/tex/style/rxiv_maker_style.bst,sha256=jbVqrJgAm6F88cow5vtZuPBwwmlcYykclTm8RvZIo6Y,24281
|
|
189
190
|
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.
|
|
191
|
+
rxiv_maker-1.16.8.dist-info/METADATA,sha256=3GydBaQKqwL3nUaxEPdNRRobVMhmb7hRvJW7e5qQ_gc,18177
|
|
192
|
+
rxiv_maker-1.16.8.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
193
|
+
rxiv_maker-1.16.8.dist-info/entry_points.txt,sha256=ghCN0hI9A1GlG7QY5F6E-xYPflA8CyS4B6bTQ1YLop0,97
|
|
194
|
+
rxiv_maker-1.16.8.dist-info/licenses/LICENSE,sha256=GSZFoPIhWDNJEtSHTQ5dnELN38zFwRiQO2antBezGQk,1093
|
|
195
|
+
rxiv_maker-1.16.8.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|