From 8c74b6cc2b6df39652dffb2e6debfdc0956bf6be Mon Sep 17 00:00:00 2001 From: hamed Date: Fri, 22 Mar 2024 10:03:13 +0300 Subject: [PATCH] Add auto name generation feature to routes in Sanic The ability to automatically generate names for routes has been added to Sanic. This feature is controlled by the 'generate_name' parameter available in the application, blueprint, and route definitions. Additionally, comprehensive tests have been added to ensure the correct functionality of this new feature. --- sanic/app.py | 7 +++++++ sanic/blueprints.py | 3 +++ sanic/mixins/base.py | 4 ++-- sanic/mixins/routes.py | 2 +- tests/test_blueprints.py | 28 ++++++++++++++++++++++++++++ 5 files changed, 41 insertions(+), 3 deletions(-) diff --git a/sanic/app.py b/sanic/app.py index 0a93e5230a..4052f6404d 100644 --- a/sanic/app.py +++ b/sanic/app.py @@ -223,6 +223,7 @@ class to use for the application. Defaults to `None`. "strict_slashes", "websocket_enabled", "websocket_tasks", + "generate_name", ) _app_registry: ClassVar[Dict[str, "Sanic"]] = {} @@ -247,6 +248,7 @@ def __init__( inspector: bool = False, inspector_class: Optional[Type[Inspector]] = None, certloader_class: Optional[Type[CertLoader]] = None, + generate_name: bool = False, ) -> None: ... @@ -269,6 +271,7 @@ def __init__( inspector: bool = False, inspector_class: Optional[Type[Inspector]] = None, certloader_class: Optional[Type[CertLoader]] = None, + generate_name: bool = False, ) -> None: ... @@ -291,6 +294,7 @@ def __init__( inspector: bool = False, inspector_class: Optional[Type[Inspector]] = None, certloader_class: Optional[Type[CertLoader]] = None, + generate_name: bool = False, ) -> None: ... @@ -313,6 +317,7 @@ def __init__( inspector: bool = False, inspector_class: Optional[Type[Inspector]] = None, certloader_class: Optional[Type[CertLoader]] = None, + generate_name: bool = False, ) -> None: ... @@ -334,6 +339,7 @@ def __init__( inspector: bool = False, inspector_class: Optional[Type[Inspector]] = None, certloader_class: Optional[Type[CertLoader]] = None, + generate_name: bool = False, ) -> None: super().__init__(name=name) # logging @@ -390,6 +396,7 @@ def __init__( self.strict_slashes: bool = strict_slashes self.websocket_enabled: bool = False self.websocket_tasks: Set[Future[Any]] = set() + self.generate_name = generate_name # Register alternative method names self.go_fast = self.run diff --git a/sanic/blueprints.py b/sanic/blueprints.py index 6617d09cc6..7b9bd641fb 100644 --- a/sanic/blueprints.py +++ b/sanic/blueprints.py @@ -117,6 +117,7 @@ class Blueprint(BaseSanic): "version", "version_prefix", "websocket_routes", + "generate_name", ) def __init__( @@ -127,6 +128,7 @@ def __init__( version: Optional[Union[int, str, float]] = None, strict_slashes: Optional[bool] = None, version_prefix: str = "/v", + generate_name: bool = False, ): super().__init__(name=name) self.reset() @@ -142,6 +144,7 @@ def __init__( ) self.version = version self.version_prefix = version_prefix + self.generate_name = generate_name def __repr__(self) -> str: args = ", ".join( diff --git a/sanic/mixins/base.py b/sanic/mixins/base.py index 9242ef9f01..0053cf599e 100644 --- a/sanic/mixins/base.py +++ b/sanic/mixins/base.py @@ -9,7 +9,7 @@ class BaseMixin(metaclass=SanicMeta): name: str strict_slashes: Optional[bool] - def _generate_name(self, *objects, methods=None, uri=None) -> str: + def _generate_name(self, *objects, route_generate=False, methods=None, uri=None) -> str: name = None named_route = False @@ -34,7 +34,7 @@ def _generate_name(self, *objects, methods=None, uri=None) -> str: raise ValueError("Could not generate a name for handler") if not name.startswith(f"{self.name}."): - if not named_route: + if route_generate and not named_route: if methods: methods = "_".join(methods) name = f"{name}_{methods}" diff --git a/sanic/mixins/routes.py b/sanic/mixins/routes.py index 90a395f574..6b5d2ddae5 100644 --- a/sanic/mixins/routes.py +++ b/sanic/mixins/routes.py @@ -139,7 +139,7 @@ def decorator(handler): # variable will be a tuple of (existing routes, handler fn) _, handler = handler - name = self._generate_name(name, handler, methods=methods, uri=uri) + name = self._generate_name(name, handler, route_generate=self.generate_name, methods=methods, uri=uri) if isinstance(host, str): host = frozenset([host]) diff --git a/tests/test_blueprints.py b/tests/test_blueprints.py index c5ecc13a8d..fd7867f2d8 100644 --- a/tests/test_blueprints.py +++ b/tests/test_blueprints.py @@ -308,6 +308,34 @@ def handler2(request): assert "test_bp_with_host_list.test_bp_host.handler2" in route_names +def test_bp_with_auto_name_generate(app: Sanic): + bp = Blueprint( + "test_bp_host", + url_prefix="/test1", + host=["example.com", "sub.example.com"], + generate_name=True, + ) + + @bp.route("/") + def handler1(request): + return text("Hello") + + @bp.route("/", host=["sub1.example.com"]) + def handler2(request): + return text("Hello subdomain!") + + @bp.route("/route_with_name", methods=["GET", "POST"], name="handler3") + def handler3(request): + return text("Hello subdomain!") + + app.blueprint(bp) + + route_names = [r.name for r in app.router.routes] + assert "test_bp_with_auto_name_generate.test_bp_host.handler1_GET_/" in route_names + assert "test_bp_with_auto_name_generate.test_bp_host.handler2_GET_/" in route_names + assert "test_bp_with_auto_name_generate.test_bp_host.handler3" in route_names + + def test_several_bp_with_host_list(app: Sanic): bp = Blueprint( "test_text",