Skip to content

Commit 882bbd3

Browse files
FedeMarchiniHotovosudiptatjeupharisaarongoin
authored
Road to production 🚀 (#27)
* # Feature (2970): Update python client to support setup command (#22) * # Feature (2970): Update python client to support setup command - Function add command now support --execution-api-key - Extra Old Function call removed * improve polyapi-python setup (#24) * improve polyapi-python setup * # Feature (3019): improve polyapi-python setup (#25) * # Feature (3019): improve polyapi-python setup * # Feature (3019): improve polyapi-python setup - UUID Validation check added --------- Co-authored-by: Sudipta at TechJays <sudipta.kumar@techjays.com> * # Feature (3007): Update python -m polyapi function add --logs options (#23) * # Feature (3007): Update python -m polyapi function add --logs options - if --logs added, then value must enabled or disabled - If Nothing passed the value is default disabled - pyproject.toml version updated * Project Glide + Refactor main command line args parsing (#26) * Refactor main command line args parsing, adding prepare and sync commands to enable project glide workflows for python * improved tests * updating version * fix for poly cache directory path construction * one more adjustment to the deployables cache directory so there can't be any conflict with any custom namespace * this better? * verbose logging on upload code to see what's failing in CI/CD * bumpity * whoops * so close * better? * okay this should be the fix * is it this? * maybe * oh for the love of pete * whatever. might be a pypi issue * removing verbose logging * fixing bugs in sync command to use correct api urls * update logging * lint * improved auth * last fix for function sync * fix bug when comment arguments don't align with the function * try forcing the poly directory to exist * test logging * remove debug logging * fixing project glide deployable types and bumping the version * fixing missing arguments in python client function upload * fixing return type for trained functions * fix bug preventing use of poly sync command locally * next version of client! --------- Co-authored-by: Sudipta at TechJays <sudipta.kumar@techjays.com> Co-authored-by: Dan Fellin <dan@polyapi.io> Co-authored-by: Aaron Goin <aarongoin@users.noreply.github.com> Co-authored-by: Dan Fellin <dan@highwaterlabs.com>
1 parent 44b5156 commit 882bbd3

17 files changed

+1740
-364
lines changed

‎.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
.env
22
.env*
3+
.venv/
4+
.venv/*
35
.DS_Store
46

57
# Pip

‎polyapi/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616

1717

1818
polyCustom: Dict[str, Any] = {
19-
"executionId": None,
20-
"executionApiKey": None,
21-
"responseStatusCode": 200,
22-
"responseContentType": None,
19+
"executionId": None,
20+
"executionApiKey": None,
21+
"responseStatusCode": 200,
22+
"responseContentType": None,
2323
}

‎polyapi/cli.py

Lines changed: 168 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,188 @@
1+
import os
12
import argparse
23

3-
from polyapi.utils import print_green
4+
from polyapi.utils import print_green, print_red
45

5-
from .config import clear_config, set_api_key_and_url
6+
from .config import initialize_config, set_api_key_and_url
67
from .generate import generate, clear
78
from .function_cli import function_add_or_update, function_execute
89
from .rendered_spec import get_and_update_rendered_spec
10+
from .prepare import prepare_deployables
11+
from .sync import sync_deployables
912

1013

1114
CLI_COMMANDS = ["setup", "generate", "function", "clear", "help", "update_rendered_spec"]
1215

13-
CLIENT_DESC = """Commands
14-
python -m polyapi setup Setup your Poly connection
15-
python -m polyapi generate Generates Poly library
16-
python -m polyapi function <command> Manages functions
17-
python -m polyapi clear Clear current generated Poly library
18-
"""
19-
20-
21-
def execute_from_cli() -> None:
16+
def execute_from_cli():
17+
# First we setup all our argument parsing logic
18+
# Then we parse the arguments (waaay at the bottom)
2219
parser = argparse.ArgumentParser(
23-
prog="python -m polyapi", description=CLIENT_DESC, formatter_class=argparse.RawTextHelpFormatter
20+
prog="python -m polyapi",
21+
description="Manage your Poly API configurations and functions",
22+
formatter_class=argparse.RawTextHelpFormatter
2423
)
25-
parser.add_argument("--context", required=False, default="")
26-
parser.add_argument("--description", required=False, default="")
27-
parser.add_argument("--client", action="store_true", help="Pass --client when adding function to add a client function.")
28-
parser.add_argument("--server", action="store_true", help="Pass --server when adding function to add a server function.")
29-
parser.add_argument("--logs", action="store_true", help="Pass --logs when adding function if you want to store and see the function logs.")
30-
parser.add_argument("--skip-generate", action="store_true", help="Pass --skip-generate to skip generating the library after adding a function.")
31-
parser.add_argument("command", choices=CLI_COMMANDS)
32-
parser.add_argument("subcommands", nargs="*")
33-
args = parser.parse_args()
34-
command = args.command
35-
36-
if command == "help":
37-
parser.print_help()
38-
elif command == "generate":
24+
25+
subparsers = parser.add_subparsers(help="Available commands")
26+
27+
###########################################################################
28+
# Setup command
29+
setup_parser = subparsers.add_parser("setup", help="Setup your Poly connection")
30+
setup_parser.add_argument("api_key", nargs="?", help="API key for Poly API")
31+
setup_parser.add_argument("url", nargs="?", help="URL for the Poly API")
32+
33+
def setup(args):
34+
if args.api_key and args.url:
35+
set_api_key_and_url(args.url, args.api_key)
36+
else:
37+
initialize_config(force=True)
38+
generate()
39+
40+
setup_parser.set_defaults(command=setup)
41+
42+
43+
###########################################################################
44+
# Generate command
45+
generate_parser = subparsers.add_parser("generate", help="Generates Poly library")
46+
47+
def generate_command(args):
48+
initialize_config()
3949
print("Generating Poly functions...", end="")
4050
generate()
4151
print_green("DONE")
42-
elif command == "setup" and len(args.subcommands) == 2:
43-
set_api_key_and_url(args.subcommands[1], args.subcommands[0])
44-
elif command == "setup":
45-
clear_config()
46-
generate()
47-
elif command == "update_rendered_spec":
48-
assert len(args.subcommands) == 1
49-
updated = get_and_update_rendered_spec(args.subcommands[0])
52+
53+
generate_parser.set_defaults(command=generate_command)
54+
55+
56+
###########################################################################
57+
# Function commands
58+
fn_parser = subparsers.add_parser("function", help="Manage and execute functions")
59+
fn_subparsers = fn_parser.add_subparsers(help="Available commands")
60+
61+
# Function - Add command
62+
fn_add_parser = fn_subparsers.add_parser("add", help="Add or update the function")
63+
fn_add_parser.add_argument("name", help="Name of the function")
64+
fn_add_parser.add_argument("file", help="Path to the function file")
65+
fn_add_parser.add_argument("--context", required=False, default="", help="Context of the function")
66+
fn_add_parser.add_argument("--description", required=False, default="", help="Description of the function")
67+
fn_add_parser.add_argument("--server", action="store_true", help="Marks the function as a server function")
68+
fn_add_parser.add_argument("--client", action="store_true", help="Marks the function as a client function")
69+
fn_add_parser.add_argument("--logs", choices=["enabled", "disabled"], default="disabled", help="Enable or disable logs for the function.")
70+
fn_add_parser.add_argument("--execution-api-key", required=False, default="", help="API key for execution (for server functions only).")
71+
fn_add_parser.add_argument("--disable-ai", "--skip-generate", action="store_true", help="Pass --disable-ai skip AI generation of missing descriptions")
72+
73+
def add_function(args):
74+
initialize_config()
75+
logs_enabled = args.logs == "enabled"
76+
err = ""
77+
if args.server and args.client:
78+
err = "Specify either `--server` or `--client`. Found both."
79+
elif not args.server and not args.client:
80+
err = "You must specify `--server` or `--client`."
81+
elif logs_enabled and not args.server:
82+
err = "Option `logs` is only for server functions (--server)."
83+
84+
if err:
85+
print_red("ERROR")
86+
print(err)
87+
exit(1)
88+
89+
function_add_or_update(
90+
name=args.name,
91+
file=args.file,
92+
context=args.context,
93+
description=args.description,
94+
client=args.client,
95+
server=args.server,
96+
logs_enabled=logs_enabled,
97+
generate=not args.disable_ai,
98+
execution_api_key=args.execution_api_key
99+
)
100+
101+
fn_add_parser.set_defaults(command=add_function)
102+
103+
104+
# Function - Execute command
105+
fn_exec_parser = fn_subparsers.add_parser("execute", help="Execute a function with the provided arguments")
106+
fn_exec_parser.add_argument("name", help="Name of the function")
107+
fn_exec_parser.add_argument("args", nargs="*", help="Arguments for the function")
108+
fn_exec_parser.add_argument("--context", required=False, default="", help="Context of the function")
109+
110+
def execute_function(args):
111+
initialize_config()
112+
print(function_execute(args.context, args.name, args.args))
113+
114+
fn_exec_parser.set_defaults(command=execute_function)
115+
116+
117+
###########################################################################
118+
# Clear command
119+
clear_parser = subparsers.add_parser("clear", help="Clear current generated Poly library")
120+
121+
def clear_command(_):
122+
print("Clearing the generated library...")
123+
clear()
124+
125+
clear_parser.set_defaults(command=clear_command)
126+
127+
128+
###########################################################################
129+
# Update rendered spec command
130+
update_spec_parser = subparsers.add_parser("update_rendered_spec", help="Update the rendered spec file")
131+
update_spec_parser.add_argument("spec", help="Specification file to update")
132+
133+
def update_rendered_spec(args):
134+
updated = get_and_update_rendered_spec(args.spec)
50135
if updated:
51136
print("Updated rendered spec!")
52137
else:
53138
print("Failed to update rendered spec!")
54139
exit(1)
55-
elif command == "clear":
56-
print("Clearing the generated library...")
57-
clear()
58-
elif command == "function":
59-
if args.subcommands[0] == "execute":
60-
print(function_execute(args.context, args.subcommands))
61-
else:
62-
function_add_or_update(args.context, args.description, args.client, args.server, args.logs, args.subcommands, not args.skip_generate)
140+
141+
update_spec_parser.set_defaults(command=update_rendered_spec)
142+
143+
144+
###########################################################################
145+
# Prepare command
146+
prepare_parser = subparsers.add_parser('prepare', help="Find and prepare all Poly deployables")
147+
prepare_parser.add_argument("--lazy", action="store_true", help="Skip prepare work if the cache is up to date. (Relies on `git`)")
148+
prepare_parser.add_argument("--disable-docs", action="store_true", help="Don't write any docstrings into the deployable files.")
149+
prepare_parser.add_argument("--disable-ai", action="store_true", help="Don't use AI to fill in any missing descriptions.")
150+
151+
def prepare(args):
152+
initialize_config()
153+
disable_ai = args.disable_ai or bool(os.getenv("DISABLE_AI"))
154+
prepare_deployables(lazy=args.lazy, disable_docs=args.disable_docs, disable_ai=disable_ai)
155+
156+
prepare_parser.set_defaults(command=prepare)
157+
158+
159+
###########################################################################
160+
# Sync command
161+
sync_parser = subparsers.add_parser("sync", help="Find and sync all Poly deployables")
162+
sync_parser.add_argument("--dry-run", action="store_true", help="Run through sync steps with logging but don't make any changes.")
163+
164+
def sync(args):
165+
initialize_config()
166+
prepare_deployables(lazy=True, disable_docs=True, disable_ai=True)
167+
if args.dry_run:
168+
print("Running dry-run of sync...")
169+
sync_deployables(dry_run=args.dry_run)
170+
print("Poly deployments synced.")
171+
172+
sync_parser.set_defaults(command=sync)
173+
174+
###########################################################################
175+
# _------. #
176+
# / , \_ __ __ _ ________ #
177+
# / / /{}\ |o\_ / / ___ / /( )_____ / ____/ /_ __ #
178+
# / \ `--' /-' \ / / / _ \/ __/// ___/ / /_ / / / / / #
179+
# | \ \ | / /___/ __/ /_ (__ ) / __/ / / /_/ / #
180+
# | |`-, | /_____/\___/\__/ /____/ /_/ /_/\__, / #
181+
# / /__/)/ /____/ #
182+
# / | #
183+
###########################################################################
184+
parsed_args = parser.parse_args()
185+
if hasattr(parsed_args, "command"):
186+
parsed_args.command(parsed_args)
187+
else:
188+
parser.print_help()

‎polyapi/config.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import configparser
44
from typing import Tuple
55

6+
from polyapi.utils import is_valid_polyapi_url, is_valid_uuid, print_green, print_yellow
7+
68
# cached values
79
API_KEY = None
810
API_URL = None
@@ -55,18 +57,34 @@ def set_api_key_and_url(key: str, url: str):
5557
config.write(f)
5658

5759

58-
def initialize_config():
60+
def initialize_config(force=False):
5961
key, url = get_api_key_and_url()
60-
if not key or not url:
62+
if force or (not key or not url):
63+
url = url or "https://na1.polyapi.io"
6164
print("Please setup your connection to PolyAPI.")
62-
url = input("? Poly API Base URL (https://na1.polyapi.io): ") or "https://na1.polyapi.io"
63-
key = input("? Poly App Key or User Key: ")
65+
url = input(f"? Poly API Base URL ({url}): ").strip() or url
66+
67+
if not key:
68+
key = input("? Poly App Key or User Key: ").strip()
69+
else:
70+
key_input = input(f"? Poly App Key or User Key ({key}): ").strip()
71+
key = key_input if key_input else key
6472

6573
if url and key:
74+
errors = []
75+
if not is_valid_polyapi_url(url):
76+
errors.append(f"{url} is not a valid Poly API Base URL")
77+
if not is_valid_uuid(key):
78+
errors.append(f"{key} is not a valid Poly App Key or User Key")
79+
if errors:
80+
print_yellow("\n".join(errors))
81+
sys.exit(1)
82+
6683
set_api_key_and_url(key, url)
84+
print_green(f"Poly setup complete.")
6785

6886
if not key or not url:
69-
print("Poly API Key and Poly API Base URL are required.")
87+
print_yellow("Poly API Key and Poly API Base URL are required.")
7088
sys.exit(1)
7189

7290
return key, url

0 commit comments

Comments
 (0)