Skip to content

Commit

Permalink
fix: flask import of _endpoint_from_view_func is now resolved new uti…
Browse files Browse the repository at this point in the history
…l function import_check_view_func python-restx#567
  • Loading branch information
Tomáš Trval committed Oct 3, 2023
1 parent 7ce0ef8 commit e5599c8
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 6 deletions.
11 changes: 5 additions & 6 deletions flask_restx/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@
from flask import url_for, request, current_app
from flask import make_response as original_flask_make_response

try:
from flask.helpers import _endpoint_from_view_func
except ImportError:
from flask.scaffold import _endpoint_from_view_func
from flask.signals import got_request_exception

from jsonschema import RefResolver
Expand Down Expand Up @@ -45,10 +41,13 @@
from .postman import PostmanCollectionV1
from .resource import Resource
from .swagger import Swagger
from .utils import default_id, camel_to_dash, unpack
from .utils import default_id, camel_to_dash, unpack, import_check_view_func
from .representations import output_json
from ._http import HTTPStatus

endpoint_from_view_func = import_check_view_func()


RE_RULES = re.compile("(<.*>)")

# List headers that should never be handled by Flask-RESTX
Expand Down Expand Up @@ -850,7 +849,7 @@ def _blueprint_setup_add_url_rule_patch(
rule = blueprint_setup.url_prefix + rule
options.setdefault("subdomain", blueprint_setup.subdomain)
if endpoint is None:
endpoint = _endpoint_from_view_func(view_func)
endpoint = endpoint_from_view_func(view_func)
defaults = blueprint_setup.url_defaults
if "defaults" in options:
defaults = dict(defaults, **options.pop("defaults"))
Expand Down
44 changes: 44 additions & 0 deletions flask_restx/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import re
import warnings
import typing

from collections import OrderedDict
from copy import deepcopy
Expand All @@ -20,6 +22,10 @@
)


class FlaskCompatibilityWarning(DeprecationWarning):
pass


def merge(first, second):
"""
Recursively merges two dictionaries.
Expand Down Expand Up @@ -118,3 +124,41 @@ def unpack(response, default_code=HTTPStatus.OK):
return data, code or default_code, headers
else:
raise ValueError("Too many response values")


def import_check_view_func():
"""
Resolve import flask _endpoint_from_view_func.
Show warning if function cannot be found and provide copy of last known implementation.
Note: This helper method exists because reoccurring problem with flask function, but
actual method body remaining the same in each flask version.
"""
import importlib.metadata

flask_version = importlib.metadata.version("flask").split(".")

def local_endpoint_from_view_func(view_func: typing.Callable) -> str:
"""Copy of flask internal helper that returns the default endpoint for a given
function. This always is the function name.
"""
assert view_func is not None, "expected view func if endpoint is not provided."
return view_func.__name__

try:
if flask_version[0] == "1":
from flask.helpers import _endpoint_from_view_func
elif flask_version[0] == "2":
from flask.scaffold import _endpoint_from_view_func
elif flask_version[0] == "3":
from flask.sansio.scaffold import _endpoint_from_view_func
else:
warnings.simplefilter("once", FlaskCompatibilityWarning)
_endpoint_from_view_func = None
except ImportError:
warnings.simplefilter("once", FlaskCompatibilityWarning)
_endpoint_from_view_func = None
if _endpoint_from_view_func is None:
_endpoint_from_view_func = local_endpoint_from_view_func
return _endpoint_from_view_func

0 comments on commit e5599c8

Please sign in to comment.