From 82f7340ebb51e5c143b804bc0f20f785e96968c0 Mon Sep 17 00:00:00 2001 From: Ben Plowman Date: Thu, 28 Jul 2022 15:01:56 -0700 Subject: [PATCH 1/2] Fix #460 - missing parse_rule method This method was removed from the public API in werkzeug 2.2.0. Copying it into this project because the method is self-contained. --- flask_restx/swagger.py | 47 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/flask_restx/swagger.py b/flask_restx/swagger.py index 478aa86e..932e8d02 100644 --- a/flask_restx/swagger.py +++ b/flask_restx/swagger.py @@ -15,7 +15,6 @@ from six import string_types, itervalues, iteritems, iterkeys from flask import current_app -from werkzeug.routing import parse_rule from . import fields from .model import Model, ModelBase, OrderedModel @@ -36,7 +35,6 @@ "default": "string", } - #: Maps Python primitives types to Swagger ones PY_TYPES = { int: "integer", @@ -55,6 +53,21 @@ r"^:raises\s+(?P[\w\d_]+)\s*:\s*(?P.*)$", re.MULTILINE ) +RE_PARSE_RULE = re.compile( + r""" + (?P[^<]*) # static rule data + < + (?: + (?P[a-zA-Z_][a-zA-Z0-9_]*) # converter name + (?:\((?P.*?)\))? # converter arguments + \: # variable delimiter + )? + (?P[a-zA-Z_][a-zA-Z0-9_]*) # variable name + > + """, + re.VERBOSE, +) + def ref(model): """Return a reference to model in definitions""" @@ -74,6 +87,36 @@ def extract_path(path): return RE_URL.sub(r"{\1}", path) +def parse_rule(rule): + """ + This originally lived in werkzeug.routing.parse_rule until it was removed in werkzeug 2.2.0. Copying it here to + avoid depending on the older version of werkzeug. + """ + pos = 0 + end = len(rule) + do_match = RE_PARSE_RULE.match + used_names = set() + while pos < end: + m = do_match(rule, pos) + if m is None: + break + data = m.groupdict() + if data["static"]: + yield None, None, data["static"] + variable = data["variable"] + converter = data["converter"] or "default" + if variable in used_names: + raise ValueError(f"variable name {variable!r} used twice.") + used_names.add(variable) + yield converter, data["args"] or None, variable + pos = m.end() + if pos < end: + remaining = rule[pos:] + if ">" in remaining or "<" in remaining: + raise ValueError(f"malformed url rule: {rule!r}") + yield None, None, remaining + + def extract_path_params(path): """ Extract Flask-style parameters from an URL pattern as Swagger ones. From 09e57b8af6ca5eddf52377aea32d99c4e03ad585 Mon Sep 17 00:00:00 2001 From: Ben Plowman Date: Tue, 2 Aug 2022 14:45:15 -0700 Subject: [PATCH 2/2] Copy over previous docstring --- flask_restx/swagger.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/flask_restx/swagger.py b/flask_restx/swagger.py index 932e8d02..2b67709e 100644 --- a/flask_restx/swagger.py +++ b/flask_restx/swagger.py @@ -89,8 +89,11 @@ def extract_path(path): def parse_rule(rule): """ - This originally lived in werkzeug.routing.parse_rule until it was removed in werkzeug 2.2.0. Copying it here to - avoid depending on the older version of werkzeug. + Parse a rule and return it as generator. Each iteration yields tuples in the form + ``(converter, arguments, variable)``. If the converter is `None` it's a static url part, otherwise it's a dynamic + one. + + Note: This originally lived in werkzeug.routing.parse_rule until it was removed in werkzeug 2.2.0. """ pos = 0 end = len(rule)