Skip to content

Commit e5599c8

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 e5599c8

File tree

2 files changed

+49
-6
lines changed

2 files changed

+49
-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: 44 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,10 @@
2022
)
2123

2224

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

0 commit comments

Comments
 (0)