execution_context.py 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. from __future__ import annotations
  2. import re
  3. from typing import Any, Optional
  4. _ARRAY_INDEX_RE = re.compile(r"^(.+)\[(\d+)\]$")
  5. class ExecutionContext:
  6. def __init__(self, inputs: dict[str, Any] | None = None):
  7. self._inputs: dict[str, Any] = inputs or {}
  8. self._step_results: dict[str, dict[str, Any]] = {}
  9. @property
  10. def inputs(self) -> dict[str, Any]:
  11. return self._inputs
  12. def put_step_result(self, step_id: str, outputs: dict[str, Any]):
  13. self._step_results[step_id] = outputs or {}
  14. def get_step_result(self, step_id: str) -> dict[str, Any] | None:
  15. return self._step_results.get(step_id)
  16. def lookup(self, path: str) -> Any:
  17. if not path:
  18. return None
  19. parts = path.split(".")
  20. if parts[0] == "inputs":
  21. current: Any = self._inputs
  22. idx = 1
  23. else:
  24. current = self._step_results.get(parts[0])
  25. idx = 1
  26. for i in range(idx, len(parts)):
  27. if current is None:
  28. return None
  29. key = parts[i]
  30. m = _ARRAY_INDEX_RE.match(key)
  31. if m:
  32. array_key = m.group(1)
  33. array_index = int(m.group(2))
  34. if isinstance(current, dict):
  35. current = current.get(array_key)
  36. else:
  37. return None
  38. if isinstance(current, list):
  39. current = current[array_index] if 0 <= array_index < len(current) else None
  40. else:
  41. return None
  42. else:
  43. if isinstance(current, dict):
  44. current = current.get(key)
  45. elif isinstance(current, list):
  46. try:
  47. index = int(key)
  48. current = current[index] if 0 <= index < len(current) else None
  49. except (ValueError, IndexError):
  50. return None
  51. else:
  52. return None
  53. return current