Skip to content

parameterspace.utils

extract_lambda_information(source_lines)

[summary]

Parameters:

Name Type Description Default
source_lines Iterable

[description]

required

Exceptions:

Type Description
RuntimeError

If function definition is not a valid Lambda function.

Returns:

Type Description
Tuple[list, str]

[description]

Source code in parameterspace/utils.py
def extract_lambda_information(source_lines: Iterable) -> Tuple[list, str]:
    """[summary]

    Args:
        source_lines: [description]

    Raises:
        RuntimeError: If function definition is not a valid Lambda function.

    Returns:
        [description]
    """
    condensed_code = "".join(source_lines).replace(os.linesep, "")  # join lines
    condensed_code = " ".join(
        condensed_code.split()
    )  # replace multiple spaces by a single one

    try:
        signature, body = condensed_code.split("lambda")[1].split(":")
    except IndexError as e:
        raise RuntimeError(
            "The function definition does not look like a valid Lambda function:\n"
            + "".join(source_lines)
        ) from e

    while len(body) > 1:
        lambda_def = f"lambda {signature}: {body}"
        try:
            _ = compile(lambda_def, "<unused filename>", "eval")
            break
        except SyntaxError:
            body = body[:-1]

    variables = [s.strip() for s in signature.split(",")]

    return variables, body.strip().rstrip(",")

store_init_arguments(init_method)

Stores init arguments (including keyword arguments) and auto converts numpy.ndarrays to lists for json serializability.

Parameters:

Name Type Description Default
init_method Callable

[description]

required

Returns:

Type Description
Callable

[description]

Source code in parameterspace/utils.py
def store_init_arguments(init_method: Callable) -> Callable:
    """Stores init arguments (including keyword arguments) and auto converts
    `numpy.ndarray`s to `list`s for json serializability.

    Args:
        init_method: [description]

    Returns:
        [description]
    """

    @wraps(init_method)
    def wrapper(self, *args, **kwargs):
        args = [a.tolist() if isinstance(a, np.ndarray) else a for a in args]

        for k, k_value in kwargs.items():
            if isinstance(k_value, np.ndarray):
                kwargs[k] = k_value.tolist()

        self._init_args = args
        self._init_kwargs = kwargs
        init_method(self, *args, **kwargs)

    return wrapper

verify_lambda(variables, body)

Check serialized lambda expression for malicious code.

Parameters:

Name Type Description Default
variables List[str]

List of the variable names used in the function body.

required
body str

Function body string representation to check for allowed expressions.

required

Returns:

Type Description
bool

True if the function body is considered safe.

Source code in parameterspace/utils.py
def verify_lambda(variables: List[str], body: str) -> bool:
    """Check serialized lambda expression for malicious code.

    Args:
        variables: List of the variable names used in the function body.
        body: Function body string representation to check for allowed expressions.

    Returns:
        True if the function body is considered safe.
    """

    if len(body) > 200:
        return False

    if "eval(" in body:
        return False

    forbidden_characters = "\\;"

    for c in forbidden_characters:
        if c in body:
            return False

    allowed_characters = ".,0123456789+-*/()<=!> "
    allowed_functions = [
        "math.sin",
        "math.cos",
        "math.exp",
        "math.log",
        "or",
        "and",
        "not",
        "in",
    ]

    for vn in variables:
        body = body.replace(vn, "")

    for fn in allowed_functions:
        body = body.replace(fn, "")

    for c in allowed_characters:
        body = body.replace(c, "")

    # remove all single quoted strings
    matches = re.findall(r"\'(.+?)\'", body)
    for m in matches:
        body = body.replace("'" + m + "'", "")

    # remove all double quoted strings
    matches = re.findall(r"\"(.+?)\"", body)
    for m in matches:
        body = body.replace('"' + m + '"', "")

    if len(body) > 0:
        print("body:", body)
        return False

    return True