Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
www/py-flask-restx: unbreak after 3232af1
>>> import flask_restx Traceback (most recent call last): File "/usr/local/lib/python3.9/site-packages/flask_restx/api.py", line 18, in <module> from flask.helpers import _endpoint_from_view_func ImportError: cannot import name '_endpoint_from_view_func' from 'flask.helpers' (/usr/local/lib/python3.9/site-packages/flask/helpers.py) During handling of the above exception, another exception occurred: Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.9/site-packages/flask_restx/__init__.py", line 2, in <module> from .api import Api # noqa File "/usr/local/lib/python3.9/site-packages/flask_restx/api.py", line 20, in <module> from flask.scaffold import _endpoint_from_view_func ModuleNotFoundError: No module named 'flask.scaffold'
- Loading branch information
Showing
2 changed files
with
128 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
https://github.com/python-restx/flask-restx/pull/572 | ||
|
||
--- flask_restx/api.py.orig 2023-10-22 12:20:40 UTC | ||
+++ flask_restx/api.py | ||
@@ -14,10 +14,6 @@ from flask import make_response as original_flask_make | ||
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 | ||
@@ -45,10 +41,13 @@ from .swagger import Swagger | ||
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 | ||
@@ -850,7 +849,7 @@ class Api(object): | ||
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")) | ||
--- flask_restx/utils.py.orig 2023-10-22 12:20:40 UTC | ||
+++ flask_restx/utils.py | ||
@@ -1,4 +1,6 @@ import re | ||
import re | ||
+import warnings | ||
+import typing | ||
|
||
from collections import OrderedDict | ||
from copy import deepcopy | ||
@@ -17,9 +19,14 @@ __all__ = ( | ||
"not_none", | ||
"not_none_sorted", | ||
"unpack", | ||
+ "import_check_view_func", | ||
) | ||
|
||
|
||
+class FlaskCompatibilityWarning(DeprecationWarning): | ||
+ pass | ||
+ | ||
+ | ||
def merge(first, second): | ||
""" | ||
Recursively merges two dictionaries. | ||
@@ -118,3 +125,43 @@ def unpack(response, default_code=HTTPStatus.OK): | ||
return data, code or default_code, headers | ||
else: | ||
raise ValueError("Too many response values") | ||
+ | ||
+ | ||
+def to_view_name(view_func: typing.Callable) -> str: | ||
+ """Helper that returns the default endpoint for a given | ||
+ function. This always is the function name. | ||
+ | ||
+ Note: copy of simple flask internal helper | ||
+ """ | ||
+ assert view_func is not None, "expected view func if endpoint is not provided." | ||
+ return view_func.__name__ | ||
+ | ||
+ | ||
+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(".") | ||
+ 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 = to_view_name | ||
+ return _endpoint_from_view_func | ||
--- tests/test_utils.py.orig 2023-10-22 12:20:40 UTC | ||
+++ tests/test_utils.py | ||
@@ -98,3 +98,17 @@ class UnpackTest(object): | ||
def test_too_many_values(self): | ||
with pytest.raises(ValueError): | ||
utils.unpack((None, None, None, None)) | ||
+ | ||
+ | ||
+class ToViewNameTest(object): | ||
+ def test_none(self): | ||
+ with pytest.raises(AssertionError): | ||
+ _ = utils.to_view_name(None) | ||
+ | ||
+ def test_name(self): | ||
+ assert utils.to_view_name(self.test_none) == self.test_none.__name__ | ||
+ | ||
+ | ||
+class ImportCheckViewFuncTest(object): | ||
+ def test_callable(self): | ||
+ assert callable(utils.import_check_view_func()) |