Structuring your Flask project the right way (no Blueprint) - flask

Intro
I've read like a thousand posts on SO and other sites trying to figure out what's wrong with my Flask structure and why I can't seem to figure out something. As a last resort, I decided to finally ask the question here.
My project is really simple:
I have to fetch some data from some networking devices via API, process the data and store it in a Postgresql DB (most part of the code is in lib/).
This project is going to be deployed on multiple environments (test, dev, staging and prod).
To do the above I'm using the following:
Flask-SQLAlchemy + Flask-Migrate + Flask-Script - all of these for handling migrations and DB related operations;
Python-dotenv - for handling sensitive configuration data
Project details
My project structure looks like this:
my_project/
├── api/
├── app.py
├── config.py
├── __init__.py
├── lib/
│   ├── exceptions.py
│   └── f5_bigip.py
├── log.py
├── logs/
├── manage.py
├── migrations/
├── models/
│   ├── __init__.py
│   ├── model1.py
│   └── model2.py
└── run.py
My app.py looks like this:
import os
import sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from dotenv import load_dotenv
from flask import Flask
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
migrate = Migrate()
def create_app():
load_dotenv()
app = Flask(__name__)
environment = app.config['ENV']
if environment == 'production':
app.config.from_object('config.ProductionConfig')
elif environment == 'testing':
app.config.from_object('config.TestingConfig')
else:
app.config.from_object('config.DevelopmentConfig')
db.init_app(app)
migrate.init_app(app, db)
return app
My config.py looks like this:
import os
from sqlalchemy.engine.url import URL
PROJECT_ROOT = os.path.dirname(os.path.realpath(__file__))
class BaseConfig:
DEBUG = False
TESTING = False
DB_DRIVERNAME = os.getenv('DB_DRIVERNAME')
DB_HOST = os.getenv('DB_HOST')
DB_PORT = os.getenv('DB_PORT')
DB_NAME = os.getenv('DB_NAME')
DB_USERNAME = os.getenv('DB_USERNAME')
DB_PASSWORD = os.getenv('DB_PASSWORD')
DB = {
'drivername': DB_DRIVERNAME,
'host': DB_HOST,
'port': DB_PORT,
'database': DB_NAME,
'username': DB_USERNAME,
'password': DB_PASSWORD,
}
SQLALCHEMY_DATABASE_URI = URL(**DB)
SQLALCHEMY_TRACK_MODIFICATIONS = False
class DevelopmentConfig(BaseConfig):
DEVELOPMENT = True
DEBUG = True
class TestingConfig(BaseConfig):
TESTING = True
class StagingConfig(BaseConfig):
DEVELOPMENT = True
DEBUG = True
class ProductionConfig(BaseConfig):
pass
My __init__.py looks like this:
from contextlib import contextmanager
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
# here, create_engine needs the SQLALCHEMY_DATABASE_URI
# how do I get it from the proper config?
engine = create_engine()
Session = sessionmaker(bind=engine)
#contextmanager
def session_scope():
"""
Provide a transactional scope around a series of operations.
"""
session = Session()
try:
yield session
session.commit()
except Exception as e:
print(f'Something went wrong here: {str(e)}. rolling back.')
session.rollback()
raise
finally:
session.close()
My manage.py looks like this:
from flask_script import Manager
from flask_migrate import MigrateCommand
from app import create_app
from models import *
manager = Manager(create_app)
manager.add_command('db', MigrateCommand)
if __name__ == '__main__':
manager.run()
My models/model1.py looks like this:
from sqlalchemy.dialects.postgresql import INET
from sqlalchemy.sql import func
from app import db
class Model1(db.Model):
__tablename__ = 'model1'
id = db.Column(db.BigInteger, primary_key=True, autoincrement=True)
ip_address = db.Column(INET, unique=True, nullable=False)
last_update = db.Column(db.DateTime(), server_default=func.now())
def __repr__(self):
return f'<Model1: {self.ip_address}>'
def __init__(self, ip_address):
self.ip_address = ip_address
Questions
Now, I have three main questions:
In my main __init__.py how can I import SQLALCHEMY_DATABASE_URI from the app's config?
Having the Session() object in the __init__.py doesn't seem too intuitive. Should it be placed in other places? For more context, the session is used in lib/f5_bigip.py and is probably going to be used in the api/ as well.
Is the overall project structure ok?

Your questions 1 and 2 are directly related to the part of your project that I found strange, so instead of answering those questions I'll just give you a much simpler and better way.
It seems in __init__.py you are implementing your own database sessions, just so that you can create a scoped session context manager. Maybe you've got that code from another project? It is not nicely integrated with the rest of your project, which uses the Flask-SQLAlchemy extension, you are just ignoring Flask-SQLAlchemy, which manages your database connections and sessions, and basically creating another connection into the database and new sessions.
What you should do instead is leverage the connections and sessions that Flask-SQLAlchemy provides. I would rewrite __init__.py as follows (doing this by memory, so excuse minor mistakes):
from contextlib import contextmanager
from app import db
#contextmanager
def session_scope():
"""
Provide a transactional scope around a series of operations.
"""
try:
yield db.session
session.commit()
except Exception as e:
print(f'Something went wrong here: {str(e)}. rolling back.')
db.session.rollback()
raise
finally:
db.session.close()
With this you are reusing the connection/sessions from Flask-SQLAlchemy. Your question 1 then is not a problem anymore. For question 2, you would use db.session anywhere in your app where you need database sessions.
Regarding question 3 I think you're mostly okay. I would suggest you do not use Flask-Script, which is a fairly old and unmaintained extension. Instead you can move your CLI to Flask's own CLI support.

Related

Tests keep using "production" database even after I change sqlalchemy_database_uri in pytest fixture

I have flask application that I am using to get familiar with the flask-sqlalchemy lib and testing using Pytest with fixtures.
I am trying to overwrite the sqlalchemy_database_uri in the app configuration in my test fixtures. But the problem is that when I run them, my tests seem to be working with the "production" database rather than with an ephemeral one. The test record I created for test via fixtures are all in the database that I create in the app initialization.
When I run the test in the example below using pytest from the root folder in that structure. The tests are collected ok, run and pass as expected. But after running the tests a new database called hello.db has been created in the instance folder. What I am trying to do is that the tests use a sqlite database in memory that disapears after the tests run.
How do I go about writing/configuring my tests so that I use an ephemeral sqlite database in memory that is only used for those tests?
# Folder structure
.
├── mini_app
│   ├── __init__.py
│   ├── app.py
│   ├── config.py
│   └── models.py
└── tests
├── __init__.py
└── test_all.py
## app.py
from flask import Flask, request
from flask_sqlalchemy import SQLAlchemy
from mini_app import config
db = SQLAlchemy()
def create_app(cfg= None):
if cfg is None:
cfg = config.Config()
app = Flask(__name__)
app.config.from_object(cfg)
# Init_apps
db.init_app(app)
#app.route("/square")
def square():
"""A view which uses no templates and no database."""
number = int(request.args.get("number", 0))
return str(number ** 2)
return app
## config.py
class Config:
SQLALCHEMY_DATABASE_URI = "sqlite:///hello.db"
## models.py
from mini_app.app import db
class Author(db.Model):
__tablename__ = "authors"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String)
## test_all.py
import pytest
import mini_app.app
import mini_app.models
#pytest.fixture
def client():
# Prepare before your test
app = mini_app.app.create_app()
app.config["TESTING"] = True
app.testing = True
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite://"
with app.test_client() as client:
with app.app_context():
mini_app.app.db.create_all()
author1 = mini_app.models.Author(id=1, name="foo")
mini_app.app.db.session.add(author1)
mini_app.app.db.session.commit()
# Give control to the test
yield client
# Cleanup after the test run.
# ... nothing here, for this simple example
def test_square(client):
rv = client.get("/square?number=8")
assert b"64" == rv.data

All routes giving 404 in flask despite the routes.py being successfully imported

I currently working on a flask backend but have hit an issue where all routes return a 404 despite the routes.py apparently running.
routes.py:
import sys, os, json
from flask import Flask, render_template
from flask_cors import CORS, cross_origin
app = Flask(__name__)
app.config.from_pyfile('config.py')
CORS(app)
#app.route('/', endpoint='index')
#app.route('/index', methods=['GET'], endpoint='index')
#cross_origin()
def index():
print('Hello world!', file=sys.stderr)
return render_template('index.html', title='home')
#app.route('/projects', endpoint='projects') # route for projects showcase including json project data loading
#cross_origin()
def projects():
projects = os.path.join(app.static_folder, 'data', 'projects.json')
with open(projects) as pData:
data = json.load(pData)
return render_template('projects.html', title='showcase', data=data)
#app.route('/contact', endpoint='contact')
def contact():
return render_template('contact.html', title='contact')
print('Hello routes!', file=sys.stderr) #testing line
When I launch it the output is this:
* Serving Flask app 'ClayG' (lazy loading)
* Environment: development
* Debug mode: on
Hello routes!
* Restarting with stat
* Debugger is active!
Hello routes!
* Debugger PIN: 274-753-929
* Running on http://127.0.0.1:5000/
the print function at the end of routes.py runs so my app is making it through, but when i visit localhost:5000 I get a 404 with only this in the terminal output
127.0.0.1 - - [05/Feb/2022 17:20:29] "GET / HTTP/1.1" 404 -
The other files and file structure
.
├── ClayG.py
├── .flaskenv
├── app
│ ├── config.py
│ ├── routes.py
│ └── __init__.py
ClayG.py
import os, sys
sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__))))
from app import app
.flaskenv
FLASK_APP=ClayGale
FLASK_ENV=development
init.py
from flask import Flask
from . import routes
app = Flask(__name__)
config.py
class Config:
STATIC_FOLDER = 'static'
TEMPLATES_FOLDER = 'templates'
DEBUG = True
TESTING = True
One thing i've noticed is that adding FLASK_ENV = 'development' to the config class is that it still launches as production and I can only get it to launch in development with the .flaskenv file. I'm unfortunately just stumped as for what to do from here so any wisdom on what to try would be helpful.
You have created two Flask apps. One in routes.py with the endpoints, and a new one in __init__.py which is completely empty. You should use the previously created app in the __init__.py file:
from . import routes
app = routes.app

Is it possible to use FastAPI with Django?

I'm a Django developer and recently stumbled onto the FastAPI framework.
Then I decided to give it a shot. But usually when you talk about building RESTful APIs with Django you usually use the Django Rest Framework (DRF).
Is anybody aware if it is possible to substitute DRF by FastAPI using Django perks, like its ORM, and still have access to all of FastAPI's async features?
Up until now I only found one article on this. But in the process of integration the author lost most of the features of FastAPI.
You can find it here.
In the FastAPI docs, they do mention that it is possible to redirect certain request to a WSGI application here.
Short Answer
Yes it's possible with WSGIMiddleware.
For example, you can use all Django features (yes admin too) with mounting, with this example code.
import os
from importlib.util import find_spec
from configurations.wsgi import get_wsgi_application
from fastapi import FastAPI
from fastapi.middleware.wsgi import WSGIMiddleware
from fastapi.staticfiles import StaticFiles
from api import router
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myapp.settings")
os.environ.setdefault("DJANGO_CONFIGURATIN", "Localdev")
application = get_wsgi_application()
app = FastAPI()
app.mount("/admin", WSGIMiddleware(application))
app.mount("/static",
StaticFiles(
directory=os.path.normpath(
os.path.join(find_spec("django.contrib.admin").origin, "..", "static")
)
),
name="static",
)
Also this one is from WSGIMiddleware documentation, it's a more straight-forward example (This one is for Flask but it demonstrates the same idea.).
from fastapi import FastAPI
from fastapi.middleware.wsgi import WSGIMiddleware
from flask import Flask, escape, request
flask_app = Flask(__name__)
#flask_app.route("/")
def flask_main():
name = request.args.get("name", "World")
return f"Hello, {escape(name)} from Flask!"
app = FastAPI()
#app.get("/v2")
def read_main():
return {"message": "Hello World"}
app.mount("/v1", WSGIMiddleware(flask_app))
Update
While it is possible in the approach listed below, I genuinely think that we should avoid coupling different frameworks in such a monolith. Doing so could lead to unexpected bugs and make it harder to scale.
Instead, we could build 1 backend service in FastAPI, 1 Django Admin service for example, and then use NGINX to route traffic to these backend services. Using NGINX to route traffic to different backend services in production is common anyway.
Integration Of FastAPI With Django (WSGI)
https://github.com/jordaneremieff/django-fastapi-example.git
After hours of searching finally I found a great implementation in the link above. It worked seamlessly for me!
Testing
In order to make this simple to test, below are some few adjustments I made to the above reference:
api/models.py
class Item(models.Model):
title = models.CharField(max_length=50)
description = models.TextField()
# owner = models.ForeignKey(
# settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="items"
# )
api/schemas.py
class Item(ItemBase):
# id: int
# owner_id: int
class Config:
orm_mode = True
POST
curl -d "{\"title\":\"le titre\", \"description\":\"la description\"}" -H "Content-Type: application/json" -X POST http://127.0.0.1:8000/api/items
GET
curl http://127.0.0.1:8000/api/items
Thank you for the awesome answers. Here is a little tweaked answer where I have fixed some imports as well as I have used a model from a Django app.
from fastapi import FastAPI
from fastapi.middleware.wsgi import WSGIMiddleware
from django.core.wsgi import get_wsgi_application
import os
from importlib.util import find_spec
from fastapi.staticfiles import StaticFiles
from django.conf import settings
# Export Django settings env variable
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')
# Get Django WSGI app
django_app = get_wsgi_application()
# Import a model
# And always import your models after you export settings
# and you get Django WSGI app
from accounts.models import Account
# Create FasatAPI instance
app = FastAPI()
# Serve Django static files
app.mount('/static',
StaticFiles(
directory=os.path.normpath(
os.path.join(find_spec('django.contrib.admin').origin, '..', 'static')
)
),
name='static',
)
# Define a FastAPI route
#app.get('/fastapi-test')
def read_main():
return {
'total_accounts': Account.objects.count(),
'is_debug': settings.DEBUG
}
# Mount Django app
app.mount('/django-test', WSGIMiddleware(django_app))
Hint: I created a file named app.py in my Django project's root directory and it worked. Here is my directory structure:
.
├── accounts
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   ├── 0001_initial.py
│   │   ├── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── app.py
├── db.sqlite3
├── project
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── manage.py
And run your FastAPI app:
(myvenv) ➜ project uvicorn --host 0.0.0.0 --port 8000 app:app --reload
INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
INFO: Started reloader process [48366] using statreload
INFO: Started server process [48368]
INFO: Waiting for application startup.
INFO: Application startup complete.
Hopefully, this will work for you. Now accessing /django-test will serve your Django project and /fastapi-test will serve the FastAPI part.
This configuration serves Django static files too and we can use our Django models in our FastAPI code as well. I'll test it further and I'll update this answer if I find any possibilities for improvement.
As Sumitrhan pointed out in a commet: There is also Django Ninja a Project that uses very similar concepts like Fast API (Routes, Pydandantic Model Validation) but simply is a Django App.
Given that current Django supports also async views in I see no point in mixing django and FastApi, to get the same feature set only much more complicated as not as good integrated.
there is good resource as follows:
Combine the power of FastAPI and Django

Flask alchemy doesn't create database table for the model class

I created a simple boilerplate flask application with one class in the model. My problem is that my app doesn't create the table in the mysql database after the app first run. Ideally, table should be created only if it doesn't exist (so I can leave the create_all instruction in the code)
project tree is:
.
├── application.py
├── module
│   ├── __init__.py
│   ├── __pycache__
│   │   └── __init__.cpython-36.pyc
│   └── models.py
├── requirements.txt
├── static
└── templates
That's the content of application.py file
from flask import Flask
from module import db
app = Flask(__name__)
app.config['DEBUG'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://oskar:secret#ipaddress/analytics'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
#app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
# with app.app_context():
db.init_app(app)
app.app_context().push()
# create tables only once
db.create_all(app=app)
db.session.commit()
app.run()
Content of module/__init__.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
Content of module/models.py
from module import db
class PostalCodeCities(db.Model):
postal_code = db.Column(db.String(6), nullable=False) # kod pocztowy
city = db.Column(db.String(126), nullable=False) # miejscowosc
street = db.Column(db.String(126))
building = db.Column(db.String(32))
municipality = db.Column(db.String(126)) # gmina
county = db.Column(db.String(126)) # powiat
voivodeship = db.Column(db.String(126)) # wojewodztwo
def __repr__(self):
return '<PostalEntry %r>' % self.postal_code
What I'm doing wrong?
Thanks!
I already found the solution. I had to move everything from __init__.py to models.py and in applications.py import db from module.models

Unable to register a blueprint

CASE UPDATED: 2016-02-10 # 19:45 UTC
I've been researching for several weeks StackOverflow after reading a couple of books related to Flask, I've been testing and trying different configuration options, playing with several codes and finally I'm forced to write asking for help because I'm totally stuck and I can't go ahead alone. I'm sorry about that.
The problem: I'm not able to register a Blueprint correctly in my app. I'm doing something wrong or something is not being done in the right way. Routes that belong to the blueprint are not working.
The error received: Not Found. The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
I'm trying to build an API with Flask and Flask-Restful. I'm new to Flask and new to Flask-Restful too, so, you can imagine how big is my actual learning curve right now.
At present time, my project has this aspect:
/
├── PROJECT
│   ├── __init__.py
│   └── api_1_0
│   ├── __init__.py
│   ├── resources
│   │   ├── __init__.py
│   │   └── users.py
│   └── routes.py
├── config.py
└── run.py
The Plan
The PROJECT (named internally SelfCare) folder will have in the future two or three more packages inside (for web modules belonging to the same project). By now the only one of them is api_1_0.
The idea #1 is to build an API with some basic functionalities. Now, the focus is to present plain messages (return 'hi hi') just to confirm all blocks are working alltogether.
The idea #2 is to build the API as a blueprint inside the SelfCare package. Now i can have only 1 API, but later on i migth have two in parallel running (v1 and v2).
Some days ago i managed to get to work idea 1 but idea 2 is what i cannot get to work. Sorry.
My current files have this contents:
File: run.py
from SelfCare import create_app
app = create_app(config_name='development')
if __name__ == '__main__':
app.run()
File: config.py
import os
class Config:
SECRET_KEY = 'whatever'
APP_DIR = os.path.abspath(os.path.realpath(__file__))
STATIC_DIR = os.path.join(APP_DIR, 'static')
IMAGES_DIR = os.path.join(STATIC_DIR, 'images')
STYLES_DIR = os.path.join(STATIC_DIR, 'styles')
TEMPLATES_DIR = os.path.join(STATIC_DIR, 'templates')
# Method with an application instance (for now, just a bypass)
#staticmethod
def init_app(app):
pass
class DevelopmentConfig(Config):
DEBUG = True
class TestingConfig(Config):
DEBUG = True
class ProductionConfig(Config):
DEBUG = False
# Finally, this is a dead simple configuration dictionary
config = {
# Possible profiles to run under
'development': DevelopmentConfig,
'testing': TestingConfig,
'production': ProductionConfig,
# Default application profile
'default': DevelopmentConfig
}
File: PROJECT/init.py
from flask import Flask, render_template
from flask.ext.moment import Moment
from config import config
moment = Moment()
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
# attach routes and custom error pages here
#app.route('/')
def index():
return 'Here we will start'
# HERE IT IS SUPPOSED THE BLUEPRINT IS REGISTERED
# AND ROUTES FROM BLUEPRINT ARE INCORPORATED TO MAIN PROGRAM
from .api_1_0 import api as api_blueprint
app.register_blueprint(api_blueprint)
return app
File: PROJECT/api_1_0/__init__.py
from flask import Blueprint
api = Blueprint('api', __name__)
from .resources import users
File: PROJECT/api_1_0/routes.py
from .api_1_0 import resources
#resources.route('/user', methods=['GET'])
def users():
return 'routes.py en blueprint api_1_0'
File: PROJECT/api_1_0/resources/__init__.py
This file is empty (a constructor).
File: PROJECT/api_1_0/resources/user.py
from flask_restful import Resource, reqparse, abort
# With the following dictionrary I do simulate a database connection
USERS = {
'user1': {'task': 'Build an API'},
'user2': {'task': 'Coordinate development'},
'user3': {'task': 'Build core'},
}
def abort_if_user_doesnt_exist(user):
if user not in USERS:
abort(404, message="User {} doesn't exist".format(user))
parser = reqparse.RequestParser()
parser.add_argument('task')
class User(Resource):
def get(self, user):
abort_if_user_doesnt_exist(user)
return USERS[user]
def delete(self, user):
abort_if_user_doesnt_exist(user)
del USERS[callsign]
return '', 204
def put(self, user):
args = parser.parse_args()
task = {'task': args['task']}
USERS[user] = task
return task, 201
So, routes.py seems not to work, so I cannot go further in the API. I'm stuck, sorry... Probably the error is just in from of me as a big stone and I cannot see it. Sorry.
Any help will be much more than appreciated.
Regards.
You're not registering flask-restful.Api and the REST routes correctly.
Install Flask-DebugToolbar - it will help you in showing your registered routes.
Change your code as follows:
In file config.py add the following two lines to the Config class:
DEBUG_TOOLBAR_ENABLED = True
REST_URL_PREFIX = '/api'
In file: PROJECT/init.py change to:
from flask import Flask, render_template
from flask.ext.moment import Moment
from config import config
moment = Moment()
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
try:
from flask_debugtoolbar import DebugToolbarExtension
DebugToolbarExtension(app)
except:
pass
# attach routes and custom error pages here
#app.route('/')
def index():
return render_template('index.html')
# HERE IT IS SUPPOSED THE BLUEPRINT IS REGISTERED
# AND ROUTES FROM BLUEPRINT ARE INCORPORATED TO MAIN PROGRAM
from PROJECT.api_1_0 import api_bp, API_VERSION_V1
app.register_blueprint(
api_bp,
url_prefix='{prefix}/v{version}'.format(prefix=app.config['REST_URL_PREFIX'], version=API_VERSION_V1),
)
# This registers the actual routes
import api_1_0.routes
return app
In file: PROJECT/api_1_0/__init__.py change to:
from flask import Blueprint
import flask_restful
API_VERSION_V1 = 1
api_bp = Blueprint('api', __name__)
api_v1 = flask_restful.Api(api_bp)
Map your resources to routes; in file: PROJECT/api_1_0/routes.py change to:
from PROJECT.api_1_0 import api_v1
from PROJECT.api_1_0.resources.user import User
api_v1.add_resource(User, '/user/<string:user>')
Your routes will now be something like :
http://127.0.0.1:5000/api/v1/user/user1 which returns:
{
"task": "Build an API"
}
http://127.0.0.1:5000/api/v1/user/user2 which returns:
{
"task": "Coordinate development"
}
Note how the routes have been built up; the REST_URL_PREFIX from config plus the version number plus the url in the routes.py add_resource.
It works!
I was confused in the way the blueprints have to be registered. Maybe it was because I'm using PyCharm 5 Pro and, even now that the code is running like a charm, the IDE is telling me in the file PROJECT/api_1_0/___init____.py this message:
api_v1 = flask_restful.Api(api_bp)
api_bp --> Expected type 'Flask', got 'Blueprint' instead.
The inspection detects type errors in function call expressions. Due
to dynamic dispatch and duck typing, this is posible in a limite but
useful number of cases. Types of function parameters can be specified
in docstrings or in Python 3 functon annotations.
No I know I don't have to pay too much attention to this message (or that my IDE is wrongly configured). Many thanks for all.
Regards.