feat(python): type is automatically inferred from default parameters

This commit is contained in:
Ruben Fiszel
2022-10-29 12:48:50 +02:00
parent b3d8d8e611
commit 84a3fbe46b
6 changed files with 64 additions and 48 deletions
+1 -1
View File
@@ -4353,7 +4353,7 @@ dependencies = [
[[package]]
name = "windmill-audit"
version = "0.1.0"
version = "1.41.0"
dependencies = [
"chrono",
"serde",
+33 -24
View File
@@ -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 = "<function call>";
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<MainArgSignature> {
} 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<serde_json::Value> {
.collect::<Vec<_>>();
Some(json!(v))
}
ExprKind::Call { .. } => Some(json!("<function call>")),
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!("<function call>")),
typ: Typ::Str(None),
default: Some(json!("test")),
has_default: true
},
Arg {
+1 -18
View File
@@ -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 {
@@ -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<serde_json::Value>,
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,
}
}
+3 -2
View File
@@ -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"
+9 -3
View File
@@ -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()