rxiv2pdf 0.1.0__tar.gz
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.
- rxiv2pdf-0.1.0/LICENSE +21 -0
- rxiv2pdf-0.1.0/PKG-INFO +191 -0
- rxiv2pdf-0.1.0/README.md +158 -0
- rxiv2pdf-0.1.0/pyproject.toml +66 -0
- rxiv2pdf-0.1.0/pyproject.toml.orig +53 -0
- rxiv2pdf-0.1.0/src/rxiv2pdf/__init__.py +8 -0
- rxiv2pdf-0.1.0/src/rxiv2pdf/__main__.py +5 -0
- rxiv2pdf-0.1.0/src/rxiv2pdf/cli.py +348 -0
- rxiv2pdf-0.1.0/src/rxiv2pdf/compile.py +285 -0
- rxiv2pdf-0.1.0/src/rxiv2pdf/fetch.py +808 -0
- rxiv2pdf-0.1.0/src/rxiv2pdf/fonts/OFL-SourceSans3.md +93 -0
- rxiv2pdf-0.1.0/src/rxiv2pdf/fonts/OFL-SourceSerif4.md +93 -0
- rxiv2pdf-0.1.0/src/rxiv2pdf/fonts/README.md +6 -0
- rxiv2pdf-0.1.0/src/rxiv2pdf/fonts/SourceSans3-Bold.ttf +0 -0
- rxiv2pdf-0.1.0/src/rxiv2pdf/fonts/SourceSans3-BoldIt.ttf +0 -0
- rxiv2pdf-0.1.0/src/rxiv2pdf/fonts/SourceSans3-It.ttf +0 -0
- rxiv2pdf-0.1.0/src/rxiv2pdf/fonts/SourceSans3-Regular.ttf +0 -0
- rxiv2pdf-0.1.0/src/rxiv2pdf/fonts/SourceSans3-Semibold.ttf +0 -0
- rxiv2pdf-0.1.0/src/rxiv2pdf/fonts/SourceSerif4SmText-Bold.ttf +0 -0
- rxiv2pdf-0.1.0/src/rxiv2pdf/fonts/SourceSerif4SmText-BoldIt.ttf +0 -0
- rxiv2pdf-0.1.0/src/rxiv2pdf/fonts/SourceSerif4SmText-It.ttf +0 -0
- rxiv2pdf-0.1.0/src/rxiv2pdf/fonts/SourceSerif4SmText-Regular.ttf +0 -0
- rxiv2pdf-0.1.0/src/rxiv2pdf/images.py +240 -0
- rxiv2pdf-0.1.0/src/rxiv2pdf/jats.py +1113 -0
- rxiv2pdf-0.1.0/src/rxiv2pdf/mathml.py +275 -0
- rxiv2pdf-0.1.0/src/rxiv2pdf/model.py +301 -0
- rxiv2pdf-0.1.0/src/rxiv2pdf/net.py +290 -0
- rxiv2pdf-0.1.0/src/rxiv2pdf/render_typst.py +764 -0
- rxiv2pdf-0.1.0/src/rxiv2pdf/resolve.py +125 -0
- rxiv2pdf-0.1.0/src/rxiv2pdf/templates/journal.typ +785 -0
- rxiv2pdf-0.1.0/src/rxiv2pdf/templates/themes/compact.typ +28 -0
- rxiv2pdf-0.1.0/src/rxiv2pdf/templates/themes/default.typ +3 -0
- rxiv2pdf-0.1.0/src/rxiv2pdf/templates/themes/sans.typ +27 -0
rxiv2pdf-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ali Zaeim
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
rxiv2pdf-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rxiv2pdf
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Turn a bioRxiv/medRxiv preprint into a two-column, journal-style PDF built from its JATS XML.
|
|
5
|
+
Keywords: biorxiv,medrxiv,preprint,jats,pdf,typst
|
|
6
|
+
Author: Ali Zaeim
|
|
7
|
+
License-Expression: MIT AND OFL-1.1
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
License-File: src/rxiv2pdf/fonts/OFL-SourceSans3.md
|
|
10
|
+
License-File: src/rxiv2pdf/fonts/OFL-SourceSerif4.md
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
20
|
+
Classifier: Topic :: Text Processing :: Markup :: XML
|
|
21
|
+
Requires-Dist: httpx>=0.27
|
|
22
|
+
Requires-Dist: lxml>=5.3
|
|
23
|
+
Requires-Dist: pillow>=11.0
|
|
24
|
+
Requires-Dist: rich>=13.7
|
|
25
|
+
Requires-Dist: typer>=0.16
|
|
26
|
+
Requires-Dist: typst>=0.15
|
|
27
|
+
Requires-Python: >=3.11
|
|
28
|
+
Project-URL: Homepage, https://github.com/ali-zaeim/rxiv2pdf
|
|
29
|
+
Project-URL: Repository, https://github.com/ali-zaeim/rxiv2pdf
|
|
30
|
+
Project-URL: Issues, https://github.com/ali-zaeim/rxiv2pdf/issues
|
|
31
|
+
Project-URL: Changelog, https://github.com/ali-zaeim/rxiv2pdf/blob/main/CHANGELOG.md
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# rxiv2pdf
|
|
35
|
+
|
|
36
|
+
[](https://github.com/ali-zaeim/rxiv2pdf/actions/workflows/ci.yml)
|
|
37
|
+
[](https://pypi.org/project/rxiv2pdf/)
|
|
38
|
+
[](https://pypi.org/project/rxiv2pdf/)
|
|
39
|
+
[](https://github.com/ali-zaeim/rxiv2pdf/blob/main/LICENSE)
|
|
40
|
+
|
|
41
|
+
Turn a bioRxiv or medRxiv preprint into a two-column, journal-style PDF.
|
|
42
|
+
|
|
43
|
+
The PDF on bioRxiv and medRxiv is the authors' submitted manuscript, often double-spaced and
|
|
44
|
+
line-numbered, with the figures at the end. rxiv2pdf rebuilds the paper from the preprint's JATS
|
|
45
|
+
XML instead, with each figure placed after the text that first cites it and the citations linked
|
|
46
|
+
to the references.
|
|
47
|
+
|
|
48
|
+
```console
|
|
49
|
+
$ rxiv2pdf https://www.biorxiv.org/content/10.64898/2026.10.16.759679v1
|
|
50
|
+
PDF 2026.10.16.759679v1.pdf
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
| Page 1 | A figure page |
|
|
54
|
+
|:--:|:--:|
|
|
55
|
+
|  |  |
|
|
56
|
+
|
|
57
|
+
<sub>Screenshots on this page: Ghosh *et al.*, "Astrocytic sEH–EET signaling regulates microglial
|
|
58
|
+
lysosomal function and suppresses the STING–Type I interferon pathway in Alzheimer's disease",
|
|
59
|
+
bioRxiv [10.64898/2026.10.16.759679](https://doi.org/10.64898/2026.10.16.759679), CC BY 4.0.</sub>
|
|
60
|
+
|
|
61
|
+
## Install
|
|
62
|
+
|
|
63
|
+
Requires Python 3.11+. Typst comes with the `typst` Python package and the fonts are bundled, so
|
|
64
|
+
nothing else is needed.
|
|
65
|
+
|
|
66
|
+
```console
|
|
67
|
+
$ pipx install rxiv2pdf # or: uv tool install rxiv2pdf
|
|
68
|
+
$ rxiv2pdf --help
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`pip install rxiv2pdf` works too. To try it without installing anything:
|
|
72
|
+
`uvx rxiv2pdf 10.1101/2024.04.17.590000`.
|
|
73
|
+
|
|
74
|
+
## Usage
|
|
75
|
+
|
|
76
|
+
```console
|
|
77
|
+
$ rxiv2pdf 10.1101/2024.04.17.590000 # bare DOI (bioRxiv by default, medRxiv tried next)
|
|
78
|
+
$ rxiv2pdf https://www.medrxiv.org/content/10.64898/2026.09.25.26364016v1.full
|
|
79
|
+
$ rxiv2pdf https://doi.org/10.64898/2026.10.22.760766 -o papers/ --theme compact --paper a4
|
|
80
|
+
$ rxiv2pdf 10.1101/2020.03.22.002386v2 # a specific version (default: latest)
|
|
81
|
+
$ rxiv2pdf --list dois.txt -o papers/ # batch: one URL/DOI per line, # comments ok
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
All options are listed under [Options](#options).
|
|
85
|
+
|
|
86
|
+
## What you get
|
|
87
|
+
|
|
88
|
+
- **Front matter:** title, authors and affiliations, abstract, and a banner with the DOI, date and
|
|
89
|
+
version. Page 1 notes that the preprint isn't peer reviewed and gives its license.
|
|
90
|
+
- **Two columns** with aligned baselines and a balanced last page.
|
|
91
|
+
- **Figures and tables** after their first citation, full width when wide, and sized by their
|
|
92
|
+
lettering, so a simple chart isn't blown up. Long tables and figures after the references get
|
|
93
|
+
pages of their own.
|
|
94
|
+
- **Linked citations,** collapsed into ranges, and DOI links in the references.
|
|
95
|
+
- **Equations, back matter** (funding, data availability…) and a banner on withdrawn preprints.
|
|
96
|
+
|
|
97
|
+
## Themes
|
|
98
|
+
|
|
99
|
+
Choose a look with `--theme`:
|
|
100
|
+
|
|
101
|
+
- `default`: serif body, numbered sans headings in navy, a shaded abstract box.
|
|
102
|
+
- `compact`: a dense letters-journal look, with smaller serif text on narrow margins, a serif title,
|
|
103
|
+
a bold abstract, capitalised headings and run-in subheadings. About 20% fewer pages.
|
|
104
|
+
- `sans`: a modern open-access look, with a teal band, a large title, ragged-right sans text, ruled
|
|
105
|
+
headings and bracketed citations.
|
|
106
|
+
|
|
107
|
+
One column per theme, each showing page 1, page 2 and a figure page of the same preprint:
|
|
108
|
+
|
|
109
|
+

|
|
110
|
+
|
|
111
|
+
## Options
|
|
112
|
+
|
|
113
|
+
| Option | Description |
|
|
114
|
+
|---|---|
|
|
115
|
+
| `-o, --outdir DIR` | Where the PDF goes. Default: the current directory. |
|
|
116
|
+
| `--preprint-version N` | Preprint version; overrides a `vN` in the URL. Default: the `vN` in the URL, else the latest. |
|
|
117
|
+
| `--server biorxiv\|medrxiv` | Override server detection. Default: detected from the URL; a bare DOI tries bioRxiv, then medRxiv. |
|
|
118
|
+
| `--theme default\|compact\|sans` | Look of the PDF; see [Themes](#themes). Default: `default`. |
|
|
119
|
+
| `--paper letter\|a4` | Paper size. Default: `letter` (US Letter). |
|
|
120
|
+
| `--list FILE` | Batch mode. Keeps going after failures, prints a summary, exits 1 if any failed. |
|
|
121
|
+
| `--supplements` | Also download the supplementary files, into `<name>-supplements/` next to the PDF. They are listed and linked in the PDF either way. |
|
|
122
|
+
| `--append-supplements` | Append the supplementary PDFs and images to the end of the PDF, one bookmarked section per file (other files, such as spreadsheets, stay linked). |
|
|
123
|
+
| `--fallback-pdf` | If no JATS XML exists yet (very new posts), save the server's original PDF. |
|
|
124
|
+
| `--refresh` | Ignore the cache and download again. |
|
|
125
|
+
| `--open` | Open the PDF when done. |
|
|
126
|
+
| `-v`, `-vv` | `-v`: log each figure download, list every figure and table, and print a traceback on internal errors. `-vv`: also log every HTTP request. |
|
|
127
|
+
| `--version` | Show the rxiv2pdf version and exit. |
|
|
128
|
+
|
|
129
|
+
Exit codes: 0 success, 1 failure (not found, no XML yet, network, internal error), 2 bad input,
|
|
130
|
+
130 interrupted (re-run to resume from the cache).
|
|
131
|
+
|
|
132
|
+
### Cache and rate limits
|
|
133
|
+
|
|
134
|
+
Downloads are cached under `~/.cache/rxiv2pdf/` (`%LOCALAPPDATA%\rxiv2pdf\Cache` on Windows;
|
|
135
|
+
`$XDG_CACHE_HOME` and `RXIV2PDF_CACHE_DIR` are honoured), so re-runs make no network requests
|
|
136
|
+
unless you pass `--refresh`.
|
|
137
|
+
|
|
138
|
+
bioRxiv rate-limits heavily: after about ten requests it asks clients to wait for up to 4 minutes.
|
|
139
|
+
rxiv2pdf waits and carries on, so a paper with many figures can take a few minutes the first time.
|
|
140
|
+
An interrupted run resumes where it stopped. To add a contact address to the User-Agent, set
|
|
141
|
+
`RXIV2PDF_CONTACT=you@example.org`.
|
|
142
|
+
|
|
143
|
+
## Limitations
|
|
144
|
+
|
|
145
|
+
- **The PDF can differ slightly from the one on bioRxiv.** It is rebuilt from bioRxiv's XML
|
|
146
|
+
conversion of the submission, not from the authors' PDF. Tables, equations and the lettering
|
|
147
|
+
inside figures come only as images, so they can't be searched or copied as text. The conversion
|
|
148
|
+
sometimes drops a space or garbles a character; rxiv2pdf repairs the cases it recognises and
|
|
149
|
+
prints a `fixed: …` line for each kind. Details such as word counts or ORCID IDs on the authors'
|
|
150
|
+
title page aren't in the XML. The running text otherwise matches closely. If you find a
|
|
151
|
+
difference in a preprint you care about, please
|
|
152
|
+
[open an issue](https://github.com/ali-zaeim/rxiv2pdf/issues).
|
|
153
|
+
- **Some false citations stay linked.** bioRxiv's XML sometimes marks numbers in superscript as
|
|
154
|
+
citations, such as residue labels like D118<sup>3.49</sup> or powers of ten; rxiv2pdf unlinks
|
|
155
|
+
those. A superscript range such as a peptide fragment (NTS<sup>8–13</sup>) looks exactly like a
|
|
156
|
+
citation range, so it stays linked. In the `default` and `compact` themes it still reads as on
|
|
157
|
+
bioRxiv; in `sans`, which brackets citations, it shows as NTS [8–13].
|
|
158
|
+
- **Equation images can differ in size,** because authors export them at different zoom levels.
|
|
159
|
+
- **The page before end-of-article figures can be sparse.** Those figures start a new page, so
|
|
160
|
+
the last page of text may hold only a few lines.
|
|
161
|
+
- **CJK characters** aren't covered by the bundled fonts.
|
|
162
|
+
- **Only bioRxiv and medRxiv are supported.** ChemRxiv, for example, publishes only the authors'
|
|
163
|
+
PDFs, so there is no XML to rebuild a paper from.
|
|
164
|
+
|
|
165
|
+
## Development
|
|
166
|
+
|
|
167
|
+
The pipeline is resolve → fetch → parse → render → compile, one module per stage in
|
|
168
|
+
`src/rxiv2pdf/`. All styling lives in `templates/journal.typ`; themes are parameter sets in
|
|
169
|
+
`templates/themes/`.
|
|
170
|
+
|
|
171
|
+
```console
|
|
172
|
+
$ uv sync # Python env with dev dependencies
|
|
173
|
+
$ uv run pytest # offline tests
|
|
174
|
+
$ uv run ruff check src tests scripts # lint (CI runs this too)
|
|
175
|
+
$ uv run pytest -m network # live test against bioRxiv (slow: rate limits)
|
|
176
|
+
$ UPDATE_SNAPSHOTS=1 uv run pytest tests/test_jats.py # after an intended model change
|
|
177
|
+
$ uv run python scripts/preview.py previews/ # page-1 PNG of every fixture
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
`tests/fixtures/` holds real bioRxiv/medRxiv API responses and JATS XML, and `tests/snapshots/`
|
|
181
|
+
the parsed model of each as JSON. bioRxiv supplies every table and equation as an image, so the
|
|
182
|
+
XML-table and MathML code is tested on native-JATS articles from other journals in
|
|
183
|
+
`tests/fixtures/external/` (sources and licenses in its README).
|
|
184
|
+
|
|
185
|
+
## License
|
|
186
|
+
|
|
187
|
+
rxiv2pdf is released under the MIT License (see `LICENSE`). Bundled fonts: Source Serif 4 and
|
|
188
|
+
Source Sans 3 (SIL Open Font License 1.1, see `src/rxiv2pdf/fonts/`).
|
|
189
|
+
|
|
190
|
+
rxiv2pdf is meant for personal reading. A rebuilt PDF is a derivative of the preprint, so sharing
|
|
191
|
+
it must follow the preprint's own license, which is printed on page 1.
|
rxiv2pdf-0.1.0/README.md
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# rxiv2pdf
|
|
2
|
+
|
|
3
|
+
[](https://github.com/ali-zaeim/rxiv2pdf/actions/workflows/ci.yml)
|
|
4
|
+
[](https://pypi.org/project/rxiv2pdf/)
|
|
5
|
+
[](https://pypi.org/project/rxiv2pdf/)
|
|
6
|
+
[](https://github.com/ali-zaeim/rxiv2pdf/blob/main/LICENSE)
|
|
7
|
+
|
|
8
|
+
Turn a bioRxiv or medRxiv preprint into a two-column, journal-style PDF.
|
|
9
|
+
|
|
10
|
+
The PDF on bioRxiv and medRxiv is the authors' submitted manuscript, often double-spaced and
|
|
11
|
+
line-numbered, with the figures at the end. rxiv2pdf rebuilds the paper from the preprint's JATS
|
|
12
|
+
XML instead, with each figure placed after the text that first cites it and the citations linked
|
|
13
|
+
to the references.
|
|
14
|
+
|
|
15
|
+
```console
|
|
16
|
+
$ rxiv2pdf https://www.biorxiv.org/content/10.64898/2026.10.16.759679v1
|
|
17
|
+
PDF 2026.10.16.759679v1.pdf
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
| Page 1 | A figure page |
|
|
21
|
+
|:--:|:--:|
|
|
22
|
+
|  |  |
|
|
23
|
+
|
|
24
|
+
<sub>Screenshots on this page: Ghosh *et al.*, "Astrocytic sEH–EET signaling regulates microglial
|
|
25
|
+
lysosomal function and suppresses the STING–Type I interferon pathway in Alzheimer's disease",
|
|
26
|
+
bioRxiv [10.64898/2026.10.16.759679](https://doi.org/10.64898/2026.10.16.759679), CC BY 4.0.</sub>
|
|
27
|
+
|
|
28
|
+
## Install
|
|
29
|
+
|
|
30
|
+
Requires Python 3.11+. Typst comes with the `typst` Python package and the fonts are bundled, so
|
|
31
|
+
nothing else is needed.
|
|
32
|
+
|
|
33
|
+
```console
|
|
34
|
+
$ pipx install rxiv2pdf # or: uv tool install rxiv2pdf
|
|
35
|
+
$ rxiv2pdf --help
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`pip install rxiv2pdf` works too. To try it without installing anything:
|
|
39
|
+
`uvx rxiv2pdf 10.1101/2024.04.17.590000`.
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
```console
|
|
44
|
+
$ rxiv2pdf 10.1101/2024.04.17.590000 # bare DOI (bioRxiv by default, medRxiv tried next)
|
|
45
|
+
$ rxiv2pdf https://www.medrxiv.org/content/10.64898/2026.09.25.26364016v1.full
|
|
46
|
+
$ rxiv2pdf https://doi.org/10.64898/2026.10.22.760766 -o papers/ --theme compact --paper a4
|
|
47
|
+
$ rxiv2pdf 10.1101/2020.03.22.002386v2 # a specific version (default: latest)
|
|
48
|
+
$ rxiv2pdf --list dois.txt -o papers/ # batch: one URL/DOI per line, # comments ok
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
All options are listed under [Options](#options).
|
|
52
|
+
|
|
53
|
+
## What you get
|
|
54
|
+
|
|
55
|
+
- **Front matter:** title, authors and affiliations, abstract, and a banner with the DOI, date and
|
|
56
|
+
version. Page 1 notes that the preprint isn't peer reviewed and gives its license.
|
|
57
|
+
- **Two columns** with aligned baselines and a balanced last page.
|
|
58
|
+
- **Figures and tables** after their first citation, full width when wide, and sized by their
|
|
59
|
+
lettering, so a simple chart isn't blown up. Long tables and figures after the references get
|
|
60
|
+
pages of their own.
|
|
61
|
+
- **Linked citations,** collapsed into ranges, and DOI links in the references.
|
|
62
|
+
- **Equations, back matter** (funding, data availability…) and a banner on withdrawn preprints.
|
|
63
|
+
|
|
64
|
+
## Themes
|
|
65
|
+
|
|
66
|
+
Choose a look with `--theme`:
|
|
67
|
+
|
|
68
|
+
- `default`: serif body, numbered sans headings in navy, a shaded abstract box.
|
|
69
|
+
- `compact`: a dense letters-journal look, with smaller serif text on narrow margins, a serif title,
|
|
70
|
+
a bold abstract, capitalised headings and run-in subheadings. About 20% fewer pages.
|
|
71
|
+
- `sans`: a modern open-access look, with a teal band, a large title, ragged-right sans text, ruled
|
|
72
|
+
headings and bracketed citations.
|
|
73
|
+
|
|
74
|
+
One column per theme, each showing page 1, page 2 and a figure page of the same preprint:
|
|
75
|
+
|
|
76
|
+

|
|
77
|
+
|
|
78
|
+
## Options
|
|
79
|
+
|
|
80
|
+
| Option | Description |
|
|
81
|
+
|---|---|
|
|
82
|
+
| `-o, --outdir DIR` | Where the PDF goes. Default: the current directory. |
|
|
83
|
+
| `--preprint-version N` | Preprint version; overrides a `vN` in the URL. Default: the `vN` in the URL, else the latest. |
|
|
84
|
+
| `--server biorxiv\|medrxiv` | Override server detection. Default: detected from the URL; a bare DOI tries bioRxiv, then medRxiv. |
|
|
85
|
+
| `--theme default\|compact\|sans` | Look of the PDF; see [Themes](#themes). Default: `default`. |
|
|
86
|
+
| `--paper letter\|a4` | Paper size. Default: `letter` (US Letter). |
|
|
87
|
+
| `--list FILE` | Batch mode. Keeps going after failures, prints a summary, exits 1 if any failed. |
|
|
88
|
+
| `--supplements` | Also download the supplementary files, into `<name>-supplements/` next to the PDF. They are listed and linked in the PDF either way. |
|
|
89
|
+
| `--append-supplements` | Append the supplementary PDFs and images to the end of the PDF, one bookmarked section per file (other files, such as spreadsheets, stay linked). |
|
|
90
|
+
| `--fallback-pdf` | If no JATS XML exists yet (very new posts), save the server's original PDF. |
|
|
91
|
+
| `--refresh` | Ignore the cache and download again. |
|
|
92
|
+
| `--open` | Open the PDF when done. |
|
|
93
|
+
| `-v`, `-vv` | `-v`: log each figure download, list every figure and table, and print a traceback on internal errors. `-vv`: also log every HTTP request. |
|
|
94
|
+
| `--version` | Show the rxiv2pdf version and exit. |
|
|
95
|
+
|
|
96
|
+
Exit codes: 0 success, 1 failure (not found, no XML yet, network, internal error), 2 bad input,
|
|
97
|
+
130 interrupted (re-run to resume from the cache).
|
|
98
|
+
|
|
99
|
+
### Cache and rate limits
|
|
100
|
+
|
|
101
|
+
Downloads are cached under `~/.cache/rxiv2pdf/` (`%LOCALAPPDATA%\rxiv2pdf\Cache` on Windows;
|
|
102
|
+
`$XDG_CACHE_HOME` and `RXIV2PDF_CACHE_DIR` are honoured), so re-runs make no network requests
|
|
103
|
+
unless you pass `--refresh`.
|
|
104
|
+
|
|
105
|
+
bioRxiv rate-limits heavily: after about ten requests it asks clients to wait for up to 4 minutes.
|
|
106
|
+
rxiv2pdf waits and carries on, so a paper with many figures can take a few minutes the first time.
|
|
107
|
+
An interrupted run resumes where it stopped. To add a contact address to the User-Agent, set
|
|
108
|
+
`RXIV2PDF_CONTACT=you@example.org`.
|
|
109
|
+
|
|
110
|
+
## Limitations
|
|
111
|
+
|
|
112
|
+
- **The PDF can differ slightly from the one on bioRxiv.** It is rebuilt from bioRxiv's XML
|
|
113
|
+
conversion of the submission, not from the authors' PDF. Tables, equations and the lettering
|
|
114
|
+
inside figures come only as images, so they can't be searched or copied as text. The conversion
|
|
115
|
+
sometimes drops a space or garbles a character; rxiv2pdf repairs the cases it recognises and
|
|
116
|
+
prints a `fixed: …` line for each kind. Details such as word counts or ORCID IDs on the authors'
|
|
117
|
+
title page aren't in the XML. The running text otherwise matches closely. If you find a
|
|
118
|
+
difference in a preprint you care about, please
|
|
119
|
+
[open an issue](https://github.com/ali-zaeim/rxiv2pdf/issues).
|
|
120
|
+
- **Some false citations stay linked.** bioRxiv's XML sometimes marks numbers in superscript as
|
|
121
|
+
citations, such as residue labels like D118<sup>3.49</sup> or powers of ten; rxiv2pdf unlinks
|
|
122
|
+
those. A superscript range such as a peptide fragment (NTS<sup>8–13</sup>) looks exactly like a
|
|
123
|
+
citation range, so it stays linked. In the `default` and `compact` themes it still reads as on
|
|
124
|
+
bioRxiv; in `sans`, which brackets citations, it shows as NTS [8–13].
|
|
125
|
+
- **Equation images can differ in size,** because authors export them at different zoom levels.
|
|
126
|
+
- **The page before end-of-article figures can be sparse.** Those figures start a new page, so
|
|
127
|
+
the last page of text may hold only a few lines.
|
|
128
|
+
- **CJK characters** aren't covered by the bundled fonts.
|
|
129
|
+
- **Only bioRxiv and medRxiv are supported.** ChemRxiv, for example, publishes only the authors'
|
|
130
|
+
PDFs, so there is no XML to rebuild a paper from.
|
|
131
|
+
|
|
132
|
+
## Development
|
|
133
|
+
|
|
134
|
+
The pipeline is resolve → fetch → parse → render → compile, one module per stage in
|
|
135
|
+
`src/rxiv2pdf/`. All styling lives in `templates/journal.typ`; themes are parameter sets in
|
|
136
|
+
`templates/themes/`.
|
|
137
|
+
|
|
138
|
+
```console
|
|
139
|
+
$ uv sync # Python env with dev dependencies
|
|
140
|
+
$ uv run pytest # offline tests
|
|
141
|
+
$ uv run ruff check src tests scripts # lint (CI runs this too)
|
|
142
|
+
$ uv run pytest -m network # live test against bioRxiv (slow: rate limits)
|
|
143
|
+
$ UPDATE_SNAPSHOTS=1 uv run pytest tests/test_jats.py # after an intended model change
|
|
144
|
+
$ uv run python scripts/preview.py previews/ # page-1 PNG of every fixture
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
`tests/fixtures/` holds real bioRxiv/medRxiv API responses and JATS XML, and `tests/snapshots/`
|
|
148
|
+
the parsed model of each as JSON. bioRxiv supplies every table and equation as an image, so the
|
|
149
|
+
XML-table and MathML code is tested on native-JATS articles from other journals in
|
|
150
|
+
`tests/fixtures/external/` (sources and licenses in its README).
|
|
151
|
+
|
|
152
|
+
## License
|
|
153
|
+
|
|
154
|
+
rxiv2pdf is released under the MIT License (see `LICENSE`). Bundled fonts: Source Serif 4 and
|
|
155
|
+
Source Sans 3 (SIL Open Font License 1.1, see `src/rxiv2pdf/fonts/`).
|
|
156
|
+
|
|
157
|
+
rxiv2pdf is meant for personal reading. A rebuilt PDF is a derivative of the preprint, so sharing
|
|
158
|
+
it must follow the preprint's own license, which is printed on page 1.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "rxiv2pdf"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Turn a bioRxiv/medRxiv preprint into a two-column, journal-style PDF built from its JATS XML."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT AND OFL-1.1"
|
|
7
|
+
license-files = [
|
|
8
|
+
"LICENSE",
|
|
9
|
+
"src/rxiv2pdf/fonts/OFL-*.md",
|
|
10
|
+
]
|
|
11
|
+
requires-python = ">=3.11"
|
|
12
|
+
keywords = [
|
|
13
|
+
"biorxiv",
|
|
14
|
+
"medrxiv",
|
|
15
|
+
"preprint",
|
|
16
|
+
"jats",
|
|
17
|
+
"pdf",
|
|
18
|
+
"typst",
|
|
19
|
+
]
|
|
20
|
+
classifiers = [
|
|
21
|
+
"Development Status :: 4 - Beta",
|
|
22
|
+
"Environment :: Console",
|
|
23
|
+
"Intended Audience :: Science/Research",
|
|
24
|
+
"Programming Language :: Python :: 3",
|
|
25
|
+
"Programming Language :: Python :: 3.11",
|
|
26
|
+
"Programming Language :: Python :: 3.12",
|
|
27
|
+
"Programming Language :: Python :: 3.13",
|
|
28
|
+
"Programming Language :: Python :: 3.14",
|
|
29
|
+
"Topic :: Scientific/Engineering :: Bio-Informatics",
|
|
30
|
+
"Topic :: Text Processing :: Markup :: XML",
|
|
31
|
+
]
|
|
32
|
+
dependencies = [
|
|
33
|
+
"httpx>=0.27",
|
|
34
|
+
"lxml>=5.3",
|
|
35
|
+
"pillow>=11.0",
|
|
36
|
+
"rich>=13.7",
|
|
37
|
+
"typer>=0.16",
|
|
38
|
+
"typst>=0.15",
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
[[project.authors]]
|
|
42
|
+
name = "Ali Zaeim"
|
|
43
|
+
|
|
44
|
+
[project.scripts]
|
|
45
|
+
rxiv2pdf = "rxiv2pdf.cli:main"
|
|
46
|
+
|
|
47
|
+
[project.urls]
|
|
48
|
+
Homepage = "https://github.com/ali-zaeim/rxiv2pdf"
|
|
49
|
+
Repository = "https://github.com/ali-zaeim/rxiv2pdf"
|
|
50
|
+
Issues = "https://github.com/ali-zaeim/rxiv2pdf/issues"
|
|
51
|
+
Changelog = "https://github.com/ali-zaeim/rxiv2pdf/blob/main/CHANGELOG.md"
|
|
52
|
+
|
|
53
|
+
[dependency-groups]
|
|
54
|
+
dev = [
|
|
55
|
+
"pytest>=8.3",
|
|
56
|
+
"ruff>=0.17,<0.18",
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
[build-system]
|
|
60
|
+
requires = ["uv_build>=0.8,<0.14"]
|
|
61
|
+
build-backend = "uv_build"
|
|
62
|
+
|
|
63
|
+
[tool.pytest.ini_options]
|
|
64
|
+
testpaths = ["tests"]
|
|
65
|
+
addopts = "-m 'not network'"
|
|
66
|
+
markers = ["network: hits the live bioRxiv/medRxiv servers (run with: pytest -m network)"]
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "rxiv2pdf"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Turn a bioRxiv/medRxiv preprint into a two-column, journal-style PDF built from its JATS XML."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT AND OFL-1.1" # code MIT; bundled Source Serif/Sans fonts OFL-1.1
|
|
7
|
+
license-files = ["LICENSE", "src/rxiv2pdf/fonts/OFL-*.md"]
|
|
8
|
+
authors = [{ name = "Ali Zaeim" }]
|
|
9
|
+
requires-python = ">=3.11"
|
|
10
|
+
keywords = ["biorxiv", "medrxiv", "preprint", "jats", "pdf", "typst"]
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Development Status :: 4 - Beta",
|
|
13
|
+
"Environment :: Console",
|
|
14
|
+
"Intended Audience :: Science/Research",
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"Programming Language :: Python :: 3.11",
|
|
17
|
+
"Programming Language :: Python :: 3.12",
|
|
18
|
+
"Programming Language :: Python :: 3.13",
|
|
19
|
+
"Programming Language :: Python :: 3.14",
|
|
20
|
+
"Topic :: Scientific/Engineering :: Bio-Informatics",
|
|
21
|
+
"Topic :: Text Processing :: Markup :: XML",
|
|
22
|
+
]
|
|
23
|
+
dependencies = [
|
|
24
|
+
"httpx>=0.27",
|
|
25
|
+
"lxml>=5.3",
|
|
26
|
+
"pillow>=11.0",
|
|
27
|
+
"rich>=13.7",
|
|
28
|
+
"typer>=0.16", # older versions crash on --help with Click 8.2+
|
|
29
|
+
"typst>=0.15", # Compiler.compile_with_warnings / query with sys_inputs
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.scripts]
|
|
33
|
+
rxiv2pdf = "rxiv2pdf.cli:main"
|
|
34
|
+
|
|
35
|
+
[project.urls]
|
|
36
|
+
Homepage = "https://github.com/ali-zaeim/rxiv2pdf"
|
|
37
|
+
Repository = "https://github.com/ali-zaeim/rxiv2pdf"
|
|
38
|
+
Issues = "https://github.com/ali-zaeim/rxiv2pdf/issues"
|
|
39
|
+
Changelog = "https://github.com/ali-zaeim/rxiv2pdf/blob/main/CHANGELOG.md"
|
|
40
|
+
|
|
41
|
+
[dependency-groups]
|
|
42
|
+
dev = ["pytest>=8.3", "ruff>=0.17,<0.18"] # ruff pinned: its default rule set changes between minor versions
|
|
43
|
+
|
|
44
|
+
[build-system]
|
|
45
|
+
requires = ["uv_build>=0.8,<0.14"]
|
|
46
|
+
build-backend = "uv_build"
|
|
47
|
+
|
|
48
|
+
[tool.pytest.ini_options]
|
|
49
|
+
testpaths = ["tests"]
|
|
50
|
+
addopts = "-m 'not network'"
|
|
51
|
+
markers = [
|
|
52
|
+
"network: hits the live bioRxiv/medRxiv servers (run with: pytest -m network)",
|
|
53
|
+
]
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""rxiv2pdf: bioRxiv/medRxiv preprint -> journal-style PDF, built from JATS XML."""
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
__version__ = version("rxiv2pdf") # single source: pyproject.toml
|
|
7
|
+
except PackageNotFoundError: # running from a source tree that was never installed
|
|
8
|
+
__version__ = "0.0.0+unknown"
|