fix: unit tests and pdf bullet rendering
All checks were successful
Deploy Plattform-Core (Int) / test (push) Successful in 1m3s
Deploy Plattform-Core (Int) / deploy (push) Successful in 9s

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
ValueOn AG 2026-06-09 23:40:43 +02:00
parent 06e68c343b
commit dce41a01ac
3 changed files with 32 additions and 12 deletions

View file

@ -828,7 +828,15 @@ class RendererPdf(BaseRenderer):
return [] return []
def _renderJsonBulletList(self, list_data: Dict[str, Any], styles: Dict[str, Any]) -> List[Any]: def _renderJsonBulletList(self, list_data: Dict[str, Any], styles: Dict[str, Any]) -> List[Any]:
"""Render a JSON bullet list to PDF elements.""" """Render a JSON bullet list to PDF elements.
Uses ReportLab's built-in ``bulletText`` parameter for proper hanging
indent: the bullet/number is drawn at ``bulletIndent`` while all text
lines (including continuation) start at ``leftIndent``. This avoids
the previous approach of prepending the bullet character to the text
which caused misaligned wrap lines when the character width did not
match the indent value.
"""
try: try:
content = list_data.get("content", {}) content = list_data.get("content", {})
if not isinstance(content, dict): if not isinstance(content, dict):
@ -836,27 +844,39 @@ class RendererPdf(BaseRenderer):
items = content.get("items", []) items = content.get("items", [])
bulletStyleDef = styles.get("bullet_list", {}) bulletStyleDef = styles.get("bullet_list", {})
indent = bulletStyleDef.get("indent", 18) indent = bulletStyleDef.get("indent", 18)
fs = bulletStyleDef.get("font_size", 11)
us = getattr(self, '_unifiedStyle', None)
primaryFont = us["fonts"]["primary"] if us else "Calibri"
fontName = _resolveFontFamily(primaryFont, False)
isNumbered = content.get("list_type") == "numbered"
bulletChar = bulletStyleDef.get("bullet_char", "\u2022")
bulletStyle = ParagraphStyle( bulletStyle = ParagraphStyle(
"BulletItem", "BulletItem",
fontSize=bulletStyleDef.get("font_size", 11), fontName=fontName,
fontSize=fs,
textColor=self._hexToColor(bulletStyleDef.get("color", styles.get("colors", {}).get("primary", "#24292e"))), textColor=self._hexToColor(bulletStyleDef.get("color", styles.get("colors", {}).get("primary", "#24292e"))),
leftIndent=indent, leftIndent=indent,
firstLineIndent=-indent, bulletIndent=0,
bulletFontName=fontName,
bulletFontSize=fs,
spaceAfter=2, spaceAfter=2,
leading=bulletStyleDef.get("font_size", 11) * 1.25, leading=fs * 1.25,
) )
bulletChar = bulletStyleDef.get("bullet_char", "\u2022")
elements = [] elements = []
for item in items: for idx, item in enumerate(items):
marker = f"{idx + 1}." if isNumbered else bulletChar
runs = self._inlineRunsForListItem(item) runs = self._inlineRunsForListItem(item)
if isinstance(item, list): if isinstance(item, list):
xml = self._renderInlineRunsToPdfXml(runs) xml = self._renderInlineRunsToPdfXml(runs)
elements.append(Paragraph(f"{bulletChar} {_wrapEmojiSpansInXml(xml)}", bulletStyle)) elements.append(Paragraph(_wrapEmojiSpansInXml(xml), bulletStyle, bulletText=marker))
elif isinstance(item, str): elif isinstance(item, str):
elements.append(Paragraph(f"{bulletChar} {self._markdownInlineToReportlabXml(item)}", bulletStyle)) elements.append(Paragraph(self._markdownInlineToReportlabXml(item), bulletStyle, bulletText=marker))
elif isinstance(item, dict) and "text" in item: elif isinstance(item, dict) and "text" in item:
elements.append(Paragraph(f"{bulletChar} {self._markdownInlineToReportlabXml(item['text'])}", bulletStyle)) elements.append(Paragraph(self._markdownInlineToReportlabXml(item['text']), bulletStyle, bulletText=marker))
if elements: if elements:
elements.append(Spacer(1, bulletStyleDef.get("space_after", 3))) elements.append(Spacer(1, bulletStyleDef.get("space_after", 3)))

View file

@ -554,7 +554,7 @@ def test_presentation_envelopes_preserves_data_slot_order_text_image_text():
) )
class _Svc: class _Svc:
interfaceDbComponent = _Mgmt() chat = _Mgmt()
pres = { pres = {
"kind": PRESENTATION_KIND, "kind": PRESENTATION_KIND,
@ -666,7 +666,7 @@ def test_presentation_envelopes_to_document_json_image_slot():
return b"\x89PNG\r\n\x1a\n" + b"\x00" * 16 return b"\x89PNG\r\n\x1a\n" + b"\x00" * 16
class _Svc: class _Svc:
interfaceDbComponent = _Mgmt() chat = _Mgmt()
out = presentation_envelopes_to_document_json( out = presentation_envelopes_to_document_json(
pres, pres,

View file

@ -596,7 +596,7 @@ def test_extract_image_slot_carries_file_id_and_mime():
class _Services: class _Services:
def __init__(self): def __init__(self):
self.interfaceDbComponent = _MgmtStub() self.chat = _MgmtStub()
envelope = { envelope = {
"schemaVersion": PRESENTATION_SCHEMA_VERSION, "schemaVersion": PRESENTATION_SCHEMA_VERSION,