recon_gen.common.rich_text
Compose rich-text XML for QuickSight SheetTextBox.Content.
QuickSight accepts a small XML dialect inside a single <text-box> root
(undocumented — full set confirmed by round-tripping a UI-authored text box
that exercised every formatting button via describe-analysis-definition):
<inline ...>text</inline>— styled run; attrsfont-size="36px",color="#hex",background-color="#hex"(highlight),font-family="Name"<b>/<i>/<s>/<u>— bold / italic / strikethrough / underline (bare HTML tags, NOT<inline>attrs)<block align="center">text</block>— paragraph alignment (center/right; left is the default, emitted with no block)<br/>— explicit line break<ul><li class="ql-indent-0">item</li></ul>— bulleted list (theql-indent-0class is required for top-level bullets)<a href="..." target="_self">Link</a>— hyperlink<expression>${pName}</expression>— live parameter-value injectionBody text between tags must be XML-escaped;
survives
Theme tokens aren’t supported by the parser, so colors are resolved to hex at generate-time and interpolated here by the caller.
Authoring helpers:
body(text)— single-line plain text, XML-escaped. Use for one-shot prose with no paragraph breaks or links.markdown(text)— multi-paragraph prose with optional inline[text](url)links.\n\nparagraph breaks become<br/><br/>, a lone\nis a CommonMark soft break that collapses to a single space,[text](url)becomes a clickable<a href="...">. Use whenever the source string is L2-YAML-supplied description prose (which is markdown-shaped by convention).markdown_inline(text)— same XML-escape +[text](url)link handling, but ALL newlines collapse to a single space (no<br/>). Use inside contexts where<br/>is not a valid child — most notably<li>: QS’s XML parser rejects<br/>as a child of<li>withElement 'li' cannot have 'br' elements as children.
bullets() is defensive: it routes items through markdown()
then strips any <br/> from each item with a UserWarning
showing the original input. Authors can choose markdown_inline
explicitly when they need a guaranteed-no-<br/> rendering of a
single string outside a bullet context.
Functions
|
Plain body text — XML-escaped, no styling. |
|
Bold run — |
|
Bulleted list at indent level 0. |
|
Bulleted list whose items are pre-composed XML (so inline styling works inside bullets). |
|
Inline monospace run. |
|
Top-level heading (32px). |
|
Styled inline run. |
|
Hyperlink opening in the same tab. |
|
Block + inline markdown → QuickSight rich-text XML. |
|
Single-line markdown with link handling but no |
|
Section subheading (20px). |
|
Wrap parts in a |
- recon_gen.common.rich_text.body(text)[source]
Plain body text — XML-escaped, no styling.
- Return type:
str- Parameters:
text (str)
- recon_gen.common.rich_text.bold(text)[source]
Bold run —
<b>(XML-escaped body).- Return type:
str- Parameters:
text (str)
- recon_gen.common.rich_text.bullets(items)[source]
Bulleted list at indent level 0.
Each item is processed through
markdown()(so inline[text](url)links render as clickable anchors) and then defensively stripped of any<br/>tags — QS’s XML parser rejects<br/>as a child of<li>withElement 'li' cannot have 'br' elements as children. A\n\nparagraph break still reflows to<br/><br/>viamarkdown()and would breakCreateAnalysisinside an<li>(the v8.5.4 → v8.5.8 regression on the L1 Drift sheet), so it is stripped here. (A lone\nis a soft break thatmarkdown()collapses to a space upstream, so it never reaches this strip.)Any stripped
<br/>raises aUserWarningshowing the original item so authors can clean the source string when the line break was actually intended (e.g. break the item into two).- Return type:
str- Parameters:
items (Iterable[str])
- recon_gen.common.rich_text.bullets_raw(items)[source]
Bulleted list whose items are pre-composed XML (so inline styling works inside bullets).
- Return type:
str- Parameters:
items (Iterable[str])
- recon_gen.common.rich_text.code(text)[source]
Inline monospace run. QS has no code tag, so this is an
<inline font-family>(render.pymaps it to a<span style="font-family:…">in App2).- Return type:
str- Parameters:
text (str)
- recon_gen.common.rich_text.heading(text, color=None)[source]
Top-level heading (32px).
- Return type:
str- Parameters:
text (str)
color (str | None)
- recon_gen.common.rich_text.inline(text, *, font_size=None, color=None)[source]
Styled inline run.
font_sizelike"24px";colorlike"#2E5090".- Return type:
str- Parameters:
text (str)
font_size (str | None)
color (str | None)
- recon_gen.common.rich_text.link(text, href)[source]
Hyperlink opening in the same tab.
- Return type:
str- Parameters:
text (str)
href (str)
- recon_gen.common.rich_text.markdown(text)[source]
Block + inline markdown → QuickSight rich-text XML.
Block structure (paragraphs split on a blank line,
\n\n+):A block whose first non-blank line is a bullet (
- `` / ``* ``) becomes a ``<ul><li class="ql-indent-0">…</li></ul>list. Non-bullet lines inside the block are continuations of the preceding item (soft-wrapped source reflows into one item). Consecutive bullet blocks (authors who separate items with blank lines) merge into one<ul>.Any other block is a prose paragraph: a lone
\nis a CommonMark soft break (→ a single space), and blocks join with<br/><br/>.
Inline (within every block):
[text](url)→ clickable<a>,**bold**→<b>,`code`→ monospace<inline>; the remaining text is XML-escaped.Use whenever the input is L2-YAML-supplied prose or any markdown-shaped string.
body()is for plain single-line text only — feeding multi-paragraph / link- / emphasis-bearing strings tobody()produces unrendered markdown in QuickSight (the v8.4.0 footgun this helper closes; AO.R.3 added bold/code/bullet parsing so dashboard panels stop rendering literal**/ ``- `` markers).- Return type:
str- Parameters:
text (str)
- recon_gen.common.rich_text.markdown_inline(text)[source]
Single-line markdown with link handling but no
<br/>.Same transformations as
markdown()for inline links and XML-escaping, but ANY whitespace run that contains a newline collapses to a single space.<br/>is never emitted. Use inside<li>(the QS XML parser rejects<br/>as an<li>child) or any other context where line breaks must not appear.Trailing / leading whitespace is stripped — useful when the input came from a YAML
|block scalar (which always ends in\n). Strip happens after link substitution so a link sitting at the end of the input stays attached to the next part rather than getting whitespace-eaten.- Return type:
str- Parameters:
text (str)
- recon_gen.common.rich_text.subheading(text, color=None)[source]
Section subheading (20px).
- Return type:
str- Parameters:
text (str)
color (str | None)
- recon_gen.common.rich_text.text_box(*parts)[source]
Wrap parts in a
<text-box>root.Auto-pads the interior with leading + trailing
<br/>so the rendered text doesn’t sit flush against the box’s top / bottom edges.SheetTextBoxitself has no padding/margin fields in the AWS API — interior breathing room only comes via the rich-text grammar insideContent. Two<br/>per side matches what hand-authored QS UI text boxes emit when an editor hits Enter twice for spacing (a common pattern).Pass already-
<br/>-paddedpartsif you want even more space; the auto-pad is additive.- Return type:
str- Parameters:
parts (str)