From adf2cc2039c2a8201f5bb4ddf679f9fef98d0115 Mon Sep 17 00:00:00 2001 From: Will Barrett Date: Tue, 10 Dec 2019 13:24:45 -0800 Subject: [PATCH] Re-enable pylint for some model files (#8770) * Allow id as a valid name for pylint * Re-enable pylint for superset/models/core.py * re-enable pylint for superset/models/sql_lab.py * re-enable pylint for superset/models/schedules.py * re-enable pylint for superset/models/helpers.py * re-enable pylint for superset/models/annotations.py * re-enable pylint on superset/models/tags.py * a couple more fixes after black formatting... * Add another inline pylint disable * Fix black * Move to inline disables for 'id' attribute on models * Fix lint disables after black reformatted them --- superset/models/annotations.py | 5 +- superset/models/core.py | 184 ++++++++++++++++++--------------- superset/models/helpers.py | 92 +++++++++-------- superset/models/schedules.py | 4 +- superset/models/sql_lab.py | 14 ++- superset/models/tags.py | 1 - 6 files changed, 167 insertions(+), 133 deletions(-) diff --git a/superset/models/annotations.py b/superset/models/annotations.py index d0239bac7c..33197ddd5c 100644 --- a/superset/models/annotations.py +++ b/superset/models/annotations.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -# pylint: disable=C,R,W """a collection of Annotation-related models""" from flask_appbuilder import Model from sqlalchemy import Column, DateTime, ForeignKey, Index, Integer, String, Text @@ -28,7 +27,7 @@ class AnnotationLayer(Model, AuditMixinNullable): """A logical namespace for a set of annotations""" __tablename__ = "annotation_layer" - id = Column(Integer, primary_key=True) + id = Column(Integer, primary_key=True) # pylint: disable=invalid-name name = Column(String(250)) descr = Column(Text) @@ -41,7 +40,7 @@ class Annotation(Model, AuditMixinNullable): """Time-related annotation""" __tablename__ = "annotation" - id = Column(Integer, primary_key=True) + id = Column(Integer, primary_key=True) # pylint: disable=invalid-name start_dttm = Column(DateTime) end_dttm = Column(DateTime) layer_id = Column(Integer, ForeignKey("annotation_layer.id"), nullable=False) diff --git a/superset/models/core.py b/superset/models/core.py index 4136d7433c..9d8addbc0a 100755 --- a/superset/models/core.py +++ b/superset/models/core.py @@ -14,7 +14,7 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -# pylint: disable=C,R,W +# pylint: disable=line-too-long,unused-argument,ungrouped-imports """A collection of ORM sqlalchemy models for Superset""" import json import logging @@ -66,8 +66,9 @@ from superset.utils import cache as cache_util, core as utils from superset.viz import BaseViz, viz_types if TYPE_CHECKING: - from superset.connectors.base.models import BaseDatasource - + from superset.connectors.base.models import ( # pylint: disable=unused-import + BaseDatasource, + ) config = app.config custom_password_store = config["SQLALCHEMY_CUSTOM_PASSWORD_STORE"] @@ -76,6 +77,7 @@ log_query = config["QUERY_LOGGER"] metadata = Model.metadata # pylint: disable=no-member PASSWORD_MASK = "X" * 10 +DB_CONNECTION_MUTATOR = config["DB_CONNECTION_MUTATOR"] def set_related_perm(mapper, connection, target): @@ -93,8 +95,8 @@ def copy_dashboard(mapper, connection, target): if dashboard_id is None: return - Session = sessionmaker(autoflush=False) - session = Session(bind=connection) + session_class = sessionmaker(autoflush=False) + session = session_class(bind=connection) new_user = session.query(User).filter_by(id=target.id).first() # copy template dashboard to user @@ -126,16 +128,16 @@ class Url(Model, AuditMixinNullable): """Used for the short url feature""" __tablename__ = "url" - id = Column(Integer, primary_key=True) + id = Column(Integer, primary_key=True) # pylint: disable=invalid-name url = Column(Text) -class KeyValue(Model): +class KeyValue(Model): # pylint: disable=too-few-public-methods """Used for any type of key-value store""" __tablename__ = "keyvalue" - id = Column(Integer, primary_key=True) + id = Column(Integer, primary_key=True) # pylint: disable=invalid-name value = Column(Text, nullable=False) @@ -144,7 +146,7 @@ class CssTemplate(Model, AuditMixinNullable): """CSS templates for dashboards""" __tablename__ = "css_templates" - id = Column(Integer, primary_key=True) + id = Column(Integer, primary_key=True) # pylint: disable=invalid-name template_name = Column(String(250)) css = Column(Text, default="") @@ -158,12 +160,14 @@ slice_user = Table( ) -class Slice(Model, AuditMixinNullable, ImportMixin): +class Slice( + Model, AuditMixinNullable, ImportMixin +): # pylint: disable=too-many-public-methods """A slice is essentially a report or a view on data""" __tablename__ = "slices" - id = Column(Integer, primary_key=True) + id = Column(Integer, primary_key=True) # pylint: disable=invalid-name slice_name = Column(String(250)) datasource_id = Column(Integer) datasource_type = Column(String(200)) @@ -175,6 +179,7 @@ class Slice(Model, AuditMixinNullable, ImportMixin): perm = Column(String(1000)) schema_perm = Column(String(1000)) owners = relationship(security_manager.user_model, secondary=slice_user) + token = "" export_fields = [ "slice_name", @@ -208,6 +213,7 @@ class Slice(Model, AuditMixinNullable, ImportMixin): cache_timeout=self.cache_timeout, ) + # pylint: disable=using-constant-test @datasource.getter # type: ignore @utils.memoized def get_datasource(self) -> Optional["BaseDatasource"]: @@ -230,6 +236,8 @@ class Slice(Model, AuditMixinNullable, ImportMixin): datasource = self.datasource return datasource.url if datasource else None + # pylint: enable=using-constant-test + @property # type: ignore @utils.memoized def viz(self) -> BaseViz: @@ -249,7 +257,7 @@ class Slice(Model, AuditMixinNullable, ImportMixin): try: d = self.viz.data self.token = d.get("token") # type: ignore - except Exception as e: + except Exception as e: # pylint: disable=broad-except logging.exception(e) d["error"] = str(e) return { @@ -275,7 +283,7 @@ class Slice(Model, AuditMixinNullable, ImportMixin): form_data: Dict[str, Any] = {} try: form_data = json.loads(self.params) - except Exception as e: + except Exception as e: # pylint: disable=broad-except logging.error("Malformed json in slice's params") logging.exception(e) form_data.update( @@ -322,9 +330,8 @@ class Slice(Model, AuditMixinNullable, ImportMixin): @property def slice_link(self) -> Markup: - url = self.slice_url name = escape(self.chart) - return Markup(f'{name}') + return Markup(f'{name}') def get_viz(self, force: bool = False) -> BaseViz: """Creates :py:class:viz.BaseViz object from the url_params_multidict. @@ -392,7 +399,7 @@ class Slice(Model, AuditMixinNullable, ImportMixin): session.flush() return slc_to_override.id session.add(slc_to_import) - logging.info("Final slice: {}".format(slc_to_import.to_json())) + logging.info("Final slice: %s", str(slc_to_import.to_json())) session.flush() return slc_to_import.id @@ -423,12 +430,14 @@ dashboard_user = Table( ) -class Dashboard(Model, AuditMixinNullable, ImportMixin): +class Dashboard( # pylint: disable=too-many-instance-attributes + Model, AuditMixinNullable, ImportMixin +): """The dashboard object!""" __tablename__ = "dashboards" - id = Column(Integer, primary_key=True) + id = Column(Integer, primary_key=True) # pylint: disable=invalid-name dashboard_title = Column(String(500)) position_json = Column(utils.MediumText()) description = Column(Text) @@ -470,7 +479,7 @@ class Dashboard(Model, AuditMixinNullable, ImportMixin): return "/superset/dashboard/{}/?preselect_filters={}".format( self.slug or self.id, filters ) - except Exception: + except Exception: # pylint: disable=broad-except pass return f"/superset/dashboard/{self.slug or self.id}/" @@ -485,8 +494,8 @@ class Dashboard(Model, AuditMixinNullable, ImportMixin): @property def sqla_metadata(self) -> None: # pylint: disable=no-member - metadata = MetaData(bind=self.get_sqla_engine()) - metadata.reflect() + meta = MetaData(bind=self.get_sqla_engine()) + meta.reflect() def dashboard_link(self) -> Markup: title = escape(self.dashboard_title or "") @@ -523,7 +532,7 @@ class Dashboard(Model, AuditMixinNullable, ImportMixin): return {} @classmethod - def import_obj( + def import_obj( # pylint: disable=too-many-locals,too-many-branches,too-many-statements cls, dashboard_to_import: "Dashboard", import_time: Optional[int] = None ) -> int: """Imports the dashboard from the object to the database. @@ -579,10 +588,10 @@ class Dashboard(Model, AuditMixinNullable, ImportMixin): dashboard.position_json = json.dumps(position_data) logging.info( - "Started import of the dashboard: {}".format(dashboard_to_import.to_json()) + "Started import of the dashboard: %s", dashboard_to_import.to_json() ) session = db.session - logging.info("Dashboard has {} slices".format(len(dashboard_to_import.slices))) + logging.info("Dashboard has %d slices", len(dashboard_to_import.slices)) # copy slices object as Slice.import_slice will mutate the slice # and will remove the existing dashboard - slice association slices = copy(dashboard_to_import.slices) @@ -599,9 +608,9 @@ class Dashboard(Model, AuditMixinNullable, ImportMixin): } for slc in slices: logging.info( - "Importing slice {} from the dashboard: {}".format( - slc.to_json(), dashboard_to_import.dashboard_title - ) + "Importing slice %s from the dashboard: %s", + slc.to_json(), + dashboard_to_import.dashboard_title, ) remote_slc = remote_id_slice_map.get(slc.id) new_slc_id = Slice.import_obj(slc, remote_slc, import_time=import_time) @@ -677,14 +686,16 @@ class Dashboard(Model, AuditMixinNullable, ImportMixin): existing_dashboard.slices = new_slices session.flush() return existing_dashboard.id - else: - dashboard_to_import.slices = new_slices - session.add(dashboard_to_import) - session.flush() - return dashboard_to_import.id # type: ignore + + dashboard_to_import.slices = new_slices + session.add(dashboard_to_import) + session.flush() + return dashboard_to_import.id # type: ignore @classmethod - def export_dashboards(cls, dashboard_ids: List) -> str: + def export_dashboards( # pylint: disable=too-many-locals + cls, dashboard_ids: List + ) -> str: copied_dashboards = [] datasource_ids = set() for dashboard_id in dashboard_ids: @@ -741,7 +752,9 @@ class Dashboard(Model, AuditMixinNullable, ImportMixin): ) -class Database(Model, AuditMixinNullable, ImportMixin): +class Database( + Model, AuditMixinNullable, ImportMixin +): # pylint: disable=too-many-public-methods """An ORM object that stores Database related information""" @@ -749,7 +762,7 @@ class Database(Model, AuditMixinNullable, ImportMixin): type = "table" __table_args__ = (UniqueConstraint("database_name"),) - id = Column(Integer, primary_key=True) + id = Column(Integer, primary_key=True) # pylint: disable=invalid-name verbose_name = Column(String(250), unique=True) # short unique name, used in permissions database_name = Column(String(250), unique=True, nullable=False) @@ -763,7 +776,9 @@ class Database(Model, AuditMixinNullable, ImportMixin): allow_ctas = Column(Boolean, default=False) allow_dml = Column(Boolean, default=False) force_ctas_schema = Column(String(250)) - allow_multi_schema_metadata_fetch = Column(Boolean, default=False) + allow_multi_schema_metadata_fetch = Column( # pylint: disable=invalid-name + Boolean, default=False + ) extra = Column( Text, default=textwrap.dedent( @@ -836,8 +851,8 @@ class Database(Model, AuditMixinNullable, ImportMixin): @property def backend(self) -> str: - url = make_url(self.sqlalchemy_uri_decrypted) - return url.get_backend_name() + sqlalchemy_url = make_url(self.sqlalchemy_uri_decrypted) + return sqlalchemy_url.get_backend_name() @property def metadata_cache_timeout(self) -> Dict[str, Any]: @@ -864,12 +879,14 @@ class Database(Model, AuditMixinNullable, ImportMixin): return self.get_extra().get("default_schemas", []) @classmethod - def get_password_masked_url_from_uri(cls, uri: str): - url = make_url(uri) - return cls.get_password_masked_url(url) + def get_password_masked_url_from_uri(cls, uri: str): # pylint: disable=invalid-name + sqlalchemy_url = make_url(uri) + return cls.get_password_masked_url(sqlalchemy_url) @classmethod - def get_password_masked_url(cls, url: URL) -> URL: + def get_password_masked_url( + cls, url: URL # pylint: disable=redefined-outer-name + ) -> URL: url_copy = deepcopy(url) if url_copy.password is not None: url_copy.password = PASSWORD_MASK @@ -884,7 +901,9 @@ class Database(Model, AuditMixinNullable, ImportMixin): self.sqlalchemy_uri = str(conn) # hides the password def get_effective_user( - self, url: URL, user_name: Optional[str] = None + self, + url: URL, # pylint: disable=redefined-outer-name + user_name: Optional[str] = None, ) -> Optional[str]: """ Get the effective user, especially during impersonation. @@ -914,18 +933,18 @@ class Database(Model, AuditMixinNullable, ImportMixin): source: Optional[int] = None, ) -> Engine: extra = self.get_extra() - url = make_url(self.sqlalchemy_uri_decrypted) - url = self.db_engine_spec.adjust_database_uri(url, schema) - effective_username = self.get_effective_user(url, user_name) + sqlalchemy_url = make_url(self.sqlalchemy_uri_decrypted) + sqlalchemy_url = self.db_engine_spec.adjust_database_uri(sqlalchemy_url, schema) + effective_username = self.get_effective_user(sqlalchemy_url, user_name) # If using MySQL or Presto for example, will set url.username # If using Hive, will not do anything yet since that relies on a # configuration parameter instead. self.db_engine_spec.modify_url_for_impersonation( - url, self.impersonate_user, effective_username + sqlalchemy_url, self.impersonate_user, effective_username ) - masked_url = self.get_password_masked_url(url) - logging.info("Database.get_sqla_engine(). Masked URL: {0}".format(masked_url)) + masked_url = self.get_password_masked_url(sqlalchemy_url) + logging.info("Database.get_sqla_engine(). Masked URL: %s", str(masked_url)) params = extra.get("engine_params", {}) if nullpool: @@ -935,7 +954,7 @@ class Database(Model, AuditMixinNullable, ImportMixin): configuration: Dict[str, Any] = {} configuration.update( self.db_engine_spec.get_configuration_for_impersonation( - str(url), self.impersonate_user, effective_username + str(sqlalchemy_url), self.impersonate_user, effective_username ) ) if configuration: @@ -945,12 +964,11 @@ class Database(Model, AuditMixinNullable, ImportMixin): params.update(self.get_encrypted_extra()) - DB_CONNECTION_MUTATOR = config["DB_CONNECTION_MUTATOR"] if DB_CONNECTION_MUTATOR: - url, params = DB_CONNECTION_MUTATOR( - url, params, effective_username, security_manager, source + sqlalchemy_url, params = DB_CONNECTION_MUTATOR( + sqlalchemy_url, params, effective_username, security_manager, source ) - return create_engine(url, **params) + return create_engine(sqlalchemy_url, **params) def get_reserved_words(self) -> Set[str]: return self.get_dialect().preparer.reserved_words @@ -958,7 +976,7 @@ class Database(Model, AuditMixinNullable, ImportMixin): def get_quoter(self): return self.get_dialect().identifier_preparer.quote - def get_df( + def get_df( # pylint: disable=too-many-locals self, sql: str, schema: str, mutator: Optional[Callable] = None ) -> pd.DataFrame: sqls = [str(s).strip(" ;") for s in sqlparse.parse(sql)] @@ -982,9 +1000,9 @@ class Database(Model, AuditMixinNullable, ImportMixin): with closing(engine.raw_connection()) as conn: with closing(conn.cursor()) as cursor: - for sql in sqls[:-1]: - _log_query(sql) - self.db_engine_spec.execute(cursor, sql) + for sql_ in sqls[:-1]: + _log_query(sql_) + self.db_engine_spec.execute(cursor, sql_) cursor.fetchall() _log_query(sqls[-1]) @@ -1012,12 +1030,14 @@ class Database(Model, AuditMixinNullable, ImportMixin): sql = str(qry.compile(engine, compile_kwargs={"literal_binds": True})) - if engine.dialect.identifier_preparer._double_percents: + if ( + engine.dialect.identifier_preparer._double_percents # pylint: disable=protected-access + ): sql = sql.replace("%%", "%") return sql - def select_star( + def select_star( # pylint: disable=too-many-arguments self, table_name: str, sql: Optional[str] = None, @@ -1109,7 +1129,7 @@ class Database(Model, AuditMixinNullable, ImportMixin): return [ utils.DatasourceName(table=table, schema=schema) for table in tables ] - except Exception as e: + except Exception as e: # pylint: disable=broad-except logging.exception(e) @cache_util.memoized_func( @@ -1139,7 +1159,7 @@ class Database(Model, AuditMixinNullable, ImportMixin): database=self, inspector=self.inspector, schema=schema ) return [utils.DatasourceName(table=view, schema=schema) for view in views] - except Exception as e: + except Exception as e: # pylint: disable=broad-except logging.exception(e) @cache_util.memoized_func( @@ -1232,7 +1252,9 @@ class Database(Model, AuditMixinNullable, ImportMixin): ) -> List[Dict[str, Any]]: return self.inspector.get_foreign_keys(table_name, schema) - def get_schema_access_for_csv_upload(self) -> List[str]: + def get_schema_access_for_csv_upload( # pylint: disable=invalid-name + self + ) -> List[str]: return self.get_extra().get("schemas_allowed_for_csv_upload", []) @property @@ -1269,13 +1291,13 @@ sqla.event.listen(Database, "after_insert", security_manager.set_perm) sqla.event.listen(Database, "after_update", security_manager.set_perm) -class Log(Model): +class Log(Model): # pylint: disable=too-few-public-methods """ORM object used to log Superset actions to the database""" __tablename__ = "logs" - id = Column(Integer, primary_key=True) + id = Column(Integer, primary_key=True) # pylint: disable=invalid-name action = Column(String(512)) user_id = Column(Integer, ForeignKey("ab_user.id")) dashboard_id = Column(Integer) @@ -1289,10 +1311,10 @@ class Log(Model): referrer = Column(String(1024)) -class FavStar(Model): +class FavStar(Model): # pylint: disable=too-few-public-methods __tablename__ = "favstar" - id = Column(Integer, primary_key=True) + id = Column(Integer, primary_key=True) # pylint: disable=invalid-name user_id = Column(Integer, ForeignKey("ab_user.id")) class_name = Column(String(50)) obj_id = Column(Integer) @@ -1303,7 +1325,7 @@ class DatasourceAccessRequest(Model, AuditMixinNullable): """ORM model for the access requests for datasources and dbs.""" __tablename__ = "access_request" - id = Column(Integer, primary_key=True) + id = Column(Integer, primary_key=True) # pylint: disable=invalid-name datasource_id = Column(Integer) datasource_type = Column(String(200)) @@ -1337,33 +1359,33 @@ class DatasourceAccessRequest(Model, AuditMixinNullable): action_list = "" perm = self.datasource.perm # pylint: disable=no-member pv = security_manager.find_permission_view_menu("datasource_access", perm) - for r in pv.role: - if r.name in self.ROLES_BLACKLIST: + for role in pv.role: + if role.name in self.ROLES_BLACKLIST: continue # pylint: disable=no-member - url = ( + href = ( f"/superset/approve?datasource_type={self.datasource_type}&" f"datasource_id={self.datasource_id}&" - f"created_by={self.created_by.username}&role_to_grant={r.name}" + f"created_by={self.created_by.username}&role_to_grant={role.name}" ) - href = 'Grant {} Role'.format(url, r.name) - action_list = action_list + "
  • " + href + "
  • " + link = 'Grant {} Role'.format(href, role.name) + action_list = action_list + "
  • " + link + "
  • " return "" @property def user_roles(self) -> str: action_list = "" - for r in self.created_by.roles: # pylint: disable=no-member + for role in self.created_by.roles: # pylint: disable=no-member # pylint: disable=no-member - url = ( + href = ( f"/superset/approve?datasource_type={self.datasource_type}&" f"datasource_id={self.datasource_id}&" - f"created_by={self.created_by.username}&role_to_extend={r.name}" + f"created_by={self.created_by.username}&role_to_extend={role.name}" ) - href = 'Extend {} Role'.format(url, r.name) - if r.name in self.ROLES_BLACKLIST: - href = "{} Role".format(r.name) - action_list = action_list + "
  • " + href + "
  • " + link = 'Extend {} Role'.format(href, role.name) + if role.name in self.ROLES_BLACKLIST: + link = "{} Role".format(role.name) + action_list = action_list + "
  • " + link + "
  • " return "" diff --git a/superset/models/helpers.py b/superset/models/helpers.py index 9bbee1d2f4..97216b9e87 100644 --- a/superset/models/helpers.py +++ b/superset/models/helpers.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -# pylint: disable=C,R,W """a collection of model-related helper classes and functions""" import json import logging @@ -22,6 +21,8 @@ import re from datetime import datetime from typing import List, Optional +# isort and pylint disagree, isort should win +# pylint: disable=ungrouped-imports import humanize import sqlalchemy as sa import yaml @@ -38,10 +39,12 @@ from superset.utils.core import QueryStatus def json_to_dict(json_str): if json_str: val = re.sub(",[ \t\r\n]+}", "}", json_str) - val = re.sub(",[ \t\r\n]+\]", "]", val) + val = re.sub( + ",[ \t\r\n]+\]", "]", val # pylint: disable=anomalous-backslash-in-string + ) return json.loads(val) - else: - return {} + + return {} class ImportMixin(object): @@ -83,24 +86,24 @@ class ImportMixin(object): if not include_parent_ref: parent_ref = cls.__mapper__.relationships.get(cls.export_parent) if parent_ref: - parent_excludes = {c.name for c in parent_ref.local_columns} + parent_excludes = {column.name for column in parent_ref.local_columns} - def formatter(c): + def formatter(column): return ( - "{0} Default ({1})".format(str(c.type), c.default.arg) - if c.default - else str(c.type) + "{0} Default ({1})".format(str(column.type), column.default.arg) + if column.default + else str(column.type) ) schema = { - c.name: formatter(c) - for c in cls.__table__.columns - if (c.name in cls.export_fields and c.name not in parent_excludes) + column.name: formatter(column) + for column in cls.__table__.columns + if (column.name in cls.export_fields and column.name not in parent_excludes) } if recursive: - for c in cls.export_children: - child_class = cls.__mapper__.relationships[c].argument.class_ - schema[c] = [ + for column in cls.export_children: + child_class = cls.__mapper__.relationships[column].argument.class_ + schema[column] = [ child_class.export_schema( recursive=recursive, include_parent_ref=include_parent_ref ) @@ -108,8 +111,12 @@ class ImportMixin(object): return schema @classmethod - def import_from_dict(cls, session, dict_rep, parent=None, recursive=True, sync=[]): + def import_from_dict( + cls, session, dict_rep, parent=None, recursive=True, sync=None + ): # pylint: disable=too-many-arguments,too-many-locals,too-many-branches """Import obj from a dictionary""" + if sync is None: + sync = [] parent_refs = cls._parent_foreign_key_mappings() export_fields = set(cls.export_fields) | set(parent_refs.keys()) new_children = { @@ -126,10 +133,10 @@ class ImportMixin(object): if not parent: if cls.export_parent: - for p in parent_refs.keys(): - if p not in dict_rep: + for prnt in parent_refs.keys(): + if prnt not in dict_rep: raise RuntimeError( - "{0}: Missing field {1}".format(cls.__name__, p) + "{0}: Missing field {1}".format(cls.__name__, prnt) ) else: # Set foreign keys to parent obj @@ -182,10 +189,10 @@ class ImportMixin(object): # Recursively create children if recursive: - for c in cls.export_children: - child_class = cls.__mapper__.relationships[c].argument.class_ + for child in cls.export_children: + child_class = cls.__mapper__.relationships[child].argument.class_ added = [] - for c_obj in new_children.get(c, []): + for c_obj in new_children.get(child, []): added.append( child_class.import_from_dict( session=session, dict_rep=c_obj, parent=obj, sync=sync @@ -193,8 +200,10 @@ class ImportMixin(object): ) # If children should get synced, delete the ones that did not # get updated. - if c in sync and not is_new_obj: - back_refs = child_class._parent_foreign_key_mappings() + if child in sync and not is_new_obj: + back_refs = ( + child_class._parent_foreign_key_mappings() # pylint: disable=protected-access + ) delete_filters = [ getattr(child_class, k) == getattr(obj, back_refs.get(k)) for k in back_refs.keys() @@ -203,7 +212,7 @@ class ImportMixin(object): session.query(child_class).filter(and_(*delete_filters)) ).difference(set(added)) for o in to_delete: - logging.info("Deleting %s %s", c, str(obj)) + logging.info("Deleting %s %s", child, str(obj)) session.delete(o) return obj @@ -234,16 +243,16 @@ class ImportMixin(object): ) } if recursive: - for c in self.export_children: + for cld in self.export_children: # sorting to make lists of children stable - dict_rep[c] = sorted( + dict_rep[cld] = sorted( [ child.export_to_dict( recursive=recursive, include_parent_ref=include_parent_ref, include_defaults=include_defaults, ) - for child in getattr(self, c) + for child in getattr(self, cld) ], key=lambda k: sorted(str(k.items())), ) @@ -276,7 +285,7 @@ class ImportMixin(object): try: if g.user: self.owners = [g.user] - except Exception: + except Exception: # pylint: disable=broad-except self.owners = [] @property @@ -288,6 +297,13 @@ class ImportMixin(object): return json_to_dict(self.template_params) +def _user_link(user): # pylint: disable=no-self-use + if not user: + return "" + url = "/superset/profile/{}/".format(user.username) + return Markup('{}'.format(url, escape(user) or "")) + + class AuditMixinNullable(AuditMixin): """Altering the AuditMixin to use nullable fields @@ -319,12 +335,6 @@ class AuditMixinNullable(AuditMixin): nullable=True, ) - def _user_link(self, user): - if not user: - return "" - url = "/superset/profile/{}/".format(user.username) - return Markup('{}'.format(url, escape(user) or "")) - def changed_by_name(self): if self.created_by: return escape("{}".format(self.created_by)) @@ -332,11 +342,11 @@ class AuditMixinNullable(AuditMixin): @renders("created_by") def creator(self): - return self._user_link(self.created_by) + return _user_link(self.created_by) @property def changed_by_(self): - return self._user_link(self.changed_by) + return _user_link(self.changed_by) @renders("changed_on") def changed_on_(self): @@ -351,14 +361,14 @@ class AuditMixinNullable(AuditMixin): return Markup(f'{self.changed_on_humanized}') -class QueryResult(object): +class QueryResult(object): # pylint: disable=too-few-public-methods """Object returned by the query interface""" - def __init__( + def __init__( # pylint: disable=too-many-arguments self, df, query, duration, status=QueryStatus.SUCCESS, error_message=None ): - self.df = df + self.df = df # pylint: disable=invalid-name self.query = query self.duration = duration self.status = status @@ -374,7 +384,7 @@ class ExtraJSONMixin: def extra(self): try: return json.loads(self.extra_json) - except Exception: + except Exception: # pylint: disable=broad-except return {} def set_extra_json(self, d): diff --git a/superset/models/schedules.py b/superset/models/schedules.py index 42118a2af6..815697ecda 100644 --- a/superset/models/schedules.py +++ b/superset/models/schedules.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -# pylint: disable=C,R,W """Models for scheduled execution of jobs""" import enum @@ -51,7 +50,7 @@ class EmailSchedule: __tablename__ = "email_schedules" - id = Column(Integer, primary_key=True) + id = Column(Integer, primary_key=True) # pylint: disable=invalid-name active = Column(Boolean, default=True, index=True) crontab = Column(String(50)) @@ -92,3 +91,4 @@ def get_scheduler_model(report_type): return DashboardEmailSchedule elif report_type == ScheduleType.slice.value: return SliceEmailSchedule + return None diff --git a/superset/models/sql_lab.py b/superset/models/sql_lab.py index 22291c7b57..820ded8065 100644 --- a/superset/models/sql_lab.py +++ b/superset/models/sql_lab.py @@ -14,11 +14,11 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -# pylint: disable=C,R,W """A collection of ORM sqlalchemy models for SQL Lab""" import re from datetime import datetime +# pylint: disable=ungrouped-imports import simplejson as json import sqlalchemy as sqla from flask import Markup @@ -48,7 +48,7 @@ class Query(Model, ExtraJSONMixin): table may represent multiple SQL statements executed sequentially""" __tablename__ = "query" - id = Column(Integer, primary_key=True) + id = Column(Integer, primary_key=True) # pylint: disable=invalid-name client_id = Column(String(11), unique=True, nullable=False) database_id = Column(Integer, ForeignKey("dbs.id"), nullable=False) @@ -149,7 +149,7 @@ class SavedQuery(Model, AuditMixinNullable, ExtraJSONMixin): """ORM model for SQL query""" __tablename__ = "saved_query" - id = Column(Integer, primary_key=True) + id = Column(Integer, primary_key=True) # pylint: disable=invalid-name user_id = Column(Integer, ForeignKey("ab_user.id"), nullable=True) db_id = Column(Integer, ForeignKey("dbs.id"), nullable=True) schema = Column(String(128)) @@ -194,7 +194,9 @@ class TabState(Model, AuditMixinNullable, ExtraJSONMixin): __tablename__ = "tab_state" # basic info - id = Column(Integer, primary_key=True, autoincrement=True) + id = Column( # pylint: disable=invalid-name + Integer, primary_key=True, autoincrement=True + ) user_id = Column(Integer, ForeignKey("ab_user.id")) label = Column(String(256)) active = Column(Boolean, default=False) @@ -245,7 +247,9 @@ class TableSchema(Model, AuditMixinNullable, ExtraJSONMixin): __tablename__ = "table_schema" - id = Column(Integer, primary_key=True, autoincrement=True) + id = Column( # pylint: disable=invalid-name + Integer, primary_key=True, autoincrement=True + ) tab_state_id = Column(Integer, ForeignKey("tab_state.id", ondelete="CASCADE")) database_id = Column(Integer, ForeignKey("dbs.id"), nullable=False) diff --git a/superset/models/tags.py b/superset/models/tags.py index 580aa71525..6c29430679 100644 --- a/superset/models/tags.py +++ b/superset/models/tags.py @@ -14,7 +14,6 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -# pylint: disable=C,R,W,no-init from __future__ import absolute_import, division, print_function, unicode_literals import enum