This is an automated email from the ASF dual-hosted git repository. maximebeauchemin 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 cc3a625 Use py3's f-strings instead of s.format(**locals()) (#6448) cc3a625 is described below commit cc3a625a4bb6b0e581b30f3112315ff5a8ab6807 Author: Maxime Beauchemin <maximebeauche...@gmail.com> AuthorDate: Sun Dec 2 13:50:49 2018 -0800 Use py3's f-strings instead of s.format(**locals()) (#6448) * Use py3's f-strings instead of s.format(**locals()) In light of the bug reported here https://github.com/apache/incubator-superset/issues/6347, which seems like an odd `.format()` issue in py3, I greped and replaced all instances of `.format(**locals())` using py3's f-strings * lint * fix tests --- superset/cli.py | 17 +++++++++-------- superset/config.py | 2 +- superset/connectors/base/models.py | 2 +- superset/connectors/druid/models.py | 8 ++++---- superset/connectors/sqla/models.py | 4 ++-- superset/db_engine_specs.py | 12 ++++++------ superset/models/core.py | 35 ++++++++++++++++++++++------------- superset/models/helpers.py | 11 ----------- superset/models/sql_lab.py | 6 +++--- superset/sql_parse.py | 6 +++--- superset/stats_logger.py | 12 +++++++----- superset/views/core.py | 15 ++++++--------- tests/core_tests.py | 10 +++++----- tests/model_tests.py | 8 ++++---- 14 files changed, 73 insertions(+), 75 deletions(-) diff --git a/superset/cli.py b/superset/cli.py index 1f36037..c6444b1 100755 --- a/superset/cli.py +++ b/superset/cli.py @@ -115,12 +115,13 @@ def runserver(debug, console_log, use_reloader, address, port, timeout, workers, addr_str = ' unix:{socket} ' if socket else' {address}:{port} ' cmd = ( 'gunicorn ' - '-w {workers} ' - '--timeout {timeout} ' - '-b ' + addr_str + + f'-w {workers} ' + f'--timeout {timeout} ' + f'-b {addr_str} ' '--limit-request-line 0 ' '--limit-request-field_size 0 ' - 'superset:app').format(**locals()) + 'superset:app' + ) print(Fore.GREEN + 'Starting server with command: ') print(Fore.YELLOW + cmd) print(Style.RESET_ALL) @@ -404,10 +405,10 @@ def flower(port, address): BROKER_URL = celery_app.conf.BROKER_URL cmd = ( 'celery flower ' - '--broker={BROKER_URL} ' - '--port={port} ' - '--address={address} ' - ).format(**locals()) + f'--broker={BROKER_URL} ' + f'--port={port} ' + f'--address={address} ' + ) logging.info( "The 'superset flower' command is deprecated. Please use the 'celery " "flower' command instead.") diff --git a/superset/config.py b/superset/config.py index a9622db..73e5a2c 100644 --- a/superset/config.py +++ b/superset/config.py @@ -450,7 +450,7 @@ DB_CONNECTION_MUTATOR = None # # def SQL_QUERY_MUTATOR(sql, username, security_manager): # dttm = datetime.now().isoformat() -# return "-- [SQL LAB] {username} {dttm}\n sql"(**locals()) +# return f"-- [SQL LAB] {username} {dttm}\n{sql}" SQL_QUERY_MUTATOR = None # When not using gunicorn, (nginx for instance), you may want to disable diff --git a/superset/connectors/base/models.py b/superset/connectors/base/models.py index 7f159a6..216ed9e 100644 --- a/superset/connectors/base/models.py +++ b/superset/connectors/base/models.py @@ -66,7 +66,7 @@ class BaseDatasource(AuditMixinNullable, ImportMixin): @property def uid(self): """Unique id across datasource types""" - return '{self.id}__{self.type}'.format(**locals()) + return f'{self.id}__{self.type}' @property def column_names(self): diff --git a/superset/connectors/druid/models.py b/superset/connectors/druid/models.py index 40a4287..0972f78 100644 --- a/superset/connectors/druid/models.py +++ b/superset/connectors/druid/models.py @@ -116,7 +116,7 @@ class DruidCluster(Model, AuditMixinNullable, ImportMixin): def get_base_broker_url(self): base_url = self.get_base_url( self.broker_host, self.broker_port) - return '{base_url}/{self.broker_endpoint}'.format(**locals()) + return f'{base_url}/{self.broker_endpoint}' def get_pydruid_client(self): cli = PyDruid( @@ -525,7 +525,7 @@ class DruidDatasource(Model, BaseDatasource): @property def link(self): name = escape(self.datasource_name) - return Markup('<a href="{self.url}">{name}</a>').format(**locals()) + return Markup(f'<a href="{self.url}">{name}</a>') @property def full_name(self): @@ -549,9 +549,9 @@ class DruidDatasource(Model, BaseDatasource): @renders('datasource_name') def datasource_link(self): - url = '/superset/explore/{obj.type}/{obj.id}/'.format(obj=self) + url = f'/superset/explore/{self.type}/{self.id}/' name = escape(self.datasource_name) - return Markup('<a href="{url}">{name}</a>'.format(**locals())) + return Markup(f'<a href="{url}">{name}</a>') def get_metric_obj(self, metric_name): return [ diff --git a/superset/connectors/sqla/models.py b/superset/connectors/sqla/models.py index 2ed2afd..cf22add 100644 --- a/superset/connectors/sqla/models.py +++ b/superset/connectors/sqla/models.py @@ -324,8 +324,8 @@ class SqlaTable(Model, BaseDatasource): @property def link(self): name = escape(self.name) - anchor = '<a target="_blank" href="{self.explore_url}">{name}</a>' - return Markup(anchor.format(**locals())) + anchor = f'<a target="_blank" href="{self.explore_url}">{name}</a>' + return Markup(anchor) @property def schema_perm(self): diff --git a/superset/db_engine_specs.py b/superset/db_engine_specs.py index 5722507..d409c87 100644 --- a/superset/db_engine_specs.py +++ b/superset/db_engine_specs.py @@ -848,15 +848,15 @@ class PrestoEngineSpec(BaseEngineSpec): if filters: l = [] # noqa: E741 for field, value in filters.items(): - l.append("{field} = '{value}'".format(**locals())) + l.append(f"{field} = '{value}'") where_clause = 'WHERE ' + ' AND '.join(l) - sql = textwrap.dedent("""\ + sql = textwrap.dedent(f"""\ SHOW PARTITIONS FROM {table_name} {where_clause} {order_by_clause} {limit_clause} - """).format(**locals()) + """) return sql @classmethod @@ -1070,10 +1070,10 @@ class HiveEngineSpec(PrestoEngineSpec): s3.upload_file( upload_path, bucket_path, os.path.join(upload_prefix, table_name, filename)) - sql = """CREATE TABLE {full_table_name} ( {schema_definition} ) + sql = f"""CREATE TABLE {full_table_name} ( {schema_definition} ) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' STORED AS TEXTFILE LOCATION '{location}' - tblproperties ('skip.header.line.count'='1')""".format(**locals()) + tblproperties ('skip.header.line.count'='1')""" logging.info(form.con.data) engine = create_engine(form.con.data.sqlalchemy_uri_decrypted) engine.execute(sql) @@ -1220,7 +1220,7 @@ class HiveEngineSpec(PrestoEngineSpec): @classmethod def _partition_query( cls, table_name, limit=0, order_by=None, filters=None): - return 'SHOW PARTITIONS {table_name}'.format(**locals()) + return f'SHOW PARTITIONS {table_name}' @classmethod def modify_url_for_impersonation(cls, url, impersonate_user, username): diff --git a/superset/models/core.py b/superset/models/core.py index 712de78..1323eed 100644 --- a/superset/models/core.py +++ b/superset/models/core.py @@ -257,8 +257,7 @@ class Slice(Model, AuditMixinNullable, ImportMixin): form_data = {'slice_id': self.id} form_data.update(overrides) params = parse.quote(json.dumps(form_data)) - return ( - '{base_url}/?form_data={params}'.format(**locals())) + return f'{base_url}/?form_data={params}' @property def slice_url(self): @@ -278,7 +277,7 @@ class Slice(Model, AuditMixinNullable, ImportMixin): def slice_link(self): url = self.slice_url name = escape(self.slice_name) - return Markup('<a href="{url}">{name}</a>'.format(**locals())) + return Markup(f'<a href="{url}">{name}</a>') def get_viz(self, force=False): """Creates :py:class:viz.BaseViz object from the url_params_multidict. @@ -299,6 +298,17 @@ class Slice(Model, AuditMixinNullable, ImportMixin): force=force, ) + @property + def icons(self): + return f""" + <a + href="{self.datasource_edit_url}" + data-toggle="tooltip" + title="{self.datasource}"> + <i class="fa fa-database"></i> + </a> + """ + @classmethod def import_obj(cls, slc_to_import, slc_to_override, import_time=None): """Inserts or overrides slc in the database. @@ -409,8 +419,7 @@ class Dashboard(Model, AuditMixinNullable, ImportMixin): def dashboard_link(self): title = escape(self.dashboard_title) - return Markup( - '<a href="{self.url}">{title}</a>'.format(**locals())) + return Markup(f'<a href="{self.url}">{title}</a>') @property def data(self): @@ -1185,11 +1194,11 @@ class DatasourceAccessRequest(Model, AuditMixinNullable): for r in pv.role: if r.name in self.ROLES_BLACKLIST: continue + # pylint: disable=no-member url = ( - '/superset/approve?datasource_type={self.datasource_type}&' - 'datasource_id={self.datasource_id}&' - 'created_by={self.created_by.username}&role_to_grant={r.name}' - .format(**locals()) + 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}' ) href = '<a href="{}">Grant {} Role</a>'.format(url, r.name) action_list = action_list + '<li>' + href + '</li>' @@ -1199,11 +1208,11 @@ class DatasourceAccessRequest(Model, AuditMixinNullable): def user_roles(self): action_list = '' for r in self.created_by.roles: # pylint: disable=no-member + # pylint: disable=no-member url = ( - '/superset/approve?datasource_type={self.datasource_type}&' - 'datasource_id={self.datasource_id}&' - 'created_by={self.created_by.username}&role_to_extend={r.name}' - .format(**locals()) + 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}' ) href = '<a href="{}">Extend {} Role</a>'.format(url, r.name) if r.name in self.ROLES_BLACKLIST: diff --git a/superset/models/helpers.py b/superset/models/helpers.py index d45ff83..f1cb1cd 100644 --- a/superset/models/helpers.py +++ b/superset/models/helpers.py @@ -277,17 +277,6 @@ class AuditMixinNullable(AuditMixin): def modified(self): return humanize.naturaltime(datetime.now() - self.changed_on) - @property - def icons(self): - return """ - <a - href="{self.datasource_edit_url}" - data-toggle="tooltip" - title="{self.datasource}"> - <i class="fa fa-database"></i> - </a> - """.format(**locals()) - class QueryResult(object): diff --git a/superset/models/sql_lab.py b/superset/models/sql_lab.py index 9d0c331..117f874 100644 --- a/superset/models/sql_lab.py +++ b/superset/models/sql_lab.py @@ -115,7 +115,7 @@ class Query(Model): tab = (self.tab_name.replace(' ', '_').lower() if self.tab_name else 'notab') tab = re.sub(r'\W+', '', tab) - return 'sqllab_{tab}_{ts}'.format(**locals()) + return f'sqllab_{tab}_{ts}' class SavedQuery(Model, AuditMixinNullable): @@ -140,8 +140,8 @@ class SavedQuery(Model, AuditMixinNullable): @property def pop_tab_link(self): - return Markup(""" + return Markup(f""" <a href="/superset/sqllab?savedQueryId={self.id}"> <i class="fa fa-link"></i> </a> - """.format(**locals())) + """) diff --git a/superset/sql_parse.py b/superset/sql_parse.py index 2f54f77..80dba4c 100644 --- a/superset/sql_parse.py +++ b/superset/sql_parse.py @@ -100,9 +100,9 @@ class SupersetQuery(object): exec_sql = '' sql = self.stripped() if overwrite: - exec_sql = 'DROP TABLE IF EXISTS {table_name};\n' - exec_sql += 'CREATE TABLE {table_name} AS \n{sql}' - return exec_sql.format(**locals()) + exec_sql = f'DROP TABLE IF EXISTS {table_name};\n' + exec_sql += f'CREATE TABLE {table_name} AS \n{sql}' + return exec_sql def __extract_from_token(self, token): if not hasattr(token, 'tokens'): diff --git a/superset/stats_logger.py b/superset/stats_logger.py index 098f53f..20f6c1f 100644 --- a/superset/stats_logger.py +++ b/superset/stats_logger.py @@ -43,13 +43,15 @@ class DummyStatsLogger(BaseStatsLogger): def timing(self, key, value): logging.debug(( - Fore.CYAN + '[stats_logger] (timing) {key} | {value} ' + - Style.RESET_ALL).format(**locals())) + Fore.CYAN + + f'[stats_logger] (timing) {key} | {value} ' + + Style.RESET_ALL)) def gauge(self, key, value): logging.debug(( - Fore.CYAN + '[stats_logger] (gauge) ' - '{key} | {value}' + Style.RESET_ALL).format(**locals())) + Fore.CYAN + '[stats_logger] (gauge) ' + + f'{key} | {value}' + + Style.RESET_ALL)) try: @@ -72,5 +74,5 @@ try: # pylint: disable=no-value-for-parameter self.client.gauge(key) -except Exception as e: +except Exception: pass diff --git a/superset/views/core.py b/superset/views/core.py index 33d31c1..7faa1e2 100755 --- a/superset/views/core.py +++ b/superset/views/core.py @@ -1275,9 +1275,8 @@ class Superset(BaseSupersetView): 'danger') return redirect( 'superset/request_access/?' - 'datasource_type={datasource_type}&' - 'datasource_id={datasource_id}&' - ''.format(**locals())) + f'datasource_type={datasource_type}&' + f'datasource_id={datasource_id}&') viz_type = form_data.get('viz_type') if not viz_type and datasource.default_endpoint: @@ -2115,7 +2114,7 @@ class Superset(BaseSupersetView): 'danger') return redirect( 'superset/request_access/?' - 'dashboard_id={dash.id}&'.format(**locals())) + f'dashboard_id={dash.id}&') dash_edit_perm = check_ownership(dash, raise_if_false=False) and \ security_manager.can_access('can_save_dash', 'Superset') @@ -2522,11 +2521,10 @@ class Superset(BaseSupersetView): start_time=utils.now_as_float()) except Exception as e: logging.exception(e) - msg = ( + msg = _( 'Failed to start remote query on a worker. ' 'Tell your administrator to verify the availability of ' - 'the message queue.' - ) + 'the message queue.') query.status = QueryStatus.FAILED query.error_message = msg session.commit() @@ -2542,8 +2540,7 @@ class Superset(BaseSupersetView): try: timeout = config.get('SQLLAB_TIMEOUT') timeout_msg = ( - 'The query exceeded the {timeout} seconds ' - 'timeout.').format(**locals()) + f'The query exceeded the {timeout} seconds timeout.') with utils.timeout(seconds=timeout, error_message=timeout_msg): # pylint: disable=no-value-for-parameter diff --git a/tests/core_tests.py b/tests/core_tests.py index 2acd842..5b45cb8 100644 --- a/tests/core_tests.py +++ b/tests/core_tests.py @@ -273,7 +273,7 @@ class CoreTests(SupersetTestCase): (slc.slice_name, 'explore_json', slc.explore_json_url), ] for name, method, url in urls: - logging.info('[{name}]/[{method}]: {url}'.format(**locals())) + logging.info(f'[{name}]/[{method}]: {url}') self.client.get(url) def test_tablemodelview_list(self): @@ -319,8 +319,8 @@ class CoreTests(SupersetTestCase): (slc.slice_name, 'slice_url', slc.slice_url), ] for name, method, url in urls: - print('[{name}]/[{method}]: {url}'.format(**locals())) - response = self.client.get(url) + print(f'[{name}]/[{method}]: {url}') + self.client.get(url) def test_doctests(self): modules = [utils, models, sql_lab] @@ -478,8 +478,8 @@ class CoreTests(SupersetTestCase): self.login('admin') dbid = get_main_database(db.session).id self.get_json_resp( - '/superset/extra_table_metadata/{dbid}/' - 'ab_permission_view/panoramix/'.format(**locals())) + f'/superset/extra_table_metadata/{dbid}/' + 'ab_permission_view/panoramix/') def test_process_template(self): maindb = get_main_database(db.session) diff --git a/tests/model_tests.py b/tests/model_tests.py index 8d3c17c..0885f31 100644 --- a/tests/model_tests.py +++ b/tests/model_tests.py @@ -76,20 +76,20 @@ class DatabaseModelTestCase(SupersetTestCase): table_name = 'energy_usage' sql = main_db.select_star( table_name, show_cols=False, latest_partition=False) - expected = textwrap.dedent("""\ + expected = textwrap.dedent(f"""\ SELECT * FROM {table_name} - LIMIT 100""".format(**locals())) + LIMIT 100""") assert sql.startswith(expected) sql = main_db.select_star( table_name, show_cols=True, latest_partition=False) - expected = textwrap.dedent("""\ + expected = textwrap.dedent(f"""\ SELECT source, target, value FROM energy_usage - LIMIT 100""".format(**locals())) + LIMIT 100""") assert sql.startswith(expected) def test_grains_dict(self):