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.