Improve CLI DX

This commit is contained in:
Andras Schmelczer 2022-05-25 22:54:40 +02:00
parent df1c9418ee
commit fbfb7ab1ce
No known key found for this signature in database
GPG key ID: 39260B5B0614A13E
4 changed files with 111 additions and 36 deletions

View file

@ -6,6 +6,7 @@
"iloc",
"inplace",
"levelno",
"matplotlib",
"plotly",
"psutil",
"pydantic",

View file

@ -1,39 +1,51 @@
#!/usr/bin/env python3
import re
from importlib import import_module
from sys import argv
import uvicorn
from uvicorn.config import LOGGING_CONFIG
from .great_ai.context import get_context
from .great_ai.exceptions import MissingArgumentError
from .parse_arguments import parse_arguments
from .utilities.logger import create_logger
logger = create_logger("GreatAI-Server")
def main() -> None:
if len(argv) < 2:
raise MissingArgumentError(f"Provide a filename such as: {argv[0]} my_app.py")
args = parse_arguments()
module_name = re.sub(r"\.py\b", "", argv[1])
file_name = re.sub(r"\.py$", "", args.file_name)
function_name = args.function_name
base = module_name.split(":")[0]
module = import_module(file_name)
import_module(base)
get_context().logger.info("Starting server")
if not function_name:
logger.warning(f"Argument function_name not provided, trying to guess it")
if ":" not in module_name:
module_name += ":app"
get_context().logger.warning(
'Service name (name of variable) is assumed to be "app",'
+ " such as: `app = create_service(predict_domain)`"
if not function_name and "app" in module.__dict__:
function_name = "app"
if not function_name and file_name in module.__dict__:
function_name = file_name
if function_name:
logger.warning(f"Found `{function_name}` as the value of function_name")
else:
raise MissingArgumentError(
"Argument function_name not provided and could not be guessed"
)
app_name = f"{file_name}:{function_name}"
logger.info(f"Starting uvicorn server with app={app_name}")
uvicorn.run(
module_name,
host="0.0.0.0",
port=6060,
timeout_keep_alive=600,
workers=1,
app_name,
host=args.host,
port=args.port,
timeout_keep_alive=args.timeout_keep_alive,
workers=args.workers,
reload=not get_context().is_production,
log_config={
**LOGGING_CONFIG,
@ -55,6 +67,6 @@ if __name__ == "__main__":
try:
main()
except (MissingArgumentError, ModuleNotFoundError) as e:
get_context().logger.error(e)
logger.error(e)
except KeyboardInterrupt:
exit()

View file

@ -7,8 +7,10 @@ from great_ai.utilities.logger import create_logger
from .large_file import LargeFile
from .parse_arguments import parse_arguments
if __name__ == "__main__":
logger = create_logger("open_s3")
def main() -> None:
parser, args = parse_arguments()
LargeFile.configure_credentials_from_file(args.secrets)
@ -16,7 +18,7 @@ if __name__ == "__main__":
if not args.cache and not args.push and not args.delete:
logger.warning("No action required.")
parser.print_help()
try:
if args.cache:
for c in args.cache:
split = c.split(":")
@ -32,6 +34,11 @@ if __name__ == "__main__":
if args.delete:
for f in args.delete:
LargeFile(f).delete()
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
logger.warning("Exiting")
exit()

View file

@ -0,0 +1,55 @@
from argparse import ArgumentParser, Namespace
def parse_arguments() -> Namespace:
parser = ArgumentParser(
description="GreatAI-Server for deploying you AI applications with ease.",
)
parser.add_argument(
"file_name",
type=str,
help="the name of the file containing your to-be-served function such as `main.py`\n",
)
parser.add_argument(
"--function_name",
type=str,
help="name of your inference function, defaults to the base name of the filename or the literal `app`",
default="",
required=False,
)
parser.add_argument(
"--host",
type=str,
help="it is passed to uvicorn which starts a server listening on this address",
default="0.0.0.0",
required=False,
)
parser.add_argument(
"--port",
type=int,
help="it is passed to uvicorn which starts a server listening on this port",
default=6060,
required=False,
)
parser.add_argument(
"--timeout_keep_alive",
type=int,
help="it is passed to uvicorn which uses it for timing out requests taking longer than this many seconds",
default=600,
required=False,
)
parser.add_argument(
"--workers",
type=int,
help="it is passed to uvicorn which starts this many server processes",
default=1,
required=False,
)
return parser.parse_args()