pyfcstm.utils.jinja2
Jinja2 environment augmentation utilities.
This module provides helpers for enriching a jinja2.Environment with
Python built-ins, common text-processing filters, and selected operating system
environment variables. It is intended to simplify template authoring by making
common Python functions available as filters, tests, and globals, while keeping
target-language-specific helpers opt-in through each template’s
config.yaml.
The module contains the following public functions:
add_builtins_to_env()- Register Python built-ins as filters, tests, and globalsadd_settings_for_env()- Apply built-ins plus additional filters and globalsto_c_path_identifier()- Build collision-resistant C path identifiersto_c_public_identifier()- Build public C/C++ identifiers that avoid reserved formsto_c_public_macro_identifier()- Build public C/C++ macro identifiersis_c_public_identifier_reserved()- Detect reserved public C/C++ identifier shapes
Note
The added filters and globals are only attached to the environment instance passed to the functions and do not affect other environments. C-family identifier helpers are exported from this module for explicit template imports, but they are not injected into every renderer environment by default.
Example:
>>> import jinja2
>>> from pyfcstm.utils.jinja2 import add_settings_for_env
>>> env = add_settings_for_env(jinja2.Environment())
>>> template = env.from_string("{{ 'Hello World'|to_identifier }}")
>>> template.render()
'Hello_World'
to_c_path_identifier
- pyfcstm.utils.jinja2.to_c_path_identifier(segments) str[source]
Convert a path sequence into a collision-resistant C identifier.
Each path segment is encoded independently and prefixed with its original length. Encoding segment boundaries this way avoids collisions such as
Root.A.BandRoot.A_B. Preserving case while escaping significant underscores also avoids collisions such asRoot.AandRoot.aorInternalandInternal_while keeping the output acceptable for C/C++ identifiers and out of the C++ reserved double-underscore namespace.- Parameters:
segments (Iterable[str]) – Iterable path segments to encode.
- Returns:
C/C++-safe path identifier.
- Return type:
str
Example:
>>> to_c_path_identifier(["Root", "A", "B"]) 'p4_Root_p1_A_p1_B' >>> to_c_path_identifier(["Root", "A_B"]) 'p4_Root_p3_Az00005FB' >>> to_c_path_identifier(["Root", "A__B"]) 'p4_Root_p4_Az00005Fz00005FB' >>> to_c_path_identifier(["Root", "Internal_"]) 'p4_Root_p9_Internalz00005F'
is_c_public_identifier_reserved
- pyfcstm.utils.jinja2.is_c_public_identifier_reserved(identifier: str) bool[source]
Return whether a public C/C++ identifier spelling should be avoided.
Generated public macros, typedefs, and function prefixes should avoid names that C or C++ reserves for implementations. This helper checks the shapes that matter for generated public identifiers: a leading underscore or any double underscore.
- Parameters:
identifier (str) – Identifier spelling to inspect.
- Returns:
Whether the spelling has a reserved public C/C++ shape.
- Return type:
bool
Example:
>>> is_c_public_identifier_reserved('_ROOT_MACHINE') True >>> is_c_public_identifier_reserved('ROOT__MACHINE') True >>> is_c_public_identifier_reserved('ROOT_MACHINE') False
to_c_public_identifier
- pyfcstm.utils.jinja2.to_c_public_identifier(input_string: str, suffix: str = '') str[source]
Convert text into a public C/C++ identifier that avoids reserved forms.
The helper keeps ordinary identifiers readable, while falling back to the lossless path encoder whenever appending
suffixwould create a public spelling with a leading underscore or a double underscore. This is intended for generated C-family public ABI prefixes such as root-machine typedefs, function prefixes, visibility macros, and header-guard components.- Parameters:
input_string (str) – Source text to encode.
suffix (str, optional) – Optional suffix to append to the generated identifier, defaults to
''.
- Returns:
Public C/C++ identifier spelling.
- Return type:
str
Example:
>>> to_c_public_identifier('Root', 'Machine') 'RootMachine' >>> to_c_public_identifier('_Root', 'Machine') 'p_p5_z00005FRootMachine' >>> to_c_public_identifier('class', '_MACHINE') 'p_p5_class_MACHINE'
to_c_public_macro_identifier
- pyfcstm.utils.jinja2.to_c_public_macro_identifier(input_string: str, suffix: str = '') str[source]
Convert text into an uppercase public C/C++ macro identifier.
This helper mirrors
to_c_public_identifier()and uppercases the final spelling for generated public macro prefixes and header guards.- Parameters:
input_string (str) – Source text to encode.
suffix (str, optional) – Optional suffix to append before uppercasing, defaults to
''.
- Returns:
Public C/C++ macro identifier spelling.
- Return type:
str
Example:
>>> to_c_public_macro_identifier('Root', '_MACHINE') 'ROOT_MACHINE' >>> to_c_public_macro_identifier('_Root', '_MACHINE') 'P_P5_Z00005FROOT_MACHINE'
add_builtins_to_env
- pyfcstm.utils.jinja2.add_builtins_to_env(env: Environment) Environment[source]
Mount Python built-in functions to a Jinja2 environment.
This function registers Python built-ins to the provided environment as:
Filters: Callable built-ins are added as filters when no naming conflict exists.
Tests: Common boolean checks are added as tests, using a simplified name for functions beginning with
is(e.g.,isinstancebecomes theinstancetest).Globals: All non-conflicting built-ins are added to the global namespace.
In addition to these automatic registrations, this function always injects several convenience filters, even if they overwrite existing names in the environment:
str:strset:setdict:dictkeys:lambda x: x.keys()values:lambda x: x.values()enumerate:enumerate()reversed:reversed()filter:lambda x, y: filter(y, x)
- Parameters:
env (jinja2.Environment) – A Jinja2 environment instance to modify.
- Returns:
The same Jinja2 environment with built-ins mounted.
- Return type:
jinja2.Environment
Warning
This function may override pre-existing filters named
str,set,dict,keys,values,enumerate,reversed, andfilter.Example:
>>> import jinja2 >>> env = add_builtins_to_env(jinja2.Environment()) >>> tmpl = env.from_string("{{ [1, 2, 3]|reversed|list }}") >>> tmpl.render() '[3, 2, 1]'
add_settings_for_env
- pyfcstm.utils.jinja2.add_settings_for_env(env: Environment) Environment[source]
Add built-ins, text filters, and environment variables to a Jinja2 environment.
This function enhances a Jinja2 environment by applying the following steps:
Register Python built-ins via
add_builtins_to_env()Add text-processing filters: -
normalize:pyfcstm.utils.text.normalize()-to_identifier:pyfcstm.utils.text.to_identifier()Add a global helper: -
indent:textwrap.indent()Add operating system environment variables as globals (only if the name does not already exist in the environment).
- Parameters:
env (jinja2.Environment) – The Jinja2 environment to enhance.
- Returns:
The enhanced Jinja2 environment.
- Return type:
jinja2.Environment
Note
Environment variables are only added if their names do not already exist in the environment’s global namespace.
Example:
>>> import jinja2 >>> env = add_settings_for_env(jinja2.Environment()) >>> template = env.from_string("{{ 'Hello World'|normalize }}") >>> template.render() 'Hello_World'