Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] python-flask server ImportError exception at launch #17063

Open
2 of 6 tasks
d3vopz-net opened this issue Nov 13, 2023 · 14 comments
Open
2 of 6 tasks

[BUG] python-flask server ImportError exception at launch #17063

d3vopz-net opened this issue Nov 13, 2023 · 14 comments

Comments

@d3vopz-net
Copy link

d3vopz-net commented Nov 13, 2023

Bug Report Checklist

  • Have you provided a full/minimal spec to reproduce the issue?
  • Have you validated the input using an OpenAPI validator (example)?
  • Have you tested with the latest master to confirm the issue still exists?
  • Have you searched for related issues/PRs?
  • What's the actual output vs expected output?
  • [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description
Exception has occurred: ImportError
cannot import name 'FlaskJSONEncoder' from 'connexion.apps' (/home/d3vopz/openapi/.venv/lib/python3.11/site-packages/connexion/apps/__init__.py)
  File "/home/d3vopz/openapi/test/resources/spec/out/python-flask-server/openapi/encoder.py", line 1, in <module>
    from connexion.apps import FlaskJSONEncoder
  File "/home/d3vopz/openapi/test/resources/spec/out/python-flask-server/openapi/__main__.py", line 5, in <module>
    from openapi import encoder
ImportError: cannot import name 'FlaskJSONEncoder' from 'connexion.apps' (/home/d3vopz/openapi/.venv/lib/python3.11/site-packages/connexion/apps/__init__.py)
openapi-generator version

7.0.1

OpenAPI declaration file content or url
Generation Details

api: python-flask server
pip3 install -r python-flask-server/requirements.txt

Steps to reproduce

curl api
unzip
pip3 install -r python-flask-server/requirements.txt
run in vscode

		"configurations": [
			{
				"name": "Python: oag",
				"type": "python",
				"request": "launch",
				"program": "/home/d3vopz/openapi/test/resources/spec/out/python-flask-server/openapi/__main__.py",
				"console": "integratedTerminal",
				"cwd": "/home/d3vopz/openapi",
				"env": {
					"PYTHONPATH": "/home/d3vopz/openapi/test/python/src:/home/d3vopz/etl/test/src:/home/d3vopz/openapi/test/resources/spec/out/python-flask-server"
				},
				"envFile": "/home/d3vopz/openapi/.env",
				"args":["--resource-path","/home/d3vopz/etl/resources/inject"]
			}
		]

cd /home/d3vopz/openapi ; /usr/bin/env /home/d3vopz/openapi/.venv/bin/python /home/d3vopz/.vscode-server/extensions/ms-python.python-2023.20.0/pythonFiles/lib/python/debugpy/adapter/../../debugpy/launcher 56187 -- /home/d3vopz/openapi/test/resources/spec/out/python-flask-server/openapi/__main__.py --resource-path /home/d3vopz/etl/resources/inject

Related issues/PRs
Suggest a fix
@MarkSchmidts
Copy link

MarkSchmidts commented Nov 16, 2023

I have a very similiar problem

 File "/app/service/app.py", line 10, in <module>
    from service.generated.encoder import JSONEncoder
  File "/app/service/generated/encoder.py", line 1, in <module>
    from connexion.apps.flask_app import FlaskJSONEncoder
ModuleNotFoundError: No module named 'connexion.apps.flask_app'

this is from my app.py

from service.generated.encoder import JSONEncoder
(...)
def create_app() -> connexion.FlaskApp:
    (...)
    connexion_app = connexion.FlaskApp(__name__, specification_dir="..")
    connexion_app.add_api("openapi.yaml")
    (...)
    connexion_app.app.json_encoder = JSONEncoder

This is the generated code beeing generated:
accountinfo/service/generated/encoder.py

from connexion.apps.flask_app import FlaskJSONEncoder
import six

from service.generated.models.base_model_ import Model


class JSONEncoder(FlaskJSONEncoder):
    include_nulls = False

    def default(self, o):
        if isinstance(o, Model):
            dikt = {}
            for attr, _ in six.iteritems(o.openapi_types):
                value = getattr(o, attr)
                if value is None and not self.include_nulls:
                    continue
                attr = o.attribute_map[attr]
                dikt[attr] = value
            return dikt
        return FlaskJSONEncoder.default(self, o)

Maybe it would work if the generator would generate the same but use the standard JSON encoder from connexion?
something like this:

from connexion.jsonifier import JSONEncoder
import six

from service.generated.models.base_model_ import Model


class JSONEncoder(JSONEncoder):
    include_nulls = False

    def default(self, o):
        if isinstance(o, Model):
            dikt = {}
            for attr, _ in six.iteritems(o.openapi_types):
                value = getattr(o, attr)
                if value is None and not self.include_nulls:
                    continue
                attr = o.attribute_map[attr]
                dikt[attr] = value
            return dikt
        return JSONEncoder.default(self, o)

@MarkSchmidts
Copy link

MarkSchmidts commented Nov 16, 2023

Actually the issue is probably solved by using FlaskJSONProvider. Flask changed with a version update.

Here's the current jsonproviderClass:
https://github.com/spec-first/connexion/blob/b244d809089eb584ce3e9661d619ed5564ca4103/connexion/frameworks/flask.py#L123

I think the current code that the generator generates is incorrect and should be replaced.

@MarkSchmidts
Copy link

This might fix it
https://github.com/OpenAPITools/openapi-generator/pull/17144/files

But I can't get the dev setup running.
If someone can check the PR, this issue could be fixed.

@d3vopz-net
Copy link
Author

d3vopz-net commented Dec 26, 2023

checked . its still in 7.2.0 :(

checked out https://github.com/MarkSchmidts/openapi-generator/tree/master

but

Traceback (most recent call last):
  File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/home/ripper/gitrepo/gitlab.com/d3vopz-public/tools/d3vopz-openapi.git/test/resources/spec/out/python-flask-server/openapi/__main__.py", line 5, in <module>
    from openapi import encoder
  File "/home/ripper/gitrepo/gitlab.com/d3vopz-public/tools/d3vopz-openapi.git/test/resources/spec/out/python-flask-server/openapi/encoder.py", line 1, in <module>
    from connexion.frameworks.flask import FlaskJSONProvider
ModuleNotFoundError: No module named 'connexion.frameworks'

Found also this swagger-api/swagger-codegen#12278

@dfsp-spirit
Copy link

Is there any workaround for this, or should we try to monkey-patch with the patch @MarkSchmidts suggested for now?

@d3vopz-net
Copy link
Author

Is there any workaround for this, or should we try to monkey-patch with the patch @MarkSchmidts suggested for now?

I got no working workaround. sorry.

@EingeoelterBolt
Copy link

EingeoelterBolt commented Jan 20, 2024

A workaround that helped me to run the generated server was to remove these lines from the requirements.txt file:

connexion[swagger-ui] >= 2.6.0; python_version>="3.6"
# 2.3 is the last version that supports python 3.4-3.5
connexion[swagger-ui] <= 2.3.0; python_version=="3.5" or python_version=="3.4"
# connexion requires werkzeug but connexion < 2.4.0 does not install werkzeug
# we must peg werkzeug versions below to fix connexion
# https://github.com/zalando/connexion/pull/1044
werkzeug == 0.16.1; python_version=="3.5" or python_version=="3.4"

and replace it with:

connexion[swagger-ui]==2.14.2

AND

replace in the Dockerfile the line

FROM python:3-alpine

to

FROM python:3.11.5

@wing328
Copy link
Member

wing328 commented Jan 27, 2024

i think this has been fixed in the latest master. please pull the latest or use the snapshot JAR to give it a try.

@d3vopz-net
Copy link
Author

i think this has been fixed in the latest master. please pull the latest or use the snapshot JAR to give it a try.

Idk why i got now this issue when starting the generator:

...
Error: Unable to initialize main class org.openapitools.codegen.OpenAPIGenerator
Caused by: java.lang.NoClassDefFoundError: io/airlift/airline/ParseArgumentsUnexpectedException

Its mentioned in modules/openapi-generator-cli/pom.xml but does not exist in modules/openapi-generator-cli/target folder.

Im sry, but is it another issue or my setup?

best

@wing328
Copy link
Member

wing328 commented Jan 28, 2024

which JDK version are you using?

the latest 7.x requires JDK11 +

@d3vopz-net
Copy link
Author

d3vopz-net commented Jan 28, 2024 via email

@wing328
Copy link
Member

wing328 commented Jan 29, 2024

can you please PM me via Slack this week to help you troubleshoot the issue?

@tomtucker
Copy link

I have followed the workaround suggested by @EingeoelterBolt above and removed, recreated, and activated my virtual environment (python -m venv venv) to make sure there are no collisions..

Now I receive the error:

(venv) 🐉 >python3 -m openapi_server
Failed to add operation for POST /capture
Traceback (most recent call last):
  File "/Users/ttucker/dev/python/PaymentsServer/openapi-generator/flask2/venv/lib/python3.11/site-packages/connexion/apis/abstract.py", line 222, in add_paths
    self.add_operation(path, method)
  File "/Users/ttucker/dev/python/PaymentsServer/openapi-generator/flask2/venv/lib/python3.11/site-packages/connexion/apis/abstract.py", line 175, in add_operation
    operation = make_operation(
                ^^^^^^^^^^^^^^^
  File "/Users/ttucker/dev/python/PaymentsServer/openapi-generator/flask2/venv/lib/python3.11/site-packages/connexion/operations/__init__.py", line 16, in make_operation
    return spec.operation_cls.from_spec(spec, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/ttucker/dev/python/PaymentsServer/openapi-generator/flask2/venv/lib/python3.11/site-packages/connexion/operations/openapi.py", line 134, in from_spec
    return cls(
           ^^^^
  File "/Users/ttucker/dev/python/PaymentsServer/openapi-generator/flask2/venv/lib/python3.11/site-packages/connexion/operations/openapi.py", line 81, in __init__
    super().__init__(
  File "/Users/ttucker/dev/python/PaymentsServer/openapi-generator/flask2/venv/lib/python3.11/site-packages/connexion/operations/abstract.py", line 101, in __init__
    self._resolution = resolver.resolve(self)
                       ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/ttucker/dev/python/PaymentsServer/openapi-generator/flask2/venv/lib/python3.11/site-packages/connexion/resolver.py", line 47, in resolve
    return Resolution(self.resolve_function_from_operation_id(operation_id), operation_id)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/ttucker/dev/python/PaymentsServer/openapi-generator/flask2/venv/lib/python3.11/site-packages/connexion/resolver.py", line 71, in resolve_function_from_operation_id
    raise ResolverError(msg, sys.exc_info())
connexion.exceptions.ResolverError: <ResolverError: Cannot resolve operationId "swagger_server.controllers.default_controller.capture_transaction"! Import error was "No module named 'swagger_server'">

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "/Users/ttucker/dev/python/PaymentsServer/openapi-generator/flask2/openapi_server/__main__.py", line 19, in <module>
    main()
  File "/Users/ttucker/dev/python/PaymentsServer/openapi-generator/flask2/openapi_server/__main__.py", line 11, in main
    app.add_api('openapi.yaml',
  File "/Users/ttucker/dev/python/PaymentsServer/openapi-generator/flask2/venv/lib/python3.11/site-packages/connexion/apps/flask_app.py", line 74, in add_api
    api = super().add_api(specification, **kwargs)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/ttucker/dev/python/PaymentsServer/openapi-generator/flask2/venv/lib/python3.11/site-packages/connexion/apps/abstract.py", line 149, in add_api
    api = self.api_cls(specification,
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/ttucker/dev/python/PaymentsServer/openapi-generator/flask2/venv/lib/python3.11/site-packages/connexion/apis/abstract.py", line 119, in __init__
    self.add_paths()
  File "/Users/ttucker/dev/python/PaymentsServer/openapi-generator/flask2/venv/lib/python3.11/site-packages/connexion/apis/abstract.py", line 229, in add_paths
    self._handle_add_operation_error(path, method, err.exc_info)
  File "/Users/ttucker/dev/python/PaymentsServer/openapi-generator/flask2/venv/lib/python3.11/site-packages/connexion/apis/abstract.py", line 244, in _handle_add_operation_error
    raise value.with_traceback(traceback)
  File "/Users/ttucker/dev/python/PaymentsServer/openapi-generator/flask2/venv/lib/python3.11/site-packages/connexion/resolver.py", line 68, in resolve_function_from_operation_id
    return self.function_resolver(operation_id)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/ttucker/dev/python/PaymentsServer/openapi-generator/flask2/venv/lib/python3.11/site-packages/connexion/utils.py", line 116, in get_function_from_name
    module = importlib.import_module(module_name)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/ttucker/.pyenv/versions/3.11.7/lib/python3.11/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen importlib._bootstrap>", line 1204, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1140, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'swagger_server'

@tomtucker
Copy link

I resolved the above issue by downgrading the python virtual environment for server execution to python 3.9 instead of python 3.11.

Still using @EingeoelterBolt's changes to requirements.txt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants