-
Notifications
You must be signed in to change notification settings - Fork 24
Expand file tree
/
Copy pathenv_utils.py
More file actions
79 lines (61 loc) · 2.6 KB
/
env_utils.py
File metadata and controls
79 lines (61 loc) · 2.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# SPDX-FileCopyrightText: GitHub, Inc.
# SPDX-License-Identifier: MIT
"""Environment variable utilities for taskflow execution."""
import os
from typing import Any
import jinja2
__all__ = ["TmpEnv", "swap_env"]
def swap_env(s: str, context: dict[str, Any] | None = None) -> str:
"""Render Jinja template expressions in a string.
Supports expressions such as ``{{ env('VAR') }}``. Template variables
like ``{{ globals.X }}`` are only available when provided by the caller
via ``context`` (e.g. ``{'globals': {...}}``).
Args:
s: String potentially containing templates.
context: Optional template context. Variables such as ``globals``
must be supplied here to be available during rendering.
Returns:
String with templates replaced.
Raises:
LookupError: If a required environment variable or template
variable is not found during rendering.
"""
# Quick check if templating needed
if '{{' not in s:
return s
try:
# Import here to avoid circular dependency
from .template_utils import create_jinja_environment
from .available_tools import AvailableTools
available_tools = AvailableTools()
jinja_env = create_jinja_environment(available_tools)
template = jinja_env.from_string(s)
# Filter out keys that collide with built-in template globals
# (e.g. the env() helper) to prevent callers from breaking them.
reserved_keys = set(jinja_env.globals)
render_context = {
key: value for key, value in (context or {}).items()
if key not in reserved_keys
}
return template.render(**render_context)
except jinja2.UndefinedError as e:
# Convert Jinja undefined to LookupError for compatibility
raise LookupError(str(e))
except jinja2.TemplateError:
# Not a template or failed to render, return as-is
return s
class TmpEnv:
"""Context manager that temporarily sets environment variables."""
def __init__(self, env: dict[str, str],
context: dict[str, Any] | None = None) -> None:
self.env = dict(env)
self.context = context
self.restore_env = dict(os.environ)
def __enter__(self) -> None:
for k, v in self.env.items():
os.environ[k] = swap_env(v, self.context)
def __exit__(self, exc_type: type | None, exc_val: BaseException | None, exc_tb: Any | None) -> None:
for k, v in self.env.items():
del os.environ[k]
if k in self.restore_env:
os.environ[k] = self.restore_env[k]