From 9d17abbb12463c81de325eef875161cf86449b25 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Wed, 16 Nov 2022 14:08:55 +0100 Subject: [PATCH] feat(python): add Resource[resource_type] as a parsed parameter --- backend/parsers/windmill-parser-py/src/lib.rs | 40 ++++++++++++---- frontend/src/lib/script_helpers.ts | 11 ++--- python-client/.vscode/settings.json | 3 ++ python-client/wmill/wmill/client.py | 46 +++++++++++++------ 4 files changed, 70 insertions(+), 30 deletions(-) create mode 100644 python-client/.vscode/settings.json diff --git a/backend/parsers/windmill-parser-py/src/lib.rs b/backend/parsers/windmill-parser-py/src/lib.rs index cad7da63d5..c9d214cd22 100644 --- a/backend/parsers/windmill-parser-py/src/lib.rs +++ b/backend/parsers/windmill-parser-py/src/lib.rs @@ -106,21 +106,35 @@ pub fn parse_python_signature(code: &str) -> error::Result { "datetime.datetime" => Typ::Datetime, _ => Typ::Unknown, }, + Located { node: ExprKind::Subscript { slice, value, .. }, .. } => { + match (*value, *slice) { + ( + Located { node: ExprKind::Name { id, .. }, .. }, + Located { + node: + ExprKind::Constant { + value: Constant::Str(resource_name), + .. + }, + .. + }, + ) if id == "Resource" || id.ends_with(".Resource") => { + Typ::Resource(resource_name) + } + _ => Typ::Unknown, + } + } _ => Typ::Unknown, }); + if typ == Typ::Unknown && default.is_some() && default != Some(json!(FUNCTION_CALL)) { typ = json_to_typ(default.as_ref().unwrap()); } - Arg { - otyp: None, - name: x.arg, - typ: typ, - has_default: default.is_some(), - default, - } + + Arg { otyp: None, name: x.arg, typ, has_default: default.is_some(), default } }) .collect(), }) @@ -332,7 +346,8 @@ import os def main(test1: str, name: datetime.datetime = datetime.now(), - byte: bytes = bytes(1)): + byte: bytes = bytes(1), + resource: Resource['postgres'] = \"g/all/resource\"): print(f\"Hello World and a warm welcome especially to {name}\") print(\"The env variable at `all/pretty_secret`: \", os.environ.get(\"ALL_PRETTY_SECRET\")) @@ -366,6 +381,13 @@ def main(test1: str, typ: Typ::Bytes, default: Some(json!("")), has_default: true + }, + Arg { + otyp: None, + name: "resource".to_string(), + typ: Typ::Resource("postgres".to_string()), + default: Some(json!("g/all/resource")), + has_default: true } ] } @@ -435,7 +457,7 @@ def main(): "; let r = parse_python_imports(code)?; - println!("{}", serde_json::to_string(&r)?); + // println!("{}", serde_json::to_string(&r)?); assert_eq!(r, vec!["wmill", "zanzibar", "matplotlib"]); Ok(()) } diff --git a/frontend/src/lib/script_helpers.ts b/frontend/src/lib/script_helpers.ts index 251a926d5a..ec26b83303 100644 --- a/frontend/src/lib/script_helpers.ts +++ b/frontend/src/lib/script_helpers.ts @@ -1,8 +1,7 @@ import type { Script } from "./gen" export const PYTHON_INIT_CODE = `import os -import wmill -from datetime import datetime +from wmill import * """ Use Cmd/Ctrl + S to autoformat the code. @@ -16,7 +15,7 @@ def main(no_default: str, obj: dict = {"even": "dicts"}, l: list = ["or", "lists!"], file_: bytes = bytes(0), - dtime: datetime = datetime.now()): + db: Resource["postgresql"] = "g/all/demodb"): """A main function is required for the script to be able to accept arguments. Types are recommended.""" print(f"Hello World and a warm welcome especially to {name}") @@ -25,7 +24,7 @@ def main(no_default: str, # secret fetching is audited by windmill. try: - secret = wmill.get_variable("g/all/pretty_secret") + secret = get_variable("g/all/pretty_secret") except: secret = "No secret yet at g/all/pretty_secret!" @@ -38,9 +37,9 @@ def main(no_default: str, return {"version": version, "splitted": name.split(), "user": user} ` export const DENO_INIT_CODE = `// reload the smart assistant on the top right if it dies to get autocompletion and syntax highlighting -// (Ctrl+space to cache dependencies on imports hover). +// (Ctrl+space to cache dependencies on imports hover, Ctrl+S to autoformat and parse parameters). -// you can use npm imports directly! +// you can use npm imports directly // import { toWords } from "npm:number-to-words@1" // import * as wmill from "https://deno.land/x/windmill@v${__pkg__.version}/mod.ts" diff --git a/python-client/.vscode/settings.json b/python-client/.vscode/settings.json new file mode 100644 index 0000000000..dc3f727cad --- /dev/null +++ b/python-client/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.analysis.typeCheckingMode": "basic" +} diff --git a/python-client/wmill/wmill/client.py b/python-client/wmill/wmill/client.py index d897d852d1..9eb3b1d407 100644 --- a/python-client/wmill/wmill/client.py +++ b/python-client/wmill/wmill/client.py @@ -9,23 +9,37 @@ from windmill_api.api.settings import backend_version from windmill_api.api.job import run_script_by_hash, get_job, get_completed_job from windmill_api.api.resource import get_resource as get_resource_api -from windmill_api.api.resource import exists_resource as exists_resource_api -from windmill_api.api.resource import update_resource as update_resource_api -from windmill_api.api.resource import create_resource as create_resource_api from windmill_api.api.variable import get_variable as get_variable_api -from windmill_api.api.variable import exists_variable as exists_variable_api -from windmill_api.api.variable import update_variable as update_variable_api -from windmill_api.api.variable import create_variable as create_variable_api +from windmill_api.api.resource import exists_resource, update_resource, create_resource +from windmill_api.api.variable import exists_variable, update_variable, create_variable + +from windmill_api.models.update_resource_json_body import UpdateResourceJsonBody from windmill_api.models.create_variable_json_body import CreateVariableJsonBody -from windmill_api.models import * +from windmill_api.models.update_variable_json_body import UpdateVariableJsonBody +from windmill_api.models.create_resource_json_body import CreateResourceJsonBody from windmill_api.models.get_job_response_200_type import GetJobResponse200Type + from windmill_api.models.run_script_by_hash_json_body import RunScriptByHashJsonBody + from enum import Enum from windmill_api.types import Unset +from typing import Generic, TypeVar, TypeAlias + +S = TypeVar("S") + + +class Resource(Generic[S]): + pass + + +postgresql = TypeAlias +mysql = TypeAlias +bigquery = TypeAlias + VAR_RESOURCE_PREFIX = "$var:" @@ -51,7 +65,9 @@ def create_client( token_: str = token or os.environ.get("WM_TOKEN") or "" global _client if _client is None: - _client = AuthenticatedClient(base_url=base_url_, token=token_, timeout=30) + _client = AuthenticatedClient( + base_url=base_url_, token=token_, timeout=30, verify_ssl=False + ) return _client @@ -74,7 +90,7 @@ def get_version() -> str: def run_script_async( hash: str, args: Dict[str, Any] = {}, - scheduled_in_secs: Union[None, float] = None, + scheduled_in_secs: Union[None, int] = None, ) -> str: """ Launch the run of a script and return immediately its job id @@ -181,10 +197,10 @@ def set_resource( path = path or get_state_path() workspace = get_workspace() client = create_client() - if not exists_resource_api.sync_detailed( + if not exists_resource.sync_detailed( workspace=workspace, path=path, client=client ).parsed: - create_resource_api.sync_detailed( + create_resource.sync_detailed( workspace=workspace, client=client, json_body=CreateResourceJsonBody( @@ -192,7 +208,7 @@ def set_resource( ), ) else: - update_resource_api.sync_detailed( + update_resource.sync_detailed( workspace=get_workspace(), client=client, path=path, @@ -228,10 +244,10 @@ def set_variable(path: str, value: str) -> None: """ workspace = get_workspace() client = create_client() - if not exists_variable_api.sync_detailed( + if not exists_variable.sync_detailed( workspace=workspace, path=path, client=client ).parsed: - create_variable_api.sync_detailed( + create_variable.sync_detailed( workspace=workspace, client=client, json_body=CreateVariableJsonBody( @@ -239,7 +255,7 @@ def set_variable(path: str, value: str) -> None: ), ) else: - update_variable_api.sync_detailed( + update_variable.sync_detailed( workspace=get_workspace(), path=path, client=client,