# variable_substitution.py # # Copyright 2025 Pavel Baksy # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # SPDX-License-Identifier: GPL-3.0-or-later import re from typing import Dict, List, Tuple, Set from .models import HttpRequest, Environment class VariableSubstitution: """Handles variable substitution with {{variable_name}} syntax.""" # Pattern to match {{variable_name}} where variable_name is alphanumeric + underscore VARIABLE_PATTERN = re.compile(r'\{\{(\w+)\}\}') @staticmethod def find_variables(text: str) -> List[str]: """ Extract all {{variable_name}} references from text. Args: text: The text to search for variable references Returns: List of variable names found (without the {{ }} delimiters) """ if not text: return [] return VariableSubstitution.VARIABLE_PATTERN.findall(text) @staticmethod def substitute(text: str, variables: Dict[str, str]) -> Tuple[str, List[str]]: """ Replace {{variable_name}} with values from variables dict. Args: text: The text containing variable placeholders variables: Dictionary mapping variable names to their values Returns: Tuple of (substituted_text, list_of_undefined_variables) """ if not text: return text, [] undefined_vars = [] def replace_var(match): var_name = match.group(1) if var_name in variables: value = variables[var_name] # Check if value is empty/None - treat as undefined for warning purposes if not value: undefined_vars.append(var_name) return "" return value else: # Variable not defined - track it and replace with empty string undefined_vars.append(var_name) return "" substituted = VariableSubstitution.VARIABLE_PATTERN.sub(replace_var, text) return substituted, undefined_vars @staticmethod def substitute_request(request: HttpRequest, environment: Environment) -> Tuple[HttpRequest, Set[str]]: """ Substitute variables in all request fields (URL, headers, body). Args: request: The HTTP request with variable placeholders environment: The environment containing variable values Returns: Tuple of (new_request_with_substitutions, set_of_undefined_variables) """ all_undefined = set() # Substitute URL new_url, url_undefined = VariableSubstitution.substitute( request.url, environment.variables ) all_undefined.update(url_undefined) # Substitute headers (both keys and values) new_headers = {} for key, value in request.headers.items(): new_key, key_undefined = VariableSubstitution.substitute( key, environment.variables ) new_value, value_undefined = VariableSubstitution.substitute( value, environment.variables ) all_undefined.update(key_undefined) all_undefined.update(value_undefined) new_headers[new_key] = new_value # Substitute body new_body, body_undefined = VariableSubstitution.substitute( request.body, environment.variables ) all_undefined.update(body_undefined) # Create new HttpRequest with substituted values new_request = HttpRequest( method=request.method, url=new_url, headers=new_headers, body=new_body, syntax=request.syntax ) return new_request, all_undefined