Skip to content

Commit

Permalink
www/py-flask-restx: unbreak after 3232af1
Browse files Browse the repository at this point in the history
>>> 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
jbeich committed Nov 27, 2023
1 parent c50a674 commit 0335abf
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 0 deletions.
1 change: 1 addition & 0 deletions www/py-flask-restx/Makefile
@@ -1,5 +1,6 @@
PORTNAME= flask-restx
PORTVERSION= 1.2.0
PORTREVISION= 1
CATEGORIES= www python
MASTER_SITES= PYPI
PKGNAMEPREFIX= ${PYTHON_PKGNAMEPREFIX}
Expand Down
127 changes: 127 additions & 0 deletions www/py-flask-restx/files/patch-flask3
@@ -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())

0 comments on commit 0335abf

Please sign in to comment.