diff --git a/flake.nix b/flake.nix index 0a8f3b9138..de74558aa5 100644 --- a/flake.nix +++ b/flake.nix @@ -127,6 +127,7 @@ # Other languages deno + typescript nushell go bun diff --git a/python-client/dev.nu b/python-client/dev.nu index 11b92503de..bb30cf5cf1 100755 --- a/python-client/dev.nu +++ b/python-client/dev.nu @@ -1,6 +1,6 @@ #! /usr/bin/env nu -let cache = "/tmp/windmill/cache/python_311/" +let cache = "/tmp/windmill/cache/python_3_11/" # Clean cache def "main clean" [] { @@ -42,7 +42,7 @@ def main [ rm -rf ($cache ++ wmill*/wmill/*) # Copy files from local ./dist to every wm-client version in cache - ls /tmp/windmill/cache/python_311/wmill* | each { + ls /tmp/windmill/cache/python_3_11/wmill* | each { |i| let path = $i | get name; diff --git a/python-client/wmill/wmill/client.py b/python-client/wmill/wmill/client.py index a51fc6ce16..0908c2a06b 100644 --- a/python-client/wmill/wmill/client.py +++ b/python-client/wmill/wmill/client.py @@ -120,22 +120,58 @@ class Windmill: args: dict = None, scheduled_in_secs: int = None, ) -> str: - """Create a script job and return its job id.""" + """Create a script job and return its job id. + + .. deprecated:: Use run_script_by_path_async or run_script_by_hash_async instead. + """ + logging.warning( + "run_script_async is deprecated. Use run_script_by_path_async or run_script_by_hash_async instead.", + ) assert not (path and hash_), "path and hash_ are mutually exclusive" + return self._run_script_async_internal(path=path, hash_=hash_, args=args, scheduled_in_secs=scheduled_in_secs) + + def _run_script_async_internal( + self, + path: str = None, + hash_: str = None, + args: dict = None, + scheduled_in_secs: int = None, + ) -> str: + """Internal helper for running scripts asynchronously.""" args = args or {} params = {"scheduled_in_secs": scheduled_in_secs} if scheduled_in_secs else {} if os.environ.get("WM_JOB_ID"): params["parent_job"] = os.environ.get("WM_JOB_ID") if os.environ.get("WM_ROOT_FLOW_JOB_ID"): params["root_job"] = os.environ.get("WM_ROOT_FLOW_JOB_ID") + if path: endpoint = f"/w/{self.workspace}/jobs/run/p/{path}" elif hash_: endpoint = f"/w/{self.workspace}/jobs/run/h/{hash_}" else: raise Exception("path or hash_ must be provided") + return self.post(endpoint, json=args, params=params).text + def run_script_by_path_async( + self, + path: str, + args: dict = None, + scheduled_in_secs: int = None, + ) -> str: + """Create a script job by path and return its job id.""" + return self._run_script_async_internal(path=path, args=args, scheduled_in_secs=scheduled_in_secs) + + def run_script_by_hash_async( + self, + hash_: str, + args: dict = None, + scheduled_in_secs: int = None, + ) -> str: + """Create a script job by hash and return its job id.""" + return self._run_script_async_internal(hash_=hash_, args=args, scheduled_in_secs=scheduled_in_secs) + def run_flow_async( self, path: str, @@ -170,20 +206,76 @@ class Windmill: cleanup: bool = True, assert_result_is_not_none: bool = False, ) -> Any: - """Run script synchronously and return its result.""" + """Run script synchronously and return its result. + + .. deprecated:: Use run_script_by_path or run_script_by_hash instead. + """ + logging.warning( + "run_script is deprecated. Use run_script_by_path or run_script_by_hash instead.", + ) + assert not (path and hash_), "path and hash_ are mutually exclusive" + return self._run_script_internal( + path=path, hash_=hash_, args=args, timeout=timeout, verbose=verbose, + cleanup=cleanup, assert_result_is_not_none=assert_result_is_not_none + ) + + def _run_script_internal( + self, + path: str = None, + hash_: str = None, + args: dict = None, + timeout: dt.timedelta | int | float | None = None, + verbose: bool = False, + cleanup: bool = True, + assert_result_is_not_none: bool = False, + ) -> Any: + """Internal helper for running scripts synchronously.""" args = args or {} if verbose: - logger.info(f"running `{path}` synchronously with {args = }") + if path: + logger.info(f"running `{path}` synchronously with {args = }") + elif hash_: + logger.info(f"running script with hash `{hash_}` synchronously with {args = }") if isinstance(timeout, dt.timedelta): timeout = timeout.total_seconds() - job_id = self.run_script_async(path=path, hash_=hash_, args=args) + job_id = self._run_script_async_internal(path=path, hash_=hash_, args=args) return self.wait_job( job_id, timeout, verbose, cleanup, assert_result_is_not_none ) + def run_script_by_path( + self, + path: str, + args: dict = None, + timeout: dt.timedelta | int | float | None = None, + verbose: bool = False, + cleanup: bool = True, + assert_result_is_not_none: bool = False, + ) -> Any: + """Run script by path synchronously and return its result.""" + return self._run_script_internal( + path=path, args=args, timeout=timeout, verbose=verbose, + cleanup=cleanup, assert_result_is_not_none=assert_result_is_not_none + ) + + def run_script_by_hash( + self, + hash_: str, + args: dict = None, + timeout: dt.timedelta | int | float | None = None, + verbose: bool = False, + cleanup: bool = True, + assert_result_is_not_none: bool = False, + ) -> Any: + """Run script by hash synchronously and return its result.""" + return self._run_script_internal( + hash_=hash_, args=args, timeout=timeout, verbose=verbose, + cleanup=cleanup, assert_result_is_not_none=assert_result_is_not_none + ) + def wait_job( self, job_id, @@ -964,13 +1056,26 @@ def run_script_by_path_async( args: Dict[str, Any] = None, scheduled_in_secs: Union[None, int] = None, ) -> str: - return _client.run_script_async( + return _client.run_script_by_path_async( path=path, args=args, scheduled_in_secs=scheduled_in_secs, ) +@init_global_client +def run_script_by_hash_async( + hash_: str, + args: Dict[str, Any] = None, + scheduled_in_secs: Union[None, int] = None, +) -> str: + return _client.run_script_by_hash_async( + hash_=hash_, + args=args, + scheduled_in_secs=scheduled_in_secs, + ) + + @init_global_client def run_script_by_path_sync( path: str, @@ -1274,7 +1379,10 @@ def run_script( cleanup: bool = True, assert_result_is_not_none: bool = True, ) -> Any: - """Run script synchronously and return its result.""" + """Run script synchronously and return its result. + + .. deprecated:: Use run_script_by_path or run_script_by_hash instead. + """ return _client.run_script( path=path, hash_=hash_, @@ -1286,6 +1394,46 @@ def run_script( ) +@init_global_client +def run_script_by_path( + path: str, + args: dict = None, + timeout: dt.timedelta | int | float = None, + verbose: bool = False, + cleanup: bool = True, + assert_result_is_not_none: bool = True, +) -> Any: + """Run script by path synchronously and return its result.""" + return _client.run_script_by_path( + path=path, + args=args, + verbose=verbose, + assert_result_is_not_none=assert_result_is_not_none, + cleanup=cleanup, + timeout=timeout, + ) + + +@init_global_client +def run_script_by_hash( + hash_: str, + args: dict = None, + timeout: dt.timedelta | int | float = None, + verbose: bool = False, + cleanup: bool = True, + assert_result_is_not_none: bool = True, +) -> Any: + """Run script by hash synchronously and return its result.""" + return _client.run_script_by_hash( + hash_=hash_, + args=args, + verbose=verbose, + assert_result_is_not_none=assert_result_is_not_none, + cleanup=cleanup, + timeout=timeout, + ) + + @init_global_client def username_to_email(username: str) -> str: """ @@ -1374,4 +1522,4 @@ def parse_variable_syntax(s: str) -> Optional[str]: """Parse variable syntax from string.""" if s.startswith("var://"): return s[6:] - return None \ No newline at end of file + return None diff --git a/typescript-client/build.jsr.sh b/typescript-client/build.jsr.sh index e203c17fdf..b08b1c894e 100755 --- a/typescript-client/build.jsr.sh +++ b/typescript-client/build.jsr.sh @@ -14,5 +14,6 @@ cp "${script_dirpath}/s3Types.ts" "${script_dirpath}/src/" echo "" >> "${script_dirpath}/src/index.ts" echo 'export type { S3Object, DenoS3LightClientSettings } from "./s3Types";' >> "${script_dirpath}/src/index.ts" echo "" >> "${script_dirpath}/src/index.ts" -echo 'export { type Base64, setClient, getVariable, setVariable, getResource, setResource, getResumeUrls, setState, getState, getIdToken, denoS3LightClientSettings, loadS3FileStream, loadS3File, writeS3File, signS3Objects, signS3Object, task, runScript, runScriptAsync, runFlow, runFlowAsync, waitJob, getRootJobId, setFlowUserState, getFlowUserState, usernameToEmail, requestInteractiveSlackApproval, Sql, requestInteractiveTeamsApproval, } from "./client";' >> "${script_dirpath}/src/index.ts" +echo 'export { type Base64, setClient, getVariable, setVariable, getResource, setResource, getResumeUrls, setState, setProgress, getProgress, getState, getIdToken, denoS3LightClientSettings, loadS3FileStream, loadS3File, writeS3File, signS3Objects, signS3Object, task, runScript, runScriptAsync, runScriptByPath, runScriptByHash, runScriptByPathAsync, runScriptByHashAsync, runFlow, runFlowAsync, waitJob, getRootJobId, setFlowUserState, getFlowUserState, usernameToEmail, requestInteractiveSlackApproval, Sql, requestInteractiveTeamsApproval } from "./client";' >> "${script_dirpath}/src/index.ts" + diff --git a/typescript-client/build.sh b/typescript-client/build.sh index 4934c5e673..bb6be9338c 100755 --- a/typescript-client/build.sh +++ b/typescript-client/build.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -eou pipefail script_dirpath="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" @@ -39,4 +39,4 @@ cp "${script_dirpath}/s3Types.ts" "${script_dirpath}/src/" echo "" >> "${script_dirpath}/src/index.ts" echo 'export type { S3Object, DenoS3LightClientSettings } from "./s3Types";' >> "${script_dirpath}/src/index.ts" echo "" >> "${script_dirpath}/src/index.ts" -echo 'export { type Base64, setClient, getVariable, setVariable, getResource, setResource, getResumeUrls, setState, setProgress, getProgress, getState, getIdToken, denoS3LightClientSettings, loadS3FileStream, loadS3File, writeS3File, signS3Objects, signS3Object, task, runScript, runScriptAsync, runFlow, runFlowAsync, waitJob, getRootJobId, setFlowUserState, getFlowUserState, usernameToEmail, requestInteractiveSlackApproval, Sql, requestInteractiveTeamsApproval } from "./client";' >> "${script_dirpath}/src/index.ts" +echo 'export { type Base64, setClient, getVariable, setVariable, getResource, setResource, getResumeUrls, setState, setProgress, getProgress, getState, getIdToken, denoS3LightClientSettings, loadS3FileStream, loadS3File, writeS3File, signS3Objects, signS3Object, task, runScript, runScriptAsync, runScriptByPath, runScriptByHash, runScriptByPathAsync, runScriptByHashAsync, runFlow, runFlowAsync, waitJob, getRootJobId, setFlowUserState, getFlowUserState, usernameToEmail, requestInteractiveSlackApproval, Sql, requestInteractiveTeamsApproval } from "./client";' >> "${script_dirpath}/src/index.ts" diff --git a/typescript-client/client.ts b/typescript-client/client.ts index dfd2da2ce3..9ac146a64d 100644 --- a/typescript-client/client.ts +++ b/typescript-client/client.ts @@ -129,22 +129,58 @@ export async function getRootJobId(jobId?: string): Promise { return await JobService.getRootJobId({ workspace, id: jobId }); } +/** + * @deprecated Use runScriptByPath or runScriptByHash instead + */ export async function runScript( path: string | null = null, hash_: string | null = null, args: Record | null = null, verbose: boolean = false +): Promise { + console.warn('runScript is deprecated. Use runScriptByPath or runScriptByHash instead.'); + if (path && hash_) { + throw new Error("path and hash_ are mutually exclusive"); + } + return _runScriptInternal(path, hash_, args, verbose); +} + +async function _runScriptInternal( + path: string | null = null, + hash_: string | null = null, + args: Record | null = null, + verbose: boolean = false ): Promise { args = args || {}; if (verbose) { - console.info(`running \`${path}\` synchronously with args:`, args); + if (path) { + console.info(`running \`${path}\` synchronously with args:`, args); + } else if (hash_) { + console.info(`running script with hash \`${hash_}\` synchronously with args:`, args); + } } - const jobId = await runScriptAsync(path, hash_, args); + const jobId = await _runScriptAsyncInternal(path, hash_, args); return await waitJob(jobId, verbose); } +export async function runScriptByPath( + path: string, + args: Record | null = null, + verbose: boolean = false +): Promise { + return _runScriptInternal(path, null, args, verbose); +} + +export async function runScriptByHash( + hash_: string, + args: Record | null = null, + verbose: boolean = false +): Promise { + return _runScriptInternal(null, hash_, args, verbose); +} + export async function runFlow( path: string | null = null, args: Record | null = null, @@ -243,16 +279,30 @@ export function task(f: (_: P) => T): (_: P) => Promise { }; } +/** + * @deprecated Use runScriptByPathAsync or runScriptByHashAsync instead + */ export async function runScriptAsync( path: string | null, hash_: string | null, args: Record | null, scheduledInSeconds: number | null = null ): Promise { + console.warn('runScriptAsync is deprecated. Use runScriptByPathAsync or runScriptByHashAsync instead.'); // Create a script job and return its job id. if (path && hash_) { throw new Error("path and hash_ are mutually exclusive"); } + return _runScriptAsyncInternal(path, hash_, args, scheduledInSeconds); +} + +async function _runScriptAsyncInternal( + path: string | null = null, + hash_: string | null = null, + args: Record | null = null, + scheduledInSeconds: number | null = null +): Promise { + // Create a script job and return its job id. args = args || {}; const params: Record = {}; @@ -278,6 +328,7 @@ export async function runScriptAsync( } else { throw new Error("path or hash_ must be provided"); } + let url = new URL(OpenAPI.BASE + endpoint); url.search = new URLSearchParams(params).toString(); @@ -291,6 +342,22 @@ export async function runScriptAsync( }).then((res) => res.text()); } +export async function runScriptByPathAsync( + path: string, + args: Record | null = null, + scheduledInSeconds: number | null = null +): Promise { + return _runScriptAsyncInternal(path, null, args, scheduledInSeconds); +} + +export async function runScriptByHashAsync( + hash_: string, + args: Record | null = null, + scheduledInSeconds: number | null = null +): Promise { + return _runScriptAsyncInternal(null, hash_, args, scheduledInSeconds); +} + export async function runFlowAsync( path: string | null, args: Record | null,