J'ai mis en place la structure la plus basique d'une API en python avec la pile
flask - connexion - flaskInjector
selon le code ci-dessous. Lorsque l'API est exécutée et que FlaskInjector est initialisé, il échoue avec le message d'erreur:
injector.CallError: appel à RequestScope. init () a échoué: init () manque 1 argument de position requis: 'injector' (pile d'injection: [])
Mon système est Ubuntu 18.04, les packages dans l'environnement conda comme suit:
Extrait pertinent de la liste conda:
127.0.0.1 - - [21/May/2019 08:16:31] "GET / HTTP/1.1" 500 - Traceback (most recent call last): File "/home/christian/.conda/envs/miccroservice/lib/python3.6/site-packages/flask/app.py", line 2309, in __call__ return self.wsgi_app(environ, start_response) File "/home/christian/.conda/envs/miccroservice/lib/python3.6/site-packages/flask/app.py", line 2295, in wsgi_app response = self.handle_exception(e) File "/home/christian/.conda/envs/miccroservice/lib/python3.6/site-packages/flask/app.py", line 1741, in handle_exception reraise(exc_type, exc_value, tb) File "/home/christian/.conda/envs/miccroservice/lib/python3.6/site-packages/flask/_compat.py", line 35, in reraise raise value File "/home/christian/.conda/envs/miccroservice/lib/python3.6/site-packages/flask/app.py", line 2292, in wsgi_app response = self.full_dispatch_request() File "/home/christian/.conda/envs/miccroservice/lib/python3.6/site-packages/flask/app.py", line 1815, in full_dispatch_request rv = self.handle_user_exception(e) File "/home/christian/.conda/envs/miccroservice/lib/python3.6/site-packages/flask/app.py", line 1718, in handle_user_exception reraise(exc_type, exc_value, tb) File "/home/christian/.conda/envs/miccroservice/lib/python3.6/site-packages/flask/_compat.py", line 35, in reraise raise value File "/home/christian/.conda/envs/miccroservice/lib/python3.6/site-packages/flask/app.py", line 1811, in full_dispatch_request rv = self.preprocess_request() File "/home/christian/.conda/envs/miccroservice/lib/python3.6/site-packages/flask/app.py", line 2087, in preprocess_request rv = func() File "/home/christian/.conda/envs/miccroservice/lib/python3.6/site-packages/flask_injector.py", line 327, in reset_request_scope_before injector_not_null.get(request_scope_class).prepare() File "/home/christian/.conda/envs/miccroservice/lib/python3.6/site-packages/injector.py", line 738, in get result = scope_instance.get(key, binding.provider).get(self) File "/home/christian/.conda/envs/miccroservice/lib/python3.6/site-packages/injector.py", line 144, in get return injector.create_object(self._cls) File "/home/christian/.conda/envs/miccroservice/lib/python3.6/site-packages/injector.py", line 789, in create_object (), additional_kwargs, e, self._stack,) File "/home/christian/.conda/envs/miccroservice/lib/python3.6/site-packages/injector.py", line 73, in reraise raise exception.with_traceback(tb) File "/home/christian/.conda/envs/miccroservice/lib/python3.6/site-packages/injector.py", line 782, in create_object init(instance, **additional_kwargs) injector.CallError: Call to RequestScope.__init__() failed: __init__() missing 1 required positional argument: 'injector' (injection stack: []) 127.0.0.1 - - [21/May/2019 08:16:31] "GET /?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 200 - 127.0.0.1 - - [21/May/2019 08:16:31] "GET /?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 200 - 127.0.0.1 - - [21/May/2019 08:16:31] "GET /?__debugger__=yes&cmd=resource&f=jquery.js HTTP/1.1" 200 - 127.0.0.1 - - [21/May/2019 08:16:31] "GET /?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 200 -
Le Le projet est organisé comme suit:
./app.py:
* Serving Flask app "app" (lazy loading) * Environment: production WARNING: Do not use the development server in a production environment. Use a production WSGI server instead. * Debug mode: on * Running on http://0.0.0.0:9090/ (Press CTRL+C to quit) * Restarting with stat * Debugger is active! * Debugger PIN: 498-670-595
./api/items.py:
swagger: "2.0" info: title: "My first API" version: "1.0" basePath: /api paths: /items/: get: responses: '200': description: 'Fetch a list of items' schema: type: array items: $ref: '#/definitions/Item' definitions: Item: type: object properties: id: type: integer format: int64 name: { type: string }
./providers/provider.py:
class ItemsProvider(object): def __init__(self, items: list = []): self._items = items def get(self, number_of_items: int = 5) -> list: if not self._items: return [] if number_of_items > len(self._items): number_of_items = len(self._items) return self._items[0:number_of_items]
./swagger/app.yaml:
from flask_injector import inject from providers.provider import ItemsProvider @inject(data_provider=ItemsProvider) def search(data_provider) -> list: return data_provider.get()
Lors de l'exécution de l'application avec python app.py, le serveur api démarre comme prévu:
from injector import Binder from flask_injector import FlaskInjector from connexion.resolver import RestyResolver import connexion from providers.provider import ItemsProvider def configure(binder: Binder) -> Binder: binder.bind( ItemsProvider, ItemsProvider([{'Name': 'Test 1'}]) ) return binder if __name__ == '__main__': app = connexion.App(__name__, specification_dir='./swagger/') app.add_api('app.yaml', resolver=RestyResolver('api')) FlaskInjector(app=app.app, modules=[configure]) app.run(port=9090, debug=True)
Cependant, en adressant le serveur ou le point de terminaison des éléments dans le navigateur, les éléments suivants la pile d'échecs apparaît:
# Name Version Build Channel ... connexion 2.2.0 pypi_0 pypi ... elasticsearch 7.0.1 pypi_0 pypi fastavro 0.21.23 pypi_0 pypi flask 1.0.2 pypi_0 pypi flask-cors 3.0.7 pypi_0 pypi flask-injector 0.12.0 pypi_0 pypi flask-opentracing 1.0.0 pypi_0 pypi flask-restplus 0.9.2 pypi_0 pypi flask-script 2.0.6 pypi_0 pypi flask-sqlalchemy 2.3.2 pypi_0 pypi ... injector 0.12.0 pypi_0 pypi ... swagger-ui-bundle 0.0.3 pypi_0 pypi ...
3 Réponses :
merci pour vos réponses. Je suis venu en attendant une solution de travail. Le décorateur @inject
peut, au moins dans mes versions actuelles, ne pas être utilisé avec des paramètres. Cela fonctionne si je change la fonction en:
@inject def search(dataprovider=ItemsProvider_()) -> list: data = dataprovider.get(0) return data
Merci!
La mise à jour de la version de l'injecteur de injector-0.12.0 à injector-0.17.0 a résolu mon problème.
J'ai eu cette erreur dans la situation suivante:
J'ai défini la classe to-be-inject dans le module où j'instancie mon application flask et configure l'injecteur:
app.py p>
from app import MyClass @inject def foo(my_object: MyClass): return 'Something'
J'injecte la classe dans un module différent:
controller.py
class MyClass: def __init__(bar) self.bar = bar # ... instantiate flask app and injector
Pour moi le la solution était de créer un module séparé où je définis MyClass
qui est différent de celui où j'instancie l'injecteur.
Il semble que le démarrage de Connexion est erroné par rapport à la documentation de l'injecteur de flacon github.com/alecthomas/ …
Avez-vous essayé de renommer vos importations? Ex: 'from flask_injector import inject as i' .. C'est un problème courant si vous avez des collisions dans votre espace de noms entre les importations.