Template analysis
Discovery, analysis, source mapping, and formatting for Python-embedded templates.
LspPosition class
A zero-based line and UTF-16 character position used by LSP clients.
Attributes
LspRange class
A half-open LSP range in a source document.
Attributes
startLspPosition- Inclusive start position.endLspPosition- Exclusive end position.
PythonComponentAssetDiscovery class
Conservative direct literal and static file component assets.
PythonComponentAssetFile class
One statically proven direct component asset-file declaration.
PythonComponentAssetFormatResult class
One validated, atomic Python component-asset formatting result.
Attributes
sourcestr- Complete formatted Python source.changed_component_assetstuple[tuple[str, PythonComponentAssetKind], ...]- Changed(component_name, kind)pairs.noticestuple[PythonComponentAssetNotice, ...]- Assets left unchanged with an explicit reason.providerstuple[str, ...]- Sorted provider identities reported by accepted results.
changed_component_assets attribute
changed_component_assets: tuple[tuple[str, PythonComponentAssetKind], ...] PythonComponentAssetNotice class
A component-specific reason why one asset was skipped or unchanged.
PythonComponentAssetPlan class
An immutable Python-source plan awaiting JavaScript and CSS providers.
A plan is bound to the complete source passed to prepare_python_component_assets. Provider work may happen asynchronously before the caller passes every reply to finish_python_component_assets.
Attributes
idstr- Stable source and selection identity echoed by provider results.sourcestr- Complete original Python source.requeststuple[PythonComponentAssetRequest, ...]- Standalone JavaScript and CSS provider requests.noticestuple[PythonComponentAssetNotice, ...]- Non-fatal embedded regions that could not be delegated.
PythonComponentAssetRegion class
One definite direct literal asset on a Citry component class.
Attributes
component_namestr- Name of the declaring component class.kindPythonComponentAssetKind- Component attribute represented by this region.source_mapPythonTemplateSourceMap- Mapping between the decoded asset and its Python literal.
PythonComponentAssetRequest class
One standalone JavaScript or CSS document offered to a provider.
Attributes
plan_idstr- Identity of the source-bound Python formatting plan.idstr- Identity of this request within the plan.component_namestr- Name of the declaring component class.asset_kindPythonComponentAssetKind- Component asset containing this provider region.languageEmbeddedLanguage- Standalone language expected by the provider.region_kindEmbeddedRegionKind | None- Template body kind, orNonefor a directjsorcssliteral.sourcestr- Decoded provider-owned source.virtual_sourcestr- Standalone source to send to the provider.
PythonTemplateDiscovery class
Conservative inline template regions and non-parser notices.
PythonTemplateFormatError class
Bases: ValueError
A formatting refusal that never exposes a partial Python candidate.
Attributes
codestr- Stable formatter failure code.noticestuple[PythonTemplateNotice, ...]- Component-specific reasons relevant to the refusal.rangetuple[int, int] | None- Optional absolute half-open Python string-offset range.diagnosticobject | None- Optional nested parser diagnostic. Template parser diagnostic offsets remain relative to the decoded template.
PythonTemplateFormatResult class
One validated, atomic Python template-formatting result.
PythonTemplateNotice class
One definite component template skipped for an explicit reason.
PythonTemplateRegion class
One definite direct literal template on a Citry component class.
PythonTemplateSourceMap class
Map Citry parser byte ranges back into an authored Python document.
The map decodes plain, raw, and Unicode string literals, including implicit literal concatenation. Parser indices address the decoded template as UTF-8 bytes. Returned positions address the Python document with the zero-based UTF-16 coordinates required by LSP.
Build a map with from_ast for valid Python or from_coordinates for a literal region found by a conservative lexical scanner.
Attributes
template_sourcestr- Decoded, common-indent-normalized Citry template text passed to the parser.
from_ast function
from_ast(host_source: str, node: Constant) -> PythonTemplateSourceMapBuild a map for a string-valued Python AST constant.
Python AST columns are interpreted as zero-based UTF-8 byte offsets, matching CPython's contract. Adjacent literals represented by the same constant are decoded as one template.
Parameters
host_sourcestr- Complete Python document text.nodeConstant- A string-valuedast.Constantfromhost_source.
Returns
PythonTemplateSourceMap: A source map whose ``template_source`` is the normalized inline
Raises
TypeError- Ifnodeis not a string-valuedast.Constant.ValueError- If source positions are missing or the authored text does not decode tonode.value.
from_coordinates function
from_coordinates(host_source: str, lineno: int, col_offset: int, end_lineno: int | None = None, end_col_offset: int | None = None, accept_incomplete: bool = False) -> PythonTemplateSourceMapBuild a map from Python parser coordinates around a literal expression.
Supply both end coordinates for complete source. A conservative lexical scanner may omit them and set accept_incomplete=True for an unfinished final triple-quoted literal, in which case the document end is the temporary content boundary.
Parameters
host_sourcestr- Complete Python document text.linenoint- 1-based line containing the first literal prefix or quote.col_offsetint- Zero-based UTF-8 byte column of that prefix or quote.end_linenoint | None- 1-based line immediately after the expression.end_col_offsetint | None- Zero-based UTF-8 byte column immediately after the expression.accept_incompletebool- Accept an unfinished final triple-quoted literal and map its content through the end of the document.
Returns
PythonTemplateSourceMap: A map for the decoded string expression.
Raises
ValueError- If coordinates, literal syntax, or escape syntax are invalid or unsupported.
map_range function
Convert one half-open parser byte range to Python-document coordinates.
Parameters
start_indexint- Inclusive UTF-8 byte offset intemplate_source.end_indexint- Exclusive UTF-8 byte offset intemplate_source.
Returns
LspRange: The corresponding zero-based LSP range in the Python document.
Raises
ValueError- If the range is reversed, outside the template, or splits a UTF-8 code point.
range_is_unambiguous function
Return whether a parser range stays inside one authored literal body.
Normalized indentation and Python escapes remain mappable inside one literal. Crossing an implicit-concatenation boundary is ambiguous for editor edits and semantic result ranges.
Parameters
start_indexint- Inclusive UTF-8 byte offset intemplate_source.end_indexint- Exclusive UTF-8 byte offset intemplate_source.
Returns
bool: ``True`` when both boundaries belong to one literal body.
Raises
ValueError- If the range is reversed, outside the template, or splits a UTF-8 code point.
parser_index_at function
parser_index_at(position: LspPosition) -> int | NoneReturn the parser byte boundary at an authored LSP position.
Positions in quotes, prefixes, comments between concatenated literals, or other Python outside the decoded template return None. A position inside an authored escape maps to the byte boundary after the decoded character.
TemplateAnalysis class
A complete, immutable snapshot of one Citry component registry.
Attributes
component_namesfrozenset[str]- Normalized registered names without thec-tag prefix. The set includes aliases and built-in component names.lintTemplateLintInfo- Application lint settings and known global variables.component_lintMapping[str, TemplateLintInfo]- Effective lint settings and known variables keyed by stable component definition ID.
parse_template function
parse_template(source: str) -> TemplateParse authored Citry source with this registry's component contracts.
The parser checks registered component inputs and slots. Extension transforms are not run because they do not currently provide a mapping back to the authored source. Names absent from component_names need a separate unknown-component diagnostic after a successful parse.
Parameters
sourcestr- Authored Citry template source.
Returns
Template: The parsed template AST.
Raises
SyntaxError- If syntax or a registered component contract is invalid.ValueError- If parser configuration is invalid.
from_dict function
from_dict(value: object) -> TemplateAnalysisRebuild a snapshot from :meth:to_dict portable data.
TemplateLintConsumer class
Describe one proven component namespace used by a physical template.
Attributes
known_namesfrozenset[str]- Root names available to this component's template.namespace_policyLiteral['closed', 'allow-extra', 'unknown']- Whether those names exhaust normalized template data.rule_unknown_template_variableLiteral['ignore', 'warning', 'error']- Configured severity for undeclared free roots.
namespace_policy attribute
namespace_policy: Literal['closed', 'allow-extra', 'unknown'] rule_unknown_template_variable attribute
rule_unknown_template_variable: Literal['ignore', 'warning', 'error'] TemplateLintFinding class
Report one parser-proven free root missing from a known namespace.
TemplateLintInfo class
Carry one component's effective lint rule and known global variables.
rule_unknown_component_js_variable attribute
rule_unknown_component_js_variable: LintSeverity from_dict function
from_dict(value: object) -> TemplateLintInfoValidate and restore one detached lint record.
TemplateVariableInfo class
Describe one known template variable using detached portable text.
from_dict function
from_dict(value: object) -> TemplateVariableInfoValidate and restore one detached variable record.
discover_python_component_assets function
discover_python_component_assets(source: str) -> PythonComponentAssetDiscoveryDiscover direct literal and static file assets on proven components.
Discovery recognizes direct template, js, and css literals, plus constant template_file, js_file, and css_file paths. It never imports the module or evaluates a computed declaration.
Parameters
sourcestr- Complete Python module source.
Returns
PythonComponentAssetDiscovery: Definite inline regions, file declarations, and explicit notices.
Raises
SyntaxError- Ifsourceis not a complete valid Python module.TypeError- Ifsourceis not a string.
discover_python_templates function
discover_python_templates(source: str, recover_incomplete: bool = False) -> PythonTemplateDiscoveryDiscover direct literal templates on provable Citry component classes.
Normal batch tooling leaves recover_incomplete false and receives the original Python SyntaxError. An interactive editor may opt into the narrow recovery of one unfinished direct triple-quoted template literal.
finish_python_component_assets function
finish_python_component_assets(plan: PythonComponentAssetPlan, results: Sequence[EmbeddedFormatResult], require_providers: bool = False) -> PythonComponentAssetFormatResultValidate provider replies and atomically finish one Python source plan.
Every selected literal is rewritten only after every provider reply, Python parse, asset rediscovery, and decoded-value check succeeds. A failure raises without exposing a partial source candidate.
Parameters
planPythonComponentAssetPlan- Exact plan returned byprepare_python_component_assets.resultsSequence[EmbeddedFormatResult]- One source-bound reply for every request inplan.require_providersbool- Reject unavailable providers and embedded regions that could not be delegated.
Returns
PythonComponentAssetFormatResult: The complete formatted Python source and provider metadata.
Raises
PythonTemplateFormatError- If replies are missing, stale, duplicated, unavailable when required, invalid, or unsafe to rewrite.TypeError- Ifplan,results, orrequire_providershas the wrong type.
format_python_component_assets function
format_python_component_assets(source: str, kinds: Collection[PythonComponentAssetKind | str] = tuple(PythonComponentAssetKind), host_offset: int | None = None, provider: Callable[[PythonComponentAssetRequest], EmbeddedFormatResult] | None = None, require_providers: bool = False) -> PythonComponentAssetFormatResultFormat selected direct component assets in one atomic Python-file edit.
This synchronous convenience function prepares a plan, invokes provider once per JavaScript or CSS request, then validates and finishes the plan. Call the two-pass prepare and finish functions directly when provider work must be asynchronous. With no provider, M2 template formatting still runs while JavaScript and CSS requests remain unchanged with notices.
Parameters
sourcestr- Complete Python module source.kindsCollection[PythonComponentAssetKind | str]- Explicittemplate,js, andcsskinds to select.host_offsetint | None- Optional zero-based Python string offset selecting only the containing direct asset.providerCallable[[PythonComponentAssetRequest], EmbeddedFormatResult] | None- Optional synchronous JavaScript/CSS formatting callback.require_providersbool- Reject the complete operation when any selected embedded region has no provider.
Returns
PythonComponentAssetFormatResult: The validated complete source, changed asset identities, notices, and
Raises
PythonTemplateFormatError- If discovery, formatting, a provider, or final validation fails. No partial candidate is exposed.TypeError- If an argument or provider reply has the wrong type.ValueError- Ifhost_offsetor a selected kind is invalid.
format_python_templates function
format_python_templates(source: str, host_offset: int | None = None) -> PythonTemplateFormatResultFormat proven direct Citry template literals in complete Python source.
With no offset, every definite inline template is one atomic operation. A host offset selects only the literal content containing that Python string position. The result preserves string prefixes, delimiters, and all host text outside the exact decoded-template rewrite hunks.
Parameters
sourcestr- Complete Python module source.host_offsetint | None- Optional zero-based Python string offset inside one template literal body.
Returns
PythonTemplateFormatResult: The validated source, changed component names, and discovery notices.
Raises
PythonTemplateFormatError- If Python or Citry syntax is invalid, a selected literal is not safely rewriteable, or validation fails.TypeError- Ifsourceorhost_offsethas the wrong type.ValueError- Ifhost_offsetis outsidesource.
prepare_python_component_assets function
prepare_python_component_assets(source: str, kinds: Collection[PythonComponentAssetKind | str] = tuple(PythonComponentAssetKind), host_offset: int | None = None) -> PythonComponentAssetPlanPrepare one atomic Python component-asset formatting operation.
Templates first receive Citry structure and Python-expression formatting. Safe script and style bodies, plus direct js and css literals, become standalone provider requests. The returned plan makes no source edit, so callers may resolve those requests asynchronously.
Parameters
sourcestr- Complete Python module source.kindsCollection[PythonComponentAssetKind | str]- Explicit component asset kinds selected for this operation.host_offsetint | None- Optional zero-based Python string offset. When supplied, only the containing selected direct asset is prepared.
Returns
PythonComponentAssetPlan: A source-bound plan and its provider requests.
Raises
PythonTemplateFormatError- If Python or selected asset syntax is invalid, or a selected literal cannot be rewritten safely.TypeError- If an argument has the wrong type.ValueError- Ifhost_offsetis outsidesourceor a kind is unknown.
lint_unknown_template_variables function
lint_unknown_template_variables(template: object, consumers: Sequence[TemplateLintConsumer]) -> tuple[TemplateLintFinding, ...]Diagnose free roots missing from at least one proven component namespace.
Parameters
templateobject- Parsed Citry template AST. Its parser-reported free variables already exclude lexical and Python-local bindings.consumersSequence[TemplateLintConsumer]- Every proven component that consumes this physical template.
Returns
TemplateLintFinding: Findings in the parser's stable free-variable order. No consumer means
Raises
TypeError- If the parsed object lacks Citry free-variable records.