Matches requests with paths specified by ``path_pattern`` regex.
| 550 | |
| 551 | |
| 552 | class PathMatches(Matcher): |
| 553 | """Matches requests with paths specified by ``path_pattern`` regex.""" |
| 554 | |
| 555 | def __init__(self, path_pattern: Union[str, Pattern]) -> None: |
| 556 | if isinstance(path_pattern, basestring_type): |
| 557 | if not path_pattern.endswith("$"): |
| 558 | path_pattern += "$" |
| 559 | self.regex = re.compile(path_pattern) |
| 560 | else: |
| 561 | self.regex = path_pattern |
| 562 | |
| 563 | assert len(self.regex.groupindex) in (0, self.regex.groups), ( |
| 564 | "groups in url regexes must either be all named or all " |
| 565 | "positional: %r" % self.regex.pattern |
| 566 | ) |
| 567 | |
| 568 | self._path, self._group_count = self._find_groups() |
| 569 | |
| 570 | def match(self, request: httputil.HTTPServerRequest) -> Optional[Dict[str, Any]]: |
| 571 | match = self.regex.match(request.path) |
| 572 | if match is None: |
| 573 | return None |
| 574 | if not self.regex.groups: |
| 575 | return {} |
| 576 | |
| 577 | path_args = [] # type: List[bytes] |
| 578 | path_kwargs = {} # type: Dict[str, bytes] |
| 579 | |
| 580 | # Pass matched groups to the handler. Since |
| 581 | # match.groups() includes both named and |
| 582 | # unnamed groups, we want to use either groups |
| 583 | # or groupdict but not both. |
| 584 | if self.regex.groupindex: |
| 585 | path_kwargs = dict( |
| 586 | (str(k), _unquote_or_none(v)) for (k, v) in match.groupdict().items() |
| 587 | ) |
| 588 | else: |
| 589 | path_args = [_unquote_or_none(s) for s in match.groups()] |
| 590 | |
| 591 | return dict(path_args=path_args, path_kwargs=path_kwargs) |
| 592 | |
| 593 | def reverse(self, *args: Any) -> Optional[str]: |
| 594 | if self._path is None: |
| 595 | raise ValueError("Cannot reverse url regex " + self.regex.pattern) |
| 596 | assert len(args) == self._group_count, ( |
| 597 | "required number of arguments " "not found" |
| 598 | ) |
| 599 | if not len(args): |
| 600 | return self._path |
| 601 | converted_args = [] |
| 602 | for a in args: |
| 603 | if not isinstance(a, (unicode_type, bytes)): |
| 604 | a = str(a) |
| 605 | converted_args.append(url_escape(utf8(a), plus=False)) |
| 606 | return self._path % tuple(converted_args) |
| 607 | |
| 608 | def _find_groups(self) -> Tuple[Optional[str], Optional[int]]: |
| 609 | """Returns a tuple (reverse string, group count) for a url. |