From 84a3fbe46b4efb321b3b676258b1fc59cd67b186 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Sat, 29 Oct 2022 12:48:50 +0200 Subject: [PATCH] feat(python): type is automatically inferred from default parameters --- backend/Cargo.lock | 2 +- backend/parsers/windmill-parser-py/src/lib.rs | 57 +++++++++++-------- backend/parsers/windmill-parser-ts/src/lib.rs | 19 +------ backend/parsers/windmill-parser/src/lib.rs | 17 ++++++ backend/windmill-audit/Cargo.toml | 5 +- frontend/src/lib/script_helpers.ts | 12 +++- 6 files changed, 64 insertions(+), 48 deletions(-) diff --git a/backend/Cargo.lock b/backend/Cargo.lock index aab9862080..f6ea991a99 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -4353,7 +4353,7 @@ dependencies = [ [[package]] name = "windmill-audit" -version = "0.1.0" +version = "1.41.0" dependencies = [ "chrono", "serde", diff --git a/backend/parsers/windmill-parser-py/src/lib.rs b/backend/parsers/windmill-parser-py/src/lib.rs index 8a980b6735..b268bd2529 100644 --- a/backend/parsers/windmill-parser-py/src/lib.rs +++ b/backend/parsers/windmill-parser-py/src/lib.rs @@ -14,7 +14,7 @@ use regex::Regex; use serde_json::json; use windmill_common::error; -use windmill_parser::{Arg, MainArgSignature, Typ}; +use windmill_parser::{json_to_typ, Arg, MainArgSignature, Typ}; use rustpython_parser::{ ast::{Constant, ExprKind, Located, StmtKind}, @@ -22,6 +22,7 @@ use rustpython_parser::{ }; const DEF_MAIN: &str = "def main("; +const FUNCTION_CALL: &str = ""; fn filter_non_main(code: &str) -> String { let mut filtered_code = String::new(); @@ -90,24 +91,32 @@ pub fn parse_python_signature(code: &str) -> error::Result { } else { None }; + + let mut typ = x.annotation.map_or(Typ::Unknown, |e| match *e { + Located { node: ExprKind::Name { id, .. }, .. } => match id.as_ref() { + "str" => Typ::Str(None), + "float" => Typ::Float, + "int" => Typ::Int, + "bool" => Typ::Bool, + "dict" => Typ::Object(vec![]), + "list" => Typ::List(Box::new(Typ::Str(None))), + "bytes" => Typ::Bytes, + "datetime" => Typ::Datetime, + "datetime.datetime" => Typ::Datetime, + _ => 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: x.annotation.map_or(Typ::Unknown, |e| match *e { - Located { node: ExprKind::Name { id, .. }, .. } => match id.as_ref() { - "str" => Typ::Str(None), - "float" => Typ::Float, - "int" => Typ::Int, - "bool" => Typ::Bool, - "dict" => Typ::Object(vec![]), - "list" => Typ::List(Box::new(Typ::Str(None))), - "bytes" => Typ::Bytes, - "datetime" => Typ::Datetime, - "datetime.datetime" => Typ::Datetime, - _ => Typ::Unknown, - }, - _ => Typ::Unknown, - }), + typ: typ, has_default: default.is_some(), default, } @@ -147,7 +156,7 @@ fn to_value(et: &ExprKind) -> Option { .collect::>(); Some(json!(v)) } - ExprKind::Call { .. } => Some(json!("")), + ExprKind::Call { .. } => Some(json!(FUNCTION_CALL)), _ => None, } } @@ -277,28 +286,28 @@ def main(test1: str, name: datetime.datetime = datetime.now(), byte: bytes = byt Arg { otyp: None, name: "f".to_string(), - typ: Typ::Unknown, + typ: Typ::Str(None), default: Some(json!("wewe")), has_default: true }, Arg { otyp: None, name: "g".to_string(), - typ: Typ::Unknown, + typ: Typ::Int, default: Some(json!(21)), has_default: true }, Arg { otyp: None, name: "h".to_string(), - typ: Typ::Unknown, + typ: Typ::List(Box::new(Typ::Int)), default: Some(json!([1, 2])), has_default: true }, Arg { otyp: None, name: "i".to_string(), - typ: Typ::Unknown, + typ: Typ::Bool, default: Some(json!(true)), has_default: true }, @@ -366,7 +375,7 @@ def main(test1: str, import os def main(test1: str, - name: datetime.datetime = datetime.now(), + name = \"test\", byte: bytes = bytes(1)): return "; @@ -387,8 +396,8 @@ def main(test1: str, Arg { otyp: None, name: "name".to_string(), - typ: Typ::Unknown, - default: Some(json!("")), + typ: Typ::Str(None), + default: Some(json!("test")), has_default: true }, Arg { diff --git a/backend/parsers/windmill-parser-ts/src/lib.rs b/backend/parsers/windmill-parser-ts/src/lib.rs index 1da385ac1c..ec2b382d01 100644 --- a/backend/parsers/windmill-parser-ts/src/lib.rs +++ b/backend/parsers/windmill-parser-ts/src/lib.rs @@ -7,9 +7,8 @@ */ use deno_core::{serde_v8, v8, JsRuntime, RuntimeOptions}; use windmill_common::error; -use windmill_parser::{Arg, MainArgSignature, ObjectProperty, Typ}; +use windmill_parser::{json_to_typ, Arg, MainArgSignature, ObjectProperty, Typ}; -use serde_json::Value; use swc_common::{sync::Lrc, FileName, SourceMap, SourceMapper, Spanned}; use swc_ecma_ast::{ ArrayLit, AssignPat, BigInt, BindingIdent, Bool, Decl, ExportDecl, Expr, FnDecl, Ident, Lit, @@ -130,22 +129,6 @@ fn binding_ident_to_arg(BindingIdent { id, type_ann }: &BindingIdent) -> (String (id.sym.to_string(), typ, nullable) } -fn json_to_typ(js: &Value) -> Typ { - match js { - Value::String(_) => Typ::Str(None), - Value::Number(n) if n.is_i64() => Typ::Int, - Value::Number(_) => Typ::Float, - Value::Bool(_) => Typ::Bool, - Value::Object(o) => Typ::Object( - o.iter() - .map(|(k, v)| ObjectProperty { key: k.to_string(), typ: Box::new(json_to_typ(v)) }) - .collect(), - ), - Value::Array(a) => Typ::List(Box::new(a.first().map(json_to_typ).unwrap_or(Typ::Unknown))), - _ => Typ::Unknown, - } -} - fn tstype_to_typ(ts_type: &TsType) -> (Typ, bool) { //println!("{:?}", ts_type); match ts_type { diff --git a/backend/parsers/windmill-parser/src/lib.rs b/backend/parsers/windmill-parser/src/lib.rs index 8a1318104d..ca597126e9 100644 --- a/backend/parsers/windmill-parser/src/lib.rs +++ b/backend/parsers/windmill-parser/src/lib.rs @@ -7,6 +7,7 @@ */ use serde::Serialize; +use serde_json::Value; #[derive(Serialize, Debug, PartialEq)] pub struct MainArgSignature { @@ -47,3 +48,19 @@ pub struct Arg { pub default: Option, pub has_default: bool, } + +pub fn json_to_typ(js: &Value) -> Typ { + match js { + Value::String(_) => Typ::Str(None), + Value::Number(n) if n.is_i64() => Typ::Int, + Value::Number(_) => Typ::Float, + Value::Bool(_) => Typ::Bool, + Value::Object(o) => Typ::Object( + o.iter() + .map(|(k, v)| ObjectProperty { key: k.to_string(), typ: Box::new(json_to_typ(v)) }) + .collect(), + ), + Value::Array(a) => Typ::List(Box::new(a.first().map(json_to_typ).unwrap_or(Typ::Unknown))), + _ => Typ::Unknown, + } +} diff --git a/backend/windmill-audit/Cargo.toml b/backend/windmill-audit/Cargo.toml index 34696a2b5e..f61eba72b2 100644 --- a/backend/windmill-audit/Cargo.toml +++ b/backend/windmill-audit/Cargo.toml @@ -1,7 +1,8 @@ [package] name = "windmill-audit" -version = "0.1.0" -edition = "2021" +version.workspace = true +authors.workspace = true +edition.workspace = true [lib] name = "windmill_audit" diff --git a/frontend/src/lib/script_helpers.ts b/frontend/src/lib/script_helpers.ts index 87d4cd3f9b..34d22fc48d 100644 --- a/frontend/src/lib/script_helpers.ts +++ b/frontend/src/lib/script_helpers.ts @@ -10,8 +10,9 @@ The client is used to interact with windmill itself through its standard API. One can explore the methods available through autocompletion of \`wmill.XXX\`. """ -def main(name: str = "Nicolas Bourbaki", - age: int = 42, +def main(name = "Nicolas Bourbaki", + age = 42, + with_type: str, obj: dict = {"even": "dicts"}, l: list = ["or", "lists!"], file_: bytes = bytes(0), @@ -22,7 +23,12 @@ def main(name: str = "Nicolas Bourbaki", print("and its acolytes..", age, obj, l, len(file_), dtime) # retrieve variables, including secrets by querying the windmill platform. # secret fetching is audited by windmill. - secret = wmill.get_variable("g/all/pretty_secret") + + try: + secret = wmill.get_variable("g/all/pretty_secret") + except: + secret = "No secret yet at g/all/pretty_secret!" + print(f"The env variable at \`g/all/pretty_secret\`: {secret}") # interact with the windmill platform to get the version version = wmill.get_version()