Source code for ramble.definitions.variables

# Copyright 2022-2026 The Ramble Authors
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.

import copy
from typing import Any, Dict, List, Optional, Set

import ramble.util.colors as rucolor


[docs] class Variable: """Class representing a variable definition""" def __init__( self, name: str, default=None, description: Optional[str] = None, values=None, expandable: bool = True, track_used: bool = True, when=None, **kwargs, ): """Constructor for a new variable Args: name (str): Name of variable default: Default value of variable description (str): Description of variable values: List of suggested values for variable expandable (bool): True if variable can be expanded, False otherwise track_used (bool): True if variable should be considered used, False to ignore it for vectorizing experiments when (list | None): List of when conditions to apply to directive """ self.name = name self.default = default self.description = description self.values = values.copy() if isinstance(values, list) else [values] self.expandable = expandable self.track_used = track_used self.when = when.copy() if when else [] def __str__(self): if not hasattr(self, "_str_indent"): self._str_indent = 0 return self.as_str(n_indent=self._str_indent)
[docs] def as_str(self, n_indent: int = 0, verbose: bool = False): """String representation of this variable Args: n_indent (int): Number of spaces to indent string lines with Returns: (str): Representation of this variable """ indentation = " " * n_indent if verbose: print_attrs = ["Description", "Default", "Values"] out_str = rucolor.title_color(f"{indentation}{self.name}:\n", n_indent) for print_attr in print_attrs: name = print_attr if print_attr == "Values": name = "Suggested Values" attr_name = print_attr.lower() attr_val = getattr(self, attr_name, None) if attr_val: out_str += ( f"{indentation} {rucolor.title_color(name, n_indent=n_indent + 4)}: " f"{rucolor.plaintext(str(attr_val))}\n" ) else: out_str = f"{indentation}{self.name}" return out_str
[docs] def copy(self): return copy.deepcopy(self)
[docs] class VariableModification: """Class representing a variable modification""" def __init__( self, name: str, modification: str, method: str = "set", separator: str = " ", when=None, **kwargs, ): """Constructor for a new variable modification Args: name (str): The variable to modify modification (str): The value to modify 'name' with method (str): How the modification should be applied mode (str): Single mode to group this modification into modes (str): List of modes to group this modification into separator (str): Optional separator to use when modifying with 'append' or 'prepend' methods. when (list | None): List of when conditions this modification should apply in Supported values are 'append', 'prepend', and 'set': 'append' will add the modification to the end of 'name' 'prepend' will add the modification to the beginning of 'name' 'set' (Default) will overwrite 'name' with the modification """ self.name = name self.modification = modification self.method = method self.separator = separator self.when = when.copy() if when else [] def __str__(self): if not hasattr(self, "_str_indent"): self._str_indent = 0 return self.as_str(n_indent=self._str_indent)
[docs] def as_str(self, n_indent: int = 0, verbose: bool = False): """String representation of this variable Args: n_indent (int): Number of spaces to indent string lines with Returns: (str): Representation of this variable """ indentation = " " * n_indent print_attrs = ["Modification", "Method", "Separator", "When"] out_str = rucolor.title_color(f"{indentation}{self.name}:\n", n_indent) for print_attr in print_attrs: name = print_attr attr_name = print_attr.lower() attr_val = getattr(self, attr_name, None) if attr_val: if print_attr == "Separator": attr_val = f"'{attr_val}'" out_str += ( f"{indentation} {rucolor.title_color(name, n_indent=n_indent + 4)}: " f"{rucolor.plaintext(str(attr_val))}\n" ) return out_str
[docs] def copy(self): return copy.deepcopy(self)
[docs] class EnvironmentVariable: """Class representing an environment variable""" def __init__( self, name: str, value=None, description: Optional[str] = None, method: str = "set", append_separator: str = ",", when=None, **kwargs, ): """EnvironmentVariable constructor Args: name (str): Name of environment variable value: Value to set environment variable to description (str): Description of the environment variable method (str): Method to use when defining the env-var. Can be "set", "append", or "prepend" append_separator (str): Separator to use when method is "append", otherwise ignored. when (list | None): List of when conditions to apply to directive """ self.name = name self.value = value self.description = description self.method = method self.separator = append_separator self.when = when.copy() if when else [] def __str__(self): if not hasattr(self, "_str_indent"): self._str_indent = 0 return self.as_str(n_indent=self._str_indent)
[docs] def as_str(self, n_indent: int = 0, verbose: bool = False): """String representation of environment variable Args: n_indent (int): Number of spaces to indent string representation by Returns: (str): String representing this environment variable """ indentation = " " * n_indent if verbose: print_attrs = ["Description", "Value", "Method"] if self.method == "append": print_attrs.append("Separator") out_str = rucolor.title_color(f"{indentation}{self.name}:\n", n_indent) for name in print_attrs: attr_name = name.lower() attr_val = getattr(self, attr_name, None) if attr_val: out_str += ( f"{indentation} {rucolor.title_color(name, n_indent=n_indent + 4)}: " f"{rucolor.plaintext(str(attr_val))}\n" ) else: out_str = f"{indentation}{self.name}" return out_str
[docs] def copy(self): return copy.deepcopy(self)
[docs] class EnvironmentVariableModifications: """Class representing modifications of an environment variable""" all_methods = ["set", "unset", "prepend", "append"] def __init__( self, name: str, modification: str, method: str = "set", when: Optional[List[str]] = None, **kwargs, ): """Constructor for environment variable modification Args: name (str): The name of the environment variable that will be modified modification (str): The value of the modification method (str): The method of the modification. mode (str | None): Name of mode this env_var_modification should apply in modes (list(str) | None): List of mode names this env_var_modification should apply in when (list | None): List of when conditions this env_var_modification should apply in Supported values for method are: - set: Defines the variable to equal the modification value - unset: Removes any definition of the variable from the environment - prepend: Prepends the modification to the beginning of the variable. Always uses the separator ':' - append: Appends the modification value to the end of the value. Allows a keyword argument of 'separator' to define the delimiter between values. """ self.name = name self.when = when.copy() if when else [] self.set: Dict[str, str] = {} self.unset: Set[str] = set() self.prepend: List[Dict[str, Dict[str, str]]] = [] self.append: List[Dict[str, Any]] = [] self.add_modification( modification=modification, method=method, **kwargs, ) def __str__(self): if not hasattr(self, "_str_indent"): self._str_indent = 0 return self.as_str(n_indent=self._str_indent)
[docs] def as_str(self, n_indent: int = 0, verbose: bool = False): """String representation of this environment variable modification Args: n_indent (int): Number of spaces to indent string lines with Returns: (str): Representation of this environment variable modification """ indentation = " " * n_indent if verbose: n = 0 out_str = rucolor.title_color(f"{indentation}{self.name}:\n", n_indent) for method in self.all_methods: if getattr(self, method): if n > 0: out_str += "\n" out_str += ( f"{indentation} " f"{rucolor.title_color('method', n_indent=n_indent + 4)}: {method}\n" ) n += 1 if method == "set": out_str += ( f"{indentation} " f"{rucolor.title_color('modification', n_indent=n_indent + 4)}: " f"{self.set[self.name]}\n" ) elif method in ["prepend", "append"]: for method_dict in getattr(self, method): for attr, val in method_dict.items(): out_str += ( f"{indentation} " f"{rucolor.title_color(attr, n_indent=n_indent + 4)}: {val}\n" ) if self.when: out_str += ( f"{indentation} " f"{rucolor.title_color('when', n_indent=n_indent + 4)}: {self.when}\n" ) else: out_str = f"{indentation}{self.name}" return out_str
[docs] def copy(self): return copy.deepcopy(self)
[docs] def add_modification( self, modification: str, method: str = "set", **kwargs, ): """Adds a modification to this environment variable Args: modification (str): The value of the modification method (str): The method of the modification. separator (str): The separator to use when appending or prepending when (list | None): List of when conditions this env_var_modification should apply in """ if method == "set": self.set = {self.name: modification} elif method == "unset": self.unset = {self.name} elif method == "prepend": prepend_dict = { "paths": {self.name: modification}, } self.prepend.append(prepend_dict) elif method == "append": append_dict = {} separator = kwargs.get("separator", ":") if separator != ":": append_dict = { "vars": {self.name: modification}, "var-separator": separator, } else: append_dict = { "paths": {self.name: modification}, } self.append.append(append_dict)