pyab_experiment.codegen.python.python_generator#
Module that translates an Abstract Syntax Tree (AST) into executable Python code.
This module contains the PythonCodeGen class which traverses an ExperimentAST and generates corresponding Python code for experiment variant selection. The generated code includes conditional logic, group assignments, and deterministic choice functions.
Module Contents#
Classes#
Generates Python code from an ExperimentAST representation. |
- class pyab_experiment.codegen.python.python_generator.PythonCodeGen(experiment_ast: pyab_experiment.language.grammar.ExperimentAST, indentation_char: str = '\t', expose_experiment_variant_function: bool = True)[source]#
Generates Python code from an ExperimentAST representation.
This class maintains state during AST traversal (like indentation level and variable tracking)and provides methods to generate formatted Python code for experiment variant selection.
- Parameters:
experiment_ast (ExperimentAST) – The AST to translate into Python code
indentation_char (str, optional) – Character used for indentation.
expose_experiment_variant_function (Defaults to " ") –
level. (Whether to expose the variant selection function at the root) –
True (Defaults to) –
- _local_vars#
Tracks local variables used in the generated code
- Type:
set
- _conditional_ids#
Tracks conditional variables referenced in predicates
- Type:
set
- _indent_depth#
Current indentation level during code generation
- Type:
int
- _generate_conditionals(condition: pyab_experiment.language.grammar.ExperimentConditional | list[pyab_experiment.language.grammar.ExperimentGroup]) str[source]#
Generates Python code for conditional statements and group return functions.
This method traverses the experiment’s conditional structure and generates the corresponding Python code. It handles: 1. Conditional statements (if/elif/else) with their predicates and branches 2. Terminal group definitions that return partial functions for variant selection
- Parameters:
condition – Either an ExperimentConditional for if/elif/else logic, or a list[ExperimentGroup] for terminal group definitions. - ExperimentConditional contains predicate and branch information - list[ExperimentGroup] contains group definitions and weights
- Returns:
- Generated Python code as a string, including:
For conditionals: if/elif/else statements with their predicates
For groups: partial function definitions for variant selection
- Return type:
str
- Raises:
RuntimeError – If an unsupported condition type is provided
- Side Effects:
Adds conditional ids to self._conditional_ids
- Example generated code:
# For conditionals: if (age >= 18):
return partial(deterministic_choice, population=[‘A’, ‘B’], weights=[1, 2])
- else:
return partial(deterministic_choice, population=[‘C’, ‘D’], weights=[1, 1])
# For direct group definitions: return partial(deterministic_choice, population=[‘A’, ‘B’], weights=[1, 1])
- _generate_group_return_statement(group_statement: list[pyab_experiment.language.grammar.ExperimentGroup]) str[source]#
unwrap the experiment group, into a partial function call that applies the splitter logic
- _generate_op(op: pyab_experiment.language.grammar.LogicalOperatorEnum | pyab_experiment.language.grammar.BooleanOperatorEnum) str[source]#
renders legal python operations
- _generate_predicate(predicate: pyab_experiment.language.grammar.TerminalPredicate | pyab_experiment.language.grammar.RecursivePredicate | None) str[source]#
Generates Python code for predicate expressions in conditional statements.
This method handles three types of predicates: 1. Terminal predicates: Simple comparisons between two terms (e.g., “age >= 18”) 2. Recursive predicates: Complex boolean expressions combining multiple predicates 3. None: Returns an empty string (used in ELSE conditions)
- Parameters:
predicate – The predicate to convert to Python code. Can be: - TerminalPredicate: For simple comparisons - RecursivePredicate: For complex boolean expressions - None: For else conditions
- Returns:
A Python expression string representing the predicate logic.
- Return type:
str
- Raises:
RuntimeError – If an unsupported predicate type is provided.
- Side Effects:
Adds conditional ids to self._conditional_ids as it encounters them
- _generate_term(term: float | int | str | tuple | pyab_experiment.language.grammar.Identifier) str[source]#
renders a term
- generate() str[source]#
main method. Does a DFS on the AST rendering python code as it traverses the nodes
- generate_key_definition() str[source]#
Generate the composite hash key used for deterministic experiment group assignment.
This method combines the experiment’s salt (if provided) with the string representation of splitting fields to create a composite key. This key is used by the deterministic_choice function to consistently assign users to experiment groups.
The composite key is constructed as follows: 1. If a salt exists, it’s used as a prefix 2. If splitting fields exist, their string representations are concatenated 3. If neither exists, returns “None”
- Example outputs:
With salt=”exp1” and fields=[user_id, country]: “‘exp1’+’’.join(map(str, [user_id, country]))”
With only fields=[device_id]: “’’’’.join(map(str, [device_id]))”
With no salt or fields: “None”
- Returns:
- A Python expression that evaluates to the composite key
used for group assignment.
- Return type:
str
- Side Effects:
Adds any splitting field variables to self._local_vars