Skip to content

Commit 55ffabe

Browse files
Andrew Schonfeldaschonfeld
Andrew Schonfeld
authored andcommitted
1.7.9
- added support for google colab using flask_ngrok - bugfixes for #73, #72, #71
1 parent a8da8ae commit 55ffabe

File tree

19 files changed

+425
-290
lines changed

19 files changed

+425
-290
lines changed

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ defaults: &defaults
55
CIRCLE_ARTIFACTS: /tmp/circleci-artifacts
66
CIRCLE_TEST_REPORTS: /tmp/circleci-test-results
77
CODECOV_TOKEN: b0d35139-0a75-427a-907b-2c78a762f8f0
8-
VERSION: 1.7.8
8+
VERSION: 1.7.9
99
PANDOC_RELEASES_URL: https://github.com/jgm/pandoc/releases
1010
steps:
1111
- checkout

CHANGES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
## Changelog
22

3+
### 1.7.9 (2020-2-24)
4+
* support for google colab
5+
* bugfixes: [#71](https://github.com/man-group/dtale/issues/71), [#72](https://github.com/man-group/dtale/issues/72), [#73](https://github.com/man-group/dtale/issues/73)
6+
37
### 1.7.8 (2020-2-22)
48
* [#77](https://github.com/man-group/dtale/issues/77), removal of multiprocessed timeouts
59

docker/2_7/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,4 @@ WORKDIR /app
4444

4545
RUN set -eux \
4646
; . /root/.bashrc \
47-
; easy_install dtale-1.7.8-py2.7.egg
47+
; easy_install dtale-1.7.9-py2.7.egg

docker/3_6/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,4 @@ WORKDIR /app
4444

4545
RUN set -eux \
4646
; . /root/.bashrc \
47-
; easy_install dtale-1.7.8-py3.7.egg
47+
; easy_install dtale-1.7.9-py3.7.egg

docs/source/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@
6464
# built documents.
6565
#
6666
# The short X.Y version.
67-
version = u'1.7.8'
67+
version = u'1.7.9'
6868
# The full version, including alpha/beta/rc tags.
69-
release = u'1.7.8'
69+
release = u'1.7.9'
7070

7171
# The language for content autogenerated by Sphinx. Refer to documentation
7272
# for a list of supported languages.

dtale/app.py

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def run(self, *args, **kwargs):
104104
:param args: Optional arguments to be passed to :meth:`flask:flask.run`
105105
:param kwargs: Optional keyword arguments to be passed to :meth:`flask:flask.run`
106106
"""
107-
self.port = str(kwargs.get('port'))
107+
self.port = str(kwargs.get('port') or '')
108108
if kwargs.get('debug', False):
109109
self.reaper_on = False
110110
self.build_reaper()
@@ -445,27 +445,24 @@ def show(data=None, host=None, port=None, name=None, debug=False, subprocess=Tru
445445
446446
..link displayed in logging can be copied and pasted into any browser
447447
"""
448-
global ACTIVE_HOST, ACTIVE_PORT
448+
global ACTIVE_HOST, ACTIVE_PORT, USE_NGROK
449449

450450
try:
451451
logfile, log_level, verbose = map(kwargs.get, ['logfile', 'log_level', 'verbose'])
452452
setup_logging(logfile, log_level or 'info', verbose)
453453

454-
initialize_process_props(host, port, force)
455454
if USE_NGROK:
456-
try:
457-
from flask_ngrok import _run_ngrok
458-
except ImportError:
459-
raise ImportError((
460-
'In order to use this functionality please install flask-ngrok!\n'
461-
'You can try running "pip install dtale[ngrok]" if you are using pip.'
462-
))
455+
if not PY3:
456+
raise Exception('In order to use ngrok you must be using Python 3 or higher!')
457+
458+
from flask_ngrok import _run_ngrok
463459

464460
ACTIVE_HOST = _run_ngrok()
465461
ACTIVE_PORT = None
466-
url = ACTIVE_HOST
467462
else:
468-
url = build_url(ACTIVE_PORT, ACTIVE_HOST)
463+
initialize_process_props(host, port, force)
464+
465+
url = build_url(ACTIVE_PORT, ACTIVE_HOST)
469466
instance = startup(url, data=data, data_loader=data_loader, name=name, context_vars=context_vars,
470467
ignore_duplicate=ignore_duplicate)
471468
is_active = not running_with_flask_debug() and is_up(url)
@@ -474,9 +471,14 @@ def _start():
474471
if open_browser:
475472
instance.open_browser()
476473
else:
474+
if USE_NGROK:
475+
thread = Timer(1, _run_ngrok)
476+
thread.setDaemon(True)
477+
thread.start()
478+
477479
def _start():
478480
app = build_app(url, reaper_on=reaper_on, host=ACTIVE_HOST)
479-
if debug:
481+
if debug and not USE_NGROK:
480482
app.jinja_env.auto_reload = True
481483
app.config['TEMPLATES_AUTO_RELOAD'] = True
482484
else:
@@ -491,15 +493,6 @@ def _start():
491493
cli.show_server_banner = lambda *x: None
492494

493495
if USE_NGROK:
494-
try:
495-
from flask_ngrok import run_with_ngrok
496-
except ImportError:
497-
raise ImportError((
498-
'In order to use this functionality please install flask-ngrok!\n'
499-
'You can try running "pip install dtale[ngrok]" if you are using pip.'
500-
))
501-
502-
run_with_ngrok(app)
503496
app.run(threaded=True)
504497
else:
505498
app.run(host='0.0.0.0', port=ACTIVE_PORT, debug=debug, threaded=True)

dtale/static/css/main.css

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8638,7 +8638,7 @@ caption {
86388638
.column-toggle__dropdown::before {
86398639
position: absolute;
86408640
bottom: 100%;
8641-
left: 0.6em;
8641+
/*left: 0.6em;*/
86428642
content: ' ';
86438643
z-index: 2;
86448644
width: 0;
@@ -8649,15 +8649,10 @@ caption {
86498649
border-left: 0.5em solid transparent;
86508650
}
86518651

8652-
.column-toggle__dropdown.right::before {
8653-
left: auto;
8654-
right: 1.6em;
8655-
}
8656-
86578652
.column-toggle__dropdown::after {
86588653
position: absolute;
86598654
bottom: calc(100% - .1em);
8660-
left: 0.6em;
8655+
/*left: 0.6em;*/
86618656
content: ' ';
86628657
z-index: 2;
86638658
width: 0;
@@ -8668,11 +8663,6 @@ caption {
86688663
border-left: 0.5em solid transparent;
86698664
}
86708665

8671-
.column-toggle__dropdown.right::after {
8672-
left: auto;
8673-
right: 1.6em;
8674-
}
8675-
86768666
.column-toggle__dropdown header {
86778667
border-bottom: solid 1px #a7b3b7;
86788668
padding: .3em .5em;

dtale/utils.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,10 @@ def build_url(port, host):
7575
:type host: str, optional
7676
:return: str
7777
"""
78+
final_port = ':{}'.format(port) if port is not None else ''
7879
if (host or '').startswith('http'):
79-
return '{}{}'.format(host, ':{}'.format(port) if port is not None else '')
80-
return 'http://{}:{}'.format(host, port)
80+
return '{}{}'.format(host, final_port)
81+
return 'http://{}{}'.format(host, final_port)
8182

8283

8384
def build_shutdown_url(base):

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "dtale",
3-
"version": "1.7.8",
3+
"version": "1.7.9",
44
"description": "Visualizer for Pandas Data Structures",
55
"main": "main.js",
66
"directories": {

setup.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def run_tests(self):
5050

5151
setup(
5252
name="dtale",
53-
version="1.7.8",
53+
version="1.7.9",
5454
author="MAN Alpha Technology",
5555
author_email="[email protected]",
5656
description="Web Client for Visualizing Pandas Objects",
@@ -65,6 +65,7 @@ def run_tests(self):
6565
"dash_daq",
6666
"Flask-Compress",
6767
"Flask",
68+
"flask-ngrok; python_version > '3.0'",
6869
"future",
6970
"itsdangerous",
7071
"pandas",
@@ -77,8 +78,7 @@ def run_tests(self):
7778
'r': [
7879
"rpy2<=2.8.6; python_version < '3.0'",
7980
"rpy2; python_version > '3.0'",
80-
],
81-
'ngrok': ["flask-ngrok; python_version > '3.0'"]
81+
]
8282
},
8383
tests_require=[
8484
"ipython",

static/__tests__/dtale/DataViewer-correlations-scatter-error-test.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ describe("DataViewer tests", () => {
103103
tsChart.cfg.options.onClick({});
104104
setTimeout(() => {
105105
result.update();
106-
t.ok(result.find(RemovableError).length == 1, "should render scatter error");
106+
t.equal(result.find(RemovableError).length, 1, "should render scatter error");
107107
done();
108108
}, 400);
109109
}, 400);
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { mount } from "enzyme";
2+
import React from "react";
3+
4+
import { positionMenu } from "../../dtale/iframe/ColumnMenu";
5+
import * as t from "../jest-assertions";
6+
import { buildInnerHTML } from "../test-utils";
7+
8+
const originalInnerWidth = Object.getOwnPropertyDescriptor(HTMLElement.prototype, "innerWidth");
9+
10+
describe("ColumnMenu position tests", () => {
11+
beforeAll(() => {
12+
Object.defineProperty(window, "innerWidth", {
13+
configurable: true,
14+
value: 100,
15+
});
16+
});
17+
18+
afterAll(() => {
19+
Object.defineProperty(window, "innerWidth", originalInnerWidth);
20+
});
21+
22+
test("ColumnMenu: calculations for menus on edge of browser window...", done => {
23+
buildInnerHTML({ settings: "" });
24+
mount(<span>Hello</span>, { attachTo: document.getElementById("content") });
25+
const menuDiv = { width: () => 20 };
26+
menuDiv.css = props => (menuDiv.currCss = props);
27+
positionMenu({ offset: () => ({ left: 90 }) }, menuDiv);
28+
t.equal(menuDiv.currCss.left, 60);
29+
positionMenu({ offset: () => ({ left: 10 }) }, menuDiv);
30+
t.equal(menuDiv.currCss.left, 10);
31+
positionMenu({ offset: () => ({ left: 15 }) }, menuDiv);
32+
t.equal(menuDiv.currCss.left, 15);
33+
done();
34+
});
35+
});

static/dtale/Filter.jsx

Lines changed: 63 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class Filter extends React.Component {
1313
super(props);
1414
this.state = { query: "", error: null };
1515
this.save = this.save.bind(this);
16+
this.renderBody = this.renderBody.bind(this);
1617
}
1718

1819
componentDidUpdate(prevProps) {
@@ -37,10 +38,70 @@ class Filter extends React.Component {
3738
});
3839
}
3940

40-
render() {
41+
renderBody() {
4142
if (!this.props.visible) {
4243
return null;
4344
}
45+
return [
46+
<RemovableError key={0} {...this.state} onRemove={() => this.setState({ error: null, traceback: null })} />,
47+
<div key={1} className="row">
48+
<div className="col-md-7">
49+
<textarea
50+
style={{ width: "100%", height: "100%" }}
51+
value={this.state.query || ""}
52+
onChange={event => this.setState({ query: event.target.value })}
53+
/>
54+
</div>
55+
<div className="col-md-5">
56+
<p className="font-weight-bold">Example queries</p>
57+
<ul>
58+
<li>
59+
{"drop NaN values: "}
60+
<span className="font-weight-bold">{"Col == Col"}</span>
61+
</li>
62+
<li>
63+
{"show only NaN values: "}
64+
<span className="font-weight-bold">{"Col != Col"}</span>
65+
</li>
66+
<li>
67+
{"date filtering: "}
68+
<span className="font-weight-bold">{`Col == '${moment().format("YYYYMMDD")}'`}</span>
69+
</li>
70+
<li>
71+
{"in-clause on string column: "}
72+
<span className="font-weight-bold">{"Col in ('foo','bar')"}</span>
73+
</li>
74+
<li>
75+
{"and-clause on numeric column: "}
76+
<span className="font-weight-bold">{"Col1 > 1 and Col2 <= 1"}</span>
77+
</li>
78+
<li>
79+
{"or-clause on numeric columns: "}
80+
<span className="font-weight-bold">{"Col1 > 1 or Col2 < 1"}</span>
81+
</li>
82+
<li>
83+
{"negative-clause: "}
84+
<span className="font-weight-bold">{"~(Col > 1)"}</span>
85+
</li>
86+
<li>
87+
{"parenthesis usage: "}
88+
<span className="font-weight-bold">{"(Col1 > 1 or Col2 < 1) and (Col3 == 3)"}</span>
89+
</li>
90+
<li>
91+
{"regex usage (search for substrings 'foo' or 'bar'):"}
92+
<br />
93+
<span className="font-weight-bold">{"Col.str.contains('(foo|bar)', case=False)"}</span>
94+
</li>
95+
</ul>
96+
</div>
97+
</div>,
98+
<div key={2} className="row">
99+
<ContextVariables dataId={this.props.dataId} />
100+
</div>,
101+
];
102+
}
103+
104+
render() {
44105
const hide = () => this.props.propagateState({ filterOpen: false });
45106
return (
46107
<Modal isOpen={this.props.visible} onRequestHide={hide} size="modal-lg" backdrop={false}>
@@ -51,63 +112,7 @@ class Filter extends React.Component {
51112
</ModalTitle>
52113
<ModalClose onClick={hide} />
53114
</ModalHeader>
54-
<ModalBody>
55-
<RemovableError {...this.state} onRemove={() => this.setState({ error: null, traceback: null })} />
56-
<div className="row">
57-
<div className="col-md-7">
58-
<textarea
59-
style={{ width: "100%", height: "100%" }}
60-
value={this.state.query || ""}
61-
onChange={event => this.setState({ query: event.target.value })}
62-
/>
63-
</div>
64-
<div className="col-md-5">
65-
<p className="font-weight-bold">Example queries</p>
66-
<ul>
67-
<li>
68-
{"drop NaN values: "}
69-
<span className="font-weight-bold">{"Col == Col"}</span>
70-
</li>
71-
<li>
72-
{"show only NaN values: "}
73-
<span className="font-weight-bold">{"Col != Col"}</span>
74-
</li>
75-
<li>
76-
{"date filtering: "}
77-
<span className="font-weight-bold">{`Col == '${moment().format("YYYYMMDD")}'`}</span>
78-
</li>
79-
<li>
80-
{"in-clause on string column: "}
81-
<span className="font-weight-bold">{"Col in ('foo','bar')"}</span>
82-
</li>
83-
<li>
84-
{"and-clause on numeric column: "}
85-
<span className="font-weight-bold">{"Col1 > 1 and Col2 <= 1"}</span>
86-
</li>
87-
<li>
88-
{"or-clause on numeric columns: "}
89-
<span className="font-weight-bold">{"Col1 > 1 or Col2 < 1"}</span>
90-
</li>
91-
<li>
92-
{"negative-clause: "}
93-
<span className="font-weight-bold">{"~(Col > 1)"}</span>
94-
</li>
95-
<li>
96-
{"parenthesis usage: "}
97-
<span className="font-weight-bold">{"(Col1 > 1 or Col2 < 1) and (Col3 == 3)"}</span>
98-
</li>
99-
<li>
100-
{"regex usage (search for substrings 'foo' or 'bar'):"}
101-
<br />
102-
<span className="font-weight-bold">{"Col.str.contains('(foo|bar)', case=False)"}</span>
103-
</li>
104-
</ul>
105-
</div>
106-
</div>
107-
<div className="row">
108-
<ContextVariables dataId={this.props.dataId} />
109-
</div>
110-
</ModalBody>
115+
<ModalBody>{this.renderBody()}</ModalBody>
111116
<ModalFooter>
112117
<button
113118
className="btn btn-secondary"

0 commit comments

Comments
 (0)