Skip to content
Open
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ rows are the enforced release-mode bounds plus one dated observation.

| Measurement | Value | Version | Platform | Build mode | Input | Command | Statistic | Measured on |
|---|---|---|---|---|---|---|---|---|
| Crates.io archive: rdocx | 1,092,256 compressed bytes, 6,498,484 member bytes, 36 members | 0.14.0 | macOS 26.6.2, Apple M5 Max, arm64 | `cargo package --locked --no-verify` | Tracked `rdocx` package inventory | `python3 scripts/readme_doctests.py --record-measurements` | gzip archive bytes, tar member bytes, tar member count | 2026-09-26 |
| Crates.io archive: rdocx | 1,095,229 compressed bytes, 6,510,120 member bytes, 36 members | 0.14.0 | macOS 26.6.2, Apple M5 Max, arm64 | `cargo package --locked --no-verify` | Tracked `rdocx` package inventory | `python3 scripts/readme_doctests.py --record-measurements` | gzip archive bytes, tar member bytes, tar member count | 2026-09-26 |
| Large-document layout throughput | minimum 250 pages/s, observed 31,019.1 pages/s | rdocx 0.14.0 | macOS 26.6.2, Apple M5 Max, arm64 | release, one test thread | 1,000 one-page paragraphs with deterministic fonts | `cargo test -p rdocx --test regression_test --release a_thousand_page_document_paginates_and_renders_within_the_declared_limits -- --ignored --exact --nocapture --test-threads=1` | pages per wall-clock second | 2026-09-19 |
| Large-document layout peak allocation | maximum 64 MiB, observed 29.03 MiB | rdocx 0.14.0 | macOS 26.6.2, Apple M5 Max, arm64 | release, one test thread | 1,000 one-page paragraphs with deterministic fonts | `cargo test -p rdocx --test regression_test --release a_thousand_page_document_paginates_and_renders_within_the_declared_limits -- --ignored --exact --nocapture --test-threads=1` | peak live allocation | 2026-09-19 |
| Large-document PDF throughput | minimum 1,000 pages/s, observed 60,058.0 pages/s | rdocx 0.14.0 | macOS 26.6.2, Apple M5 Max, arm64 | release, one test thread | 1,000 deterministic layout pages | `cargo test -p rdocx --test regression_test --release a_thousand_page_document_paginates_and_renders_within_the_declared_limits -- --ignored --exact --nocapture --test-threads=1` | pages per wall-clock second | 2026-09-19 |
Expand Down
1 change: 1 addition & 0 deletions crates/rdocx-py/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ extension-module = ["pyo3/extension-module"]
oxml-py-support = { workspace = true }
pyo3 = { workspace = true }
rdocx = { workspace = true, features = ["system-fonts"] }
rdocx-oxml = { workspace = true }
smallvec = { workspace = true }

[dev-dependencies]
Expand Down
3 changes: 2 additions & 1 deletion crates/rdocx-py/python/rdocx/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Python bindings for rdocx."""

from .enum.table import WD_CELL_VERTICAL_ALIGNMENT, WD_TABLE_ALIGNMENT
from .enum.table import WD_CELL_VERTICAL_ALIGNMENT, WD_ROW_HEIGHT_RULE, WD_TABLE_ALIGNMENT
from .enum.text import WD_ALIGN_PARAGRAPH, WD_UNDERLINE
from .shared import Cm, Emu, Inches, Length, Mm, Pt, RGBColor

Expand Down Expand Up @@ -108,6 +108,7 @@ class LayoutError(RdocxError):
"TocRebuildReport",
"WD_ALIGN_PARAGRAPH",
"WD_CELL_VERTICAL_ALIGNMENT",
"WD_ROW_HEIGHT_RULE",
"WD_TABLE_ALIGNMENT",
"WD_UNDERLINE",
"XmlError",
Expand Down
87 changes: 86 additions & 1 deletion crates/rdocx-py/python/rdocx/_rdocx.pyi
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
import datetime as _datetime
import os as _os
from collections.abc import Iterator as _Iterator
from collections.abc import Iterator as _Iterator, Sequence as _Sequence
from typing import Literal as _Literal, NoReturn as _Never, final as _final, overload as _overload

from . import shared as _shared
from .enum import table as _table
from .enum import text as _text

_Path = str | _os.PathLike[str]
_BorderStyle = _Literal[
"none", "single", "thick", "double", "dotted", "dashed", "dotDash", "wave"
]
_BorderEdge = _Literal["top", "bottom", "left", "right", "insideH", "insideV"]
_Margins = tuple[
_shared.Length | None, _shared.Length | None, _shared.Length | None, _shared.Length | None
]
__all__ = [
"BoundingBox", "Cell", "CellCollection", "CellParagraphCollection",
"Comment", "ComparisonDiagnostic", "ContentFragment", "Document", "Font", "HeaderFooterVariant",
Expand Down Expand Up @@ -449,6 +456,30 @@ class Document:
def comments(self) -> tuple[Comment, ...]: ...
@property
def sections(self) -> tuple[Section, ...]: ...
def update_section(
self,
index: int,
*,
orientation: _Literal["portrait", "landscape"] | None = None,
page_width: int | None = None,
page_height: int | None = None,
margin_top: int | None = None,
margin_right: int | None = None,
margin_bottom: int | None = None,
margin_left: int | None = None,
gutter: int | None = None,
column_count: int | None = None,
column_spacing: int | None = None,
page_number_start: int | None = None,
header_distance: int | None = None,
footer_distance: int | None = None,
different_first_page: bool | None = None,
break_type: _Literal[
"nextPage", "continuous", "evenPage", "oddPage", "nextColumn"
] | None = None,
) -> Section: ...
def insert_section(self, index: int) -> None: ...
def remove_section(self, index: int) -> None: ...
@property
def styles(self) -> tuple[Style, ...]: ...
@property
Expand Down Expand Up @@ -531,6 +562,7 @@ class Document:
def find_content_index(self, content: str) -> int: ...
def find_content_indices(self, text: str) -> tuple[int, ...]: ...
def insert_paragraph(self, index: int, text: str) -> Paragraph: ...
def insert_table(self, index: int, rows: int, cols: int) -> Table: ...
def pop_content(self, index: int) -> ContentFragment: ...
def insert_content(self, destination: int, fragment: ContentFragment) -> None: ...
def clone_content(self, source: Paragraph | Table, destination: int) -> None: ...
Expand Down Expand Up @@ -715,6 +747,23 @@ class Table:
def width(self) -> _shared.Length | None: ...
@width.setter
def width(self, value: int) -> None: ...
def set_borders(self, style: _BorderStyle, *, size: int, color: str) -> None: ...
def set_border(
self, edge: _BorderEdge, style: _BorderStyle, *, size: int, color: str
) -> None: ...
def border(self, edge: _BorderEdge) -> tuple[str, int | None, str | None] | None: ...
@property
def cell_margins(self) -> _Margins | None: ...
def set_cell_margins(self, *, top: int, right: int, bottom: int, left: int) -> None: ...
@property
def grid_widths(self) -> tuple[_shared.Length, ...]: ...
@grid_widths.setter
def grid_widths(self, value: _Sequence[int]) -> None: ...
def set_column_width(self, column: int, width: int) -> None: ...
def set_cell_grid_span(self, row: int, col: int, span: int | None) -> None: ...
def set_cell_vertical_merge(
self, row: int, col: int, merge: _Literal["restart", "continue"] | None
) -> None: ...
def clone_row(self, index: int, at: int | None = None) -> Row: ...
def remove_row(self, index: int) -> None: ...

Expand All @@ -735,6 +784,27 @@ class Row:
def __new__(cls, *, _private: _Never) -> Row: ...
@property
def cells(self) -> CellCollection: ...
# height and height_rule read None for a w:trHeight with an auto rule,
# which python-docx reads as its value and AUTO, or with no value.
# Assigning a height keeps the rule of an exact height and writes a
# minimum otherwise, so an auto rule, or an exact rule without a value,
# becomes a minimum.
@property
def height(self) -> _shared.Length | None: ...
@height.setter
def height(self, value: int) -> None: ...
@property
def height_rule(self) -> _table.WD_ROW_HEIGHT_RULE | None: ...
@height_rule.setter
def height_rule(self, value: _table.WD_ROW_HEIGHT_RULE) -> None: ...
@property
def cant_split(self) -> bool | None: ...
@cant_split.setter
def cant_split(self, value: bool | None) -> None: ...
@property
def is_header(self) -> bool | None: ...
@is_header.setter
def is_header(self, value: bool | None) -> None: ...


@_final
Expand Down Expand Up @@ -766,6 +836,21 @@ class Cell:
def vertical_alignment(self) -> _table.WD_CELL_VERTICAL_ALIGNMENT | None: ...
@vertical_alignment.setter
def vertical_alignment(self, value: _table.WD_CELL_VERTICAL_ALIGNMENT) -> None: ...
@property
def grid_span(self) -> int: ...
@property
def vertical_merge(self) -> _Literal["restart", "continue"] | None: ...
@property
def shading(self) -> str | None: ...
@shading.setter
def shading(self, value: str) -> None: ...
def border(self, edge: _BorderEdge) -> tuple[str, int | None, str | None] | None: ...
def set_border(
self, edge: _BorderEdge, style: _BorderStyle, *, size: int, color: str
) -> None: ...
@property
def margins(self) -> _Margins | None: ...
def set_margins(self, *, top: int, right: int, bottom: int, left: int) -> None: ...


@_final
Expand Down
9 changes: 8 additions & 1 deletion crates/rdocx-py/python/rdocx/enum/table.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,11 @@ class WD_CELL_VERTICAL_ALIGNMENT(IntEnum):
BOTTOM = 3


__all__ = ["WD_TABLE_ALIGNMENT", "WD_CELL_VERTICAL_ALIGNMENT"]
class WD_ROW_HEIGHT_RULE(IntEnum):
"""How a table row height is applied."""

AT_LEAST = 1
EXACTLY = 2


__all__ = ["WD_TABLE_ALIGNMENT", "WD_CELL_VERTICAL_ALIGNMENT", "WD_ROW_HEIGHT_RULE"]
Loading
Loading