GIT-2045: enable versioning and strict slash on BlueprintGroup (#2047)
* GIT-2045: enable versioning and strict slash on BlueprintGroup * GIT-2045: convert named tuple into typed format + unit tests * GIT-2045: add example code for versioned bpg * GIT-2045: None value for strict slashes check * GIT-2045: refactor handler types and add benchmark for urlparse * GIT-2045: reduce urlparse benchmark iterations * GIT-2045: add unit test and url merge behavior * GIT-2045: cleanup example code and remove print * GIT-2045: add test for slash duplication avoidence * GIT-2045: fix issue with tailing / getting appended * GIT-2045: use Optional instead of Union for Typing * GIT-2045: use string for version arg * GIT-2045: combine optional with union
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
from collections.abc import MutableSequence
|
||||
from typing import List
|
||||
from typing import List, Optional, Union
|
||||
|
||||
import sanic
|
||||
|
||||
|
||||
class BlueprintGroup(MutableSequence):
|
||||
@@ -16,6 +18,11 @@ class BlueprintGroup(MutableSequence):
|
||||
bp1 = Blueprint('bp1', url_prefix='/bp1')
|
||||
bp2 = Blueprint('bp2', url_prefix='/bp2')
|
||||
|
||||
bp3 = Blueprint('bp3', url_prefix='/bp4')
|
||||
bp3 = Blueprint('bp3', url_prefix='/bp4')
|
||||
|
||||
bpg = BlueprintGroup(bp3, bp4, url_prefix="/api", version="v1")
|
||||
|
||||
@bp1.middleware('request')
|
||||
async def bp1_only_middleware(request):
|
||||
print('applied on Blueprint : bp1 Only')
|
||||
@@ -28,6 +35,14 @@ class BlueprintGroup(MutableSequence):
|
||||
async def bp2_route(request, param):
|
||||
return text(param)
|
||||
|
||||
@bp3.route('/')
|
||||
async def bp1_route(request):
|
||||
return text('bp1')
|
||||
|
||||
@bp4.route('/<param>')
|
||||
async def bp2_route(request, param):
|
||||
return text(param)
|
||||
|
||||
group = Blueprint.group(bp1, bp2)
|
||||
|
||||
@group.middleware('request')
|
||||
@@ -36,18 +51,23 @@ class BlueprintGroup(MutableSequence):
|
||||
|
||||
# Register Blueprint group under the app
|
||||
app.blueprint(group)
|
||||
app.blueprint(bpg)
|
||||
"""
|
||||
|
||||
__slots__ = ("_blueprints", "_url_prefix")
|
||||
__slots__ = ("_blueprints", "_url_prefix", "_version", "_strict_slashes")
|
||||
|
||||
def __init__(self, url_prefix=None):
|
||||
def __init__(self, url_prefix=None, version=None, strict_slashes=None):
|
||||
"""
|
||||
Create a new Blueprint Group
|
||||
|
||||
:param url_prefix: URL: to be prefixed before all the Blueprint Prefix
|
||||
:param version: API Version for the blueprint group. This will be inherited by each of the Blueprint
|
||||
:param strict_slashes: URL Strict slash behavior indicator
|
||||
"""
|
||||
self._blueprints = []
|
||||
self._url_prefix = url_prefix
|
||||
self._version = version
|
||||
self._strict_slashes = strict_slashes
|
||||
|
||||
@property
|
||||
def url_prefix(self) -> str:
|
||||
@@ -59,7 +79,7 @@ class BlueprintGroup(MutableSequence):
|
||||
return self._url_prefix
|
||||
|
||||
@property
|
||||
def blueprints(self) -> List:
|
||||
def blueprints(self) -> List["sanic.Blueprint"]:
|
||||
"""
|
||||
Retrieve a list of all the available blueprints under this group.
|
||||
|
||||
@@ -67,6 +87,25 @@ class BlueprintGroup(MutableSequence):
|
||||
"""
|
||||
return self._blueprints
|
||||
|
||||
@property
|
||||
def version(self) -> Optional[Union[str, int, float]]:
|
||||
"""
|
||||
API Version for the Blueprint Group. This will be applied only in case if the Blueprint doesn't already have
|
||||
a version specified
|
||||
|
||||
:return: Version information
|
||||
"""
|
||||
return self._version
|
||||
|
||||
@property
|
||||
def strict_slashes(self) -> Optional[bool]:
|
||||
"""
|
||||
URL Slash termination behavior configuration
|
||||
|
||||
:return: bool
|
||||
"""
|
||||
return self._strict_slashes
|
||||
|
||||
def __iter__(self):
|
||||
"""
|
||||
Tun the class Blueprint Group into an Iterable item
|
||||
@@ -121,7 +160,33 @@ class BlueprintGroup(MutableSequence):
|
||||
"""
|
||||
return len(self._blueprints)
|
||||
|
||||
def insert(self, index: int, item: object) -> None:
|
||||
def _sanitize_blueprint(self, bp: "sanic.Blueprint") -> "sanic.Blueprint":
|
||||
"""
|
||||
Sanitize the Blueprint Entity to override the Version and strict slash behaviors as required.
|
||||
|
||||
:param bp: Sanic Blueprint entity Object
|
||||
:return: Modified Blueprint
|
||||
"""
|
||||
if self._url_prefix:
|
||||
merged_prefix = "/".join(
|
||||
u.strip("/") for u in [self._url_prefix, bp.url_prefix or ""]
|
||||
).rstrip("/")
|
||||
bp.url_prefix = f"/{merged_prefix}"
|
||||
for _attr in ["version", "strict_slashes"]:
|
||||
if getattr(bp, _attr) is None:
|
||||
setattr(bp, _attr, getattr(self, _attr))
|
||||
return bp
|
||||
|
||||
def append(self, value: "sanic.Blueprint") -> None:
|
||||
"""
|
||||
The Abstract class `MutableSequence` leverages this append method to
|
||||
perform the `BlueprintGroup.append` operation.
|
||||
:param value: New `Blueprint` object.
|
||||
:return: None
|
||||
"""
|
||||
self._blueprints.append(self._sanitize_blueprint(bp=value))
|
||||
|
||||
def insert(self, index: int, item: "sanic.Blueprint") -> None:
|
||||
"""
|
||||
The Abstract class `MutableSequence` leverages this insert method to
|
||||
perform the `BlueprintGroup.append` operation.
|
||||
@@ -130,7 +195,7 @@ class BlueprintGroup(MutableSequence):
|
||||
:param item: New `Blueprint` object.
|
||||
:return: None
|
||||
"""
|
||||
self._blueprints.insert(index, item)
|
||||
self._blueprints.insert(index, self._sanitize_blueprint(item))
|
||||
|
||||
def middleware(self, *args, **kwargs):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user