Skip to content

Commit

Permalink
Add REPL context
Browse files Browse the repository at this point in the history
  • Loading branch information
goodki-d committed Jan 9, 2025
1 parent a575f5c commit 7c5fb44
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 1 deletion.
3 changes: 3 additions & 0 deletions sanic/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
from sanic.mixins.listeners import ListenerEvent
from sanic.mixins.startup import StartupMixin
from sanic.mixins.static import StaticHandleMixin
from sanic.models.ctx_types import REPLContext
from sanic.models.futures import (
FutureException,
FutureListener,
Expand Down Expand Up @@ -219,6 +220,7 @@ class to use for the application. Defaults to `None`.
"strict_slashes",
"websocket_enabled",
"websocket_tasks",
"repl_ctx",
)

_app_registry: ClassVar[dict[str, Sanic]] = {}
Expand Down Expand Up @@ -382,6 +384,7 @@ def __init__(
self.strict_slashes: bool = strict_slashes
self.websocket_enabled: bool = False
self.websocket_tasks: set[Future[Any]] = set()
self.repl_ctx = REPLContext()

# Register alternative method names
self.go_fast = self.run
Expand Down
17 changes: 16 additions & 1 deletion sanic/cli/console.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,25 @@ def __init__(self, app: Sanic, start: Optional[Default] = None):
"sanic": sanic,
"do": do,
}

user_locals = {
user_local.name: user_local.var for user_local in app.repl_ctx
}

client_availability = ""
variable_descriptions = [
f" - {Colors.BOLD + Colors.SANIC}app{Colors.END}: The Sanic application instance - {Colors.BOLD + Colors.BLUE}{str(app)}{Colors.END}", # noqa: E501
f" - {Colors.BOLD + Colors.SANIC}sanic{Colors.END}: The Sanic module - {Colors.BOLD + Colors.BLUE}import sanic{Colors.END}", # noqa: E501
f" - {Colors.BOLD + Colors.SANIC}do{Colors.END}: An async function to fake a request to the application - {Colors.BOLD + Colors.BLUE}Result(request, response){Colors.END}", # noqa: E501
]

user_locals_descriptions = [
f" - {Colors.SANIC}{user_local.name}{Colors.END} "
f"{Colors.GREY}{type(user_local.var)}{Colors.END} : "
f"{user_local.desc}"
for user_local in app.repl_ctx
]

if HTTPX_AVAILABLE:
locals_available["client"] = SanicClient(app)
variable_descriptions.append(
Expand All @@ -136,7 +149,7 @@ def __init__(self, app: Sanic, start: Optional[Default] = None):
"To enable it, install httpx:\n\t"
f"pip install httpx{Colors.END}\n"
)
super().__init__(locals=locals_available)
super().__init__(locals={**locals_available, **user_locals})
self.compile.compiler.flags |= PyCF_ALLOW_TOP_LEVEL_AWAIT
self.loop = new_event_loop()
self._start = start
Expand All @@ -163,6 +176,8 @@ def __init__(self, app: Sanic, start: Optional[Default] = None):
client_availability,
"The following objects are available for your convenience:", # noqa: E501
*variable_descriptions,
"\nREPL Context:",
*user_locals_descriptions,
"\nThe async/await keywords are available for use here.", # noqa: E501
f"To exit, press {Colors.BOLD}CTRL+C{Colors.END}, "
f"{Colors.BOLD}CTRL+D{Colors.END}, or type {Colors.BOLD}exit(){Colors.END}.\n", # noqa: E501
Expand Down
35 changes: 35 additions & 0 deletions sanic/models/ctx_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from typing import Any, NamedTuple, Optional


class REPLLocal(NamedTuple):
var: Any
name: str
desc: str


class REPLContext:
def __init__(self):
self._locals: set[REPLLocal] = set()

def add_local(
self,
var: Any,
name: Optional[str] = None,
desc: Optional[str] = None,
):
if name is None:
name = var.__name__

if desc is None:
desc = var.__doc__

desc = self._truncate(desc)

self._locals.add(REPLLocal(var, name, desc))

def __iter__(self):
return iter(self._locals)

@staticmethod
def _truncate(s: str, limit: int = 40):
return s[:limit] + "..." if len(s) > limit else s

0 comments on commit 7c5fb44

Please sign in to comment.