Skip to content

provide explicit namespace to eval in user_defined_transform()#46

Merged
bobby-payne merged 1 commit intomainfrom
feat/numpy-in-transforms
Oct 24, 2025
Merged

provide explicit namespace to eval in user_defined_transform()#46
bobby-payne merged 1 commit intomainfrom
feat/numpy-in-transforms

Conversation

@bobby-payne
Copy link
Copy Markdown
Contributor

@bobby-payne bobby-payne commented Oct 23, 2025

Summary

This PR addresses #45: a NameError: name 'np' is not defined error occurring when applying certain user-defined transforms (e.g., np.log(x)) in user_defined_transform(). The root cause was that eval() was executed without a namespace, leaving references like np undefined inside the evaluated expression.

Changes

Adds an evaluation context ({"np": np, "x": x}) to eval() so transforms can safely access numpy operations and the variable x.
The execution environment remains isolated — no global variables are leaked or modified.

Modified file

nc2pt/nc2pt/computations.py

Before (beginning on line 30):

    for transform in var.transform:
        try:
            x = 1.0  # noqa: F841
            eval(transform)  # x is implicitly a variable from the config
        except SyntaxError:
            raise SyntaxError(f"Invalid transform in config {transform}.")

        def func(x):
            return eval(transform)

        logging.info(f"🧮 Applying transform {transform} to {var.name}...")
        ds[var.name] = xr.apply_ufunc(func, ds[var.name], dask="parallelized")

After:

    for transform in var.transform:
        try:
            x = 1.0
            eval(transform, {"np": np, "x": x})  # x is implicitly a variable from the config
        except SyntaxError:
            raise SyntaxError(f"Invalid transform in config {transform}.")

        def func(x):
            return eval(transform, {"np": np, "x": x})

        logging.info(f"🧮 Applying transform {transform} to {var.name}...")
        ds[var.name] = xr.apply_ufunc(func, ds[var.name], dask="parallelized")

Notes

Tested with np.nan_to_num(x) as transform on indices calculated from ERA5 and USask-WRF data. Produced no errors and worked as intended.

eval() remains restricted — no access to built-ins or globals other than np and x.

Could later replace with numexpr for improved safety, as eval allows for arbitrary code execution.

@bobby-payne bobby-payne requested a review from SBeairsto October 23, 2025 23:53
Copy link
Copy Markdown
Collaborator

@SBeairsto SBeairsto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@bobby-payne bobby-payne merged commit cb530b9 into main Oct 24, 2025
0 of 3 checks passed
@bobby-payne bobby-payne deleted the feat/numpy-in-transforms branch October 24, 2025 17:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants