diff --git a/.vscode/settings.json b/.vscode/settings.json index fbf0fd2..6ffc536 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,6 +6,7 @@ "iloc", "inplace", "levelno", + "matplotlib", "plotly", "psutil", "pydantic", diff --git a/great_ai/src/great_ai/__main__.py b/great_ai/src/great_ai/__main__.py index a94af48..928a8c5 100644 --- a/great_ai/src/great_ai/__main__.py +++ b/great_ai/src/great_ai/__main__.py @@ -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() diff --git a/great_ai/src/great_ai/open_s3/__main__.py b/great_ai/src/great_ai/open_s3/__main__.py index 901f8c9..2d83500 100644 --- a/great_ai/src/great_ai/open_s3/__main__.py +++ b/great_ai/src/great_ai/open_s3/__main__.py @@ -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") +logger = create_logger("open_s3") + + +def main() -> None: parser, args = parse_arguments() LargeFile.configure_credentials_from_file(args.secrets) @@ -16,22 +18,27 @@ if __name__ == "__main__": if not args.cache and not args.push and not args.delete: logger.warning("No action required.") parser.print_help() + + if args.cache: + for c in args.cache: + split = c.split(":") + file_name = split[0] + version = None if len(split) == 1 else int(split[1]) + LargeFile(file_name, "r", version=version).get() + + if args.push: + for p in args.push: + path = Path(p) + LargeFile(path.name, "w").push(path) + + if args.delete: + for f in args.delete: + LargeFile(f).delete() + + +if __name__ == "__main__": try: - if args.cache: - for c in args.cache: - split = c.split(":") - file_name = split[0] - version = None if len(split) == 1 else int(split[1]) - LargeFile(file_name, "r", version=version).get() - - if args.push: - for p in args.push: - path = Path(p) - LargeFile(path.name, "w").push(path) - - if args.delete: - for f in args.delete: - LargeFile(f).delete() + main() except KeyboardInterrupt: logger.warning("Exiting") exit() diff --git a/great_ai/src/great_ai/parse_arguments.py b/great_ai/src/great_ai/parse_arguments.py new file mode 100644 index 0000000..c68f8b2 --- /dev/null +++ b/great_ai/src/great_ai/parse_arguments.py @@ -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()