Skip to content

Commit 77ff259

Browse files
author
Tomáš Trval
committed
fix: flask import of _endpoint_from_view_func is now resolved new util function import_check_view_func #567
1 parent 7ce0ef8 commit 77ff259

File tree

2 files changed

+47
-6
lines changed

2 files changed

+47
-6
lines changed

flask_restx/api.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,6 @@
1414
from flask import url_for, request, current_app
1515
from flask import make_response as original_flask_make_response
1616

17-
try:
18-
from flask.helpers import _endpoint_from_view_func
19-
except ImportError:
20-
from flask.scaffold import _endpoint_from_view_func
2117
from flask.signals import got_request_exception
2218

2319
from jsonschema import RefResolver
@@ -45,10 +41,13 @@
4541
from .postman import PostmanCollectionV1
4642
from .resource import Resource
4743
from .swagger import Swagger
48-
from .utils import default_id, camel_to_dash, unpack
44+
from .utils import default_id, camel_to_dash, unpack, import_check_view_func
4945
from .representations import output_json
5046
from ._http import HTTPStatus
5147

48+
endpoint_from_view_func = import_check_view_func()
49+
50+
5251
RE_RULES = re.compile("(<.*>)")
5352

5453
# List headers that should never be handled by Flask-RESTX
@@ -850,7 +849,7 @@ def _blueprint_setup_add_url_rule_patch(
850849
rule = blueprint_setup.url_prefix + rule
851850
options.setdefault("subdomain", blueprint_setup.subdomain)
852851
if endpoint is None:
853-
endpoint = _endpoint_from_view_func(view_func)
852+
endpoint = endpoint_from_view_func(view_func)
854853
defaults = blueprint_setup.url_defaults
855854
if "defaults" in options:
856855
defaults = dict(defaults, **options.pop("defaults"))

flask_restx/utils.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import re
2+
import warnings
3+
import typing
24

35
from collections import OrderedDict
46
from copy import deepcopy
@@ -20,6 +22,9 @@
2022
)
2123

2224

25+
class FlaskCompatibilityWarning(DeprecationWarning):
26+
pass
27+
2328
def merge(first, second):
2429
"""
2530
Recursively merges two dictionaries.
@@ -118,3 +123,40 @@ def unpack(response, default_code=HTTPStatus.OK):
118123
return data, code or default_code, headers
119124
else:
120125
raise ValueError("Too many response values")
126+
127+
128+
def import_check_view_func():
129+
"""
130+
Resolve import flask _endpoint_from_view_func.
131+
132+
Show warning if function cannot be found and provide copy of last known implementation.
133+
134+
Note: This helper method exists because reoccurring problem with flask function, but
135+
actual method body remaining the same in each flask version.
136+
"""
137+
import importlib.metadata
138+
flask_version = importlib.metadata.version("flask").split(".")
139+
140+
def local_endpoint_from_view_func(view_func: typing.Callable) -> str:
141+
"""Copy of flask internal helper that returns the default endpoint for a given
142+
function. This always is the function name.
143+
"""
144+
assert view_func is not None, "expected view func if endpoint is not provided."
145+
return view_func.__name__
146+
try:
147+
if flask_version[0] == "1":
148+
from flask.helpers import _endpoint_from_view_func
149+
elif flask_version[0] == "2":
150+
from flask.scaffold import _endpoint_from_view_func
151+
elif flask_version[0] == "3":
152+
from flask.sansio.scaffold import _endpoint_from_view_func
153+
else:
154+
warnings.simplefilter("once", FlaskCompatibilityWarning)
155+
_endpoint_from_view_func = None
156+
except ImportError:
157+
warnings.simplefilter("once", FlaskCompatibilityWarning)
158+
_endpoint_from_view_func = None
159+
if _endpoint_from_view_func is None:
160+
_endpoint_from_view_func = local_endpoint_from_view_func
161+
return _endpoint_from_view_func
162+

0 commit comments

Comments
 (0)