This is an automated email from the ASF dual-hosted git repository.

johnbodley pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git


The following commit(s) were added to refs/heads/master by this push:
     new b010c35  style(mypy): Enforcing typing for views.database (#9920)
b010c35 is described below

commit b010c358871678723499eb9541221119aaaed34f
Author: John Bodley <[email protected]>
AuthorDate: Wed May 27 21:04:48 2020 -0700

    style(mypy): Enforcing typing for views.database (#9920)
    
    Co-authored-by: John Bodley <[email protected]>
---
 setup.cfg                             |  2 +-
 superset/views/database/api.py        | 20 +++++++++-----------
 superset/views/database/decorators.py | 12 +++++++++---
 superset/views/database/filters.py    | 18 +++++++++---------
 superset/views/database/forms.py      | 20 +++++++++++---------
 superset/views/database/mixins.py     | 19 +++++++++++--------
 superset/views/database/validators.py |  5 +++--
 superset/views/database/views.py      | 20 ++++++++++++++------
 8 files changed, 67 insertions(+), 49 deletions(-)

diff --git a/setup.cfg b/setup.cfg
index 8e798de..fd028af 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -53,7 +53,7 @@ order_by_type = false
 ignore_missing_imports = true
 no_implicit_optional = true
 
-[mypy-superset.bin.*,superset.charts.*,superset.commands.*,superset.common.*,superset.connectors.*,superset.dao.*,superset.dashboards.*,superset.datasets.*,superset.db_engine_specs.*,superset.db_engines.*,superset.examples.*,superset.migrations.*,superset.models.*,uperset.queries.*,superset.security.*,superset.sql_validators.*,superset.tasks.*,superset.translations.*,superset.views.dashboard.*]
+[mypy-superset.bin.*,superset.charts.*,superset.commands.*,superset.common.*,superset.connectors.*,superset.dao.*,superset.dashboards.*,superset.datasets.*,superset.db_engine_specs.*,superset.db_engines.*,superset.examples.*,superset.migrations.*,superset.models.*,uperset.queries.*,superset.security.*,superset.sql_validators.*,superset.tasks.*,superset.translations.*,superset.views.dashboard.*,superset.views.database.*]
 check_untyped_defs = true
 disallow_untyped_calls = true
 disallow_untyped_defs = true
diff --git a/superset/views/database/api.py b/superset/views/database/api.py
index 166abb7..b1cfce9 100644
--- a/superset/views/database/api.py
+++ b/superset/views/database/api.py
@@ -22,6 +22,7 @@ from sqlalchemy.exc import NoSuchTableError, SQLAlchemyError
 
 from superset import event_logger
 from superset.models.core import Database
+from superset.typing import FlaskResponse
 from superset.utils.core import error_msg_from_exception
 from superset.views.base_api import BaseSupersetModelRestApi
 from superset.views.database.decorators import check_datasource_access
@@ -49,7 +50,7 @@ def get_indexes_metadata(
     return indexes
 
 
-def get_col_type(col: Dict) -> str:
+def get_col_type(col: Dict[Any, Any]) -> str:
     try:
         dtype = f"{col['type']}"
     except Exception:  # pylint: disable=broad-except
@@ -145,14 +146,14 @@ class DatabaseRestApi(DatabaseMixin, 
BaseSupersetModelRestApi):
 
     openapi_spec_tag = "Database"
 
-    @expose(
-        "/<int:pk>/table/<string:table_name>/<string:schema_name>/", 
methods=["GET"]
-    )
+    @expose("/<int:pk>/table/<table_name>/<schema_name>/", methods=["GET"])
     @protect()
     @check_datasource_access
     @safe
     @event_logger.log_this
-    def table_metadata(self, database: Database, table_name: str, schema_name: 
str):
+    def table_metadata(
+        self, database: Database, table_name: str, schema_name: str
+    ) -> FlaskResponse:
         """ Table schema info
         ---
         get:
@@ -276,18 +277,15 @@ class DatabaseRestApi(DatabaseMixin, 
BaseSupersetModelRestApi):
         self.incr_stats("success", self.table_metadata.__name__)
         return self.response(200, **table_info)
 
-    @expose("/<int:pk>/select_star/<string:table_name>/", methods=["GET"])
-    @expose(
-        "/<int:pk>/select_star/<string:table_name>/<string:schema_name>/",
-        methods=["GET"],
-    )
+    @expose("/<int:pk>/select_star/<table_name>/", methods=["GET"])
+    @expose("/<int:pk>/select_star/<table_name>/<schema_name>/", 
methods=["GET"])
     @protect()
     @check_datasource_access
     @safe
     @event_logger.log_this
     def select_star(
         self, database: Database, table_name: str, schema_name: Optional[str] 
= None
-    ):
+    ) -> FlaskResponse:
         """ Table schema info
         ---
         get:
diff --git a/superset/views/database/decorators.py 
b/superset/views/database/decorators.py
index 322b420..0d2e83b 100644
--- a/superset/views/database/decorators.py
+++ b/superset/views/database/decorators.py
@@ -16,7 +16,7 @@
 # under the License.
 import functools
 import logging
-from typing import Optional
+from typing import Any, Callable, Optional
 
 from flask import g
 from flask_babel import lazy_gettext as _
@@ -24,16 +24,22 @@ from flask_babel import lazy_gettext as _
 from superset.models.core import Database
 from superset.sql_parse import Table
 from superset.utils.core import parse_js_uri_path_item
+from superset.views.base_api import BaseSupersetModelRestApi
 
 logger = logging.getLogger(__name__)
 
 
-def check_datasource_access(f):
+def check_datasource_access(f: Callable) -> Callable:
     """
     A Decorator that checks if a user has datasource access
     """
 
-    def wraps(self, pk: int, table_name: str, schema_name: Optional[str] = 
None):
+    def wraps(
+        self: BaseSupersetModelRestApi,
+        pk: int,
+        table_name: str,
+        schema_name: Optional[str] = None,
+    ) -> Any:
         schema_name_parsed = parse_js_uri_path_item(schema_name, 
eval_undefined=True)
         table_name_parsed = parse_js_uri_path_item(table_name)
         if not table_name_parsed:
diff --git a/superset/views/database/filters.py 
b/superset/views/database/filters.py
index 4999e3c..1941835 100644
--- a/superset/views/database/filters.py
+++ b/superset/views/database/filters.py
@@ -14,7 +14,10 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
+from typing import Any, Set
+
 from sqlalchemy import or_
+from sqlalchemy.orm import Query
 
 from superset import security_manager
 from superset.views.base import BaseFilter
@@ -22,16 +25,13 @@ from superset.views.base import BaseFilter
 
 class DatabaseFilter(BaseFilter):
     # TODO(bogdan): consider caching.
-    def schema_access_databases(self):  # noqa pylint: disable=no-self-use
-        found_databases = set()
-        for vm in security_manager.user_view_menu_names("schema_access"):
-            database_name, _ = security_manager.unpack_schema_perm(vm)
-            found_databases.add(database_name)
-        return found_databases
+    def schema_access_databases(self) -> Set[str]:  # noqa pylint: 
disable=no-self-use
+        return {
+            security_manager.unpack_schema_perm(vm)[0]
+            for vm in security_manager.user_view_menu_names("schema_access")
+        }
 
-    def apply(
-        self, query, func
-    ):  # noqa pylint: disable=unused-argument,arguments-differ
+    def apply(self, query: Query, value: Any) -> Query:
         if security_manager.all_database_access():
             return query
         database_perms = 
security_manager.user_view_menu_names("database_access")
diff --git a/superset/views/database/forms.py b/superset/views/database/forms.py
index 4ae1abb..2fb6290 100644
--- a/superset/views/database/forms.py
+++ b/superset/views/database/forms.py
@@ -15,6 +15,8 @@
 # specific language governing permissions and limitations
 # under the License.
 """Contains the logic to create cohesive forms on the explore view"""
+from typing import List
+
 from flask_appbuilder.fieldwidgets import BS3TextFieldWidget
 from flask_appbuilder.forms import DynamicForm
 from flask_babel import lazy_gettext as _
@@ -25,25 +27,25 @@ from wtforms.validators import DataRequired, Length, 
NumberRange, Optional
 
 from superset import app, db, security_manager
 from superset.forms import CommaSeparatedListField, filter_not_empty_values
-from superset.models import core as models
+from superset.models.core import Database
 
 config = app.config
 
 
 class CsvToDatabaseForm(DynamicForm):
     # pylint: disable=E0211
-    def csv_allowed_dbs():  # type: ignore
-        csv_allowed_dbs = []
+    def csv_allowed_dbs() -> List[Database]:  # type: ignore
         csv_enabled_dbs = (
-            
db.session.query(models.Database).filter_by(allow_csv_upload=True).all()
+            db.session.query(Database).filter_by(allow_csv_upload=True).all()
         )
-        for csv_enabled_db in csv_enabled_dbs:
-            if 
CsvToDatabaseForm.at_least_one_schema_is_allowed(csv_enabled_db):
-                csv_allowed_dbs.append(csv_enabled_db)
-        return csv_allowed_dbs
+        return [
+            csv_enabled_db
+            for csv_enabled_db in csv_enabled_dbs
+            if CsvToDatabaseForm.at_least_one_schema_is_allowed(csv_enabled_db)
+        ]
 
     @staticmethod
-    def at_least_one_schema_is_allowed(database):
+    def at_least_one_schema_is_allowed(database: Database) -> bool:
         """
         If the user has access to the database or all datasource
             1. if schemas_allowed_for_csv_upload is empty
diff --git a/superset/views/database/mixins.py 
b/superset/views/database/mixins.py
index 452860a..a10345a 100644
--- a/superset/views/database/mixins.py
+++ b/superset/views/database/mixins.py
@@ -22,6 +22,7 @@ from sqlalchemy import MetaData
 
 from superset import app, security_manager
 from superset.exceptions import SupersetException
+from superset.models.core import Database
 from superset.security.analytics_db_safety import check_sqlalchemy_uri
 from superset.utils import core as utils
 from superset.views.database.filters import DatabaseFilter
@@ -199,7 +200,7 @@ class DatabaseMixin:
         "backend": _("Backend"),
     }
 
-    def _pre_add_update(self, database):
+    def _pre_add_update(self, database: Database) -> None:
         if app.config["PREVENT_UNSAFE_DB_CONNECTIONS"]:
             check_sqlalchemy_uri(database.sqlalchemy_uri)
         self.check_extra(database)
@@ -214,23 +215,23 @@ class DatabaseMixin:
                 "schema_access", security_manager.get_schema_perm(database, 
schema)
             )
 
-    def pre_add(self, database):
+    def pre_add(self, database: Database) -> None:
         self._pre_add_update(database)
 
-    def pre_update(self, database):
+    def pre_update(self, database: Database) -> None:
         self._pre_add_update(database)
 
-    def pre_delete(self, obj):  # pylint: disable=no-self-use
-        if obj.tables:
+    def pre_delete(self, database: Database) -> None:  # pylint: 
disable=no-self-use
+        if database.tables:
             raise SupersetException(
                 Markup(
                     "Cannot delete a database that has tables attached. "
                     "Here's the list of associated tables: "
-                    + ", ".join("{}".format(o) for o in obj.tables)
+                    + ", ".join("{}".format(table) for table in 
database.tables)
                 )
             )
 
-    def check_extra(self, database):  # pylint: disable=no-self-use
+    def check_extra(self, database: Database) -> None:  # pylint: 
disable=no-self-use
         # this will check whether json.loads(extra) can succeed
         try:
             extra = database.get_extra()
@@ -252,7 +253,9 @@ class DatabaseMixin:
                     )
                 )
 
-    def check_encrypted_extra(self, database):  # pylint: disable=no-self-use
+    def check_encrypted_extra(  # pylint: disable=no-self-use
+        self, database: Database
+    ) -> None:
         # this will check whether json.loads(secure_extra) can succeed
         try:
             database.get_encrypted_extra()
diff --git a/superset/views/database/validators.py 
b/superset/views/database/validators.py
index 0800c11..dd96a71 100644
--- a/superset/views/database/validators.py
+++ b/superset/views/database/validators.py
@@ -15,7 +15,7 @@
 # specific language governing permissions and limitations
 # under the License.
 
-from typing import Type
+from typing import Optional, Type
 
 from flask_babel import lazy_gettext as _
 from marshmallow import ValidationError
@@ -23,6 +23,7 @@ from sqlalchemy.engine.url import make_url
 from sqlalchemy.exc import ArgumentError
 
 from superset import security_manager
+from superset.models.core import Database
 
 
 def sqlalchemy_uri_validator(
@@ -43,7 +44,7 @@ def sqlalchemy_uri_validator(
         )
 
 
-def schema_allows_csv_upload(database, schema):
+def schema_allows_csv_upload(database: Database, schema: Optional[str]) -> 
bool:
     if not database.allow_csv_upload:
         return False
     schemas = database.get_schema_access_for_csv_upload()
diff --git a/superset/views/database/views.py b/superset/views/database/views.py
index 208d351..ae4b3bc 100644
--- a/superset/views/database/views.py
+++ b/superset/views/database/views.py
@@ -20,6 +20,7 @@ from typing import TYPE_CHECKING
 
 from flask import flash, g, redirect
 from flask_appbuilder import SimpleFormView
+from flask_appbuilder.forms import DynamicForm
 from flask_appbuilder.models.sqla.interface import SQLAInterface
 from flask_babel import lazy_gettext as _
 from wtforms.fields import StringField
@@ -31,8 +32,10 @@ from superset.connectors.sqla.models import SqlaTable
 from superset.constants import RouteMethod
 from superset.exceptions import CertificateException
 from superset.sql_parse import Table
+from superset.typing import FlaskResponse
 from superset.utils import core as utils
 from superset.views.base import DeleteMixin, SupersetModelView, YamlExportMixin
+from superset.views.database.forms import CsvToDatabaseForm
 
 from .forms import CsvToDatabaseForm
 from .mixins import DatabaseMixin
@@ -45,14 +48,19 @@ config = app.config
 stats_logger = config["STATS_LOGGER"]
 
 
-def sqlalchemy_uri_form_validator(_, field: StringField) -> None:
+def sqlalchemy_uri_form_validator(  # pylint: disable=unused-argument
+    form: DynamicForm, field: StringField
+) -> None:
     """
         Check if user has submitted a valid SQLAlchemy URI
     """
+
     sqlalchemy_uri_validator(field.data, exception=ValidationError)
 
 
-def certificate_form_validator(_, field: StringField) -> None:
+def certificate_form_validator(  # pylint: disable=unused-argument
+    form: DynamicForm, field: StringField
+) -> None:
     """
         Check if user has submitted a valid SSL certificate
     """
@@ -63,7 +71,7 @@ def certificate_form_validator(_, field: StringField) -> None:
             raise ValidationError(ex.message)
 
 
-def upload_stream_write(form_file_field: "FileStorage", path: str):
+def upload_stream_write(form_file_field: "FileStorage", path: str) -> None:
     chunk_size = app.config["UPLOAD_CHUNK_SIZE"]
     with open(path, "bw") as file_description:
         while True:
@@ -88,7 +96,7 @@ class DatabaseView(
 
     yaml_dict_key = "databases"
 
-    def _delete(self, pk):
+    def _delete(self, pk: int) -> None:
         DeleteMixin._delete(self, pk)
 
 
@@ -98,7 +106,7 @@ class CsvToDatabaseView(SimpleFormView):
     form_title = _("CSV to Database configuration")
     add_columns = ["database", "schema", "table_name"]
 
-    def form_get(self, form):
+    def form_get(self, form: CsvToDatabaseForm) -> None:
         form.sep.data = ","
         form.header.data = 0
         form.mangle_dupe_cols.data = True
@@ -108,7 +116,7 @@ class CsvToDatabaseView(SimpleFormView):
         form.decimal.data = "."
         form.if_exists.data = "fail"
 
-    def form_post(self, form):
+    def form_post(self, form: CsvToDatabaseForm) -> FlaskResponse:
         database = form.con.data
         csv_table = Table(table=form.name.data, schema=form.schema.data)
 

Reply via email to