from typing import Annotated, Literal from fastapi import Body, Depends, FastAPI, HTTPException, Path, Query from ipython_shell import App from ipython_shell.models import CallOptions app = FastAPI(title="IPython Demo", version="0.1.0") ShellApp = App() # global, scary @app.get("/info") def get_info(): return ShellApp.info() @app.get("/shells") def list_shells(): shells = ShellApp.list_shells() if not shells: raise HTTPException(status_code=404, detail="No shells found") return shells @app.post("/shells/new", status_code=201) def create_shell(): return ShellApp.create_shell() @app.get("/shells/last") def get_last_shell(): try: return ShellApp.get_last_shell() except KeyError as error: raise HTTPException(status_code=404, detail=str(error)) from error @app.get("/shells/{shell_name}") def get_shell( shell_name: Annotated[ str, Path(..., description="The shell to query for metadata"), ], ): try: return ShellApp.get_shell(shell_name) except KeyError as error: raise HTTPException(status_code=404, detail=str(error)) from error @app.post("/shells/{shell_name}/run") def run_code( shell_name: Annotated[ Literal["last", "new"] | str, Path(..., description="The shell to run code in"), ], code: Annotated[ str, Body(..., description="The code to execute", media_type="text/plain") ], options: Annotated[CallOptions, Depends()], ): return ShellApp.run_code(code, shell_name, options=options) @app.post("/run") def run_code_2( code: Annotated[ str, Body(..., description="The code to execute", media_type="text/plain") ], options: Annotated[CallOptions, Depends()], shell_name: Annotated[ Literal["last", "new"] | str, Query(description="The shell to run code in"), ] = "last", ): return ShellApp.run_code(code, shell_name, options=options) def main() -> None: """Run the HTTP API with Uvicorn.""" import uvicorn uvicorn.run(app, host="::", port=8000, log_level="info") if __name__ == "__main__": main()