Differences from a Sphinx build¶
The ubCode preview is built for instant feedback while you type:
it parses and renders your document on every keystroke,
so it deliberately skips the slower, whole-project transforms
that a full sphinx-build runs at the end.
This page is the honest register of the resulting user-visible differences,
so you can trust what you see and know when to reach for a real build.
Every entry below describes the Rendered preview mode (in Structural mode every directive and role renders as a uniform placeholder; see Authoring). Unless a status line says otherwise, none of these differences affect the correctness of background indexing or diagnostics — they change only what the preview panel displays.
The main entries follow the same shape — what you write, what the preview shows, what a Sphinx build does, and a short status note; smaller differences are grouped into bullet lists.
Not yet rendered¶
These constructs are recognised and shown as self-describing placeholders, but the transform that gives them their final form does not run in the preview yet.
- Footnotes and citations
You write footnote and citation references such as
[1]_,[#]_, or[CIT2002]_, with their matching definitions.The preview shows each reference as a superscript label, but the label is not linked or resolved to its definition.
A Sphinx build numbers auto footnotes, resolves each reference, and renders bidirectional links between reference and definition.
Status — reference resolution is a whole-document transform the preview does not run. Indexing and diagnostics are unaffected.
- Hyperlink references
You write a named reference such as
target_or`phrase`_to a target defined in the same document — an external link target (.. _t: https://example.com), an indirect target (.. _alias: t_), an explicit internal target, or a section title.The preview shows the reference linked to a slug guessed from its name (
#target): correct for a same-page section or internal target, but a dead link for an external or indirect target.A Sphinx build (and
ubc build html) resolves the reference through the document’s target table — a reference to an external target renders the real URL, a reference to an indirect target follows the chain to its resolved end, and a reference to no target (or to a duplicated name) is reported as an error.Status —
ubc build htmlresolves external and indirect references, and this does affect diagnostics: a dangling or ambiguous named reference now raises an error (ref.unknown_target,ref.duplicate_target,ref.circular_indirect,ref.nonexistent_indirect,ref.anonymous_mismatch) in indexing,ubc check, and the build warning count. The live preview keeps the slug guess (reference resolution is a whole-document transform it does not run per keystroke).- Math
You write a formula with the
:math:role or a.. math::block.The preview shows the raw source, not typeset.
A Sphinx build typesets the math (via MathJax, KaTeX, or images).
Status — no math typesetting engine is bundled with the preview yet. Indexing and diagnostics are unaffected.
- Needs flow diagram (
needflow) You write a
.. needflow::traceability graph.A Sphinx build draws it from the resolved need set via the configured Graphviz or PlantUML engine (an SVG/PNG image).
The preview and
ubc build htmldraw the same graph as a Mermaidflowchart, rendered client-side by the bundled Mermaid runtime (the list and table views render their real output too; theneedpieandneedbarcharts remain placeholders — see below).Status — implemented, with these deliberate differences from Sphinx-Needs (the output is self-consistent, not byte-identical to either upstream engine):
Engine — ubCode always renders Mermaid.
:engine:(graphviz/plantuml) is accepted and ignored.:config:(Graphviz/PlantUML style snippets) is likewise accepted and ignored, except the two PlantUML direction names —lefttorightselects a left-to-right flowchart andtoptobottoma top-down one (the default).:scale:and:alt:are accepted and ignored (they apply to a raster image, not an SVG).Link types — with no
:link_types:option the diagram draws edges of every configured link type (exceptparent_needs, which is never drawn), matching Sphinx-Needs’ effective behaviour: itsneedflowdirective defaults:link_types:to all link fields, so theneeds_flow_link_typesconfig (default["links"]) is inert forneedflowin Sphinx-Needs 8.3.0 — ubCode intentionally has no equivalent key.Node cap — a default cap of 100 drawn nodes (with a shown-vs-total notice) keeps a large graph readable and within Mermaid’s edge limits;
:max_items: 0draws them all. Sphinx-Needs has no such option.Flat, need-level graph — a need’s parts are not drawn as their own nodes: they are not matched as separate items (the project-wide convention the
:need_count:role also follows), so an edge to a part collapses to that part’s base need. The parent/child hierarchy is likewise not drawn as nesting (Sphinx-Needs clusters child needs inside their parent).No click-through — nodes are not yet click-through links (the Mermaid runtime is initialised in its strict security mode, which strips link bindings); use the surrounding need cards / references to navigate.
Caption — a
:caption:renders as a caption paragraph rather than a docutilsfigure, and its inline markup is not parsed (as for diagram captions above).``:root_depth:`` — the
:root_id:walk bounds by shortest-path distance from the root (a breadth-first walk), rather than Sphinx-Needs’ order-dependent last-recorded distance; the two agree except at the exact depth boundary of a diamond-shaped graph.``:border_color:`` — applied as a literal colour (a bare 3- or 6-digit hex such as
FF0000is accepted, as Sphinx-Needs does; a per-need variant expression is not resolved yet).
- Needs chart views (
needpie/needbar) You write a
.. needpie::or.. needbar::chart.The preview shows a self-describing placeholder naming the directive and its options.
A Sphinx build draws the chart (Matplotlib) from the resolved need set.
Status — the chart-view transforms are not implemented in the ubCode engine yet; this applies to
ubc build htmlas well as the live preview. Indexing and diagnostics over the underlying needs are unaffected.
Document structure¶
- Docinfo
You write a document that opens with a bibliographic field list (
:Author:,:Version:,:Date:, and so on).The preview shows a plain field list, the same as any field list appearing mid-document.
A Sphinx build turns the leading field list into a bibliographic docinfo table.
Status — the preview does not model docinfo. Indexing and diagnostics are unaffected.
rst_prolog/rst_epilogYou write content in
rst_prologorrst_epilog(in your parsing configuration).The preview shows the prologue and epilogue spliced as their own blocks at the very start and end of each RST document, at the document root — not merged into the document’s section structure. A prologue that begins with a heading never swallows the rest of the document. State set there, such as a default role, still applies to the whole document. A malformed prolog is silently not shown.
A Sphinx build appends the epilogue text inside the document’s trailing section, and a prologue that opens a section can absorb the whole document.
Status — the splice is structural rather than a raw text concatenation. Indexing and diagnostics are unaffected by where the splice lands; the background index splices the prologue and epilogue too, so state and substitutions defined there apply to both the preview and the index.
Included files¶
.. include:: expands inline in the Rendered preview.
A few things differ from how a Sphinx build splices the same file textually:
State set inside an included file — a
.. default-role::, for example — is scoped to that file in the preview. A Sphinx build lets that state leak into the rest of the host document.A section heading in an included file that uses the same underline level as the host nests one level deeper in the preview than in a Sphinx build.
Clicking inside spliced content does not jump to the included file; sync-scroll maps spliced content back to the
.. include::line in the host document.Include options the preview does not support are flagged with a diagnostic and ignored; the file is still spliced in.
Markdown documents splice too.
A MyST {include}, {literalinclude} or {csv-table} with :file:
reads its file on every surface — the Rendered preview, the background index,
ubc check and ubc build html — exactly as the reStructuredText forms do.
Three things are specific to a Markdown host:
The included file is parsed as Markdown, whatever its extension. A fragment is parsed in the syntax of the document that includes it, which is what both Sphinx and
myst-parserdo: including a.rstfile into a Markdown document yields paragraphs and plain text, not directives. (The reverse also holds and is unchanged: a.. include::of a.mdfile is parsed as reStructuredText.)An included file’s headings nest inside the include, not into the page. They keep their relative structure — a
##under a#stays nested — but they never close the host’s sections, and an included heading never becomes the page’s title. They do appear in the page’s “on this page” contents, and a target under an included heading keeps that heading as its title. A Sphinx build integrates them into the page at their literal levels, so an included#can open a section beside the page title; it also means an included file that starts at##renders one heading level deeper here than it does there.:heading-offset:therefore has no effect and raises a warning, as do:relative-docs:and:relative-images:.An included file’s front matter is ignored, as in a Sphinx build.
A file that includes itself, directly or through a chain,
reports directive.include_circular and shows an error message in place of
that one include; the rest of the page renders normally.
This applies to both formats and to every surface —
the preview, ubc check, the background index and ubc build html.
A Sphinx build with myst-parser has no cycle detection at all
and crashes instead.
.. literalinclude:: renders the named file as a code block —
in the Rendered preview, in ubc build html, and validated by ubc check.
Its selection options — :lines:, :start-after: / :start-at:,
:end-before: / :end-at:, :dedent:, :prepend: / :append:
and :tab-width: — apply exactly as in a Sphinx build, in the same order.
Three options are not applied; each raises a warning
and the file still renders with the remaining options applied:
:pyobject:— selecting a Python class or function by name.:diff:— rendering a unified diff against a second file.:encoding:— files are always read as UTF-8.utf-8andutf-8-sigare honoured (they are what a Sphinx build uses by default); any other value warns and the file is still read as UTF-8.
A leading byte-order mark is stripped, as in a Sphinx build —
unless you ask for :encoding: utf-8 explicitly, which keeps it.
A :tab-width: above 1000 is clamped.
A missing file, a marker that is not found, a line spec that selects nothing, and a conflicting option pair each show a visible error message in place of the block — the equivalent of the error a Sphinx build renders into the page. A file that exists but is not valid UTF-8 is reported as an encoding problem, not as a missing file. Line-number options behave exactly as they do for code blocks (see below).
The background index now splices .. include:: too:
a target, need, or glossary term defined in an included file
is registered in the host document — a reference to it from the host resolves —
while goto-definition and the hydrated title still point at the included file
where it was written.
A default-role (or similar state) set inside an included file therefore
applies within that file’s spliced content on both the preview and the index.
Note
Both the preview and the background index splice
rst_prolog / rst_epilog,
so they agree on spliced content.
Between indexing passes, the per-keystroke checks hold back
undefined substitution diagnostics —
a reference might be defined in your prologue —
until the next background pass catches up.
Raw content¶
.. raw:: html passes its body through to the output verbatim,
in a block position and inside a substitution definition
(.. |br| raw:: html) —
which is what makes an rst_prolog-defined |br| render as a real line break
on every page that references it.
As in every Sphinx build, raw HTML is enabled by default and is emitted unescaped,
so treat a raw block as content you are responsible for.
Two controls exist for when that assumption does not hold;
both are described under Trust controls below.
The format argument is a list:
.. raw:: html latexemits in an HTML build, and.. raw:: latexis silently dropped, exactly as docutils does.:class:wraps the payload in a<div>(block) or<span>(substitution) carrying those classes; without the option there is no wrapper markup at all.:file:reads the named file and records it as a dependency, so editing that file re-renders the page that embeds it.:url:is not supported — it would need a network fetch at build time. It raises a warning and the directive renders nothing.:encoding:is accepted but files are always read as UTF-8 (a non-UTF-8 value warns); a leading byte-order mark is stripped.Where docutils would insert a red error block into the page — a missing
:file:, a file and body content, neither of them — ubCode raises a warning and renders nothing, rather than injecting an error into the byte stream you are controlling.
Trust controls¶
Raw content assumes the author of a page is a party you trust to write HTML into your output. Two independent controls apply when that is not true.
Disabling the directive — set raw_enabled to false
(see Parsing):
[parse]
raw_enabled = false
Every .. raw::, and its MyST {raw} twin, then passes nothing through:
it raises a directive.raw_disabled warning
and renders a placeholder showing its own source, escaped, instead —
a framed block, or an inline chip where the directive defines a substitution
(so a |br|-style definition stays valid inside the paragraphs that use it).
The :file: form is not read at all, so no dependency on it is recorded.
This is the docutils setting of the same name (which Sphinx never changes),
and it applies wherever a document is processed —
ubc build, ubc check, and the preview alike.
It is meant for pipelines that build contributions you do not control,
such as an auto-deployed preview of an external pull request.
Like the docutils setting, it gates the raw directive only.
HTML written directly in a Markdown document
(<div>…</div> in a paragraph, or an HTML block)
is not a directive, so raw_enabled does not affect it.
Escaping in an untrusted workspace — the preview panel can render raw HTML
escaped rather than injected, showing the markup as text.
Unlike raw_enabled this is not project configuration
(a repository you do not trust also supplies its own ubproject.toml):
it is driven by the editor’s own trust state, per session,
and it covers both syntaxes —
the raw directive and Markdown’s native raw HTML.
Note
In VS Code this control is currently redundant: the ubCode extension does not declare support for untrusted workspaces, so VS Code disables the extension entirely in one — a stronger guarantee than escaping, with no preview at all. The escaping path exists in the language server, and the editor client already reports its trust state on every render, so the two stay in step if that posture is ever relaxed.
Conditional content¶
.. only:: evaluates its tag expression
(and / or / not, parentheses, and the a if b else c form)
against the build’s tags: html, format_html and builder_html,
plus everything in the top-level build_tags key
(see Configuring a project with ubproject.toml).
A truthy expression includes the body transparently;
a falsy one excludes it from the built output entirely,
while the preview shows it as a collapsed, greyed block so you can see it exists.
An expression that cannot be parsed raises only.invalid_expression
and the body is kept — the same fail-open direction a Sphinx build takes
(it evaluates only in a post-transform that keeps the children on any
error), so a typo can never silently delete a page’s content.
Warning
Content inside an excluded only block is not indexed.
A Sphinx build parses the body at read time and removes it only when writing,
so a :ref: into a target defined inside a falsy only still resolves there.
ubCode decides earlier and discards the body entirely,
so targets, needs and glossary terms written inside an excluded block
are not registered, and an inbound reference to one renders as an
unresolved reference chip.
No build warning is raised for an unresolved reference today,
so this breaks silently —
define anything you reference from elsewhere outside the only block.
sphinx-design components¶
The :octicon: role renders natively —
in the Rendered preview, in ubc build html, and validated by ubc check.
Write :octicon:`name`, :octicon:`name;height` or
:octicon:`name;height;classes`, as in a sphinx-design build;
it emits the same inline <svg class="sd-octicon sd-octicon-{name} …">,
so a stylesheet written against those classes keeps working.
Only a subset of the GitHub octicon set is embedded. The full set is 328 icons, an unreasonable weight to carry for a decorative role. A name outside the embedded subset raises
directive.octicon_unknownand the role keeps its self-describing chip, so your source stays visible.A height that is not a number followed by
px,emorremraisesdirective.octicon_invalid_height, and a class name containing anything but letters, digits,_and-raisesdirective.octicon_invalid_class— the rendered SVG is emitted verbatim, so an unsafe class name is refused rather than escaped. Both keep the chip.
The sphinx-design directives render natively too —
grid / grid-item / grid-item-card, card (with its
card-header / card-footer sub-directives), dropdown, div,
and button-link / button-ref.
They emit the same sd-* classes and element nesting sphinx-design does,
so a stylesheet written against those classes keeps working.
ubc build html ships its own minimal design stylesheet
(_static/ubc-design.css) covering the 12-column responsive grid,
the card, dropdown and button chrome, and the spacing, sizing, display,
border and text utility families.
A site with no sphinx-design markup neither links nor writes it.
The stylesheet is not loaded in the live preview yet,
so a grid there stacks rather than laying out in columns;
the markup and the semantics are the same either way.
What differs from a sphinx-design build:
A card’s header and footer come from sub-directives. Write
.. card-header::and.. card-footer::inside acardorgrid-item-card; they are hoisted into their slots wherever you put them. The legacy^^^header separator is not supported — usecard-header. Acard-headerorcard-footeroutside a card raises a warning and renders its content in place.The legacy
+++footer separator is honoured, but write exactly three. ubCode splits the parsed body where sphinx-design splits the raw lines, which cuts both ways. Better: a+++inside a code block, a literal block or a nested card is not treated as a separator here, where sphinx-design’s line scan claims it. Worse: a run of four or more+is a transition character in reStructuredText, so the parser claims it first — a standalone++++still splits, but a++++written directly under a line of text is read as a section underline and that line is dropped. That shape raisesdirective.card_separator_invalidtelling you to write+++or usecard-footer.A
grid-itemorgrid-item-cardoutside a grid raises a warning (as it does in a sphinx-design build) and still renders, as does agridchild that is neither.A dropdown’s default icon is not read from
conf.py. sphinx-design lets a project set per-directive option defaults through thesd_custom_directivesconfiguration value, which ubCode has no equivalent for, so dropdowns relying on it render without their configured icon. A:icon:naming an icon outside the embedded subset raisesdirective.octicon_unknownand the dropdown renders icon-less.A card or dropdown title is parsed as reStructuredText, on both host formats — so an
:octicon:role in agrid-item-cardtitle renders as an icon. Abutton-linkwith no content falls back to showing its URL verbatim; abutton-refwith no content shows the resolved title of its target, as in a sphinx-design build.A button’s content is inline-only. It becomes the link text, and a link may only contain inline markup, so a single wrapping paragraph is unwrapped. Block content (a list, an admonition, a nested directive) produces invalid nesting — sphinx-design has the same limitation, since it inline-parses the content lines. Keep button content to one line of inline markup.
A link’s text has no wrapping
<span>. sphinx-design wraps a button’s and a card link’s text in one because docutils requires a reference to hold an element child; no stylesheet rule targets it, so ubCode emits the text directly.A component container carries no trailing
docutilsclass. docutils’ writer appends that token to every container it writes; no sphinx-design selector uses it, so it is not reproduced. For the same reason thesd-card-textclass is not stamped onto a card’s or dropdown’s body paragraphs — the ubCode stylesheet reproduces its one effect with a.sd-card-body > p:last-childrule instead.``:img-background:`` is ignored (with a warning), and
card-carousel,article-info, the badge roles and the tab directives are not implemented — they still show the generic placeholder.
Needs and variants¶
Need directives render as need cards. How a card looks compared with a Sphinx-Needs build:
A hydrated card lists the fields you authored plus any added by
needextend— not the full set of config-default fields a Sphinx-Needs build can show in layouts that list every field.Cards and their links refresh after each background indexing pass completes — a bounded refresh, not one per keystroke.
A falsy
.. if::block stays visible but collapsed and greyed out, labelled with its condition; a Sphinx-Needs build omits the block entirely.A need referenced only inside a non-indexed include fragment (for example an extensionless or excluded file) keeps its placeholder chip, because the background index does not look inside such fragments.
A
needlistwith no:sort_by:lists its needs in id order; a Sphinx-Needs build lists them in document order. ubCode sorts by id so the output is reproducible build-to-build — the incremental index has no stable document-processing order to preserve. Giving:sort_by:a field name orders by that field in both.:need_count:counts needs only; a Sphinx-Needs build counts needs and their parts in the filtered case. (The plain total counts needs in both.) In particular, a count filtered on theis_partcontext constant renders 0 (need parts are not modelled), where a Sphinx-Needs build counts the parts.A
needtableand aneedlistcap their rendered rows/items at 100 by default and append an honest “Showing the first 100 of N needs” notice when the cap bites; a Sphinx-Needs build renders every matched need. The cap keeps an unfiltered view on a large project from dominating render (and live-preview) times. Set:max_items: 0for no cap, or:max_items: Nfor a specific limit; the cap applies after the filter and the sort.A
needtablerenders as a static table inside a scroll frame with a sticky header row, whatever its:style:(DATATABLES, the Sphinx-Needs default, renders the same static table). Interactive client-side sorting, filtering, and pagination are a planned enhancement; the scroll frame and sticky header are the interim.A
needtablewith no:sort:sorts by id (case-insensitively), matching a Sphinx-Needs build’s default; where two needs would tie on the sort key, ubCode breaks the tie by id rather than by document order (the same reproducibility reason asneedlistabove). The:columns:and:sort:options accept the same names as Sphinx-Needs; an unknown name raises a warning with a “did you mean” suggestion and renders an empty column (:columns:) or falls back to id order (:sort:).
See also
RST preview for how need cards hydrate, Variants for the variant authoring constructs, and the if directive for variant conditions.
Diagrams¶
Mermaid and PlantUML diagram directives render, with a few option differences:
:width:and:height:size the diagram container in the preview (a bare number is treated as pixels). A Sphinx build drops these options for Mermaid diagrams.:alt:,:scale:,:config:,:title:, and:zoom:are parsed but not applied.Caption text is rendered as plain text; inline markup inside a caption is not parsed.
Tables¶
.. tabularcolumns:: is a LaTeX-only marker and correctly renders nothing,
matching an HTML sphinx-build.
Code blocks¶
code-block (with its aliases sourcecode and code), :: literal blocks,
literalinclude and .. highlight:: render with syntax highlighting,
with a few differences from a Sphinx build:
The preview highlights client-side with a bundled set of common languages, not Pygments — colours differ from your Sphinx theme, and a language Pygments knows but the preview does not is shown as plain preformatted text (never mangled).
The bundled set includes
rst/restructuredtext,myst, andcypher, highlighted with community grammars rather than Pygments lexers, so token boundaries can differ slightly from a Sphinx build.:linenos:,:lineno-start:, and:emphasize-lines:are parsed but not applied — no line numbers or emphasised lines yet. The same holds forliteralinclude, which also has:lineno-match:.:dedent:and:force:are parsed but not applied on a code block. (literalincludedoes apply:dedent:— it selects content there, rather than only re-indenting a block you already wrote.):caption:text is rendered as plain text above the block; inline markup inside a caption is not parsed (as for diagram captions above).An argument-less
code-block(or a plain::block) with no.. highlight::language and no configuredhighlight_languagestays unhighlighted; a Sphinx build falls back to highlighting it as Python (itsdefault).
Substitutions¶
|name| substitution references expand in the preview:
your own .. |name| replace:: definitions,
and the Sphinx specials |version|, |release|, and |today|
(fed by the version, release, today, and today_fmt keys
of the [project] table in ubproject.toml).
A few differences from a Sphinx build remain:
An undefined or circular substitution keeps its literal
|name|chip and raises a diagnostic; a Sphinx build reports these as errors in the build log instead.Definitions whose expansion would grow without bound are cut off with an oversized diagnostic — a guard with no Sphinx equivalent (a Sphinx build can take unboundedly long on such input).
Structure and inline detail¶
Some finer points of block and inline rendering differ from a Sphinx build:
Directive titles and arguments are not inline-parsed: markup in an admonition title, a version-marker line, or
centeredappears literally.The body of
parsed-literalshows inline markup literally.Nested line blocks render flattened rather than progressively indented.
.. container:: insand.. container:: delrender as plain containers — insertion and deletion semantics are not applied.Attribution lines (
-- author) inepigraph,highlights, andpull-quotestay plain paragraphs rather than becoming attributions.An unsupported option on a structural block makes the whole directive fall back to the generic placeholder.
Unknown directives and roles¶
- Unknown directives
You write a directive ubCode does not recognise, such as
.. wibble::.The preview shows a generic directive placeholder.
A Sphinx build reports an error and typically drops or marks the construct.
Status — unknown directives also raise a configurable lint diagnostic. Register the directive with
extend_directives, or silence it withignore_directives, in your parsing configuration; see Linting.- Unknown roles
You write text marked up with an inline role ubCode does not recognise, such as a
:wibble:role.The preview shows a placeholder chip naming the role and its content.
A Sphinx build reports an error and typically drops or marks the construct.
Status — the chip is self-describing, so you can spot the unrecognised role at a glance.
ubCode-only view filters¶
The needlist view directive accepts a ubCode-only :cypher: option —
a read-only Cypher selection
(a bare WHERE-style expression such as n.status = 'open',
or a full single-node-column query MATCH (n) ... RETURN n) —
in place of the portable python filter surfaces.
You write a
needlistwith a:cypher:option.The preview shows the needs the Cypher query selects, exactly as a
:filter:selection would.A Sphinx build reports an error: Sphinx-Needs has no
:cypher:option, so the unknown option is a directive error.Status —
:cypher:is a deliberate ubCode extension; Sphinx-Needs will not gain it, and the interoperability cost is accepted. It is mutually exclusive with the python filter surfaces (:filter:/:status:/:tags:/:types:); combining them raises aneeds.filter_conflictwarning and the Cypher selection wins.
Filter expression syntax¶
ubCode evaluates :filter: options and :need_count: targets with its own
filter engine, which accepts the whole portable subset Sphinx-Needs documents
(comparisons in either operand order, in / not in, is None,
and / or / not, var.* variant fields, search(), and a bare
True / False).
A few forms Sphinx-Needs accepts are deliberately not accepted here;
each raises a needs.filter_invalid warning (with the source column) and
renders an empty result, and each has a workaround.
Raw-string prefix¶
You write a filter using a raw-string regex, such as
search(r"[\w\s]+", title).A Sphinx build accepts it (Python treats
r"..."and"..."alike).Status — drop the
rprefix and writesearch("[\w\s]+", title). Regex escapes that are not also Python string escapes —\w,\d,\s— are preserved in an ordinary string, so the pattern is unchanged. But\b(word boundary),\nand\tdo change meaning without therprefix (Python reads them as backspace, newline, tab): keep those as an explicit character class or double the backslash (\\b). Note also thatsearch()patterns must be valid for ubCode’s regex engine, which does not support lookaround ((?=...),(?<=...)) or backreferences (\1) — such patterns raiseneeds.filter_invalid.
Tuple or set containers¶
You write a membership test against a tuple or set literal, such as
id in ("a", "b")orid in {"a", "b"}.A Sphinx build accepts the tuple/set form.
Status — use a list literal instead:
id in ["a", "b"].
Ordering comparisons against non-numbers¶
You write an ordering comparison (
</<=/>/>=) whose other operand is a string, boolean orNone— in either operand order, such asdeadline < "2024-06-01"or"beta" < status.A Sphinx build accepts it: Python applies the operator to the values at runtime, and only raises if the types are not orderable.
Status — the ordering operators support numeric literals only (
priority > 3,5 <= level); equality (==/!=) and membership (in) work for strings. Use a numeric field for ordering. Date-string ordering has no direct portable equivalent — model the date as a sortable numeric field, or select with equality /in.
Unrecognised function calls¶
You write a filter calling a function other than the recognised helpers, such as
bool(arch).A Sphinx build accepts it (its
evalhas the Python builtins available).Status — the only calls the engine recognises are
search(),len(),.lower(),.upper(),.startswith()and.endswith(). Forbool(arch), write the bare fieldarch— truthiness is supported (0,""and[]are falsy, as in Python).
Images¶
A local image whose file lives outside your workspace folder does not load in the preview; the preview can only read files within the workspace.
Remote images referenced by an
https://URL load directly.
Closing the gap¶
The preview grows release by release:
ubCode actively closes the gap with Sphinx and Sphinx-Needs —
substitutions and toctree rendering moved off this page’s
“not yet rendered” list recently —
and the constructs still shown as placeholders,
math and resolved footnotes,
are tracked on the Roadmap.
When you need the final, fully-transformed output, run a full sphinx-build.