Skip to content
Closed
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
23 changes: 23 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,26 @@
- Reuse utility functions in `tests/utils.py` and `tests/utils_snapshot.py` when authoring new tests to ensure consistent normalization of RTF strings.
- Consult `scripts/update_color_table.R` and `scripts/update_unicode_latex.py` when modifying color tables or Unicode handling to avoid drifting from validated data sources.
- Public API exports are centralized in `src/rtflite/__init__.py`; update `__all__` when adding new user-facing classes or helpers.

## System Architecture: Pagination & Rendering

The project uses a modular, strategy-based architecture for pagination and rendering.

### 1. Strategy Registry & Index
- **Pagination Logic**: Decoupled from the core distributor.
- **Strategies**:
- `DefaultPaginationStrategy`: Standard row-limit based pagination.
- `PageByStrategy`: Handles `page_by` grouping logic.
- `SublineStrategy`: Handles `subline_by` logic.
- **Registry**: `StrategyRegistry` resolves strategies based on configuration.

### 2. Unified Rendering Pipeline
- **`UnifiedRTFEncoder`**: Handles all document encoding (replacing legacy split strategies).
- **Flow**:
1. **Paginate**: Select strategy -> Split DataFrame into `List[PageContext]`.
2. **Process**: Apply per-page features (borders, headers, dynamic attributes) via `PageFeatureProcessor`.
3. **Render**: Use `PageRenderer` to convert each `PageContext` to RTF.
4. **Assemble**: Concatenate page RTF chunks.

### 3. Feature Isolation
- Page-specific features (top/bottom borders, spanning rows, footnotes) are calculated and finalized on the `PageContext` object before rendering.
1 change: 0 additions & 1 deletion docs/articles/rtf/advanced-group-by-single.rtf
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
{\pard\hyphpar\sb180\sa180\fi0\li0\ri0\qc\fs24{\f0 Adverse Events Listing}\line\fs24{\f0 Example 1: Single Column group_by}\par}



\trowd\trgaph108\trleft0\trqc
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx2455
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx5727
Expand Down
1 change: 0 additions & 1 deletion docs/articles/rtf/example-ae-summary.rtf
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
{\pard\hyphpar\sb180\sa180\fi0\li0\ri0\qc\fs24{\f0 Analysis of Subjects With Specific Adverse Events}\line\fs24{\f0 (Incidence > 5 Subjects in One or More Treatment Groups)}\line\fs24{\f0 ASaT}\par}



\trowd\trgaph108\trleft0\trqc
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx3600
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx5400
Expand Down
4 changes: 0 additions & 4 deletions docs/articles/rtf/intro-ae1.rtf
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@

\paperw12240\paperh15840
\margl1800\margr1440\margt2520\margb1800\headery2520\footery1449




\trowd\trgaph108\trleft0\trqc
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx2250
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx4500
Expand Down
4 changes: 0 additions & 4 deletions docs/articles/rtf/intro-ae11.rtf
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@

\paperw12240\paperh15840
\margl1800\margr1440\margt2520\margb1800\headery2520\footery1449




\trowd\trgaph108\trleft0\trqc
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx3000
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx5000
Expand Down
4 changes: 0 additions & 4 deletions docs/articles/rtf/intro-ae2.rtf
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@

\paperw12240\paperh15840
\margl1800\margr1440\margt2520\margb1800\headery2520\footery1449




\trowd\trgaph108\trleft0\trqc
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx3000
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx5000
Expand Down
4 changes: 0 additions & 4 deletions docs/articles/rtf/intro-ae3.rtf
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@

\paperw12240\paperh15840
\margl1800\margr1440\margt2520\margb1800\headery2520\footery1449




\trowd\trgaph108\trleft0\trqc
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx3000
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx5000
Expand Down
1 change: 0 additions & 1 deletion docs/articles/rtf/intro-ae5.rtf
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
{\pard\hyphpar\sb180\sa180\fi0\li0\ri0\qc\fs24{\f0 Summary of Adverse Events by Treatment Group}\line\fs24{\f0 Safety Analysis Set}\par}



\trowd\trgaph108\trleft0\trqc
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx3000
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx5000
Expand Down
4 changes: 0 additions & 4 deletions docs/articles/rtf/intro-ae6.rtf
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@

\paperw12240\paperh15840
\margl1800\margr1440\margt2520\margb1800\headery2520\footery1449




\trowd\trgaph108\trleft0\trqc
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx4500
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx6000
Expand Down
4 changes: 0 additions & 4 deletions docs/articles/rtf/intro-ae7.rtf
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@

\paperw12240\paperh15840
\margl1800\margr1440\margt2520\margb1800\headery2520\footery1449




\trowd\trgaph108\trleft0\trqc
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrs\brdrw15\clvertalb\cellx3000
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrdb\brdrw15\clvertalb\cellx5000
Expand Down
1 change: 0 additions & 1 deletion docs/articles/rtf/intro-ae8.rtf
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
{\pard\hyphpar\sb180\sa180\fi0\li0\ri0\qc\fs24{\f0 Summary of Adverse Events by Treatment Group}\line\fs24{\f0 With Page Headers and Footers}\par}



\trowd\trgaph108\trleft0\trqc
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx3000
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx5000
Expand Down
1 change: 0 additions & 1 deletion docs/articles/rtf/intro-ae8b.rtf
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
{\pard\hyphpar\sb180\sa180\fi0\li0\ri0\qc\fs24{\f0 Adverse Events with Custom Headers/Footers}\par}



\trowd\trgaph108\trleft0\trqc
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx3000
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx5000
Expand Down
4 changes: 0 additions & 4 deletions docs/articles/rtf/row-border-styles.rtf
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@

\paperw12240\paperh15840
\margl1800\margr1440\margt2520\margb1800\headery2520\footery1449




\trowd\trgaph108\trleft0\trqc
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx4500
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrr\brdrs\brdrw15\clbrdrb\brdrw15\clvertalb\cellx9000
Expand Down
4 changes: 0 additions & 4 deletions docs/articles/rtf/row-column-widths.rtf
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@

\paperw12240\paperh15840
\margl1800\margr1440\margt2520\margb1800\headery2520\footery1449




\trowd\trgaph108\trleft0\trqc
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx1500
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx4500
Expand Down
4 changes: 0 additions & 4 deletions docs/articles/rtf/text-color.rtf
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@

\paperw12240\paperh15840
\margl1800\margr1440\margt2520\margb1800\headery2520\footery1449




\trowd\trgaph108\trleft0\trqc
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx4500
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrr\brdrs\brdrw15\clbrdrb\brdrw15\clvertalb\cellx9000
Expand Down
1 change: 0 additions & 1 deletion docs/articles/rtf/text-convert.rtf
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
{\pard\hyphpar\sb180\sa180\fi0\li0\ri0\qc\fs24{\f0 Study Parameters with Text Conversion Enabled}\par}



\trowd\trgaph108\trleft0\trqc
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx4500
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx6750
Expand Down
4 changes: 0 additions & 4 deletions docs/articles/rtf/text-font-size-alignment.rtf
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@

\paperw12240\paperh15840
\margl1800\margr1440\margt2520\margb1800\headery2520\footery1449




\trowd\trgaph108\trleft0\trqc
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx3000
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx6000
Expand Down
4 changes: 0 additions & 4 deletions docs/articles/rtf/text-format-styles.rtf
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@

\paperw12240\paperh15840
\margl1800\margr1440\margt2520\margb1800\headery2520\footery1449




\trowd\trgaph108\trleft0\trqc
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx2250
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx4500
Expand Down
4 changes: 0 additions & 4 deletions docs/articles/rtf/text-indentation.rtf
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@

\paperw12240\paperh15840
\margl1800\margr1440\margt2520\margb1800\headery2520\footery1449




\trowd\trgaph108\trleft0\trqc
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrb\brdrw15\clvertalb\cellx4500
\clbrdrl\brdrs\brdrw15\clbrdrt\brdrdb\brdrw15\clbrdrr\brdrs\brdrw15\clbrdrb\brdrw15\clvertalb\cellx9000
Expand Down
9 changes: 0 additions & 9 deletions docs/reference/pagination.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,6 @@ Main pagination controller for handling page breaks and content distribution.
Calculates optimal page break positions.

::: rtflite.pagination.PageBreakCalculator
options:
show_root_heading: false
show_source: false

## ContentDistributor

Distributes content across pages while maintaining formatting.

::: rtflite.pagination.ContentDistributor
options:
show_root_heading: false
show_source: false
32 changes: 19 additions & 13 deletions src/rtflite/__init__.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,42 @@
from .convert import LibreOfficeConverter
from .core import RTFConfiguration, RTFConstants
"""rtflite: A Python library for creating RTF documents."""

from .attributes import TableAttributes
from .encode import RTFDocument
from .figure import rtf_read_figure
from .encoding import RTFEncodingEngine
from .input import (
RTFBody,
RTFColumnHeader,
RTFFigure,
RTFFootnote,
RTFPage,
RTFPageFooter,
RTFPageHeader,
RTFSource,
RTFSubline,
RTFTitle,
)
from .pagination import ContentDistributor, PageBreakCalculator, RTFPagination
from .pagination import PageBreakCalculator, RTFPagination
from .strwidth import get_string_width
from .convert import LibreOfficeConverter

Check failure on line 20 in src/rtflite/__init__.py

View workflow job for this annotation

GitHub Actions / ruff-check

Ruff (I001)

src/rtflite/__init__.py:3:1: I001 Import block is un-sorted or un-formatted

__version__ = "0.0.1"

__all__ = [
"LibreOfficeConverter",
"RTFDocument",
"RTFEncodingEngine",
"RTFBody",
"RTFColumnHeader",
"RTFFigure",
"RTFPage",
"RTFTitle",
"RTFPageHeader",
"RTFPageFooter",
"RTFColumnHeader",
"RTFFootnote",
"RTFSource",
"rtf_read_figure",
"RTFFigure",
"RTFPageHeader",
"RTFPageFooter",
"RTFSubline",
"TableAttributes",
"RTFPagination",
"PageBreakCalculator",
"ContentDistributor",
"RTFConstants",
"RTFConfiguration",
"get_string_width",
"LibreOfficeConverter",
]
11 changes: 3 additions & 8 deletions src/rtflite/encoding/__init__.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
"""RTF encoding engine module.

This module separates document structure from RTF encoding logic,
supports multiple encoding strategies, and prepares for future content types.
"""
"""RTF encoding module."""

from .engine import RTFEncodingEngine
from .strategies import PaginatedStrategy, SinglePageStrategy
from .unified_encoder import UnifiedRTFEncoder

__all__ = [
"RTFEncodingEngine",
"SinglePageStrategy",
"PaginatedStrategy",
"UnifiedRTFEncoder",
]
21 changes: 21 additions & 0 deletions src/rtflite/encoding/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING

if TYPE_CHECKING:
from ..encode import RTFDocument


class EncodingStrategy(ABC):
"""Abstract base class for RTF encoding strategies."""

@abstractmethod
def encode(self, document: "RTFDocument") -> str:
"""Encode the document using this strategy.

Args:
document: The RTF document to encode

Returns:
Complete RTF string
"""
pass
33 changes: 7 additions & 26 deletions src/rtflite/encoding/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

from typing import TYPE_CHECKING

from .strategies import EncodingStrategy, PaginatedStrategy, SinglePageStrategy
from .base import EncodingStrategy

Check failure on line 5 in src/rtflite/encoding/engine.py

View workflow job for this annotation

GitHub Actions / ruff-check

Ruff (F401)

src/rtflite/encoding/engine.py:5:19: F401 `.base.EncodingStrategy` imported but unused
from .unified_encoder import UnifiedRTFEncoder

if TYPE_CHECKING:
from ..encode import RTFDocument
Expand All @@ -11,40 +12,20 @@
class RTFEncodingEngine:
"""Main engine for RTF document encoding.

This class orchestrates the encoding process by selecting the appropriate
strategy based on document characteristics and delegating the actual
encoding to strategy classes.
This class orchestrates the encoding process using the UnifiedRTFEncoder
which implements the strategy pattern for pagination and rendering.
"""

def __init__(self):
from ..services.document_service import RTFDocumentService

self._document_service = RTFDocumentService()
self._single_page_strategy = SinglePageStrategy()
self._paginated_strategy = PaginatedStrategy()
self._encoder = UnifiedRTFEncoder()

def encode_document(self, document: "RTFDocument") -> str:
"""Encode an RTF document using the appropriate strategy.
"""Encode an RTF document using the unified encoder.

Args:
document: The RTF document to encode

Returns:
Complete RTF string
"""
strategy = self._select_strategy(document)
return strategy.encode(document)

def _select_strategy(self, document: "RTFDocument") -> "EncodingStrategy":
"""Select the appropriate encoding strategy based on document characteristics.

Args:
document: The RTF document to analyze

Returns:
The selected encoding strategy
"""
if self._document_service.needs_pagination(document):
return self._paginated_strategy
else:
return self._single_page_strategy
return self._encoder.encode(document)
Loading
Loading