Skip to content
Browse files

Add type anno (#7342)

* Updated local dev instructions to include missing step

* First pass at type annotations
  • Loading branch information...
craig-rueda authored and mistercrunch committed Apr 23, 2019
1 parent 621cef7 commit 48b2af471c006893a2a2de9727940a839086340e
Showing with 37 additions and 31 deletions.
  1. +0 −2 .travis.yml
  2. +1 −1 superset/utils/
  3. +36 −28 superset/utils/
@@ -14,8 +14,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
pip: true
- language: python
@@ -20,7 +20,7 @@
from superset import tables_cache

def view_cache_key(*unused_args, **unused_kwargs):
def view_cache_key(*unused_args, **unused_kwargs) -> str:
args_hash = hash(frozenset(request.args.items()))
return 'view/{}/{}'.format(request.path, args_hash)

@@ -31,15 +31,17 @@
import signal
import smtplib
import sys
from typing import Optional, Tuple
from time import struct_time
from typing import List, Optional, Tuple
import uuid
import zlib

import bleach
import celery
from dateutil.parser import parse
from dateutil.relativedelta import relativedelta
from flask import flash, g, Markup, render_template
from flask import flash, Flask, g, Markup, render_template
from import User
from flask_babel import gettext as __
from flask_babel import lazy_gettext as _
from flask_caching import Cache
@@ -51,6 +53,7 @@
import sqlalchemy as sa
from sqlalchemy import event, exc, select, Text
from sqlalchemy.dialects.mysql import MEDIUMTEXT
from sqlalchemy.sql.type_api import Variant
from sqlalchemy.types import TEXT, TypeDecorator

from superset.exceptions import SupersetException, SupersetTimeoutException
@@ -138,11 +141,11 @@ def wrapper(f):
return wrapper

def js_string_to_python(item):
def js_string_to_python(item: str) -> Optional[str]:
return None if item in ('null', 'undefined') else item

def string_to_num(s):
def string_to_num(s: str):
"""Converts a string to an int/float
Returns ``None`` if it can't be converted
@@ -182,7 +185,7 @@ def __init__(self, **args):

def list_minus(l, minus):
def list_minus(l: List, minus: List) -> List:
"""Returns l without what is in minus
>>> list_minus([1, 2, 3], [2])
@@ -230,7 +233,7 @@ def parse_human_datetime(s):
return dttm

def dttm_from_timtuple(d):
def dttm_from_timtuple(d: struct_time) -> datetime:
return datetime(
d.tm_year, d.tm_mon, d.tm_mday, d.tm_hour, d.tm_min, d.tm_sec)

@@ -284,7 +287,7 @@ def default(self, o):
return json.JSONEncoder.default(self, o)

def parse_human_timedelta(s):
def parse_human_timedelta(s: str):
Returns ``datetime.datetime`` from natural language time deltas
@@ -349,7 +352,7 @@ def base_json_conv(obj):
return '[bytes]'

def json_iso_dttm_ser(obj, pessimistic=False):
def json_iso_dttm_ser(obj, pessimistic: Optional[bool] = False):
json serializer that deals with dates
@@ -420,7 +423,7 @@ def error_msg_from_exception(e):
return msg or '{}'.format(e)

def markdown(s, markup_wrap=False):
def markdown(s: str, markup_wrap: Optional[bool] = False) -> str:
safe_markdown_tags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'b', 'i',
'strong', 'em', 'tt', 'p', 'br', 'span',
'div', 'blockquote', 'code', 'hr', 'ul', 'ol',
@@ -438,7 +441,7 @@ def markdown(s, markup_wrap=False):
return s

def readfile(file_path):
def readfile(file_path: str) -> Optional[str]:
with open(file_path) as f:
content =
return content
@@ -677,29 +680,32 @@ def send_MIME_email(e_from, e_to, mime_msg, config, dryrun=False):

def get_email_address_list(address_string):
def get_email_address_list(address_string: str) -> List[str]:
address_string_list: List[str] = []
if isinstance(address_string, str):
if ',' in address_string:
address_string = address_string.split(',')
address_string_list = address_string.split(',')
elif '\n' in address_string:
address_string = address_string.split('\n')
address_string_list = address_string.split('\n')
elif ';' in address_string:
address_string = address_string.split(';')
address_string_list = address_string.split(';')
address_string = [address_string]
return [x.strip() for x in address_string if x.strip()]
address_string_list = [address_string]
return [x.strip() for x in address_string_list if x.strip()]

def choicify(values):
"""Takes an iterable and makes an iterable of tuples with it"""
return [(v, v) for v in values]

def setup_cache(app, cache_config):
def setup_cache(app: Flask, cache_config) -> Optional[Cache]:
"""Setup the flask-cache on a flask app"""
if cache_config and cache_config.get('CACHE_TYPE') != 'null':
return Cache(app, config=cache_config)

return None

def zlib_compress(data):
@@ -766,7 +772,7 @@ def to_adhoc(filt, expressionType='SIMPLE', clause='where'):
return result

def merge_extra_filters(form_data):
def merge_extra_filters(form_data: dict):
# extra_filters are temporary/contextual filters (using the legacy constructs)
# that are external to the slice definition. We use those for dynamic
# interactive filters like the ones emitted by the "Filter Box" visualization.
@@ -837,7 +843,7 @@ def get_filter_key(f):
del form_data['extra_filters']

def merge_request_params(form_data, params):
def merge_request_params(form_data: dict, params: dict):
url_params = {}
for key, value in params.items():
if key in ('form_data', 'r'):
@@ -846,19 +852,21 @@ def merge_request_params(form_data, params):
form_data['url_params'] = url_params

def get_update_perms_flag():
def get_update_perms_flag() -> bool:
val = os.environ.get('SUPERSET_UPDATE_PERMS')
return val.lower() not in ('0', 'false', 'no') if val else True

def user_label(user):
def user_label(user: User) -> Optional[str]:
"""Given a user ORM FAB object, returns a label"""
if user:
if user.first_name and user.last_name:
return user.first_name + ' ' + user.last_name
return user.username

return None

def get_or_create_main_db():
from superset import conf, db
@@ -887,7 +895,7 @@ def get_main_database(session):

def is_adhoc_metric(metric):
def is_adhoc_metric(metric) -> bool:
return (
isinstance(metric, dict) and
@@ -913,7 +921,7 @@ def get_metric_names(metrics):
return [get_metric_name(metric) for metric in metrics]

def ensure_path_exists(path):
def ensure_path_exists(path: str):
except OSError as exc:
@@ -997,7 +1005,7 @@ def get_since_until(time_range: Optional[str] = None,
return since, until # noqa: T400

def add_ago_to_since(since):
def add_ago_to_since(since: str) -> str:
Backwards compatibility hack. Without this slices with since: 7 days will
be treated as 7 days in the future.
@@ -1072,17 +1080,17 @@ def split_adhoc_filters_into_base_filters(fd):
fd['filters'] = simple_where_filters

def get_username():
def get_username() -> Optional[str]:
"""Get username if within the flask context, otherwise return noffin'"""
return g.user.username
except Exception:
return None

def MediumText():
def MediumText() -> Variant:
return Text().with_variant(MEDIUMTEXT(), 'mysql')

def shortid():
def shortid() -> str:
return '{}'.format(uuid.uuid4())[-12:]

0 comments on commit 48b2af4

Please sign in to comment.
You can’t perform that action at this time.