Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow passing typst template file as bytes #89

Merged
merged 1 commit into from
Mar 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 22 additions & 22 deletions python/typst/__init__.pyi
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import pathlib
from typing import List, Optional, TypeVar, overload, Dict, Union, Literal

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

class Compiler:
def __init__(
self,
input: PathLike,
root: Optional[PathLike] = None,
font_paths: List[PathLike] = [],
input: Input,
root: Optional[Input] = None,
font_paths: List[Input] = [],
ignore_system_fonts: bool = False,
sys_inputs: Dict[str, str] = {},
pdf_standards: Optional[Union[Literal["1.7", "a-2b", "a-3b"], List[Literal["1.7", "a-2b", "a-3b"]]]] = []
) -> None:
"""Initialize a Typst compiler.
Args:
input (PathLike): Project's main .typ file.
input: .typ file bytes or path to project's main .typ file.
root (Optional[PathLike], optional): Root path for the Typst project.
font_paths (List[PathLike]): Folders with fonts.
ignore_system_fonts (bool): Ignore system fonts.
Expand All @@ -25,7 +25,7 @@ class Compiler:

def compile(
self,
output: Optional[PathLike] = None,
output: Optional[Input] = None,
format: Optional[OutputFormat] = None,
ppi: Optional[float] = None,
) -> Optional[Union[bytes, List[bytes]]]:
Expand Down Expand Up @@ -59,10 +59,10 @@ class Compiler:

@overload
def compile(
input: PathLike,
output: PathLike,
root: Optional[PathLike] = None,
font_paths: List[PathLike] = [],
input: Input,
output: Input,
root: Optional[Input] = None,
font_paths: List[Input] = [],
ignore_system_fonts: bool = False,
format: Optional[OutputFormat] = None,
ppi: Optional[float] = None,
Expand All @@ -71,21 +71,21 @@ def compile(
) -> None: ...
@overload
def compile(
input: PathLike,
input: Input,
output: None = None,
root: Optional[PathLike] = None,
font_paths: List[PathLike] = [],
root: Optional[Input] = None,
font_paths: List[Input] = [],
ignore_system_fonts: bool = False,
format: Optional[OutputFormat] = None,
ppi: Optional[float] = None,
sys_inputs: Dict[str, str] = {},
pdf_standards: Optional[Union[Literal["1.7", "a-2b", "a-3b"], List[Literal["1.7", "a-2b", "a-3b"]]]] = []
) -> bytes: ...
def compile(
input: PathLike,
output: Optional[PathLike] = None,
root: Optional[PathLike] = None,
font_paths: List[PathLike] = [],
input: Input,
output: Optional[Input] = None,
root: Optional[Input] = None,
font_paths: List[Input] = [],
ignore_system_fonts: bool = False,
format: Optional[OutputFormat] = None,
ppi: Optional[float] = None,
Expand All @@ -94,7 +94,7 @@ def compile(
) -> Optional[Union[bytes, List[bytes]]]:
"""Compile a Typst project.
Args:
input (PathLike): Project's main .typ file.
input: .typ file bytes or path to project's main .typ file.
output (Optional[PathLike], optional): Path to save the compiled file.
Allowed extensions are `.pdf`, `.svg` and `.png`
root (Optional[PathLike], optional): Root path for the Typst project.
Expand All @@ -109,19 +109,19 @@ def compile(
"""

def query(
input: PathLike,
input: Input,
selector: str,
field: Optional[str] = None,
one: bool = False,
format: Optional[Literal["json", "yaml"]] = None,
root: Optional[PathLike] = None,
font_paths: List[PathLike] = [],
root: Optional[Input] = None,
font_paths: List[Input] = [],
ignore_system_fonts: bool = False,
sys_inputs: Dict[str, str] = {},
) -> str:
"""Query a Typst document.
Args:
input (PathLike): Project's main .typ file.
input: .typ file bytes or path to project's main .typ file.
selector (str): Typst selector like `<label>`.
field (Optional[str], optional): Field to query.
one (bool, optional): Query only one element.
Expand Down
14 changes: 6 additions & 8 deletions src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use typst::foundations::Datetime;
use typst::html::HtmlDocument;
use typst::layout::PagedDocument;
use typst::syntax::{FileId, Source, Span};
use typst::{World, WorldExt};
use typst::WorldExt;

use crate::world::SystemWorld;

Expand All @@ -21,10 +21,6 @@ impl SystemWorld {
ppi: Option<f32>,
pdf_standards: &[typst_pdf::PdfStandard],
) -> StrResult<Vec<Vec<u8>>> {
// Reset everything and ensure that the main file is present.
self.reset();
self.source(self.main()).map_err(|err| err.to_string())?;

let Warned { output, warnings } = typst::compile(self);

match output {
Expand All @@ -40,7 +36,10 @@ impl SystemWorld {
"png" => Ok(export_image(&document, ImageExportFormat::Png, ppi)?),
"svg" => Ok(export_image(&document, ImageExportFormat::Svg, ppi)?),
"html" => {
let Warned { output, warnings } = typst::compile::<HtmlDocument>(self);
let Warned {
output,
warnings: _,
} = typst::compile::<HtmlDocument>(self);
Ok(vec![export_html(&output.unwrap(), self)?])
}
fmt => Err(eco_format!("unknown format: {fmt}")),
Expand Down Expand Up @@ -70,11 +69,10 @@ fn export_pdf(
world: &SystemWorld,
standards: typst_pdf::PdfStandards,
) -> StrResult<Vec<u8>> {
let ident = world.input().to_string_lossy();
let buffer = typst_pdf::pdf(
document,
&typst_pdf::PdfOptions {
ident: typst::foundations::Smart::Custom(&ident),
ident: typst::foundations::Smart::Auto,
timestamp: now().map(typst_pdf::Timestamp::new_utc),
standards,
..Default::default()
Expand Down
20 changes: 14 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ mod output_template {
}
}

#[derive(FromPyObject)]
pub enum Input {
Path(PathBuf),
Bytes(Vec<u8>),
}

/// A typst compiler
#[pyclass(module = "typst._typst")]
pub struct Compiler {
Expand Down Expand Up @@ -104,17 +110,19 @@ impl Compiler {
sys_inputs = HashMap::new()
))]
fn new(
input: PathBuf,
input: Input,
root: Option<PathBuf>,
font_paths: Vec<PathBuf>,
ignore_system_fonts: bool,
sys_inputs: HashMap<String, String>,
) -> PyResult<Self> {
let input = input.canonicalize()?;
let root = if let Some(root) = root {
root.canonicalize()?
} else if let Some(dir) = input.parent() {
dir.into()
} else if let Input::Path(path) = &input {
path.canonicalize()?
.parent()
.map(Into::into)
.unwrap_or_else(|| PathBuf::new())
} else {
PathBuf::new()
};
Expand Down Expand Up @@ -227,7 +235,7 @@ impl Compiler {
#[allow(clippy::too_many_arguments)]
fn compile(
py: Python<'_>,
input: PathBuf,
input: Input,
output: Option<PathBuf>,
root: Option<PathBuf>,
font_paths: Vec<PathBuf>,
Expand Down Expand Up @@ -260,7 +268,7 @@ fn compile(
#[allow(clippy::too_many_arguments)]
fn py_query(
py: Python<'_>,
input: PathBuf,
input: Input,
selector: &str,
field: Option<&str>,
one: bool,
Expand Down
4 changes: 0 additions & 4 deletions src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@ pub enum SerializationFormat {

/// Execute a query command.
pub fn query(world: &mut SystemWorld, command: &QueryCommand) -> StrResult<String> {
// Reset everything and ensure that the main file is present.
world.reset();
world.source(world.main()).map_err(|err| err.to_string())?;

let Warned { output, warnings } = typst::compile(world);

match output {
Expand Down
Loading