Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V2routing #37

Merged
merged 16 commits into from May 31, 2021
2 changes: 1 addition & 1 deletion sanic_routing/group.py
Expand Up @@ -139,7 +139,7 @@ def depth(self) -> int:
@property
def dynamic_path(self) -> bool:
return any(
(param.label == "path") or (r"/" in param.label)
(param.label == "path") or ("/" in param.label)
for param in self.params.values()
)

Expand Down
34 changes: 16 additions & 18 deletions sanic_routing/route.py
Expand Up @@ -102,7 +102,9 @@ def __eq__(self, other) -> bool:
# Equality specifically uses self.segments and not self.parts.
# In general, these properties are nearly identical.
# self.segments is generalized and only displays dynamic param types
# and self.parts has both the param key and the param type
# and self.parts has both the param key and the param type.
# In this test, we use the & operator so that we create a union and a
# positive equality if there is one or more overlaps in the methods.
return bool(
(
self.segments,
Expand All @@ -118,7 +120,7 @@ def __eq__(self, other) -> bool:
def _ingest_path(self, path):
segments = []
for part in path.split(self.router.delimiter):
if "<" in part and ":" not in part:
if part.startswith("<") and ":" not in part:
name = part[1:-1]
part = f"<{name}:str>"
segments.append(part)
Expand All @@ -132,7 +134,7 @@ def _setup_params(self):
if not self.static:
parts = path_to_parts(key_path, self.router.delimiter)
for idx, part in enumerate(parts):
if "<" in part:
if part.startswith("<"):
(
name,
label,
Expand Down Expand Up @@ -160,16 +162,14 @@ def add_parameter(

pattern = re.compile(pattern)

is_regex = label not in self.router.regex_types
priority = (
0
if is_regex
else list(self.router.regex_types.keys()).index(label)
)
self._params[idx] = ParamInfo(
name,
raw_path,
label,
cast,
pattern,
label not in self.router.regex_types,
list(self.router.regex_types.keys()).index(label)
if label in self.router.regex_types
else 0,
name, raw_path, label, cast, pattern, is_regex, priority
)

def _finalize_params(self):
Expand Down Expand Up @@ -246,12 +246,10 @@ def segments(self) -> t.Tuple[str, ...]:
include param keys since they have no impact on routing.
"""
return tuple(
[
f"<__dynamic__:{self._params[idx].label}>"
if self._params.get(idx)
else segment
for idx, segment in enumerate(self.parts)
]
f"<__dynamic__:{self._params[idx].label}>"
if idx in self._params
else segment
for idx, segment in enumerate(self.parts)
)

@property
Expand Down
5 changes: 4 additions & 1 deletion sanic_routing/router.py
Expand Up @@ -536,6 +536,8 @@ def _optimize(self, node) -> None:
test.op, ast.And
):
values.extend(test.values)
else:
...
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this?

combined = ast.BoolOp(op=ast.And(), values=values)

current.test = combined
Expand All @@ -553,7 +555,8 @@ def _optimize(self, node) -> None:
# foo2()
if (
all(isinstance(child, ast.If) for child in node.body)
and len({child.test for child in node.body})
# TODO: create func to peoperly compare equality of conditions
# and len({child.test for child in node.body})
and len(node.body) > 1
):
first, *rem = node.body
Expand Down
31 changes: 23 additions & 8 deletions sanic_routing/tree.py
Expand Up @@ -89,7 +89,7 @@ def display(self) -> None:

def render(self) -> t.Tuple[t.List[Line], t.List[Line]]:
# output - code injected into the source as it is being
# called/evalueated
# called/evaluated
# delayed - code that is injected after you do all of its children
# first
# final - code that is injected at the very end of all rendering
Expand All @@ -110,7 +110,7 @@ def to_src(self) -> t.Tuple[t.List[Line], t.List[Line], t.List[Line]]:
first_sibling: t.Optional[Node] = None

if not self.first:
first_sibling = list(siblings.values())[0]
first_sibling = next(iter(siblings.values()))

self.base_indent = (
bool(self.level >= 1 or self.first) + self.parent.base_indent
Expand Down Expand Up @@ -176,7 +176,7 @@ def to_src(self) -> t.Tuple[t.List[Line], t.List[Line], t.List[Line]]:
else ""
)

self.equality_check = self.equality_check or bool(len_check)
self.equality_check |= bool(len_check)

src.append(
Line(
Expand All @@ -195,6 +195,16 @@ def to_src(self) -> t.Tuple[t.List[Line], t.List[Line], t.List[Line]]:

# Do any missing equality_check
if not self.equality_check:
# If if we have not done an equality check and there are
# children nodes, then we know there is a CHECK 1
# for the children that starts at the same level, and will
# be an exclusive conditional to what is being evaluated here.
# Therefore, we can use elif
# example:
# if num == 7: # CHECK 1
# child_node_stuff
# elif num == 6: # CHECK 5
# current_node_stuff
conditional = "elif" if self.children else "if"
ahopkins marked this conversation as resolved.
Show resolved Hide resolved
operation = "=="
location.append(
Expand Down Expand Up @@ -247,20 +257,25 @@ def _inject_param_check(self, location, indent, idx):
"""
Try and cast relevant path segments.
"""
unquote_start = "unquote(" if self.unquote else ""
unquote_end = ")" if self.unquote else ""
lines = [
Line("try:", indent),
Line(
f"basket['__matches__'][{idx}] = "
f"{unquote_start}{self.param.cast.__name__}(parts[{idx}])"
f"{unquote_end}",
f"{self.param.cast.__name__}(parts[{idx}])",
indent + 1,
),
Line("except ValueError:", indent),
Line("pass", indent + 1),
Line("else:", indent),
]
if self.unquote:
lines.append(
Line(
f"basket['__matches__'][{idx}] = "
f"unquote(basket['__matches__'][{idx}])",
indent + 1,
)
)
self.base_indent += 1
ahopkins marked this conversation as resolved.
Show resolved Hide resolved

location.extend(lines)
ahopkins marked this conversation as resolved.
Show resolved Hide resolved
Expand Down Expand Up @@ -289,7 +304,7 @@ def _inject_method_check(self, location, indent, group):

def _inject_return(self, location, indent, route_idx, group):
"""
The return statement for the node if neededs
The return statement for the node if needed
"""
routes = "regex_routes" if group.regex else "dynamic_routes"
route_return = "" if group.router.stacking else f"[{route_idx}]"
Expand Down