"""Genererar ett fristående Python-script från ett sparat flöde.
Det exporterade scriptet importerar rpa-paketet och anropar samma
run_flow()-motor som webui:t använder - ingen logik dupliceras, så
beteendet blir identiskt med att köra flödet via "Kör flöde".
"""
from pprint import pformat
from .migrate import flow_to_graph
SCRIPT_TEMPLATE = '''#!/usr/bin/env python
"""Fristående script, exporterat från flödet "{name}" (RPA-verktyg).
Kör med:
python {filename}.py
python {filename}.py --headless
python {filename}.py --close-mode never
python {filename}.py --set "Test" # använd ett sparat värde-set
python {filename}.py --var org_id=9 # sätt en indata-variabel (upprepbar)
Kräver att rpa-paketet finns tillgängligt (kör från projektroten där
rpa/ och data/ ligger, eller kopiera med hela rpa/-mappen och låt en
data/-mapp skapas bredvid scriptet vid första körningen).
"""
import argparse
from rpa import config
from rpa.flow_engine import run_flow
NODES = {nodes_json}
EDGES = {edges_json}
START = {start_json}
SUBFLOWS = {subflows_json}
SETTINGS = {settings_json}
INPUTS = {inputs_json}
INPUT_SETS = {input_sets_json}
def build_initial_vars(chosen_set, var_overrides):
resolved = {{}}
for inp in INPUTS:
if inp.get("name") and inp.get("default") not in (None, ""):
resolved[str(inp["name"])] = str(inp["default"])
if chosen_set:
if chosen_set not in INPUT_SETS:
raise SystemExit(f"Okänt värde-set: {{chosen_set!r}}. Tillgängliga: {{list(INPUT_SETS)}}")
resolved.update({{str(k): str(v) for k, v in INPUT_SETS[chosen_set].items()}})
for item in var_overrides or []:
if "=" not in item:
raise SystemExit(f"--var förväntar NAMN=VÄRDE, fick: {{item!r}}")
k, v = item.split("=", 1)
resolved[k.strip()] = v
return resolved
def main() -> None:
parser = argparse.ArgumentParser(description="Kör flödet: {name}")
parser.add_argument(
"--headless", action="store_true",
help="Kör utan synligt webbläsarfönster (kräver en redan giltig inloggningssession)",
)
parser.add_argument(
"--close-mode", choices=["always", "on_success", "never"], default="always",
help="Vad som ska hända med webbläsaren när flödet är klart",
)
parser.add_argument("--set", dest="value_set", default=None, help="Namn på ett sparat värde-set")
parser.add_argument("--var", action="append", default=[], metavar="NAMN=VÄRDE",
help="Sätt en indata-variabel (kan upprepas)")
args = parser.parse_args()
settings = dict(SETTINGS)
if args.headless:
settings["headless"] = True
run_flow(
{{"format": "graph", "nodes": NODES, "edges": EDGES, "start": START, "subflows": SUBFLOWS}},
log=print,
download_dir=config.DOWNLOAD_DIR,
close_mode=args.close_mode,
settings=settings,
initial_vars=build_initial_vars(args.value_set, args.var),
)
if __name__ == "__main__":
main()
'''
def generate_standalone_script(name: str, flow: dict) -> str:
# pformat (inte json.dumps) - genererad kod är Python, inte JSON: JSON:s
# true/false/null är inte giltig Python-syntax (True/False/None krävs).
def src(value):
return pformat(value, indent=2, width=100, sort_dicts=False)
g = flow_to_graph(flow)
return SCRIPT_TEMPLATE.format(
name=name,
filename=name,
nodes_json=src(g.get("nodes", [])),
edges_json=src(g.get("edges", [])),
start_json=src(g.get("start")),
subflows_json=src(flow.get("subflows", [])),
settings_json=src(flow.get("settings", {})),
inputs_json=src(flow.get("inputs", [])),
input_sets_json=src(flow.get("input_sets", {})),
)