Skip to content

Commit

Permalink
Only unquote on string casts (#74)
Browse files Browse the repository at this point in the history
* Only unquote on string casts

* line length

* Add unit tests

* squash

* Fix typing issue
  • Loading branch information
ahopkins authored Jul 19, 2023
1 parent e840866 commit 412f75d
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 5 deletions.
2 changes: 1 addition & 1 deletion sanic_routing/route.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def __init__(
name: str,
handler: t.Callable[..., t.Any],
methods: t.Union[t.Sequence[str], t.FrozenSet[str]],
requirements: t.Dict[str, t.Any] = None,
requirements: t.Optional[t.Dict[str, t.Any]] = None,
strict: bool = False,
unquote: bool = False,
static: bool = False,
Expand Down
15 changes: 11 additions & 4 deletions sanic_routing/tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from .group import RouteGroup
from .line import Line
from .patterns import REGEX_PARAM_NAME, REGEX_PARAM_NAME_EXT
from .patterns import REGEX_PARAM_NAME, REGEX_PARAM_NAME_EXT, alpha, ext, slug

logger = getLogger("sanic.root")

Expand All @@ -16,6 +16,7 @@ def __init__(
parent=None,
router=None,
param=None,
unquote=False,
) -> None:
self.root = root
self.part = part
Expand All @@ -34,7 +35,7 @@ def __init__(
self.children_param_injected = False
self.has_deferred = False
self.equality_check = False
self.unquote = False
self.unquote = unquote
self.router = router

def __str__(self) -> str:
Expand Down Expand Up @@ -268,7 +269,7 @@ def _inject_param_check(self, location, indent, idx):
Line("pass", indent + 1),
Line("else:", indent),
]
if self.unquote:
if self.unquote and self._cast_as_str(self.param.cast):
lines.append(
Line(
f"basket['__matches__'][{idx}] = "
Expand All @@ -280,6 +281,11 @@ def _inject_param_check(self, location, indent, idx):

location.extend(lines)

@staticmethod
def _cast_as_str(cast) -> bool:
return_type_hint = t.get_type_hints(cast).get("return")
return cast in (str, ext, slug, alpha) or return_type_hint is str

@staticmethod
def _inject_method_check(location, indent, group):
"""
Expand Down Expand Up @@ -436,6 +442,7 @@ def generate(self, groups: t.Iterable[RouteGroup]) -> None:
"""
for group in groups:
current = self.root
current.unquote = current.unquote or group.unquote
for level, part in enumerate(group.parts):
param = None
dynamic = part.startswith("<")
Expand All @@ -452,14 +459,14 @@ def generate(self, groups: t.Iterable[RouteGroup]) -> None:
parent=current,
router=self.router,
param=param,
unquote=current.unquote,
)
child.dynamic = dynamic
current.add_child(child)
current = current._children[part]
current.level = level + 1

current.groups.append(group)
current.unquote = current.unquote or group.unquote

def display(self) -> None:
"""
Expand Down
1 change: 1 addition & 0 deletions tests/test_builtin_param_types.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from unittest.mock import Mock

import pytest

from sanic_routing import BaseRouter
from sanic_routing.exceptions import InvalidUsage, NotFound

Expand Down
52 changes: 52 additions & 0 deletions tests/test_unquote.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
from unittest.mock import Mock

from sanic_routing import BaseRouter


class Router(BaseRouter):
def get(self, path, method, extra=None):
return self.resolve(path=path, method=method, extra=extra)


def test_no_unquote():
handler = Mock(return_value=123)

router = Router()
router.add("/<foo>/<bar>", methods=["GET"], handler=handler, unquote=False)
router.finalize()

_, handler, params = router.get("/%F0%9F%98%8E/sunglasses", "GET")
assert params == {"bar": "sunglasses", "foo": "%F0%9F%98%8E"}

_, handler, params = router.get("/😎/sunglasses", "GET")
assert params == {"bar": "sunglasses", "foo": "😎"}


def test_unquote():
handler = Mock(return_value=123)

router = Router()
router.add("/<foo>/<bar>", methods=["GET"], handler=handler, unquote=True)
router.finalize()

_, handler, params = router.get("/%F0%9F%98%8E/sunglasses", "GET")
assert params == {"bar": "sunglasses", "foo": "😎"}

_, handler, params = router.get("/😎/sunglasses", "GET")
assert params == {"bar": "sunglasses", "foo": "😎"}


def test_unquote_non_string():
handler = Mock(return_value=123)

router = Router()
router.add(
"/<foo>/<bar:int>", methods=["GET"], handler=handler, unquote=True
)
router.finalize()

_, handler, params = router.get("/%F0%9F%98%8E/123", "GET")
assert params == {"bar": 123, "foo": "😎"}

_, handler, params = router.get("/😎/123", "GET")
assert params == {"bar": 123, "foo": "😎"}

0 comments on commit 412f75d

Please sign in to comment.