Skip to content

Commit

Permalink
Better replacement strategy for variables so that variables can be us…
Browse files Browse the repository at this point in the history
…ed in URLs.
  • Loading branch information
fniessink committed Nov 27, 2023
1 parent 08ef9e6 commit 8f59aad
Show file tree
Hide file tree
Showing 7 changed files with 20 additions and 16 deletions.
4 changes: 2 additions & 2 deletions src/builder/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ def accept_element(self, tag: str) -> bool:
"""Return whether the builder accepts the element."""
return True

def in_element(self, tag: str, attributes: TreeBuilderAttributes = None) -> bool:
def in_element(self, tag: str, attributes: TreeBuilderAttributes | None = None) -> bool:
"""Return whether we are currently in an element with the specified tag and attributes."""
return self.nr_elements(tag, attributes) > 0

def nr_elements(self, tag: str, attributes: TreeBuilderAttributes = None) -> int:
def nr_elements(self, tag: str, attributes: TreeBuilderAttributes | None = None) -> int:
"""Return how many elements with the specified tag and attributes are currently being built."""
attributes = attributes or {}
return len(
Expand Down
4 changes: 2 additions & 2 deletions src/builder/pptx_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ def text(self, tag: str, text: str, attributes: TreeBuilderAttributes) -> None:
self.add_slide(self.CONTENT_SLIDE, text)
self.current_slide.shapes.title.text_frame.paragraphs[0].font.size = Pt(24) # type: ignore
else:
if len(self.current_slide.shapes) == 1:
if len(self.current_slide.shapes) == 1: # type: ignore
self.add_text_box()
self.current_slide.shapes[1].text = text # type: ignore
else:
paragraph = self.current_slide.shapes[1].text_frame.add_paragraph()
paragraph = self.current_slide.shapes[1].text_frame.add_paragraph() # type: ignore
paragraph.text = text
paragraph.font.size = Pt(20)
elif (
Expand Down
2 changes: 1 addition & 1 deletion src/converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def convert(self, builder: Builder) -> None:
self.convert_element(self.root, builder)
builder.end_document()

def convert_element(self, element: Element, builder: Builder, parent: Element = None) -> None:
def convert_element(self, element: Element, builder: Builder, parent: Element | None = None) -> None:
"""Recursively convert the element using the builder."""
if not builder.accept_element(element.tag):
return
Expand Down
2 changes: 1 addition & 1 deletion src/custom_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@

JSON = NewType("JSON", dict[str, Any])
Settings = NewType("Settings", dict[str, Any])
TreeBuilderAttributes = dict[bytes | str, bytes | str]
TreeBuilderAttributes = dict[str, str]
Variables = NewType("Variables", dict[str, Any])
16 changes: 7 additions & 9 deletions src/markdown_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ def process_line(self, line: str) -> None:
self.end_lists()
self.end_table()
return # Empty line, nothing further to do
stripped_line = self.process_variables(stripped_line)
if match := re.match(markdown_syntax.BEGIN_PATTERN, stripped_line):
attributes: dict[bytes | str, bytes | str] = {}
if attribute := match.group(2):
Expand All @@ -145,6 +146,10 @@ def process_line(self, line: str) -> None:
with self.element(xmltags.PARAGRAPH):
self.process_formatted_text(stripped_line)

def process_variables(self, line: str) -> str:
"""Replace the variables with their values."""
return re.sub(markdown_syntax.VARIABLE_USE_PATTERN, lambda variable: self.variables[variable.group(1)], line)

def process_heading(self, heading: str, level: int) -> None:
"""Process a heading."""
if level == self.APPENDIX_LEVEL and heading == self.APPENDIX_HEADING:
Expand Down Expand Up @@ -271,13 +276,6 @@ def process_formatted_text(self, line: str) -> None:
with self.element(xmltags.ANCHOR, {xmltags.ANCHOR_LINK: match.group(2)}):
self.process_formatted_text(match.group(1))
line = line[len(match.group(0)) :]
elif (match := re.match(markdown_syntax.VARIABLE_USE_PATTERN, line)) is not None:
format_found = True
self.flush(seen)
seen = ""
match = cast(re.Match, match)
self.builder.data(self.variables[match.group(1)])
line = line[len(match.group(0)) :]
elif match := re.match(markdown_syntax.IMAGE_PATTERN, line):
format_found = True
self.flush(seen)
Expand Down Expand Up @@ -305,13 +303,13 @@ def end_document(self) -> None:
self.end_sections()
self.builder.end(xmltags.DOCUMENT)

def add_element(self, tag: str, text: str = "", attributes: TreeBuilderAttributes = None) -> None:
def add_element(self, tag: str, text: str = "", attributes: TreeBuilderAttributes | None = None) -> None:
"""Add an element with text."""
with self.element(tag, attributes):
self.flush(text)

@contextlib.contextmanager
def element(self, tag: str, attributes: TreeBuilderAttributes = None):
def element(self, tag: str, attributes: TreeBuilderAttributes | None = None):
"""Return a context manager."""
element = self.builder.start(tag, attributes or {})
try:
Expand Down
2 changes: 1 addition & 1 deletion src/markdown_syntax.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@
NUMBERED_LIST_PATTERN = r"^[0-9A-Za-z]+\. "
STRIKETROUGH_START = STRIKETROUGH_END = "~~"
TABLE_MARKER = "|"
VARIABLE_USE_PATTERN = r"^\$([^\$]+)\$"
VARIABLE_USE_PATTERN = r"\$([^\$]+)\$"
6 changes: 6 additions & 0 deletions tests/test_markdown_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,12 @@ def test_variable(self):
"""Test that a variable is replaced with its value."""
self.assertEqual("Replace variable.", self.xml().find(xmltags.PARAGRAPH).text)

@patch("markdown_converter.open", mock_open(read_data="Replace [anchor](https://$var$/).\n"))
def test_variable_in_url(self):
"""Test that a variable in a URL is replaced with its value."""
anchor_link = self.xml().find(xmltags.PARAGRAPH).find(xmltags.ANCHOR).attrib[xmltags.ANCHOR_LINK]
self.assertEqual("https://variable/", anchor_link)

@patch(
"markdown_converter.open", mock_open(read_data="<!-- begin: measure -->\nMeasure\n<!-- end: measure -->\n")
)
Expand Down

0 comments on commit 8f59aad

Please sign in to comment.