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

Pdf #12

Merged
merged 3 commits into from
Jan 10, 2024
Merged

Pdf #12

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
Binary file modified example.docx
Binary file not shown.
9 changes: 8 additions & 1 deletion example.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,14 @@ <h2>
<span>The first paragraph.</span>
</p>
<p>
<span>The second paragraph.</span>
<strong>
<span>Kava</span>
</strong>
<span> or </span>
<strong>
<span>kava kava</span>
</strong>
<span> (Piper methysticum: Latin 'pepper' and Latinized Greek 'intoxicating') is a crop of the Pacific Islands.</span>
</p>
<p>
<span>We allow </span>
Expand Down
Binary file modified example.pdf
Binary file not shown.
5 changes: 3 additions & 2 deletions example.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import datetime
import io

from red_tape_kit.ast import Attachment, Document, InlineSequence, Section, Table, TableCellSpan, UnorderedList
from red_tape_kit.ast import Attachment, Document, InlineSequence, Section, Strong, Table, TableCellSpan, UnorderedList


doc = Document(
Expand All @@ -20,7 +20,8 @@
title='The First Section',
body=[
'The first paragraph.',
'The second paragraph.',
Strong('Kava') + ' or ' + Strong('kava kava') + ' (Piper methysticum: Latin \'pepper\''
' and Latinized Greek \'intoxicating\') is a crop of the Pacific Islands.',
InlineSequence([
'We allow ',
Attachment(
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "red-tape-kit"
version = "0.5.0"
version = "0.5.1"
description = ""
authors = ["Your Name <[email protected]>"]
readme = "README.md"
Expand Down
15 changes: 15 additions & 0 deletions red_tape_kit/ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ def normalized(self) -> 'InlineElement':
def plain_string(self) -> str:
raise NotImplementedError

def __add__(self, other: 'InlineElement') -> 'InlineSequence':
return InlineSequence(items=[self, other])


@dataclass
class Document:
Expand Down Expand Up @@ -263,6 +266,18 @@ def plain_string(self) -> str:
return self.text.plain_string


@dataclass(frozen=True)
class Strong(InlineElement):
text: InlineElement

def normalized(self) -> 'Strong':
return Strong(text=normalized_inline(self.text))

@property
def plain_string(self) -> str:
return self.text.plain_string


def normalized_inline(element: InlineElement) -> InlineElement:
if isinstance(element, str):
return Text(text=element).normalized()
Expand Down
7 changes: 5 additions & 2 deletions red_tape_kit/html.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
from base64 import b64encode

from .ast import (
Attachment, DefinitionList, Image, InlineSequence, Paragraph, Section, Sequence, Table, TableCellSpan, Text,
UnorderedList,
Attachment, DefinitionList, Image, InlineSequence, Paragraph, Section, Sequence, Strong, Table, TableCellSpan,
Text, UnorderedList,
)


Expand Down Expand Up @@ -131,6 +131,9 @@ def add_inline_element(self, html_el, element):
self.add_inline_element(html_el, sub_element)
elif isinstance(element, Attachment):
self.add_attachment(html_el, element)
elif isinstance(element, Strong):
strong = ET.SubElement(html_el, 'strong')
self.add_inline_element(strong, element.text)
else:
raise ValueError(f'Unknown inline element type {type(element)}')

Expand Down
26 changes: 18 additions & 8 deletions red_tape_kit/pdf.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from logging import getLogger

from fpdf import FPDF, TitleStyle, XPos, YPos
from fpdf import FPDF, FontFace, TitleStyle, XPos, YPos

from .ast import (
Attachment, DefinitionList, Image, InlineSequence, Paragraph, Section, Sequence, Table, TableCellSpan, Text,
UnorderedList,
Attachment, DefinitionList, Image, InlineSequence, Paragraph, Section, Sequence, Strong, Table, TableCellSpan,
Text, UnorderedList,
)


Expand All @@ -19,7 +19,10 @@ class FPDFRenderer(FPDF):
MARGIN_RIGHT = 20 # mm
MARGIN_TOP = 20 # mm
MARGIN_BOTTOM = 20 # mm
SEQUENCE_SPACE = 7 # mm
UNORDERED_LIST_HSPACE = 7 # mm
UNORDERED_LIST_BULLET = '-'
UNORDERED_LIST_BULLET_SPACE = 5 # mm

def __init__(self, document, **kwargs):
super().__init__(**kwargs, unit='mm', format='A4')
Expand Down Expand Up @@ -114,7 +117,7 @@ def add_sequence(self, sequence, level):
ln_required = False
for sub_element in sequence.items:
if ln_required:
self.ln(7)
self.ln(self.SEQUENCE_SPACE)
ln_required = self.add_element(sub_element, level)
if ln_required:
anything_generated = True
Expand All @@ -125,7 +128,8 @@ def add_section(self, section, level):
return self.add_element(section.body, level + 1)

def add_paragraph(self, paragraph):
return self.add_inline_element(paragraph.text)
self.add_inline_element(paragraph.text)
return True

def add_table(self, table_data):
with self.table(
Expand All @@ -150,11 +154,11 @@ def add_elementary_table(self, pdf_table, elementary_table):

def add_unordered_list(self, unordered_list):
orig_left_margin = self.l_margin
new_left_margin = orig_left_margin + 5
new_left_margin = orig_left_margin + self.UNORDERED_LIST_BULLET_SPACE
self.set_left_margin(new_left_margin)
for i, item in enumerate(unordered_list.items):
if i > 0:
self.ln(7)
self.ln(self.UNORDERED_LIST_HSPACE)
with self.unbreakable() as self:
self.set_x(orig_left_margin)
self.cell(text=self.UNORDERED_LIST_BULLET)
Expand Down Expand Up @@ -184,12 +188,14 @@ def add_inline_element(self, inline_element):
return self.add_inline_sequence(inline_element)
elif isinstance(inline_element, Attachment):
return self.add_attachment(inline_element)
elif isinstance(inline_element, Strong):
return self.add_strong(inline_element)
else:
raise ValueError(f'Unknown inline element type {inline_element}')

def add_text(self, text):
self.write_lh(text.text)
return text != ''
return text.text != ''

def add_inline_sequence(self, inline_sequence):
anything_generated = False
Expand All @@ -216,6 +222,10 @@ def add_attachment(self, attachment):
)
return True

def add_strong(self, strong):
with self.use_font_face(FontFace(emphasis="BOLD")):
return self.add_inline_element(strong.text)

def header(self):
pass

Expand Down
27 changes: 27 additions & 0 deletions tests/test_renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,33 @@ def test_not_dependent_on_current_date(render):
assert a == b


@pytest.mark.xfail(reason='Preserving final ln in fpdf is hard')
def test_empty_paragraph_at_the_end_is_represented(render):
doc_a = DocumentFactory(
body=Sequence([
Paragraph(text=Text('A')),
Paragraph(text=Text('')),
]),
)
doc_b = DocumentFactory(
body=Paragraph(text=Text('A')),
)
assert render(doc_a) != render(doc_b)


def test_empty_paragraph_is_represented(render):
doc_a = DocumentFactory(
body=Sequence([
Paragraph(text=Text('')),
Paragraph(text=Text('A')),
]),
)
doc_b = DocumentFactory(
body=Paragraph(text=Text('A')),
)
assert render(doc_a) != render(doc_b)


def test_empty_attachment_no_smoke(render):
doc = DocumentFactory(
body=Paragraph(text=Attachment(
Expand Down