diff --git a/src/ohmyapi/cli.py b/src/ohmyapi/cli.py index 58b4f11..4f4a824 100644 --- a/src/ohmyapi/cli.py +++ b/src/ohmyapi/cli.py @@ -10,9 +10,6 @@ from ohmyapi.core import scaffolding, runtime from pathlib import Path app = typer.Typer(help="OhMyAPI — Django-flavored FastAPI scaffolding with tightly integrated TortoiseORM.") -banner = """OhMyAPI Shell | Project: {project_name} -Find your loaded project singleton via identifier: `p` -""" @app.command() @@ -40,52 +37,50 @@ def serve(root: str = ".", host="127.0.0.1", port=8000): @app.command() def shell(root: str = "."): - """ - Launch an interactive IPython shell with the project and apps loaded. - """ project_path = Path(root).resolve() project = runtime.Project(project_path) - # Ensure the ORM is shutdown - async def close_project(): + banner = f""" + OhMyAPI Project Shell: {getattr(project.settings, 'PROJECT_NAME', 'MyProject')} + Find your loaded project singleton via identifier: `p`; i.e.: `p.apps` + """ + + async def init_and_cleanup(): + try: + await project.init_orm() + return True + except Exception as e: + print(f"Failed to initialize ORM: {e}") + return False + + async def cleanup(): try: await project.close_orm() print("Tortoise ORM closed successfully.") except Exception as e: print(f"Error closing ORM: {e}") - def cleanup(): - loop = None - try: - loop = asyncio.get_running_loop() - except RuntimeError: - pass - if loop and loop.is_running(): - asyncio.create_task(close_project()) - else: - asyncio.run(close_project()) + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + loop.run_until_complete(init_and_cleanup()) - # Ensure the ORM is initialized - asyncio.run(project.init_orm()) + # Prepare shell vars that are to be directly available + shell_vars = {"p": project} try: from IPython import start_ipython - shell_vars = { - "p": project, - } from traitlets.config.loader import Config + c = Config() c.TerminalIPythonApp.display_banner = True - c.TerminalInteractiveShell.banner2 = banner.format(**{ - "project_name": f"{f'{project.settings.PROJECT_NAME} ' if getattr(project.settings, 'PROJECT_NAME', '') else ''}[{Path(project_path).resolve()}]", - }) - atexit.register(cleanup) + c.TerminalInteractiveShell.banner2 = banner + start_ipython(argv=[], user_ns=shell_vars, config=c) except ImportError: - typer.echo("IPython is not installed. Falling back to built-in Python shell.") import code - atexit.register(cleanup) - code.interact(local={"p": project}) + code.interact(local=shell_vars, banner=banner) + finally: + loop.run_until_complete(cleanup()) @app.command()