API#
Every entry links to its source with [source].
Interfaces#
- class handcalcs.HandCalcs(renderer=None)[source]#
- __call__(source_or_path, supplied_globals=None, supplied_locals=None, *, inputs=None, strict=True, allow_computed=False, destination=None)[source]#
Renders ‘source_or_path’ and returns what the renderer produces: a str for the text renderers, a document or workbook for the Word and Excel renderers.
If ‘destination’ is given, the render is written to that file instead (with the renderer’s ‘to_file’: a complete LaTeX or HTML document, or the saved .docx or .xlsx) and its path is returned as a pathlib.Path.
If ‘supplied_globals’ and ‘supplied_locals’ are each None, then the source code will be executed to create the globals and locals dicts. If either dictionary are supplied, code execution will not occur. Empty dictionaries are acceptable but will produce numerical substitutions of ‘NoValue()’.
‘inputs’ maps names to values that replace the values the source assigns them (see handcalcs.parsing.inputs.bind_inputs, which also describes ‘strict’ and ‘allow_computed’); the source is then executed with them. A number replaces only the number of a value with units, so ‘L = 6 * m’ with inputs={“L”: 8} renders and runs as ‘L = 8 * m’. A quantity is converted to the units of such a line, so with inputs={“L”: 8000 * mm} it runs and renders as ‘L = 8 * m’ too. Other objects (arrays, quantities on a line without units) are used as they are.
- demo(destination=None)[source]#
Renders the demo with the current renderer; with ‘destination’, writes it to that file and returns the path, as calling the object does.
A renderer that cannot render the general demo (e.g. the ExcelRenderer, which has no worksheet form for loops or collections) provides its own source as a
demo_sourceattribute, which is used instead.
- handcalcs.handcalc(renderer=None, render_context=None)[source]#
Decorate a calculation function so that a call returns
(return_value, rendered). Without a renderer, thedefault_rendereroption’s is used (the ASCIIRenderer unless set). Usable as@handcalc(renderer),@handcalc()or@handcalc.- Parameters:
renderer (BaseRenderer | None)
render_context (dict | None)
- handcalcs.find_inputs(source_or_path)[source]#
The candidate inputs of a script: each name whose first top-level assignment is a literal or a number times units, with its value in the script (only the number, for a number times units). The result is a template for
inputs.
The Jupyter magics (%%render, %hc_default_renderer, %hc_format_code) are described
in the Jupyter interface.
Configuration#
- handcalcs.set_option(option, value)[source]#
Set the value of
optiontovaluein the global configuration.This affects the in-memory configuration only; call
save_configto make the change permanent. Base options are type-checked; any other option name is accepted with any value, so custom renderers can store their own settings.- The following base options are recognised (arbitrary extra options may also be set for use by custom renderers):
default_renderer: str (default = ‘ascii’) jupyter_renderer: str (default = ‘markdown’) format_code: str (default = ‘.5g’) line_values: bool (default = True)
- handcalcs.get_option(option, default=None)[source]#
Return the value of
optionin the current configuration.
- handcalcs.reset_option(option)[source]#
Reset
optionto its built-in default, or remove it if it is a custom field.This affects the in-memory configuration only; call
save_configto persist.- Parameters:
option (str)
- Return type:
None
- handcalcs.reset_config()[source]#
Reset the entire in-memory configuration to the built-in defaults.
- Return type:
None
Renderers#
- handcalcs.renderers.get_renderer(name)[source]#
Return the renderer class registered under ‘name’, or None if no renderer with that name has been defined/imported.
- Parameters:
name (str)
- Return type:
type[BaseRenderer] | None
- class handcalcs.renderers.BaseRenderer[source]#
- render(node, base_context=None)[source]#
Render a node.
If ‘context’ is None, a new context is created.
- Parameters:
node (HcNode)
base_context (BaseRenderContext | None)
- Return type:
- render_root(root, base_context)[source]#
Render an HcSequence (root node) into the master list.
The sequence-level pre/post renderers are registered against the pseudo node type ‘root’ (i.e. ‘root:pre’ and ‘root:post’); they run before and after the sequence body and contribute leading/trailing items.
- Parameters:
root (HcSequence)
base_context (BaseRenderContext)
- Return type:
- complete(tree, base_context)[source]#
A function called at the completion of every render. This function is intended to be over-ridden by individual renderers in order to “complete” the rendering.
The BaseRenderer that all renderers inherit from includes a special “.join” method with the same function signature as this one. For many renderers that return a str, calling the .join() method will be sufficient as the implementation for this function.
- Parameters:
tree (list)
base_context (BaseRenderContext)
- Return type:
- to_file(rendered, path)[source]#
Write
rendered, the result ofcomplete(), to the file atpathand return the path. Text is written as UTF-8 betweenpreambleandpostamble. A renderer whosecomplete()returns another kind of object (a workbook, a document) overrides this to save it.
- join(tree, base_context=None)[source]#
Join a rendered nested-list structure into final text.
This is the post-render pass that inserts the spacing, indentation and newlines that the node handlers deliberately leave out:
a string item is a whole line (heading, comment, block header);
an all-string list is a rendered line whose components are joined by a single space;
a
[header_string, body_list]list is a block: the header is a line at the current depth and the body lines are rendered one level deeper.
Falsy items (
None,"",[]) render nothing (they are command/ignored lines), so they never produce a stray blank line.base_contextis optional: callers that just want text from a tree (tests,demo()post-processing) can omit it and get a default context.- Parameters:
tree (list)
base_context (BaseRenderContext | None)
- Return type:
- render_node(node, base_context)[source]#
Render one node with an existing context.
Rules registered against this node type run in category order: ‘pre’ (always), then ‘sym’ or ‘num’ gated on
context.current_mode, then the node handler, then ‘post’ on the rendered result. Multiple rules in a category run in registration order.- Parameters:
node (HcNode)
base_context (BaseRenderContext)
- Return type:
- render_header(node, base_context)[source]#
Render the introductory/context-establishing header line for a block node.
Dispatches to the handler registered under ‘header:{node.type}’. Block nodes with no registered header handler render no header (empty string), letting a renderer opt in per block type.
- Parameters:
node (HcNode)
base_context (BaseRenderContext)
- Return type:
- classmethod register(node_classifier)[source]#
Register a render handler (or a pre/sym/num/post/header rule) for a given node classifier, at the class level. See
_route_registration.
- register_handler(node_classifier, handler)[source]#
Instance-scoped counterpart of
register. See_route_registration.
- format_param_grid(rows, base_context)[source]#
Format a params grid (
rowsof cells, each cell already rendered to a list of components like["f", "=", "1"], orNonefor padding) into the final text block.The base implementation is plain-text oriented: cell components are joined by the context space, columns are left-justified to a shared per-column width, columns are separated by a gap and rows by the context newline. Renderers that emit tabular markup (LaTeX array, HTML table) override this.
- Parameters:
rows (list)
base_context (BaseRenderContext)
- Return type:
- format_calc_grid(rows, base_context)[source]#
Format a multi-line (“long”) calc.
rowsare[id, eq, value]triples: the first carries the assignment target, the rest an empty id so every row aligns oneq. A row with an emptyeqcontinues the value of the row above (a line continuation in the source) and is indented byCONTINUATION_INDENT.The base implementation is plain-text oriented: the id column is padded to a common width so the
=signs line up, and rows are joined by the context newline. Renderers that emit tabular markup (HTML table, LaTeX aligned) override this.- Parameters:
rows (list)
base_context (BaseRenderContext)
- Return type:
- class handcalcs.renderers.ASCIIRenderer[source]#
Renders a calculation as monospaced text for terminals, logs and docstrings.
Headings are underlined in the setext/reStructuredText style and set off by blank lines. Calc lines are aligned on their first
=: the left-hand sides are right-aligned to the widest one between two headings.- complete(tree, base_context)[source]#
A function called at the completion of every render. This function is intended to be over-ridden by individual renderers in order to “complete” the rendering.
The BaseRenderer that all renderers inherit from includes a special “.join” method with the same function signature as this one. For many renderers that return a str, calling the .join() method will be sufficient as the implementation for this function.
- Parameters:
tree (list)
base_context (BaseRenderContext)
- Return type:
- class handcalcs.renderers.LatexRenderer[source]#
Renders a HandCalcs sequence as a LaTeX fragment (requires amsmath) that can be pasted into the body of a .tex document.
Prose (headings, comment paragraphs, imports, block headers) is emitted as text-mode paragraphs. Each run of calc lines (a CalcsBlock) becomes one flush-left display-style
alignedgroup, aligned on the first=of every row. The body of a nested block (if/for/def) is indented with alistenvironment.The class attributes below are the structural tokens; override them in a subclass to change the document wrappers.
- complete(tree, base_context)[source]#
A function called at the completion of every render. This function is intended to be over-ridden by individual renderers in order to “complete” the rendering.
The BaseRenderer that all renderers inherit from includes a special “.join” method with the same function signature as this one. For many renderers that return a str, calling the .join() method will be sufficient as the implementation for this function.
- Parameters:
tree (list)
base_context (BaseRenderContext)
- join_item(item, depth, base_context)[source]#
LaTeX counterpart of
BaseRenderer.join_item. Master-list shapes:bare string -> a text paragraph (headings, the params grid, which is already a complete math group); a one-shot line break ->
\medskip;headerless block whose body is opened by MATH_OPEN (a CalcsBlock) -> one
alignedmath group, rows separated by\\, no group at all when every row is empty (e.g. all lines# hc: -i);other headerless block (a CommentsBlock) -> its body at this level;
[header, body]-> the header paragraph, then the body indented in alistenvironment;all-string list -> a text paragraph whose parts join with a space.
- Parameters:
depth (int)
base_context (BaseRenderContext)
- Return type:
- paragraph(text)[source]#
Prefix a text paragraph with PARAGRAPH (
\noindent) unless it is already a complete structural command (a heading or a math group).
- join_math_group(rows, depth, base_context)[source]#
Join the rows of a CalcsBlock into a single
alignedmath group.- Parameters:
rows (list)
depth (int)
base_context (BaseRenderContext)
- Return type:
- math_group(rows)[source]#
Wrap pre-joined
alignedrows in MATH_OPEN/MATH_CLOSE, with MATH_SKIP paragraphs before and after.
- join_math_row(row, base_context)[source]#
Join one calc line’s components into an
alignedrow, placing the alignment point&before its first assignment symbol. A string row (a pre-formatted multiline grid, or a one-shot line break) passes through unchanged; a line break is dropped since rows are already separated.The inline comment of a calc line that shows substitution columns (more than
target = value) moves to its own row, at the alignment point, so it does not lengthen an already long row.- Parameters:
base_context (BaseRenderContext)
- Return type:
- format_param_grid(rows, base_context)[source]#
A params grid is its own
alignedgroup, laid out like the v1 params cell: eachid = value [comment]cell is anr lcolumn pair and cells are joined by a bare&. As in v1, a thin\;after each value is the gap between cells. In a grid with comments, a comment sits one\;after its value (its leading\quadis dropped) and every non-last cell is followed by a\qquad, so the gap to the next assignment is wider than the gap inside a cell, whether or not that cell has a comment.- Parameters:
rows (list)
base_context (BaseRenderContext)
- Return type:
- format_calc_grid(rows, base_context)[source]#
A multiline (
# hc: -m) calc: onealignedrow per[id, eq, value]triple, all aligned oneq. Returned as a single pre-joined string that sits as one row inside its CalcsBlock’s math group.A row with an empty
eqcontinues the row above (a line continuation in the source) and is indented byCONTINUATION_INDENT. An empty group{}closes the row before it and opens the continuation, so an operator at the break keeps its binary spacing.- Parameters:
rows (list)
base_context (BaseRenderContext)
- Return type:
- class handcalcs.renderers.MarkdownRenderer[source]#
Renders a HandCalcs sequence as Markdown prose with LaTeX math, for Jupyter-type front-ends that typeset
$...$/$$...$$with MathJax or KaTeX.It is the default renderer of the
%%rendercell magic (thejupyter_rendererconfig option); its output is shown withIPython.display.Markdown.Math is inherited from LatexRenderer, with a few changes for MathJax and KaTeX: comparisons use
\lt/\gt, and text inside math (inline comments, strings) goes throughmath_text. The text-mode structure is replaced:headings are
#headings, comment lines are plain paragraphs and imports are code spans, all Markdown-escaped (markdown_prose);each calc group is one
$$\begin{aligned} ... \end{aligned}$$on a single physical line, with\\between the rows;a
# hc: -bline break is an spacer paragraph;the body of an if/for/def block is a blockquote, with one
>per nesting level. Blank lines inside a body are quoted too, and every quote ends with an unquoted blank line, so Markdown’s lazy continuation never pulls the following text into a deeper quote (seequote).
See
markdown_renderer_plan.mdfor the reasoning behind each rule.- join_item(item, depth, base_context)[source]#
As
LatexRenderer.join_item, except that:the body of a
[header, body]block is a blockquote (seequote) rather than alistenvironment;an all-string line made of complete math groups (consecutive params grids in a block body arrive this way) emits each group as its own paragraph, since two
$$groups cannot share a line.
- Parameters:
depth (int)
base_context (BaseRenderContext)
- Return type:
- quote(chunks)[source]#
Quote a joined block body: every line gets one BLOCK_PREFIX, so a block nested in a quoted body ends up quoted twice. Blank lines between the body’s paragraphs are quoted too (a bare
>), which keeps the quote continuous and stops a> textline after a> > textline from being absorbed into the inner quote by lazy continuation. The quote ends with an unquoted blank line, so the following text is not absorbed either.
- class handcalcs.renderers.HTMLRenderer(theme_color='#0B5F66')[source]#
Renders a calculation as a self-contained HTML fragment for Jupyter, VS Code or any web page.
Fonts, text colour and headings are left to the host page. On top of that, one theme colour (
theme_color, default petrol#0B5F66) gives the calculation a quiet visual structure: each result is highlighted, inline comments are muted, imports sit in small code chips, block headers (Since ... is True:,Iterating over ...) are tinted callouts, params grids sit on a tinted panel, multi-line calcs carry an accent bar, and nested block bodies get coloured indent guides. Backgrounds are translucent tints of the theme, so they work on light and dark pages alike.Every colour is a CSS custom property on
.handcalcs(--hc-accent,--hc-guide-1to--hc-guide-3,--hc-tint,--hc-muted, …), so a host stylesheet can restyle the output without changing the renderer.- Parameters:
theme_color (str)
- complete(tree, base_context)[source]#
A function called at the completion of every render. This function is intended to be over-ridden by individual renderers in order to “complete” the rendering.
The BaseRenderer that all renderers inherit from includes a special “.join” method with the same function signature as this one. For many renderers that return a str, calling the .join() method will be sufficient as the implementation for this function.
- Parameters:
tree (list)
base_context (BaseRenderContext)
- Return type:
- format_param_grid(rows, base_context)[source]#
Format a params grid (
rowsof cells, each cell already rendered to a list of components like["f", "=", "1"], orNonefor padding) into the final text block.The base implementation is plain-text oriented: cell components are joined by the context space, columns are left-justified to a shared per-column width, columns are separated by a gap and rows by the context newline. Renderers that emit tabular markup (LaTeX array, HTML table) override this.
- Parameters:
rows (list)
base_context (BaseRenderContext)
- Return type:
- format_calc_grid(rows, base_context)[source]#
Format a multi-line (“long”) calc.
rowsare[id, eq, value]triples: the first carries the assignment target, the rest an empty id so every row aligns oneq. A row with an emptyeqcontinues the value of the row above (a line continuation in the source) and is indented byCONTINUATION_INDENT.The base implementation is plain-text oriented: the id column is padded to a common width so the
=signs line up, and rows are joined by the context newline. Renderers that emit tabular markup (HTML table, LaTeX aligned) override this.- Parameters:
rows (list)
base_context (BaseRenderContext)
- Return type:
- class handcalcs.renderers.ExcelRenderer(sheet_name='Calculations', value_format=None, formula_format=None, filepath=None, general_format='General')[source]#
Renders a HandCalcs sequence as a live, formula-based Excel worksheet.
Every calculation becomes a real Excel formula that references other rows through worksheet-scoped defined names, so editing an input in Excel recalculates the sheet.
Options (all validated here, at instantiation):
sheet_name: the worksheet name (Excel’s naming rules apply).value_format/formula_format: how the value column (E) is styled; see “Cell formats” below.filepath: if given,complete()also saves the workbook there.general_format: the Excel number format used for format codes that have no exact Excel equivalent (e.g. the default.5g).
Cell formats#
value_formatandformula_formatstyle the two kinds of cell in the value column, so a reader can tell at a glance which cells to edit:value_formatstyles input cells: literal assignments such asa = 2orL = 300*mm. These hold plain numbers and are the cells a user edits.formula_formatstyles formula cells: every calculation such asx = (-b + sqrt(b**2 - 4*a*c)) / (2*a). A calculation forced into the input layout with# hc: -pstill holds a formula, so it also takesformula_format.
Both are dicts with any of these keys:
"bold":TrueorFalse."text_color": the font colour."cell_color": the cell’s fill colour;Nonefor no fill.
A colour is
"#RRGGBB","RRGGBB"or an(r, g, b)tuple of ints from 0 to 255. Every key is optional: the keys you give are merged over the defaults, and the keys you leave out keep their default. The defaults are:value_format = {"bold": False, "text_color": "#000000", "cell_color": "#FFF2CC"} formula_format = {"bold": True, "text_color": "#000000", "cell_color": None}
That is, inputs sit on a light-yellow fill (the common engineering convention for “edit me”) and formulas are bold with no fill. An unknown key, a non-bool
"bold"or a malformed colour raisesValueErrorwhen the renderer is created. The merged result is available as thevalue_formatandformula_formatattributes.Examples:
from handcalcs import HandCalcs from handcalcs.renderers.excel import ExcelRenderer # Defaults: yellow inputs, bold formulas. renderer = ExcelRenderer() # Blue text, bold text for inputs, keeping the default yellow fill; for renderer = ExcelRenderer(value_format={"text_color": "#0000FF", 'bold': True}) # No fill on inputs; formulas on a light-green fill, not bold. renderer = ExcelRenderer( sheet_name='Calculations', value_format={"cell_color": None}, formula_format={"bold": False, "cell_color": (226, 239, 218)}, filepath='my_calc_sheet.xlsx' ) # Plain sheet: no highlighting at all. renderer = ExcelRenderer( value_format={"cell_color": None}, formula_format={"bold": False}, ) workbook = HandCalcs(renderer=renderer)(source) workbook.save("calcs.xlsx")
functionsmaps Python callables toformulas.ExcelFunctiontranslations; extend a renderer’s copy to support more functions.- render_root(root, base_context)[source]#
Render every statement into one flat list of rows.
- Parameters:
base_context (BaseRenderContext)
- Return type:
list[CalcRow | ParamRow | HeadingRow | CommentRow | BlankRow | PageBreakRow]
- complete(tree, base_context)[source]#
Lay the rows out as a one-sheet workbook; save it if
filepathis set.- Parameters:
tree (list[CalcRow | ParamRow | HeadingRow | CommentRow | BlankRow | PageBreakRow])
base_context (BaseRenderContext)
- Return type:
ExcelWorkbook
- class handcalcs.renderers.WordRenderer(filepath=None, layout='aligned', template=None, document=None)[source]#
Renders a HandCalcs sequence as a Word document (.docx) whose calculations are native, editable Word equations (Office Math Markup, OMML).
Like the LaTeX renderer, the node handlers return math as strings, here OMML fragments (see
omml), and the base renderer’s line and block machinery works on them unchanged.complete()writes the render tree as a python-docxDocument; python-docx (pip install handcalcs[word]) is imported only then.Options:
filepath: if given,complete()also saves the document there.layout: how a run of calc lines is set out."aligned"(the default) is one equation array per run, aligned on the first=of each row, as in the LaTeX renderer."lines"makes each row an equation of its own with no alignment; use it for Google Docs and LibreOffice, which don’t show Word’s equation arrays. A# hc: layout = "lines"comment changes it for the calcs that follow.template: a .docx to start each new document from (a company template: its styles, page setup and any content it already has).document: a python-docxDocumentto append to instead, so several calcs build one report. Give a template or a document, not both.
The renderer adds two styles when the document doesn’t define them:
HC Mathfor equation paragraphs andHC Codefor imports. Define them in a template to restyle both. Equations take their paragraph’s font size.Examples:
HandCalcs(WordRenderer(filepath="calc.docx"))(source) report = docx.Document("company.docx") calc = HandCalcs(WordRenderer(document=report)) calc(beam_source) calc(column_source) report.save("report.docx")
- Parameters:
filepath (Optional[str | pathlib.Path])
layout (str)
template (Optional[str | pathlib.Path])
document (Any)
- complete(tree, base_context)[source]#
Write the render tree as a Word document and return it; save it if
filepathis set. The calc is appended todocumentif one was given, or else to a new document (fromtemplate, if given).- Parameters:
tree (list)
base_context (BaseRenderContext)
- Return type:
- write_item(writer, item, depth, base_context)[source]#
Word counterpart of
BaseRenderer.join_item. Master-list shapes:a
Heading,CodeorParamsTableitem -> its paragraph or table;a string -> a text paragraph; a one-shot line break -> an empty one;
a headerless block whose body opens with a
MathGroup(a CalcsBlock) -> its equations (seeDocumentWriter.math_group);another headerless block (a CommentsBlock) -> its body at this level;
[header, body]-> the header paragraph, then the body indented one level;a calc row (a list of strings) or a
CalcGridon its own -> its equations; a list of plain strings -> a text paragraph.
- Parameters:
writer (DocumentWriter)
depth (int)
- Return type:
None
- join_math_row(parts, base_context)[source]#
One calc line’s components as an equation row, split before its first assignment symbol (the alignment point). A line with no math (a docstring) is prose; an ignored line is no row.
As in the LaTeX renderer, the inline comment of a line that shows substitution columns (more than
target = value) moves to its own row, at the alignment point, so it does not lengthen a long row.
- format_param_grid(rows, base_context)[source]#
Format a params grid (
rowsof cells, each cell already rendered to a list of components like["f", "=", "1"], orNonefor padding) into the final text block.The base implementation is plain-text oriented: cell components are joined by the context space, columns are left-justified to a shared per-column width, columns are separated by a gap and rows by the context newline. Renderers that emit tabular markup (LaTeX array, HTML table) override this.
- Parameters:
rows (list)
- Return type:
ParamsTable
- format_calc_grid(rows, base_context)[source]#
Format a multi-line (“long”) calc.
rowsare[id, eq, value]triples: the first carries the assignment target, the rest an empty id so every row aligns oneq. A row with an emptyeqcontinues the value of the row above (a line continuation in the source) and is indented byCONTINUATION_INDENT.The base implementation is plain-text oriented: the id column is padded to a common width so the
=signs line up, and rows are joined by the context newline. Renderers that emit tabular markup (HTML table, LaTeX aligned) override this.- Parameters:
rows (list)
- Return type:
CalcGrid
Render context#
- class handcalcs.renderers.base.RenderContext(space=' ', newline='\n', indent=' ', assign='=', mode='full', format_code='.5g', param_line=False, lpar='(', rpar=')', greek_prefixes=True, subscripts='comma', max_items=10, edge_items=3, **kwargs)[source]#
- Parameters:
- classmethod sparse(**kwargs)[source]#
Build a context that carries only the given attributes, with no defaults.
This is the line-scoped layer of a
BaseRenderContext: because it holds only explicitly-set overrides,BaseRenderContext.current(a ChainMap of line over global) falls through to the global context for every key the line does not override. A fullRenderContext()here would instead shadow the global context with its own defaults.- Return type:
- class handcalcs.renderers.base.BaseRenderContext(global_context, line_context)[source]#
- Parameters:
global_context (RenderContext)
line_context (RenderContext)
Helpers#
- handcalcs.renderers.latex.latex_identifier(identifier, options=None)[source]#
Typeset a Python identifier as a LaTeX math symbol (see
identifiers.parse_identifier).Single underscores are subscripts:
N_pl_Rd->N_{\mathrm{pl,Rd}}in the comma style (the default),x_a_b->x_{a_{b}}in the nested style.Double underscores are spaces and triple underscores literal underscores.
A component that names a greek letter becomes that letter (
omega_2->\omega_{2}), and so does a Unicode Greek letter (σ_R->\sigma_{R},ΔH->\Delta H) and, withgreek_prefixes, a leading Greek name followed by an uppercase letter or a digit (DeltaH->\Delta H). Each__-separated word gets the same lookup (Delta__H->\Delta\ H).hat,bar,primeandstardecorate the component before them (x_hat->\hat{x},M_star->M^{*}).Any other component longer than one character is a word, set upright (
class_section->\mathrm{class}_{\mathrm{section}}).An identifier in
options.symbolsis typeset from its spec.
Text that isn’t an identifier (it already holds LaTeX, from a
name:prerule or an earlier pass) is returned unchanged, so the swap is idempotent.- Parameters:
identifier (str)
options (IdentifierOptions | None)
- Return type:
- handcalcs.renderers.identifiers.parse_identifier(identifier, options=IdentifierOptions(greek_prefixes=True, subscripts='comma', symbols={}))[source]#
Parse an identifier into a
Symbol:___is a literal underscore and__a space between words;_starts a subscript, in theoptions.subscriptsstyle;hat,bar,dotandddotput an accent over the component before them,primeadds a prime to it andstara superscript*(M_star-> M*,x_hat_max-> x̂ with subscript max);every word is split into Greek and text pieces (
split_greek).
An identifier in
options.symbolsis parsed from its spec instead (seeparse_spec). A leading or trailing underscore makes the whole identifier literal text (_x).- Parameters:
identifier (str)
options (IdentifierOptions)
- Return type:
- handcalcs.renderers.identifiers.parse_spec(spec, greek_prefixes=True)[source]#
Parse a display spec from the
symbolsoption into aSymbol. The syntax is TeX-like but renderer-neutral:N_{pl,Rd}: subscripts in braces, siblings separated by commas;N_Rdtakes the run of letters and digits after_;M^{*},x^2: superscripts, the same way;x_{a_{b}}: a subscript can have its own subscripts;spaces separate words (
Delta H);'after a base adds a prime;hat(x),bar(x),dot(V),ddot(x)put an accent over a base (bar(x)_{m}: the subscript stays outside);Greek letters as names or Unicode, as in identifiers (
Delta H,ΔH,sigma_{max}).
- handcalcs.renderers.identifiers.identifier_options(renderer, base_context=None)[source]#
The identifier options in effect: the
greek_prefixes,subscriptsandsymbolsrender-context fields (set withset_optionor a# hc:comment), defaulting to Greek prefixes on, comma subscripts and no symbols.- Parameters:
- Return type:
- handcalcs.renderers.identifiers.split_greek(word, prefixes=True)[source]#
A word as
(is_greek, text)pieces, where a Greek piece’s text is its canonical name (a key ofGREEK_UNICODE):"sigma"->[(True, "sigma")]"ΔHvap"->[(True, "Delta"), (False, "Hvap")]"DeltaH"->[(True, "Delta"), (False, "H")](only withprefixes)"metal"->[(False, "metal")]
A word with no Greek letter is always one text piece, so a renderer can keep its usual formatting for it.
- class handcalcs.renderers.identifiers.Symbol(words, accents=<factory>, primes=0, subscripts=<factory>, superscripts=<factory>)[source]#
One displayed symbol: its base (
__-separated words, each a list ofsplit_greekpieces), the accents over the base, its primes, and the symbols set as its subscripts and superscripts. Several subscripts are siblings, shown separated by commas.
- class handcalcs.renderers.identifiers.IdentifierOptions(greek_prefixes=True, subscripts='comma', symbols=<factory>)[source]#
How identifiers are parsed: see
identifier_options.
- handcalcs.renderers.latex.latex_prose(text)[source]#
Escape a comment written as prose (headings, comment paragraphs, inline comments) and typeset its light markup: a pair of backticks becomes
\texttt{}and an opening quote becomes a left quote (TeX otherwise sets'a'as two right quotes). An unpaired backtick is kept literally.
- handcalcs.renderers.latex.format_latex_number(value, format_code)[source]#
Format a real number with
format_codeand typeset any exponent as `` imes 10^{n}`` (e.g.2e+05->2 imes 10^{5}).
- handcalcs.renderers.base.infix_binop(node, renderer, allow_spaces=True, base_context=None)[source]#
- Parameters:
node (BinOp)
renderer (BaseRenderer)
base_context (BRC)
- Return type:
- handcalcs.renderers.base.render_condition(renderer, condition, base_context, mode)[source]#
Render an if/elif condition in the given mode (‘sym’ or ‘num’) and return the joined string. Shared by the if/elif header handlers.
conditionmay be the whole test node or a bare deque of comparison components. ACompareis unwrapped to itscomparisondeque (whose elements are joined tightly, matching the relational-operator symbols); any other test node (e.g. a booleanand/orop, or a loneName) is rendered directly.- Parameters:
renderer (BaseRenderer)
base_context (BaseRenderContext)
mode (str)
- Return type:
- handcalcs.renderers.base.render_block_body(renderer, node, base_context)[source]#
Render a block as
[header_string, body_list]: the header line as a string (the first element), followed by the block’s body lines gathered into their own nested sublist. Indentation is applied by the join step, according to nesting depth, not embedded here.The header is produced by the handler registered under ‘header:{node.type}’ (empty string if none is registered), so a renderer customizes a block’s intro line simply by registering its own ‘header:…’ handler.
- Parameters:
renderer (BaseRenderer)
node (HcNode)
base_context (BaseRenderContext)
- Return type: