diff --git a/caravel/assets/images/tutorial/add_db.png b/caravel/assets/images/tutorial/add_db.png
deleted file mode 100644
index 728234376b4c..000000000000
Binary files a/caravel/assets/images/tutorial/add_db.png and /dev/null differ
diff --git a/caravel/assets/images/viz_thumbnails/bar.png b/caravel/assets/images/viz_thumbnails/bar.png
deleted file mode 100644
index b41014788a2f..000000000000
Binary files a/caravel/assets/images/viz_thumbnails/bar.png and /dev/null differ
diff --git a/caravel/assets/images/viz_thumbnails/big_number.png b/caravel/assets/images/viz_thumbnails/big_number.png
deleted file mode 100644
index 2420f25e9fbb..000000000000
Binary files a/caravel/assets/images/viz_thumbnails/big_number.png and /dev/null differ
diff --git a/caravel/assets/images/viz_thumbnails/bubble.png b/caravel/assets/images/viz_thumbnails/bubble.png
deleted file mode 100644
index 08de51f4ff6e..000000000000
Binary files a/caravel/assets/images/viz_thumbnails/bubble.png and /dev/null differ
diff --git a/caravel/assets/images/viz_thumbnails/filter.png b/caravel/assets/images/viz_thumbnails/filter.png
deleted file mode 100644
index 209259c699a2..000000000000
Binary files a/caravel/assets/images/viz_thumbnails/filter.png and /dev/null differ
diff --git a/caravel/assets/images/viz_thumbnails/force_directed.png b/caravel/assets/images/viz_thumbnails/force_directed.png
deleted file mode 100644
index 1cc7ce95799a..000000000000
Binary files a/caravel/assets/images/viz_thumbnails/force_directed.png and /dev/null differ
diff --git a/caravel/assets/images/viz_thumbnails/line.png b/caravel/assets/images/viz_thumbnails/line.png
deleted file mode 100644
index 67f8fe887f09..000000000000
Binary files a/caravel/assets/images/viz_thumbnails/line.png and /dev/null differ
diff --git a/caravel/assets/images/viz_thumbnails/percent_change.png b/caravel/assets/images/viz_thumbnails/percent_change.png
deleted file mode 100644
index 00b0a7c515f2..000000000000
Binary files a/caravel/assets/images/viz_thumbnails/percent_change.png and /dev/null differ
diff --git a/caravel/assets/images/viz_thumbnails/pie.png b/caravel/assets/images/viz_thumbnails/pie.png
deleted file mode 100644
index ab76749f74cc..000000000000
Binary files a/caravel/assets/images/viz_thumbnails/pie.png and /dev/null differ
diff --git a/caravel/assets/images/viz_thumbnails/pivot_table.png b/caravel/assets/images/viz_thumbnails/pivot_table.png
deleted file mode 100644
index 37f86af079c2..000000000000
Binary files a/caravel/assets/images/viz_thumbnails/pivot_table.png and /dev/null differ
diff --git a/caravel/assets/images/viz_thumbnails/sankey.png b/caravel/assets/images/viz_thumbnails/sankey.png
deleted file mode 100644
index 981cdba8708f..000000000000
Binary files a/caravel/assets/images/viz_thumbnails/sankey.png and /dev/null differ
diff --git a/caravel/assets/images/viz_thumbnails/stacked.png b/caravel/assets/images/viz_thumbnails/stacked.png
deleted file mode 100644
index 86f1080cda5b..000000000000
Binary files a/caravel/assets/images/viz_thumbnails/stacked.png and /dev/null differ
diff --git a/caravel/assets/images/viz_thumbnails/sunburst.png b/caravel/assets/images/viz_thumbnails/sunburst.png
deleted file mode 100644
index f155363aad48..000000000000
Binary files a/caravel/assets/images/viz_thumbnails/sunburst.png and /dev/null differ
diff --git a/caravel/assets/images/viz_thumbnails/table.png b/caravel/assets/images/viz_thumbnails/table.png
deleted file mode 100644
index a3dd1bee98dd..000000000000
Binary files a/caravel/assets/images/viz_thumbnails/table.png and /dev/null differ
diff --git a/caravel/assets/images/viz_thumbnails/word_cloud.png b/caravel/assets/images/viz_thumbnails/word_cloud.png
deleted file mode 100644
index 03936e1253d5..000000000000
Binary files a/caravel/assets/images/viz_thumbnails/word_cloud.png and /dev/null differ
diff --git a/caravel/assets/javascripts/modules/caravel.js b/caravel/assets/javascripts/modules/caravel.js
index 88c11e7967fd..07059b20bd16 100644
--- a/caravel/assets/javascripts/modules/caravel.js
+++ b/caravel/assets/javascripts/modules/caravel.js
@@ -272,9 +272,13 @@ var px = (function () {
$('.query-and-save button').removeAttr('disabled');
always(data);
},
- error: function (msg) {
+ error: function (error) {
+ var msg = error.responseText;
token.find("img.loading").hide();
var err = '
' + msg + '
';
+ if (error.getResponseHeader("Caravel-Exception") === "NoResultsException") {
+ err = '' + msg + '
';
+ }
container.html(err);
container.show();
$('span.query').removeClass('disabled');
diff --git a/caravel/assets/visualizations/big_number.js b/caravel/assets/visualizations/big_number.js
index 676c9b46c225..6d4dc62b3500 100644
--- a/caravel/assets/visualizations/big_number.js
+++ b/caravel/assets/visualizations/big_number.js
@@ -13,7 +13,7 @@ function bigNumberVis(slice) {
d3.json(slice.jsonEndpoint(), function (error, payload) {
//Define the percentage bounds that define color from red to green
if (error !== null) {
- slice.error(error.responseText);
+ slice.error(error);
return '';
}
var fd = payload.form_data;
diff --git a/caravel/assets/visualizations/directed_force.js b/caravel/assets/visualizations/directed_force.js
index a0252067e636..eb1c7703b3ce 100644
--- a/caravel/assets/visualizations/directed_force.js
+++ b/caravel/assets/visualizations/directed_force.js
@@ -16,7 +16,7 @@ function directedForceVis(slice) {
d3.json(slice.jsonEndpoint(), function (error, json) {
if (error !== null) {
- slice.error(error.responseText);
+ slice.error(error);
return '';
}
var links = json.data;
diff --git a/caravel/assets/visualizations/heatmap.js b/caravel/assets/visualizations/heatmap.js
index 55ec7ef46efd..7209b0b71051 100644
--- a/caravel/assets/visualizations/heatmap.js
+++ b/caravel/assets/visualizations/heatmap.js
@@ -23,7 +23,7 @@ function heatmapVis(slice) {
d3.json(slice.jsonEndpoint(), function (error, payload) {
var matrix = {};
if (error) {
- slice.error(error.responseText);
+ slice.error(error);
return '';
}
var fd = payload.form_data;
diff --git a/caravel/assets/visualizations/sankey.js b/caravel/assets/visualizations/sankey.js
index 4c85ff1414ba..e1230b595f33 100644
--- a/caravel/assets/visualizations/sankey.js
+++ b/caravel/assets/visualizations/sankey.js
@@ -36,7 +36,7 @@ function sankeyVis(slice) {
d3.json(slice.jsonEndpoint(), function (error, json) {
if (error !== null) {
- slice.error(error.responseText);
+ slice.error(error);
return '';
}
var links = json.data;
diff --git a/caravel/assets/visualizations/sunburst.js b/caravel/assets/visualizations/sunburst.js
index 25df68aa2d6e..f71b5e983022 100644
--- a/caravel/assets/visualizations/sunburst.js
+++ b/caravel/assets/visualizations/sunburst.js
@@ -54,7 +54,7 @@ function sunburstVis(slice) {
d3.json(slice.jsonEndpoint(), function (error, rawData) {
if (error !== null) {
- slice.error(error.responseText);
+ slice.error(error);
return '';
}
diff --git a/caravel/assets/visualizations/word_cloud.js b/caravel/assets/visualizations/word_cloud.js
index 7efd7c03193c..7f72b9a2072f 100644
--- a/caravel/assets/visualizations/word_cloud.js
+++ b/caravel/assets/visualizations/word_cloud.js
@@ -8,7 +8,7 @@ function wordCloudChart(slice) {
function refresh() {
d3.json(slice.jsonEndpoint(), function (error, json) {
if (error !== null) {
- slice.error(error.responseText);
+ slice.error(error);
return '';
}
var data = json.data;
diff --git a/caravel/assets/visualizations/world_map.js b/caravel/assets/visualizations/world_map.js
index 87f09b30be38..b5ee11c3a084 100644
--- a/caravel/assets/visualizations/world_map.js
+++ b/caravel/assets/visualizations/world_map.js
@@ -17,7 +17,7 @@ function worldMapChart(slice) {
var fd = json.form_data;
if (error !== null) {
- slice.error(error.responseText);
+ slice.error(error);
return '';
}
var ext = d3.extent(json.data, function (d) {
diff --git a/caravel/models.py b/caravel/models.py
index ed95467e50e9..89736a9b9976 100644
--- a/caravel/models.py
+++ b/caravel/models.py
@@ -576,7 +576,20 @@ def query( # sqla
select_exprs += [timestamp_grain]
groupby_exprs += [timestamp_grain]
- tf = '%Y-%m-%d %H:%M:%S.%f'
+ # UGLY: I guess correct way is to delegate on SQLAlchemy dialect
+ # UPDATE: Datetime depends on each dialect and I haven't found an easy way to manage
+ # Maybe we can allow user to define its custome format at Database definition
+ def get_dtformat(type):
+ if type == 'SMALLDATETIME' or type == 'DATETIME':
+ return '%Y-%m-%d %H:%M:%S'
+ if type == 'DATE':
+ return '%Y-%m-%d'
+ if type == 'TIME':
+ return '%H:%M:%S'
+ return '%Y-%m-%d %H:%M:%S.%f'
+
+ tf = get_dtformat(cols[granularity].type or 'DATE')
+
time_filter = [
timestamp >= from_dttm.strftime(tf),
timestamp <= to_dttm.strftime(tf),
diff --git a/caravel/utils.py b/caravel/utils.py
index 891964e0d523..492b421e8107 100644
--- a/caravel/utils.py
+++ b/caravel/utils.py
@@ -224,3 +224,7 @@ def readfile(filepath):
with open(filepath) as f:
content = f.read()
return content
+
+
+class NoResultsException(Exception):
+ pass
diff --git a/caravel/views.py b/caravel/views.py
index 738f80f9d50d..c9dfba1de8d4 100644
--- a/caravel/views.py
+++ b/caravel/views.py
@@ -27,6 +27,7 @@
from wtforms.validators import ValidationError
from caravel import appbuilder, db, models, viz, utils, app, sm, ascii_art
+from caravel.utils import NoResultsException
config = app.config
log_this = models.Log.log_this
@@ -40,12 +41,12 @@ def validate_json(form, field): # noqa
raise ValidationError("json isn't valid")
-def generate_download_headers(extension):
+def generate_download_headers(extension, headers=None):
filename = datetime.now().strftime("%Y%m%d_%H%M%S")
content_disp = "attachment; filename={}.{}".format(filename, extension)
- headers = {
- "Content-Disposition": content_disp,
- }
+ if headers is None:
+ headers = {}
+ headers["Content-Disposition"] = content_disp
return headers
@@ -481,18 +482,24 @@ def explore(self, datasource_type, datasource_id):
slice=slc)
if request.args.get("json") == "true":
status = 200
+ headers = {}
try:
payload = obj.get_json()
except Exception as e:
+ t = type(e)
+ headers["Caravel-Exception"] = t.__name__
logging.exception(e)
- if config.get("DEBUG"):
- raise e
- payload = str(e)
+ if t is NoResultsException:
+ payload = "No results"
+ else:
+ if config.get("DEBUG"):
+ raise e
+ payload = str(e)
status = 500
resp = Response(
payload,
status=status,
- headers=generate_download_headers("json"),
+ headers=generate_download_headers("json", headers),
mimetype="application/json")
return resp
elif request.args.get("csv") == "true":
diff --git a/caravel/viz.py b/caravel/viz.py
index 9592235e36b4..efb867fe673d 100644
--- a/caravel/viz.py
+++ b/caravel/viz.py
@@ -26,6 +26,9 @@
from caravel import app, utils, cache
from caravel.forms import FormFactory
+
+from caravel.utils import NoResultsException
+
config = app.config
@@ -139,8 +142,10 @@ def get_df(self, query_obj=None):
self.results = self.datasource.query(**query_obj)
self.query = self.results.query
df = self.results.df
- if df is None or df.empty:
- raise Exception("No data, review your incantations!")
+ if df is None:
+ raise Exception("Error retrieving data")
+ elif df.empty:
+ raise NoResultsException()
else:
if 'timestamp' in df.columns:
df.timestamp = pd.to_datetime(df.timestamp, utc=False)
diff --git a/docs/gallery.rst b/docs/gallery.rst
deleted file mode 100644
index 16d9af24e490..000000000000
--- a/docs/gallery.rst
+++ /dev/null
@@ -1,45 +0,0 @@
-Gallery
-=======
-
-.. image:: _static/img/viz_thumbnails/line.png
- :scale: 25 %
-
-.. image:: _static/img/viz_thumbnails/bubble.png
- :scale: 25 %
-
-.. image:: _static/img/viz_thumbnails/table.png
- :scale: 25 %
-
-.. image:: _static/img/viz_thumbnails/pie.png
- :scale: 25 %
-
-.. image:: _static/img/viz_thumbnails/bar.png
- :scale: 25 %
-
-.. image:: _static/img/viz_thumbnails/sankey.png
- :scale: 25 %
-
-.. image:: _static/img/viz_thumbnails/word_cloud.png
- :scale: 25 %
-
-.. image:: _static/img/viz_thumbnails/filter.png
- :scale: 25 %
-
-.. image:: _static/img/viz_thumbnails/pivot_table.png
- :scale: 25 %
-
-.. image:: _static/img/viz_thumbnails/force_directed.png
- :scale: 25 %
-
-.. image:: _static/img/viz_thumbnails/percent_change.png
- :scale: 25 %
-
-.. image:: _static/img/viz_thumbnails/sunburst.png
- :scale: 25 %
-
-.. image:: _static/img/viz_thumbnails/stacked.png
- :scale: 25 %
-
-.. image:: _static/img/viz_thumbnails/big_number.png
- :scale: 25 %
-
diff --git a/tests/core_tests.py b/tests/core_tests.py
index 430877b7e353..f4258018b187 100644
--- a/tests/core_tests.py
+++ b/tests/core_tests.py
@@ -3,6 +3,7 @@
import os
import unittest
+import sys
from flask import escape
import caravel
@@ -58,7 +59,10 @@ def test_slices(self):
slc.viz.json_endpoint,
]
for url in urls:
- self.client.get(url)
+ try:
+ self.client.get(url)
+ except Exception:
+ raise ValueError(url, None, sys.exc_info()[2])
def test_csv(self):
self.client.get('/caravel/explore/table/1/?viz_type=table&granularity=ds&since=100+years&until=now&metrics=count&groupby=name&limit=50&show_brush=y&show_brush=false&show_legend=y&show_brush=false&rich_tooltip=y&show_brush=false&show_brush=false&show_brush=false&show_brush=false&y_axis_format=&x_axis_showminmax=y&show_brush=false&line_interpolation=linear&rolling_type=None&rolling_periods=&time_compare=&num_period_compare=&where=&having=&flt_col_0=gender&flt_op_0=in&flt_eq_0=&flt_col_0=gender&flt_op_0=in&flt_eq_0=&slice_id=14&slice_name=Boys&collapsed_fieldsets=&action=&datasource_name=birth_names&datasource_id=1&datasource_type=table&previous_viz_type=line&csv=true')