Improve CLI DX
This commit is contained in:
parent
df1c9418ee
commit
fbfb7ab1ce
4 changed files with 111 additions and 36 deletions
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
|
|
@ -6,6 +6,7 @@
|
||||||
"iloc",
|
"iloc",
|
||||||
"inplace",
|
"inplace",
|
||||||
"levelno",
|
"levelno",
|
||||||
|
"matplotlib",
|
||||||
"plotly",
|
"plotly",
|
||||||
"psutil",
|
"psutil",
|
||||||
"pydantic",
|
"pydantic",
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,51 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import re
|
import re
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
from sys import argv
|
|
||||||
|
|
||||||
import uvicorn
|
import uvicorn
|
||||||
from uvicorn.config import LOGGING_CONFIG
|
from uvicorn.config import LOGGING_CONFIG
|
||||||
|
|
||||||
from .great_ai.context import get_context
|
from .great_ai.context import get_context
|
||||||
from .great_ai.exceptions import MissingArgumentError
|
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:
|
def main() -> None:
|
||||||
if len(argv) < 2:
|
args = parse_arguments()
|
||||||
raise MissingArgumentError(f"Provide a filename such as: {argv[0]} my_app.py")
|
|
||||||
|
|
||||||
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)
|
if not function_name:
|
||||||
get_context().logger.info("Starting server")
|
logger.warning(f"Argument function_name not provided, trying to guess it")
|
||||||
|
|
||||||
if ":" not in module_name:
|
if not function_name and "app" in module.__dict__:
|
||||||
module_name += ":app"
|
function_name = "app"
|
||||||
get_context().logger.warning(
|
|
||||||
'Service name (name of variable) is assumed to be "app",'
|
if not function_name and file_name in module.__dict__:
|
||||||
+ " such as: `app = create_service(predict_domain)`"
|
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(
|
uvicorn.run(
|
||||||
module_name,
|
app_name,
|
||||||
host="0.0.0.0",
|
host=args.host,
|
||||||
port=6060,
|
port=args.port,
|
||||||
timeout_keep_alive=600,
|
timeout_keep_alive=args.timeout_keep_alive,
|
||||||
workers=1,
|
workers=args.workers,
|
||||||
reload=not get_context().is_production,
|
reload=not get_context().is_production,
|
||||||
log_config={
|
log_config={
|
||||||
**LOGGING_CONFIG,
|
**LOGGING_CONFIG,
|
||||||
|
|
@ -55,6 +67,6 @@ if __name__ == "__main__":
|
||||||
try:
|
try:
|
||||||
main()
|
main()
|
||||||
except (MissingArgumentError, ModuleNotFoundError) as e:
|
except (MissingArgumentError, ModuleNotFoundError) as e:
|
||||||
get_context().logger.error(e)
|
logger.error(e)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
exit()
|
exit()
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,10 @@ from great_ai.utilities.logger import create_logger
|
||||||
from .large_file import LargeFile
|
from .large_file import LargeFile
|
||||||
from .parse_arguments import parse_arguments
|
from .parse_arguments import parse_arguments
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
logger = create_logger("open_s3")
|
logger = create_logger("open_s3")
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
parser, args = parse_arguments()
|
parser, args = parse_arguments()
|
||||||
|
|
||||||
LargeFile.configure_credentials_from_file(args.secrets)
|
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:
|
if not args.cache and not args.push and not args.delete:
|
||||||
logger.warning("No action required.")
|
logger.warning("No action required.")
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
try:
|
|
||||||
if args.cache:
|
if args.cache:
|
||||||
for c in args.cache:
|
for c in args.cache:
|
||||||
split = c.split(":")
|
split = c.split(":")
|
||||||
|
|
@ -32,6 +34,11 @@ if __name__ == "__main__":
|
||||||
if args.delete:
|
if args.delete:
|
||||||
for f in args.delete:
|
for f in args.delete:
|
||||||
LargeFile(f).delete()
|
LargeFile(f).delete()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
main()
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
logger.warning("Exiting")
|
logger.warning("Exiting")
|
||||||
exit()
|
exit()
|
||||||
|
|
|
||||||
55
great_ai/src/great_ai/parse_arguments.py
Normal file
55
great_ai/src/great_ai/parse_arguments.py
Normal 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()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue