Pyteryx/alteryx_runner/engine/context.py

53 lines
1.8 KiB
Python

from __future__ import annotations
import tempfile
from pathlib import Path
import duckdb
from .type_mapper import TypeMapper
from expression.transpiler import ExpressionTranspiler
class RunContext:
def __init__(
self,
workflow_dir: str,
verbose: bool = False,
output_dir: str | None = None,
params: dict | None = None,
):
self.workflow_dir = Path(workflow_dir)
self.verbose = verbose
self.output_dir: Path | None = Path(output_dir) if output_dir else None
self.duckdb_con = duckdb.connect(":memory:")
self.temp_dir = Path(tempfile.mkdtemp(prefix="alteryx_runner_"))
self.type_mapper = TypeMapper()
self.transpiler = ExpressionTranspiler(self.duckdb_con)
self.constants: dict = params or {}
def resolve_path(self, path: str) -> Path:
# Normalise Windows backslashes so relative segments like .. work on
# POSIX platforms (workflow XMLs are authored on Windows).
path = path.replace("\\", "/")
path = path.replace("%temp%", str(self.temp_dir) + "/")
path = path.replace("%Desktop%", str(Path.home() / "Desktop") + "/")
# Substitute workflow constants
for k, v in self.constants.items():
path = path.replace(f"%{k}%", v)
p = Path(path)
if not p.is_absolute():
p = self.workflow_dir / p
# If output_dir override active, remap file-write destinations
return p
def resolve_output_path(self, path: str) -> Path:
p = self.resolve_path(path)
if self.output_dir is not None:
return self.output_dir / p.name
return p
def __del__(self):
try:
self.duckdb_con.close()
except Exception:
pass