FLM Environment: flm.flmenvironment

Pylatexenc specializations

class flm.flmenvironment.FLMParsingState(**kwargs)

Bases: ParsingState

Parsing state extends pylatexenc’s parsing state class to include information about whether or not we are currently in “block level mode” or not. E.g., we should not accept contents such as tables and figures when parsing the argument to a text format macro like \textbf.

is_block_level

Indicates whether or not we are parsing content in block-level mode. If True, then we are in block level mode. If False then block-level constructs such as enumeration lists, figures, paragraph breaks, etc. are disallowed. If None, then the parser should keep the ability to auto-detect whether the contents is block-level mode or not.

set_fields(*, is_block_level=None, **kwargs)

Create a new parsing state with modified fields.

This method is called internally by pylatexenc when constructing a sub-context. It sets the is_block_level attribute along with any other fields forwarded to the parent class.

Parameters:

is_block_level – Whether the new state should parse block-level content (True), inline content (False), or auto-detect (None).

class flm.flmenvironment.FLMParsingStateDeltaSetBlockLevel(is_block_level=None)

Bases: ParsingStateDelta

Parsing state delta class (see pylatexenc.latexnodes.ParsingStateDelta) that updates the parsing state to set the block level mode attribute (is_block_level).

flm.flmenvironment.FLMArgumentSpec(parser: str | ~pylatexenc.latexnodes.parsers._base.LatexParserBase, argname: str | None, is_block_level: bool | None | ~typing.Type[~flm.flmenvironment._NotProvided] = <class 'flm.flmenvironment._NotProvided'>, flm_doc: None | str = None, parsing_state_delta: ~pylatexenc.latexnodes._parsingstatedelta.ParsingStateDelta | None = None)

Create an argument specification for an FLM macro or environment.

This is a factory function that returns a pylatexenc.latexnodes.LatexArgumentSpec instance configured with FLM-specific options, notably the block-level parsing mode for the argument’s contents.

Parameters:
  • parser – The argument parser specification (e.g., '{' for a mandatory argument, '[' for an optional argument). May also be a pylatexenc parser instance.

  • argname – A name for the argument, used to retrieve it later via ParsedArgumentsInfo.

  • is_block_level – Whether the argument contents should be parsed in block-level mode (True), inline mode (False), or auto-detect (None). Defaults to False if the argument is not provided.

  • flm_doc – Optional documentation string describing the argument, used by the self-documenting environment feature.

  • parsing_state_delta – An optional ParsingStateDelta instance to apply when parsing this argument. If provided, is_block_level should be set to None (or omitted) to avoid conflicts.

Returns:

A LatexArgumentSpec instance.

class flm.flmenvironment.FLMLatexWalker(*, flm_text, default_parsing_state, flm_environment, parsing_state_event_handler=None, standalone_mode=False, resource_info=None, parsing_mode=None, what=None, input_lineno_colno_offsets=None, **kwargs)

Bases: LatexWalker

A LatexWalker class that is meant to parse FLM code.

This walker class takes care to add additional information to node lists that is then needed by the code that renders FLM fragments into output formats (e.g. HTML). For instance, node lists need to be split into “blocks” (paragraphs or block-level content) as they are parsed (see make_nodelist()).

This class also accepts a custom parsing state event handler instance. See flm.flmstd for how it is set in the standard environment.

parsing_state_event_handler()
make_nodelist(nodelist, parsing_state, **kwargs)
make_node(node_class, **kwargs)
filter_whitespace_comments_nodes(nodelist)

Utility to filter out nodes from nodelist that are pure whitespace, comments, None, or paragraph break markers (’nn’).

Finalizing nodes and handling text blocks

A “nodes finalizer” is meant to process a compiled node or compiled node list to add some relevant meta-information and normalize content appropriately. In particular, we auto-detect whether or not the node list is in block-level mode or not (if not already specified) and we handle space characters (remove them between block-level components and surrounding text; keep one space between inline components).

class flm.flmenvironment.NodesFinalizer(text_processing_options=None)

Bases: object

Responsible for adding additional meta-information to nodes to tell whether nodes and node lists are block-level or inline text.

This finalizer is invoked automatically by FLMLatexWalker when nodes and node lists are created during parsing. It handles:

  • Inferring whether a node list is block-level or inline (when not already specified by the parsing state).

  • Decomposing block-level node lists into blocks (paragraphs and standalone block-level items) via BlocksBuilder.

  • Processing character nodes to apply text transformations (whitespace simplification, automatic Unicode quote conversion, ligature replacements for dashes and ellipses).

REMEMBER: After a Node or NodeList is “finalized” (call to finalize_node/finalize_nodelist is over), then we should NOT modify any attributes on that node. In particular, finalize_nodelist() should NOT set/modify any attributes on existing child nodes instances (we should clone them if necessary).

Parameters:

text_processing_options – A dictionary of text processing options. Supported keys: 'auto' (True/False/'quotes'/'ligatures'), 'simplify_whitespace', 'auto_unicode_quotes', 'ligature_unicode_quotes', 'ligature_unicode_dashes', 'ligature_unicode_ellipses'.

finalize_nodelist(latexnodelist)

Inspect the node list and set information about whether or not it is block level.

  • If the parsing state does not specify the block level, infer whether or not the node list is block-level by inspecting the nodes in the node list.

  • If the parsing state does specify that the node list is not block level (i.e. it is inline level), then make sure that all nodes in the node list are allowed to appear there.

  • In all cases, inspect how the node list is split into blocks, and store the relevant information in a property flm_blocks_info

finalize_node(node)

Finalize a single parsed node by applying text processing transformations.

For LatexCharsNode instances that do not already have an flm_chars_value attribute, this method sets flm_chars_value to the result of process_text() applied to the node’s character content.

Parameters:

node – The node to finalize.

Returns:

The finalized node (the same object, possibly with flm_chars_value set).

process_text(chars)
infer_is_block_level_nodelist(latexnodelist)
make_blocks_builder(latexnodelist)
rx_inline_space = re.compile('[ \\t\\n\\r]+')
class flm.flmenvironment.BlocksBuilder(latexnodelist, simplify_whitespace=True)

Bases: object

Decomposes a LatexNodeList into a sequence of blocks (paragraphs and standalone block-level nodes).

Block decomposition is driven by nodes whose flm_is_block_level attribute is True. Paragraph break markers (flm_is_paragraph_break_marker) cause a paragraph flush without producing their own block. Block headings (flm_is_block_heading) start a new paragraph and are included in it as a leading element.

Whitespace between blocks is stripped, and whitespace within paragraphs is simplified when simplify_whitespace is True.

Parameters:
  • latexnodelist – The node list to decompose.

  • simplify_whitespace – If True (the default), collapse runs of whitespace characters within paragraphs to a single space.

rx_space = re.compile('[ \\t\\n\\r]+')
rx_only_space = re.compile('^[ \\t\\n\\r]+$')
flush_paragraph()
simplify_whitespace_chars(chars, is_head=False, is_tail=False)
finalize_paragraph(paragraph_nodes)
build_blocks()

The main FLMEnvironment class

class flm.flmenvironment.FLMEnvironment(features, parsing_state, latex_context, *, tolerant_parsing=False, parsing_mode_deltas=None, text_processing_options=None)

Bases: object

The central class that collects feature definitions and parsing settings for processing FLM content.

An environment provides:

  • A set of features that define the available macros, environments, and specials.

  • A parsing state that controls parsing options (e.g., comment syntax, math delimiters).

  • Methods to create fragments (make_fragment()) and documents (make_document()).

Typically, use make_standard_environment() instead of constructing this class directly.

Parameters:
  • features – A list of Feature instances. Features are automatically sorted by dependency order.

  • parsing_state – A FLMParsingState instance to serve as the default parsing state. Its latex_context field should be None; the environment will populate it from the features’ definitions.

  • latex_context – A pylatexenc.macrospec.LatexContextDb instance. If None is given to make_standard_environment(), a new empty context database is created automatically.

  • tolerant_parsing – If True, parsing errors are handled more leniently.

  • parsing_mode_deltas – A dictionary mapping parsing mode names (strings) to ParsingStateDelta instances. When a non-trivial parsing_mode= argument is specified to make_latex_walker(), the corresponding delta is applied onto the default parsing state.

  • text_processing_options – Options passed to NodesFinalizer controlling text processing (whitespace simplification, automatic Unicode quote and ligature conversion).

supports_feature(feature_name)

Return True if a feature with the given name is registered in this environment.

feature(feature_name)

Return the Feature instance for the given feature name. Raises KeyError if not found.

parsing_state_event_handler = None

There is no parsing state event handler by default. If you want to allow unknown macros etc. in math mode, set this property to a FLMLatexWalkerParsingStateEventHandler() instance.

make_latex_walker(flm_text, *, standalone_mode, is_block_level, parsing_mode=None, resource_info=None, tolerant_parsing=None, what=None, input_lineno_colno_offsets=None)
define_parsing_mode(parsing_mode, parsing_mode_delta)
make_parsing_state(is_block_level, parsing_mode=None)
make_fragment(flm_text, **kwargs)

Parse FLM text and return a FLMFragment.

If flm_text is already an FLMFragment instance, it is returned as-is (after validating that its settings are compatible with any explicitly requested keyword arguments).

Parameters:
  • flm_text – The FLM source text to parse, or an already-parsed FLMFragment.

  • is_block_level – Whether to parse as block-level (True), inline (False), or auto-detect (None, the default).

  • standalone_mode – If True, disables features that require a document context (e.g., cross-references).

  • what – A short description of this fragment for error messages.

  • resource_info – Custom object to help locate external resources (e.g., the filesystem path of the source file).

  • silent – If True, suppress error logging on parse failure.

Returns:

A FLMFragment instance.

make_document(render_callback, **kwargs)

Instantiates a FLMDocument object with the relevant arguments (environment instance, feature objects).

This method also calls the document’s initialize() method.

Returns the instantiated document object.

get_features_selection(enable_features)
environment_get_located_error_message = None
get_located_error_message(exception_object)
finalize_nodelist(nodelist)

Finalize a node list by delegating to the environment’s NodesFinalizer.

This method is called automatically by FLMLatexWalker when a node list is created via make_nodelist(). It sets the flm_is_block_level attribute and, for block-level lists, decomposes the list into blocks (flm_blocks).

Parameters:

nodelist – A LatexNodeList to finalize.

Returns:

The finalized node list.

finalize_node(node)

Finalize a single node by delegating to the environment’s NodesFinalizer and assigning a unique node identifier.

This method is called automatically by FLMLatexWalker when a node is created via make_node(). It applies text processing (see NodesFinalizer.finalize_node()) and sets the internal _flm_node_id attribute on the node.

Note

FIXME: change method name — This method has the same name as macrospec._specclasses.CallableSpec.finalize_node(), which is called by pylatexenc’s macro call parser; the present method is unrelated.

Parameters:

node – The node to finalize.

Returns:

The finalized node.

Constructing a “standard” environment

Convenience functions for constructing a standard environment with appropriate definitions and handlers.

flm.flmenvironment.standard_parsing_state(*, force_block_level: None | bool = None, enable_comments: bool = True, comment_start: str = '%%', extra_forbidden_characters: str = '', dollar_inline_math_mode: bool = False)

Return a ParsingState configured in a standard way for parsing FLM content. E.g., we typically disable commands and $-math mode, unless you specify keyword arguments to override this behavior.

The latex_context field of the returned object is None, and this value will be accepted if you use this parsing state as an argument to standard_features().

flm.flmenvironment.make_standard_environment(features, parsing_state=None, latex_context=None, flm_environment_options=None, parsing_state_options=None)

Create a standard FLMEnvironment with sensible defaults.

This is the recommended way to create an FLM environment. It sets up the parsing state, latex context database, math mode handling, and error message formatting.

Usage example:

from flm.flmenvironment import make_standard_environment
from flm.stdfeatures import standard_features

environ = make_standard_environment(features=standard_features())
fragment = environ.make_fragment(r'Hello, \emph{world}.', standalone_mode=True)
Parameters:
Returns:

A configured FLMEnvironment instance.

class flm.flmenvironment.FLMLatexWalkerMathContextParsingStateEventHandler

Bases: LatexWalkerParsingStateEventHandler

Handle enter/exit math mode to update the latex context database appropriately.

Upon entering math mode, the latex context database (see pylatexenc.macrospec.LatexContextDb) is extended to allow any unknown LaTeX macros and environments.

enter_math_mode(math_mode_delimiter=None, trigger_token=None)

Callback is called upon entering math mode. See pylatexenc.latexnodes.LatexWalkerParsingStateEventHandler.

leave_math_mode(trigger_token=None)

Callback is called upon entering math mode. See pylatexenc.latexnodes.LatexWalkerParsingStateEventHandler.

flm.flmenvironment.standard_environment_get_located_error_message(environment, exception_object)

Presents a more refined, and hopefully helpful, error message, assuming a standard enough FLM environment, for the given error exception_object. The latter is assumed to be a pylatexenc.latexnodes.LatexWalkerLocatedError instance.

Does NOT include any FLM traceback, the return value is simply a potentially more helpful string to use as the exception’s main msg message. Might return None if no more meaningful message than exception_object.msg is available.

Some error messages are changed to make them more useful:

  • If a forbidden ‘%’ is encountered, you’d normally get an error message like '%' is a forbidden character. To be more useful, a new error message is provided pointing the user to either using \% to typeset a literal percent sign or %% to start a comment.

  • If a forbidden ‘$’ is encountered, then pointers to the syntax \(...\), \[...\], and \$ are reported.

  • We might add more error message transformations in the future.

If you’d like to write your own error message handler, you’ll find interesting information about the error in exception_object.error_type_info.

Helpers to create macro/environment/specials nodes

It is sometimes useful, in a render function, to create new “virtual” nodes in order to call fragment renderer routines. For instance, an enumeration list will likely create nodes for the enumerator tag with automatic numbering.

For this purpose, you should use the latex walker’ methods pylatexenc.latexwalker.LatexWalker.make_node() and pylatexenc.latexwalker.LatexWalker.make_nodelist(). (Recall that the latex walker instance is accessible as node.latex_walker.) As a convenience, we provide the following methods to create nodes that represent an “invocable” instance, e.g., a LaTeX macro possibly given with specific arguments.

flm.flmenvironment.make_invocable_arguments(flm_spec, args, *, latex_walker, parsing_state)

Create argument nodes for a “virtual” macro/environment invocation.

This is useful when programmatically constructing nodes (e.g., for auto-generated numbering labels in enumeration lists).

Parameters:
  • flm_spec – The FLMSpecInfo instance whose argument specification to use.

  • args – A dictionary mapping argument names to values (strings, nodes, or node lists). None means no arguments.

  • latex_walker – The FLMLatexWalker instance.

  • parsing_state – The current parsing state.

Returns:

A list of argument nodes matching the spec’s argument list.

flm.flmenvironment.make_invocable_node_instance(node_type, flm_spec, *, args=None, latex_walker, parsing_state, body_nodelist=None, node_kwargs=None)

Create a fully finalized “virtual” node representing a macro, environment, or specials invocation.

The returned node can be used to call fragment renderer methods as if the construct had been parsed from source text. For example, enumeration features use this to create nodes for auto-generated item labels.

Parameters:
  • node_type – The pylatexenc node class (e.g., LatexMacroNode, LatexEnvironmentNode, LatexSpecialsNode).

  • flm_spec – The FLMSpecInfo instance for the construct.

  • args – A dictionary mapping argument names to values.

  • latex_walker – The FLMLatexWalker instance.

  • parsing_state – The current parsing state.

  • body_nodelist – For environments, the body node list.

  • node_kwargs – Additional keyword arguments for the node constructor.

Returns:

A finalized node instance.