Skip to content

Commit 6d387f9

Browse files
committed
Allow passing typst template file as bytes
1 parent 187571e commit 6d387f9

File tree

5 files changed

+86
-91
lines changed

5 files changed

+86
-91
lines changed

python/typst/__init__.pyi

+22-22
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
import pathlib
22
from typing import List, Optional, TypeVar, overload, Dict, Union, Literal
33

4-
PathLike = TypeVar("PathLike", str, pathlib.Path)
4+
Input = TypeVar("Input", str, pathlib.Path, bytes)
55
OutputFormat = Literal["pdf", "svg", "png", "html"]
66

77
class Compiler:
88
def __init__(
99
self,
10-
input: PathLike,
11-
root: Optional[PathLike] = None,
12-
font_paths: List[PathLike] = [],
10+
input: Input,
11+
root: Optional[Input] = None,
12+
font_paths: List[Input] = [],
1313
ignore_system_fonts: bool = False,
1414
sys_inputs: Dict[str, str] = {},
1515
pdf_standards: Optional[Union[Literal["1.7", "a-2b", "a-3b"], List[Literal["1.7", "a-2b", "a-3b"]]]] = []
1616
) -> None:
1717
"""Initialize a Typst compiler.
1818
Args:
19-
input (PathLike): Project's main .typ file.
19+
input: .typ file bytes or path to project's main .typ file.
2020
root (Optional[PathLike], optional): Root path for the Typst project.
2121
font_paths (List[PathLike]): Folders with fonts.
2222
ignore_system_fonts (bool): Ignore system fonts.
@@ -25,7 +25,7 @@ class Compiler:
2525

2626
def compile(
2727
self,
28-
output: Optional[PathLike] = None,
28+
output: Optional[Input] = None,
2929
format: Optional[OutputFormat] = None,
3030
ppi: Optional[float] = None,
3131
) -> Optional[Union[bytes, List[bytes]]]:
@@ -59,10 +59,10 @@ class Compiler:
5959

6060
@overload
6161
def compile(
62-
input: PathLike,
63-
output: PathLike,
64-
root: Optional[PathLike] = None,
65-
font_paths: List[PathLike] = [],
62+
input: Input,
63+
output: Input,
64+
root: Optional[Input] = None,
65+
font_paths: List[Input] = [],
6666
ignore_system_fonts: bool = False,
6767
format: Optional[OutputFormat] = None,
6868
ppi: Optional[float] = None,
@@ -71,21 +71,21 @@ def compile(
7171
) -> None: ...
7272
@overload
7373
def compile(
74-
input: PathLike,
74+
input: Input,
7575
output: None = None,
76-
root: Optional[PathLike] = None,
77-
font_paths: List[PathLike] = [],
76+
root: Optional[Input] = None,
77+
font_paths: List[Input] = [],
7878
ignore_system_fonts: bool = False,
7979
format: Optional[OutputFormat] = None,
8080
ppi: Optional[float] = None,
8181
sys_inputs: Dict[str, str] = {},
8282
pdf_standards: Optional[Union[Literal["1.7", "a-2b", "a-3b"], List[Literal["1.7", "a-2b", "a-3b"]]]] = []
8383
) -> bytes: ...
8484
def compile(
85-
input: PathLike,
86-
output: Optional[PathLike] = None,
87-
root: Optional[PathLike] = None,
88-
font_paths: List[PathLike] = [],
85+
input: Input,
86+
output: Optional[Input] = None,
87+
root: Optional[Input] = None,
88+
font_paths: List[Input] = [],
8989
ignore_system_fonts: bool = False,
9090
format: Optional[OutputFormat] = None,
9191
ppi: Optional[float] = None,
@@ -94,7 +94,7 @@ def compile(
9494
) -> Optional[Union[bytes, List[bytes]]]:
9595
"""Compile a Typst project.
9696
Args:
97-
input (PathLike): Project's main .typ file.
97+
input: .typ file bytes or path to project's main .typ file.
9898
output (Optional[PathLike], optional): Path to save the compiled file.
9999
Allowed extensions are `.pdf`, `.svg` and `.png`
100100
root (Optional[PathLike], optional): Root path for the Typst project.
@@ -109,19 +109,19 @@ def compile(
109109
"""
110110

111111
def query(
112-
input: PathLike,
112+
input: Input,
113113
selector: str,
114114
field: Optional[str] = None,
115115
one: bool = False,
116116
format: Optional[Literal["json", "yaml"]] = None,
117-
root: Optional[PathLike] = None,
118-
font_paths: List[PathLike] = [],
117+
root: Optional[Input] = None,
118+
font_paths: List[Input] = [],
119119
ignore_system_fonts: bool = False,
120120
sys_inputs: Dict[str, str] = {},
121121
) -> str:
122122
"""Query a Typst document.
123123
Args:
124-
input (PathLike): Project's main .typ file.
124+
input: .typ file bytes or path to project's main .typ file.
125125
selector (str): Typst selector like `<label>`.
126126
field (Optional[str], optional): Field to query.
127127
one (bool, optional): Query only one element.

src/compiler.rs

+6-8
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use typst::foundations::Datetime;
77
use typst::html::HtmlDocument;
88
use typst::layout::PagedDocument;
99
use typst::syntax::{FileId, Source, Span};
10-
use typst::{World, WorldExt};
10+
use typst::WorldExt;
1111

1212
use crate::world::SystemWorld;
1313

@@ -21,10 +21,6 @@ impl SystemWorld {
2121
ppi: Option<f32>,
2222
pdf_standards: &[typst_pdf::PdfStandard],
2323
) -> StrResult<Vec<Vec<u8>>> {
24-
// Reset everything and ensure that the main file is present.
25-
self.reset();
26-
self.source(self.main()).map_err(|err| err.to_string())?;
27-
2824
let Warned { output, warnings } = typst::compile(self);
2925

3026
match output {
@@ -40,7 +36,10 @@ impl SystemWorld {
4036
"png" => Ok(export_image(&document, ImageExportFormat::Png, ppi)?),
4137
"svg" => Ok(export_image(&document, ImageExportFormat::Svg, ppi)?),
4238
"html" => {
43-
let Warned { output, warnings } = typst::compile::<HtmlDocument>(self);
39+
let Warned {
40+
output,
41+
warnings: _,
42+
} = typst::compile::<HtmlDocument>(self);
4443
Ok(vec![export_html(&output.unwrap(), self)?])
4544
}
4645
fmt => Err(eco_format!("unknown format: {fmt}")),
@@ -70,11 +69,10 @@ fn export_pdf(
7069
world: &SystemWorld,
7170
standards: typst_pdf::PdfStandards,
7271
) -> StrResult<Vec<u8>> {
73-
let ident = world.input().to_string_lossy();
7472
let buffer = typst_pdf::pdf(
7573
document,
7674
&typst_pdf::PdfOptions {
77-
ident: typst::foundations::Smart::Custom(&ident),
75+
ident: typst::foundations::Smart::Auto,
7876
timestamp: now().map(typst_pdf::Timestamp::new_utc),
7977
standards,
8078
..Default::default()

src/lib.rs

+14-6
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ mod output_template {
4343
}
4444
}
4545

46+
#[derive(FromPyObject)]
47+
pub enum Input {
48+
Path(PathBuf),
49+
Bytes(Vec<u8>),
50+
}
51+
4652
/// A typst compiler
4753
#[pyclass(module = "typst._typst")]
4854
pub struct Compiler {
@@ -104,17 +110,19 @@ impl Compiler {
104110
sys_inputs = HashMap::new()
105111
))]
106112
fn new(
107-
input: PathBuf,
113+
input: Input,
108114
root: Option<PathBuf>,
109115
font_paths: Vec<PathBuf>,
110116
ignore_system_fonts: bool,
111117
sys_inputs: HashMap<String, String>,
112118
) -> PyResult<Self> {
113-
let input = input.canonicalize()?;
114119
let root = if let Some(root) = root {
115120
root.canonicalize()?
116-
} else if let Some(dir) = input.parent() {
117-
dir.into()
121+
} else if let Input::Path(path) = &input {
122+
path.canonicalize()?
123+
.parent()
124+
.map(Into::into)
125+
.unwrap_or_else(|| PathBuf::new())
118126
} else {
119127
PathBuf::new()
120128
};
@@ -227,7 +235,7 @@ impl Compiler {
227235
#[allow(clippy::too_many_arguments)]
228236
fn compile(
229237
py: Python<'_>,
230-
input: PathBuf,
238+
input: Input,
231239
output: Option<PathBuf>,
232240
root: Option<PathBuf>,
233241
font_paths: Vec<PathBuf>,
@@ -260,7 +268,7 @@ fn compile(
260268
#[allow(clippy::too_many_arguments)]
261269
fn py_query(
262270
py: Python<'_>,
263-
input: PathBuf,
271+
input: Input,
264272
selector: &str,
265273
field: Option<&str>,
266274
one: bool,

src/query.rs

-4
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,6 @@ pub enum SerializationFormat {
3535

3636
/// Execute a query command.
3737
pub fn query(world: &mut SystemWorld, command: &QueryCommand) -> StrResult<String> {
38-
// Reset everything and ensure that the main file is present.
39-
world.reset();
40-
world.source(world.main()).map_err(|err| err.to_string())?;
41-
4238
let Warned { output, warnings } = typst::compile(world);
4339

4440
match output {

0 commit comments

Comments
 (0)