rustypaper 0.2.1__tar.gz → 0.2.2__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.
Files changed (45) hide show
  1. {rustypaper-0.2.1 → rustypaper-0.2.2}/Cargo.lock +2 -2
  2. {rustypaper-0.2.1 → rustypaper-0.2.2}/Cargo.toml +2 -2
  3. {rustypaper-0.2.1 → rustypaper-0.2.2}/PKG-INFO +29 -6
  4. {rustypaper-0.2.1/rustypaper → rustypaper-0.2.2}/README.md +28 -5
  5. {rustypaper-0.2.1 → rustypaper-0.2.2}/pyproject.toml +4 -1
  6. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/Cargo.toml +1 -2
  7. {rustypaper-0.2.1 → rustypaper-0.2.2/rustypaper}/README.md +28 -5
  8. rustypaper-0.2.2/rustypaper/__main__.py +3 -0
  9. rustypaper-0.2.2/rustypaper/cli.py +10 -0
  10. rustypaper-0.2.1/rustypaper/src/main.rs → rustypaper-0.2.2/rustypaper/src/cli.rs +34 -5
  11. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/src/lib.rs +1 -0
  12. rustypaper-0.2.2/rustypaper/src/main.rs +3 -0
  13. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper-py/src/lib.rs +8 -0
  14. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/__init__.py +0 -0
  15. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/examples/ingest_share.rs +0 -0
  16. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/src/backend/mod.rs +0 -0
  17. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/src/backend/rustium.rs +0 -0
  18. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/src/compress.rs +0 -0
  19. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/src/doc.rs +0 -0
  20. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/src/emit/markdown.rs +0 -0
  21. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/src/emit/mod.rs +0 -0
  22. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/src/emit/text.rs +0 -0
  23. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/src/emit/typst.rs +0 -0
  24. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/src/error.rs +0 -0
  25. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/src/figure.rs +0 -0
  26. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/src/ir.rs +0 -0
  27. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/src/layout/columns.rs +0 -0
  28. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/src/layout/furniture.rs +0 -0
  29. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/src/layout/mod.rs +0 -0
  30. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/src/layout/order.rs +0 -0
  31. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/src/layout/stats.rs +0 -0
  32. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/src/math/build.rs +0 -0
  33. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/src/math/latex.rs +0 -0
  34. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/src/math/mod.rs +0 -0
  35. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/src/math/symbols.rs +0 -0
  36. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/src/pipeline.rs +0 -0
  37. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/src/refs.rs +0 -0
  38. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/src/table.rs +0 -0
  39. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/src/text/lines.rs +0 -0
  40. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/src/text/mod.rs +0 -0
  41. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/src/text/vocab.rs +0 -0
  42. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/src/util.rs +0 -0
  43. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/tests/cli.rs +0 -0
  44. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper/tests/robustness.rs +0 -0
  45. {rustypaper-0.2.1 → rustypaper-0.2.2}/rustypaper-py/Cargo.toml +0 -0
@@ -567,7 +567,7 @@ dependencies = [
567
567
 
568
568
  [[package]]
569
569
  name = "rustypaper"
570
- version = "0.2.1"
570
+ version = "0.2.2"
571
571
  dependencies = [
572
572
  "anyhow",
573
573
  "clap",
@@ -580,7 +580,7 @@ dependencies = [
580
580
 
581
581
  [[package]]
582
582
  name = "rustypaper-py"
583
- version = "0.2.1"
583
+ version = "0.2.2"
584
584
  dependencies = [
585
585
  "pyo3",
586
586
  "rustypaper",
@@ -3,14 +3,14 @@ resolver = "2"
3
3
  members = ["rustypaper", "rustypaper-py"]
4
4
 
5
5
  [workspace.package]
6
- version = "0.2.1"
6
+ version = "0.2.2"
7
7
  edition = "2021"
8
8
  rust-version = "1.94"
9
9
  license = "MIT OR Apache-2.0"
10
10
  repository = "https://github.com/pgarrett-scripps/rustypaper"
11
11
 
12
12
  [workspace.dependencies]
13
- rustypaper = { path = "rustypaper", version = "0.2.1" }
13
+ rustypaper = { path = "rustypaper", version = "0.2.2" }
14
14
  # The pure-Rust PDF backend, from the registry. Deliberately not a path dependency: a path
15
15
  # only resolves where the sibling checkout happens to exist, which is this machine and not a
16
16
  # CI runner, and `cargo fmt --all` walks into it whether it is there or not. To develop the
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rustypaper
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Topic :: Text Processing :: Markup
6
6
  Classifier: Topic :: Scientific/Engineering
@@ -28,15 +28,38 @@ crates that exist are generic text extractors with no notion of a paper. This ai
28
28
  ## Install
29
29
 
30
30
  ```sh
31
- cargo install rustypaper # the command-line tool
31
+ pip install rustypaper
32
+ rustypaper convert paper.pdf
33
+ python -m rustypaper convert paper.pdf
32
34
  ```
33
35
 
34
- ```toml
35
- rustypaper = "0.2" # the library
36
- ```
36
+ The Python installation includes the same command line interface as the Rust executable.
37
+ All commands and options are shared, including batch conversion, figure extraction, and
38
+ diagnostics. No Rust compiler is needed when installing a supported platform wheel.
39
+
40
+ Standalone executables are available on the
41
+ [GitHub Releases page](https://github.com/pgarrett-scripps/rustypaper/releases).
42
+ Download the archive for your platform, verify it against `SHA256SUMS`, extract it,
43
+ and put `rustypaper` (or `rustypaper.exe`) on your `PATH`. These executables do not need Python.
44
+
45
+ | Platform | Targets |
46
+ |---|---|
47
+ | Linux with glibc 2.35 or newer | x86_64, aarch64 |
48
+ | macOS | Intel, Apple Silicon |
49
+ | Windows | x86_64 |
50
+
51
+ Alternatively, use [cargo-binstall](https://github.com/cargo-bins/cargo-binstall)
52
+ to download a release executable, or Cargo to compile it locally:
37
53
 
38
54
  ```sh
39
- pip install rustypaper # the Python bindings
55
+ cargo binstall rustypaper
56
+ cargo install rustypaper
57
+ ```
58
+
59
+ For the Rust library:
60
+
61
+ ```toml
62
+ rustypaper = "0.2"
40
63
  ```
41
64
 
42
65
  **Nothing else to install.** PDFs are read with
@@ -15,15 +15,38 @@ crates that exist are generic text extractors with no notion of a paper. This ai
15
15
  ## Install
16
16
 
17
17
  ```sh
18
- cargo install rustypaper # the command-line tool
18
+ pip install rustypaper
19
+ rustypaper convert paper.pdf
20
+ python -m rustypaper convert paper.pdf
19
21
  ```
20
22
 
21
- ```toml
22
- rustypaper = "0.2" # the library
23
- ```
23
+ The Python installation includes the same command line interface as the Rust executable.
24
+ All commands and options are shared, including batch conversion, figure extraction, and
25
+ diagnostics. No Rust compiler is needed when installing a supported platform wheel.
26
+
27
+ Standalone executables are available on the
28
+ [GitHub Releases page](https://github.com/pgarrett-scripps/rustypaper/releases).
29
+ Download the archive for your platform, verify it against `SHA256SUMS`, extract it,
30
+ and put `rustypaper` (or `rustypaper.exe`) on your `PATH`. These executables do not need Python.
31
+
32
+ | Platform | Targets |
33
+ |---|---|
34
+ | Linux with glibc 2.35 or newer | x86_64, aarch64 |
35
+ | macOS | Intel, Apple Silicon |
36
+ | Windows | x86_64 |
37
+
38
+ Alternatively, use [cargo-binstall](https://github.com/cargo-bins/cargo-binstall)
39
+ to download a release executable, or Cargo to compile it locally:
24
40
 
25
41
  ```sh
26
- pip install rustypaper # the Python bindings
42
+ cargo binstall rustypaper
43
+ cargo install rustypaper
44
+ ```
45
+
46
+ For the Rust library:
47
+
48
+ ```toml
49
+ rustypaper = "0.2"
27
50
  ```
28
51
 
29
52
  **Nothing else to install.** PDFs are read with
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "rustypaper"
3
- version = "0.2.1"
3
+ version = "0.2.2"
4
4
  description = "Structure-aware conversion of born-digital scientific PDFs to Markdown, Typst and JSON."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.9"
@@ -15,6 +15,9 @@ classifiers = [
15
15
  [project.urls]
16
16
  Repository = "https://github.com/pgarrett-scripps/rustypaper"
17
17
 
18
+ [project.scripts]
19
+ rustypaper = "rustypaper.cli:main"
20
+
18
21
  # Built with maturin from the workspace root:
19
22
  # maturin build -m rustypaper-py/Cargo.toml
20
23
  # `scripts/build.sh` is the no-maturin path: cargo produces an importable .so directly.
@@ -18,8 +18,7 @@ name = "rustypaper"
18
18
  path = "src/main.rs"
19
19
 
20
20
  [dependencies]
21
- # Used by the binary only, but cargo has no way to say so for a bin inside a library crate.
22
- # They are small and pure Rust, so the cost to a library consumer is compile time, not weight.
21
+ # The native executable and Python entry point share the command line implementation.
23
22
  anyhow.workspace = true
24
23
  clap.workspace = true
25
24
 
@@ -15,15 +15,38 @@ crates that exist are generic text extractors with no notion of a paper. This ai
15
15
  ## Install
16
16
 
17
17
  ```sh
18
- cargo install rustypaper # the command-line tool
18
+ pip install rustypaper
19
+ rustypaper convert paper.pdf
20
+ python -m rustypaper convert paper.pdf
19
21
  ```
20
22
 
21
- ```toml
22
- rustypaper = "0.2" # the library
23
- ```
23
+ The Python installation includes the same command line interface as the Rust executable.
24
+ All commands and options are shared, including batch conversion, figure extraction, and
25
+ diagnostics. No Rust compiler is needed when installing a supported platform wheel.
26
+
27
+ Standalone executables are available on the
28
+ [GitHub Releases page](https://github.com/pgarrett-scripps/rustypaper/releases).
29
+ Download the archive for your platform, verify it against `SHA256SUMS`, extract it,
30
+ and put `rustypaper` (or `rustypaper.exe`) on your `PATH`. These executables do not need Python.
31
+
32
+ | Platform | Targets |
33
+ |---|---|
34
+ | Linux with glibc 2.35 or newer | x86_64, aarch64 |
35
+ | macOS | Intel, Apple Silicon |
36
+ | Windows | x86_64 |
37
+
38
+ Alternatively, use [cargo-binstall](https://github.com/cargo-bins/cargo-binstall)
39
+ to download a release executable, or Cargo to compile it locally:
24
40
 
25
41
  ```sh
26
- pip install rustypaper # the Python bindings
42
+ cargo binstall rustypaper
43
+ cargo install rustypaper
44
+ ```
45
+
46
+ For the Rust library:
47
+
48
+ ```toml
49
+ rustypaper = "0.2"
27
50
  ```
28
51
 
29
52
  **Nothing else to install.** PDFs are read with
@@ -0,0 +1,3 @@
1
+ from .cli import main
2
+
3
+ raise SystemExit(main())
@@ -0,0 +1,10 @@
1
+ """Command line entry point backed by the shared Rust implementation."""
2
+
3
+ import sys
4
+
5
+ from ._rustypaper import _run_cli
6
+
7
+
8
+ def main():
9
+ """Return the native CLI's exit status without exiting the Python host."""
10
+ return _run_cli(["rustypaper", *sys.argv[1:]])
@@ -1,4 +1,8 @@
1
+ //! Shared command line implementation for the native executable and Python package.
2
+
3
+ use crate as rustypaper;
1
4
  use std::collections::BTreeMap;
5
+ use std::ffi::OsString;
2
6
  use std::io::{BufWriter, Write};
3
7
  use std::path::PathBuf;
4
8
  use std::time::Instant;
@@ -52,7 +56,7 @@ impl From<Caveman> for rustypaper::compress::Level {
52
56
  enum Format {
53
57
  /// GitHub-flavoured Markdown.
54
58
  Md,
55
- /// The document model, which is the real output; every other format renders this.
59
+ /// The document model. Every other format renders this.
56
60
  Json,
57
61
  /// Typst, which models figures, tables and references natively.
58
62
  Typst,
@@ -95,7 +99,7 @@ enum Command {
95
99
  #[arg(long, default_value_t = 150.0)]
96
100
  figure_dpi: f32,
97
101
  /// Strip grammatical scaffolding from the prose, for feeding to a model that charges by
98
- /// the token. `light` drops articles, copulas and stock phrases; `hard` also drops
102
+ /// the token. `light` drops articles, copulas and stock phrases. `hard` also drops
99
103
  /// prepositions, pronouns and filler. Maths, tables and citations are left alone.
100
104
  #[arg(long, value_enum, num_args = 0..=1, default_missing_value = "light")]
101
105
  caveman: Option<Caveman>,
@@ -112,10 +116,35 @@ enum Command {
112
116
  },
113
117
  }
114
118
 
115
- fn main() -> Result<()> {
119
+ /// Run a command, including its program name, without terminating the host process.
120
+ pub fn run(args: impl IntoIterator<Item = OsString>) -> i32 {
121
+ let cli = match Cli::try_parse_from(args) {
122
+ Ok(cli) => cli,
123
+ Err(error) => {
124
+ let code = error.exit_code();
125
+ if let Err(error) = error.print() {
126
+ return if error.kind() == std::io::ErrorKind::BrokenPipe {
127
+ 0
128
+ } else {
129
+ 1
130
+ };
131
+ }
132
+ return code;
133
+ }
134
+ };
135
+ match execute(cli.command) {
136
+ Ok(()) => 0,
137
+ Err(error) => {
138
+ let _ = writeln!(std::io::stderr().lock(), "Error: {error:?}");
139
+ 1
140
+ }
141
+ }
142
+ }
143
+
144
+ fn execute(command: Command) -> Result<()> {
116
145
  let mut out = BufWriter::new(std::io::stdout().lock());
117
146
 
118
- let result = match Cli::parse().command {
147
+ let result = match command {
119
148
  Command::Dump { pdf, page, pretty } => dump(&mut out, pdf, page, pretty),
120
149
  Command::Convert {
121
150
  pdf,
@@ -146,7 +175,7 @@ fn is_broken_pipe(error: &anyhow::Error) -> bool {
146
175
  // A write that fails on a closed pipe can arrive as either type, and which one depends
147
176
  // on who was writing. `serde_json` wraps the io error rather than returning it, so
148
177
  // looking only for `io::Error` misses every failure from `--pretty`, which serialises
149
- // straight to the stream — `dump --pretty | head` exited 1 for exactly that reason.
178
+ // straight to the stream. `dump --pretty | head` exited 1 for exactly that reason.
150
179
  if let Some(io) = e.downcast_ref::<std::io::Error>() {
151
180
  return io.kind() == std::io::ErrorKind::BrokenPipe;
152
181
  }
@@ -13,6 +13,7 @@
13
13
  //! The `Document` is the real output; Markdown is one rendering of it.
14
14
 
15
15
  pub mod backend;
16
+ pub mod cli;
16
17
  pub mod compress;
17
18
  pub mod doc;
18
19
  pub mod emit;
@@ -0,0 +1,3 @@
1
+ fn main() -> std::process::ExitCode {
2
+ std::process::ExitCode::from(rustypaper::cli::run(std::env::args_os()) as u8)
3
+ }
@@ -12,6 +12,7 @@
12
12
  use pyo3::create_exception;
13
13
  use pyo3::exceptions::{PyIOError, PyValueError};
14
14
  use pyo3::prelude::*;
15
+ use std::ffi::OsString;
15
16
 
16
17
  create_exception!(
17
18
  _rustypaper,
@@ -152,6 +153,7 @@ fn extract_json(py: Python<'_>, path: &str) -> PyResult<String> {
152
153
 
153
154
  #[pymodule]
154
155
  fn _rustypaper(module: &Bound<'_, PyModule>) -> PyResult<()> {
156
+ module.add_function(wrap_pyfunction!(_run_cli, module)?)?;
155
157
  module.add("__version__", env!("CARGO_PKG_VERSION"))?;
156
158
  module.add("ScannedDocument", module.py().get_type::<ScannedDocument>())?;
157
159
  module.add_function(wrap_pyfunction!(to_markdown, module)?)?;
@@ -162,3 +164,9 @@ fn _rustypaper(module: &Bound<'_, PyModule>) -> PyResult<()> {
162
164
  module.add_function(wrap_pyfunction!(extract_json, module)?)?;
163
165
  Ok(())
164
166
  }
167
+
168
+ /// Run the same CLI as the native executable, returning its exit status.
169
+ #[pyfunction]
170
+ fn _run_cli(py: Python<'_>, args: Vec<OsString>) -> i32 {
171
+ py.detach(|| rustypaper::cli::run(args))
172
+ }