Skip to content

Commit

Permalink
fix: FAB_INDEX_VIEW type check (#1883)
Browse files Browse the repository at this point in the history
* fix: FAB_INDEX_VIEW type check

* fix lint and init of index view
  • Loading branch information
dpgaspar committed Jul 5, 2022
1 parent 449afe4 commit cc8e359
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 75 deletions.
2 changes: 1 addition & 1 deletion examples/factoryapp/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Create an Admin user and insert test data::

Run it::

$ export FLASK_APP="app:create_app('config')"
$ export FLASK_APP="app.app:create_app('config')"
$ flask fab create-admin
$ flask run

Expand Down
24 changes: 0 additions & 24 deletions examples/factoryapp/app/__init__.py
Original file line number Diff line number Diff line change
@@ -1,24 +0,0 @@
import logging

from flask import Flask
from flask_appbuilder import AppBuilder, SQLA

logging.basicConfig(format="%(asctime)s:%(levelname)s:%(name)s:%(message)s")
logging.getLogger().setLevel(logging.DEBUG)

db = SQLA()
appbuilder = AppBuilder()


def create_app(config):
app = Flask(__name__)
with app.app_context():
app.config.from_object(config)
db.init_app(app)
appbuilder.init_app(app, db.session)
from . import views # noqa

db.create_all()
appbuilder.post_init()
views.fill_gender()
return app
36 changes: 36 additions & 0 deletions examples/factoryapp/app/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import logging

from flask import Flask
from flask_appbuilder import AppBuilder, SQLA

logging.basicConfig(format="%(asctime)s:%(levelname)s:%(name)s:%(message)s")
logging.getLogger().setLevel(logging.DEBUG)


def create_app(config):
app = Flask(__name__)
db = SQLA()
appbuilder = AppBuilder()
with app.app_context():
app.config.from_object(config)
db.init_app(app)
appbuilder.init_app(app, db.session)

from .views import ContactModelView, GroupModelView, fill_gender

appbuilder.add_view(
ContactModelView,
"List Contacts",
icon="fa-envelope",
category="Contacts",
category_icon="fa-envelope",
)

appbuilder.add_view(
GroupModelView, "List Groups", icon="fa-folder-open-o", category="Contacts"
)

db.create_all()
appbuilder.post_init()
fill_gender()
return app
26 changes: 8 additions & 18 deletions examples/factoryapp/app/views.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
from flask_appbuilder import ModelView
from flask import current_app
from flask_appbuilder import ModelView, IndexView
from flask_appbuilder.models.sqla.interface import SQLAInterface

from . import appbuilder, db
from .models import Contact, ContactGroup, Gender


def fill_gender():
try:
db.session.add(Gender(name="Male"))
db.session.add(Gender(name="Female"))
db.session.commit()
current_app.appbuilder.session.add(Gender(name="Male"))
current_app.appbuilder.session.add(Gender(name="Female"))
current_app.appbuilder.session.commit()
except Exception:
db.session.rollback()
current_app.appbuilder.session.rollback()


class ContactModelView(ModelView):
Expand Down Expand Up @@ -71,20 +71,10 @@ class ContactModelView(ModelView):
]


appbuilder.add_view(
ContactModelView,
"List Contacts",
icon="fa-envelope",
category="Contacts",
category_icon="fa-envelope",
)


class GroupModelView(ModelView):
datamodel = SQLAInterface(ContactGroup)
related_views = [ContactModelView]


appbuilder.add_view(
GroupModelView, "List Groups", icon="fa-folder-open-o", category="Contacts"
)
class MyIndexView(IndexView):
index_template = "my_index.html"
2 changes: 2 additions & 0 deletions examples/factoryapp/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
# SQLALCHEMY_DATABASE_URI = 'postgresql://scott:tiger@localhost:5432/myapp'
# SQLALCHEMY_ECHO = True

FAB_INDEX_VIEW = "app.views.MyIndexView"

BABEL_DEFAULT_LOCALE = "en"
BABEL_DEFAULT_FOLDER = "translations"
LANGUAGES = {
Expand Down
27 changes: 14 additions & 13 deletions examples/factoryapp/testdata.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from datetime import datetime
import random

from app import create_app, db
from flask import current_app
from app.app import create_app
from app.models import Contact, ContactGroup, Gender

app = create_app("config")
Expand All @@ -17,19 +18,19 @@ def get_random_name(names_list, size=1):


try:
db.session.add(ContactGroup(name="Friends"))
db.session.add(ContactGroup(name="Family"))
db.session.add(ContactGroup(name="Work"))
db.session.commit()
current_app.appbuilder.session.add(ContactGroup(name="Friends"))
current_app.appbuilder.session.add(ContactGroup(name="Family"))
current_app.appbuilder.session.add(ContactGroup(name="Work"))
current_app.appbuilder.session.commit()
except Exception:
db.session.rollback()
current_app.appbuilder.session.rollback()

try:
db.session.add(Gender(name="Male"))
db.session.add(Gender(name="Female"))
db.session.commit()
current_app.appbuilder.session.add(Gender(name="Male"))
current_app.appbuilder.session.add(Gender(name="Female"))
current_app.appbuilder.session.commit()
except Exception:
db.session.rollback()
current_app.appbuilder.session.rollback()

f = open("NAMES.DIC", "rb")
names_list = [x.strip() for x in f.readlines()]
Expand All @@ -50,9 +51,9 @@ def get_random_name(names_list, size=1):
month = random.choice(range(1, 12))
day = random.choice(range(1, 28))
c.birthday = datetime(year, month, day)
db.session.add(c)
current_app.appbuilder.session.add(c)
try:
db.session.commit()
current_app.appbuilder.session.commit()
print("inserted {0}".format(c))
except Exception:
db.session.rollback()
current_app.appbuilder.session.rollback()
50 changes: 31 additions & 19 deletions flask_appbuilder/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@


DynamicImportType = Union[
Type["BaseManager"], Type["BaseView"], Type["BaseSecurityManager"], Type[Menu]
Type["BaseManager"],
Type["BaseView"],
Type["BaseSecurityManager"],
Type[Menu],
Type["AbstractViewApi"],
]


Expand Down Expand Up @@ -93,7 +97,7 @@ def __init__(
app: Optional[Flask] = None,
session: Optional[SessionBase] = None,
menu: Optional[Menu] = None,
indexview: Optional["AbstractViewApi"] = None,
indexview: Optional[Type["AbstractViewApi"]] = None,
base_template: str = "appbuilder/baselayout.html",
static_folder: str = "static/appbuilder",
static_url_path: str = "/appbuilder",
Expand Down Expand Up @@ -121,7 +125,7 @@ def __init__(
optional, update permissions flag (Boolean) you can use
FAB_UPDATE_PERMS config key also
"""
self.baseviews: List["AbstractViewApi"] = []
self.baseviews: List[Union[Type["AbstractViewApi"], "AbstractViewApi"]] = []

# temporary list that hold addon_managers config key
self._addon_managers: List[str] = []
Expand Down Expand Up @@ -172,12 +176,11 @@ def init_app(self, app: Flask, session: SessionBase) -> None:
"FAB_STATIC_URL_PATH", self.static_url_path
)
_index_view = app.config.get("FAB_INDEX_VIEW", None)
if _index_view is not None:
view = dynamic_class_import(_index_view)
if isinstance(view, BaseView):
self.indexview = view
if _index_view:
self.indexview = dynamic_class_import(_index_view) # type: ignore
else:
self.indexview = self.indexview or IndexView()
self.indexview = self.indexview or IndexView

_menu = app.config.get("FAB_MENU", None)

# Setup Menu
Expand Down Expand Up @@ -229,7 +232,7 @@ def _init_extension(self, app: Flask) -> None:
def post_init(self) -> None:
for baseview in self.baseviews:
# instantiate the views and add session
self._check_and_init(baseview)
baseview = self._check_and_init(baseview)
# Register the views has blueprints
if baseview.__class__.__name__ not in self.get_app.blueprints.keys():
self.register_blueprint(baseview)
Expand Down Expand Up @@ -313,12 +316,11 @@ def _add_global_static(self) -> None:

def _add_admin_views(self) -> None:
"""
Registers indexview, utilview (back function), babel views and Security views.
Registers indexview, utilview (back function), babel views and Security views.
"""
if self.indexview:
self.indexview = self._check_and_init(self.indexview)
self.add_view_no_menu(self.indexview)
self.add_view_no_menu(UtilView())
self._indexview = self.add_view_no_menu(self.indexview)
self.add_view_no_menu(UtilView)
self.bm.register_views()
self.sm.register_views()
self.openapi_manager.register_views()
Expand All @@ -344,7 +346,9 @@ def _add_addon_views(self) -> None:
log.exception(e)
log.error(LOGMSG_ERR_FAB_ADDON_PROCESS.format(addon, e))

def _check_and_init(self, baseview: "AbstractViewApi") -> "AbstractViewApi":
def _check_and_init(
self, baseview: Union[Type["AbstractViewApi"], "AbstractViewApi"]
) -> "AbstractViewApi":
# If class if not instantiated, instantiate it
# and add db session from security models.
if hasattr(baseview, "datamodel"):
Expand All @@ -356,7 +360,7 @@ def _check_and_init(self, baseview: "AbstractViewApi") -> "AbstractViewApi":

def add_view(
self,
baseview: "AbstractViewApi",
baseview: Union[Type["AbstractViewApi"], "AbstractViewApi"],
name: str,
href: str = "",
icon: str = "",
Expand Down Expand Up @@ -536,7 +540,7 @@ def add_separator(

def add_view_no_menu(
self,
baseview: "AbstractViewApi",
baseview: Union[Type["AbstractViewApi"], "AbstractViewApi"],
endpoint: Optional[str] = None,
static_folder: Optional[str] = None,
) -> "AbstractViewApi":
Expand Down Expand Up @@ -565,7 +569,7 @@ def add_view_no_menu(
log.warning(LOGMSG_WAR_FAB_VIEW_EXISTS.format(baseview.__class__.__name__))
return baseview

def add_api(self, baseview: "AbstractViewApi") -> "AbstractViewApi":
def add_api(self, baseview: Type["AbstractViewApi"]) -> "AbstractViewApi":
"""
Add a BaseApi class or child to AppBuilder
Expand Down Expand Up @@ -621,9 +625,11 @@ def get_url_for_logout(self) -> str:

@property
def get_url_for_index(self) -> str:
if self.indexview is None:
if self._indexview is None:
return ""
return url_for("%s.%s" % (self.indexview.endpoint, self.indexview.default_view))
return url_for(
"%s.%s" % (self._indexview.endpoint, self._indexview.default_view)
)

@property
def get_url_for_userinfo(self) -> str:
Expand All @@ -640,8 +646,11 @@ def get_url_for_locale(self, lang: str) -> str:
)

def add_permissions(self, update_perms: bool = False) -> None:
from flask_appbuilder.baseviews import AbstractViewApi

if self.update_perms or update_perms:
for baseview in self.baseviews:
baseview = cast(AbstractViewApi, baseview)
self._add_permission(baseview, update_perms=update_perms)
self._add_menu_permissions(update_perms=update_perms)

Expand Down Expand Up @@ -695,7 +704,10 @@ def _view_exists(self, view: "AbstractViewApi") -> bool:
return False

def _process_inner_views(self) -> None:
from flask_appbuilder.baseviews import AbstractViewApi

for view in self.baseviews:
view = cast(AbstractViewApi, view)
for inner_class in view.get_uninit_inner_views():
for v in self.baseviews:
if (
Expand Down

0 comments on commit cc8e359

Please sign in to comment.