App registry (#1979)
* Add app level registry * Add documentation for app registry * Remove unused import * Add force_create keyword to Sanic.get_app * Add force_commit to docs
This commit is contained in:
parent
262f89f2b6
commit
449bc417a3
|
@ -60,3 +60,26 @@ Open the address `http://0.0.0.0:8000 <http://0.0.0.0:8000>`_ in your web browse
|
||||||
the message *Hello world!*.
|
the message *Hello world!*.
|
||||||
|
|
||||||
You now have a working Sanic server!
|
You now have a working Sanic server!
|
||||||
|
|
||||||
|
5. Application registry
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
When you instantiate a Sanic instance, that can be retrieved at a later time from the Sanic app registry. This can be useful, for example, if you need to access your Sanic instance from a location where it is not otherwise accessible.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# ./path/to/server.py
|
||||||
|
from sanic import Sanic
|
||||||
|
|
||||||
|
app = Sanic("my_awesome_server")
|
||||||
|
|
||||||
|
# ./path/to/somewhere_else.py
|
||||||
|
from sanic import Sanic
|
||||||
|
|
||||||
|
app = Sanic.get_app("my_awesome_server")
|
||||||
|
|
||||||
|
If you call ``Sanic.get_app("non-existing")`` on an app that does not exist, it will raise ``SanicException`` by default. You can, instead, force the method to return a new instance of ``Sanic`` with that name:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
app = Sanic.get_app("my_awesome_server", force_create=True)
|
||||||
|
|
45
sanic/app.py
45
sanic/app.py
|
@ -2,12 +2,11 @@ import logging
|
||||||
import logging.config
|
import logging.config
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import warnings
|
|
||||||
|
|
||||||
from asyncio import CancelledError, Protocol, ensure_future, get_event_loop
|
from asyncio import CancelledError, Protocol, ensure_future, get_event_loop
|
||||||
from collections import defaultdict, deque
|
from collections import defaultdict, deque
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from inspect import getmodulename, isawaitable, signature, stack
|
from inspect import isawaitable, signature
|
||||||
from socket import socket
|
from socket import socket
|
||||||
from ssl import Purpose, SSLContext, create_default_context
|
from ssl import Purpose, SSLContext, create_default_context
|
||||||
from traceback import format_exc
|
from traceback import format_exc
|
||||||
|
@ -38,6 +37,9 @@ from sanic.websocket import ConnectionClosed, WebSocketProtocol
|
||||||
|
|
||||||
|
|
||||||
class Sanic:
|
class Sanic:
|
||||||
|
_app_registry: Dict[str, "Sanic"] = {}
|
||||||
|
test_mode = False
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
name=None,
|
name=None,
|
||||||
|
@ -52,15 +54,10 @@ class Sanic:
|
||||||
|
|
||||||
# Get name from previous stack frame
|
# Get name from previous stack frame
|
||||||
if name is None:
|
if name is None:
|
||||||
warnings.warn(
|
raise SanicException(
|
||||||
"Sanic(name=None) is deprecated and None value support "
|
"Sanic instance cannot be unnamed. "
|
||||||
"for `name` will be removed in the next release. "
|
|
||||||
"Please use Sanic(name='your_application_name') instead.",
|
"Please use Sanic(name='your_application_name') instead.",
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
)
|
||||||
frame_records = stack()[1]
|
|
||||||
name = getmodulename(frame_records[1])
|
|
||||||
|
|
||||||
# logging
|
# logging
|
||||||
if configure_logging:
|
if configure_logging:
|
||||||
|
@ -90,7 +87,8 @@ class Sanic:
|
||||||
self.named_response_middleware = {}
|
self.named_response_middleware = {}
|
||||||
# Register alternative method names
|
# Register alternative method names
|
||||||
self.go_fast = self.run
|
self.go_fast = self.run
|
||||||
self.test_mode = False
|
|
||||||
|
self.__class__.register_app(self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def loop(self):
|
def loop(self):
|
||||||
|
@ -1401,9 +1399,36 @@ class Sanic:
|
||||||
# -------------------------------------------------------------------- #
|
# -------------------------------------------------------------------- #
|
||||||
# Configuration
|
# Configuration
|
||||||
# -------------------------------------------------------------------- #
|
# -------------------------------------------------------------------- #
|
||||||
|
|
||||||
def update_config(self, config: Union[bytes, str, dict, Any]):
|
def update_config(self, config: Union[bytes, str, dict, Any]):
|
||||||
"""Update app.config.
|
"""Update app.config.
|
||||||
|
|
||||||
Please refer to config.py::Config.update_config for documentation."""
|
Please refer to config.py::Config.update_config for documentation."""
|
||||||
|
|
||||||
self.config.update_config(config)
|
self.config.update_config(config)
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------- #
|
||||||
|
# Class methods
|
||||||
|
# -------------------------------------------------------------------- #
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def register_app(cls, app: "Sanic") -> None:
|
||||||
|
"""Register a Sanic instance"""
|
||||||
|
if not isinstance(app, cls):
|
||||||
|
raise SanicException("Registered app must be an instance of Sanic")
|
||||||
|
|
||||||
|
name = app.name
|
||||||
|
if name in cls._app_registry and not cls.test_mode:
|
||||||
|
raise SanicException(f'Sanic app name "{name}" already in use.')
|
||||||
|
|
||||||
|
cls._app_registry[name] = app
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_app(cls, name: str, *, force_create: bool = False) -> "Sanic":
|
||||||
|
"""Retrieve an instantiated Sanic instance"""
|
||||||
|
try:
|
||||||
|
return cls._app_registry[name]
|
||||||
|
except KeyError:
|
||||||
|
if force_create:
|
||||||
|
return cls(name)
|
||||||
|
raise SanicException(f'Sanic app name "{name}" not found.')
|
||||||
|
|
|
@ -11,6 +11,7 @@ from sanic.router import RouteExists, Router
|
||||||
|
|
||||||
|
|
||||||
random.seed("Pack my box with five dozen liquor jugs.")
|
random.seed("Pack my box with five dozen liquor jugs.")
|
||||||
|
Sanic.test_mode = True
|
||||||
|
|
||||||
if sys.platform in ["win32", "cygwin"]:
|
if sys.platform in ["win32", "cygwin"]:
|
||||||
collect_ignore = ["test_worker.py"]
|
collect_ignore = ["test_worker.py"]
|
||||||
|
|
|
@ -258,7 +258,7 @@ def test_handle_request_with_nested_sanic_exception(app, monkeypatch, caplog):
|
||||||
|
|
||||||
|
|
||||||
def test_app_name_required():
|
def test_app_name_required():
|
||||||
with pytest.deprecated_call():
|
with pytest.raises(SanicException):
|
||||||
Sanic()
|
Sanic()
|
||||||
|
|
||||||
|
|
||||||
|
@ -274,14 +274,35 @@ def test_app_has_test_mode_sync():
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
|
|
||||||
|
|
||||||
# @pytest.mark.asyncio
|
def test_app_registry():
|
||||||
# async def test_app_has_test_mode_async():
|
instance = Sanic("test")
|
||||||
# app = Sanic("test")
|
assert Sanic._app_registry["test"] is instance
|
||||||
|
|
||||||
# @app.get("/")
|
|
||||||
# async def handler(request):
|
|
||||||
# assert request.app.test_mode
|
|
||||||
# return text("test")
|
|
||||||
|
|
||||||
# _, response = await app.asgi_client.get("/")
|
def test_app_registry_wrong_type():
|
||||||
# assert response.status == 200
|
with pytest.raises(SanicException):
|
||||||
|
Sanic.register_app(1)
|
||||||
|
|
||||||
|
|
||||||
|
def test_app_registry_name_reuse():
|
||||||
|
Sanic("test")
|
||||||
|
Sanic.test_mode = False
|
||||||
|
with pytest.raises(SanicException):
|
||||||
|
Sanic("test")
|
||||||
|
Sanic.test_mode = True
|
||||||
|
|
||||||
|
|
||||||
|
def test_app_registry_retrieval():
|
||||||
|
instance = Sanic("test")
|
||||||
|
assert Sanic.get_app("test") is instance
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_app_does_not_exist():
|
||||||
|
with pytest.raises(SanicException):
|
||||||
|
Sanic.get_app("does-not-exist")
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_app_does_not_exist_force_create():
|
||||||
|
assert isinstance(
|
||||||
|
Sanic.get_app("does-not-exist", force_create=True), Sanic
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user