def test_cleanup(): from dtale.views import DtaleData with ExitStack() as stack: mock_cleanup = stack.enter_context(mock.patch("dtale.global_state.cleanup")) instance = DtaleData(9999, "user/root/proxy/9999") instance.cleanup() mock_cleanup.assert_called_once_with(9999)
def _instance_msgs(): for data_id in global_state.keys(): data_obj = DtaleData(data_id, build_url(ACTIVE_PORT, ACTIVE_HOST)) name = global_state.get_name(data_id) yield [data_id, name or "", data_obj.build_main_url(data_id=data_id)] if name is not None: yield [ global_state.convert_name_to_url_path(name), name, data_obj.build_main_url(), ]
def test_ipython_notebook_funcs(): from dtale.views import DtaleData getter = namedtuple('get', 'ok') def mock_requests_get(url, verify=True): return getter(True) df = pd.DataFrame([1, 2, 3]) with ExitStack() as stack: mock_iframe = stack.enter_context( mock.patch('IPython.display.IFrame', mock.Mock())) stack.enter_context(mock.patch('requests.get', mock_requests_get)) stack.enter_context( mock.patch('dtale.views.in_ipython_frontend', return_value=True)) stack.enter_context( mock.patch('dtale.global_state.DATA', return_value={9999: df})) instance = DtaleData(9999, 'http://localhost:9999') instance.notebook_correlations(col1='col1', col2='col2') mock_iframe.assert_called_once() url_parser = get_url_parser() [path, query] = mock_iframe.call_args[0][0].split('?') assert path == 'http://localhost:9999/dtale/popup/correlations/9999' assert dict(url_parser(query)) == dict(col1='col1', col2='col2') instance.notebook_charts(x='col1', y='col2', group=['col3', 'col4'], agg='count') [path, query] = mock_iframe.call_args[0][0].split('?') assert path == 'http://localhost:9999/charts/9999' assert dict(url_parser(query)) == dict(chart_type='line', agg='count', group='["col3", "col4"]', x='col1', y='["col2"]', cpg='false') instance.notebook_charts(x='col1', y='col2', agg='count') [_path, query] = mock_iframe.call_args[0][0].split('?') assert dict(url_parser(query)) == dict(chart_type='line', agg='count', x='col1', y='["col2"]', cpg='false') instance.notebook_charts(x='col1', y='col2', group=['col3', 'col4']) [_path, query] = mock_iframe.call_args[0][0].split('?') assert dict(url_parser(query)) == dict(chart_type='line', x='col1', y='["col2"]', group='["col3", "col4"]', cpg='false')
def test_jupyter_server_proxy_kill(): from dtale.views import DtaleData with ExitStack() as stack: stack.enter_context(mock.patch("dtale.app.ACTIVE_HOST", "foo")) stack.enter_context(mock.patch("dtale.app.ACTIVE_PORT", 40000)) stack.enter_context(mock.patch("dtale.app.JUPYTER_SERVER_PROXY", True)) stack.enter_context( mock.patch("dtale.views.in_ipython_frontend", return_value=True)) mock_requests = stack.enter_context( mock.patch("requests.get", mock.Mock())) instance = DtaleData(9999, "user/root/proxy/9999") instance.kill() mock_requests.assert_called_once_with("http://foo:40000/shutdown")
def instances(): """ Returns a dictionary of data IDs & :class:dtale.views.DtaleData objects pertaining to all the current pieces of data being viewed :return: dict """ return {data_id: DtaleData(data_id, build_url(ACTIVE_PORT, ACTIVE_HOST)) for data_id in DATA}
def instances(): """ Prints all urls to the current pieces of data being viewed """ print('\n'.join([ DtaleData(data_id, build_url(ACTIVE_PORT, ACTIVE_HOST)).main_url() for data_id in DATA ]))
def _instance_msgs(): for data_id in global_state.keys(): startup_url, final_app_root = build_startup_url_and_app_root() instance = DtaleData( data_id, startup_url, is_proxy=JUPYTER_SERVER_PROXY, app_root=final_app_root, ) name = global_state.get_name(data_id) yield [data_id, name or "", instance.build_main_url()] if name is not None: yield [ global_state.convert_name_to_url_path(name), name, instance.build_main_url(), ]
def instances(): """ Prints all urls to the current pieces of data being viewed """ curr_data = global_state.get_data() if len(curr_data): print('\n'.join([DtaleData(data_id, build_url(ACTIVE_PORT, ACTIVE_HOST)).main_url() for data_id in curr_data])) else: print('currently no running instances...')
def get_instance(data_id): """ Returns a :class:`dtale.views.DtaleData` object for the data_id passed as input, will return None if the data_id does not exist :param data_id: integer string identifier for a D-Tale process's data :type data_id: str :return: :class:`dtale.views.DtaleData` """ data_id_str = str(data_id) if data_id_str in DATA: return DtaleData(data_id_str, build_url(ACTIVE_PORT, ACTIVE_HOST)) return None
def get_instance(data_id): """ Returns a :class:`dtale.views.DtaleData` object for the data_id passed as input, will return None if the data_id does not exist :param data_id: integer string identifier for a D-Tale process's data :type data_id: str :return: :class:`dtale.views.DtaleData` """ data_id_str = global_state.find_data_id(str(data_id)) if data_id_str is not None: startup_url, _ = build_startup_url_and_app_root() return DtaleData(data_id_str, startup_url) return None
def test_ipython_notebook_funcs(): from dtale.views import DtaleData getter = namedtuple('get', 'ok') def mock_requests_get(url, verify=True): return getter(True) df = pd.DataFrame([1, 2, 3]) with ExitStack() as stack: mock_iframe = stack.enter_context( mock.patch('IPython.display.IFrame', mock.Mock())) stack.enter_context(mock.patch('requests.get', mock_requests_get)) stack.enter_context( mock.patch('dtale.views.in_ipython_frontend', return_value=True)) stack.enter_context( mock.patch('dtale.views.DATA', return_value={9999: df})) instance = DtaleData(9999, 'http://localhost:9999') instance.notebook_correlations(col1='col1', col2='col2') mock_iframe.assert_called_once() assert mock_iframe.call_args[0][ 0] == 'http://localhost:9999/dtale/popup/correlations/9999?col1=col1&col2=col2' instance.notebook_charts('col1', 'col2', group=['col3', 'col4'], aggregation='count') charts_url = 'http://localhost:9999/dtale/popup/charts/9999?aggregation=count&group=col3,col4&x=col1&y=col2' assert mock_iframe.call_args[0][0] == charts_url instance.notebook_charts('col1', 'col2', aggregation='count') charts_url = 'http://localhost:9999/dtale/popup/charts/9999?aggregation=count&x=col1&y=col2' assert mock_iframe.call_args[0][0] == charts_url instance.notebook_charts('col1', 'col2', group=['col3', 'col4']) charts_url = 'http://localhost:9999/dtale/popup/charts/9999?group=col3,col4&x=col1&y=col2' assert mock_iframe.call_args[0][0] == charts_url
def get_instance(data_id): """ Returns a :class:`dtale.views.DtaleData` object for the data_id passed as input, will return None if the data_id does not exist :param data_id: integer identifier for a D-Tale process's data :type data_id: int :return: :class:`dtale.views.DtaleData` """ if not global_state.contains(data_id): return None if data_id is not None: startup_url, _ = build_startup_url_and_app_root() return DtaleData(data_id, startup_url) return None
def test_started_with_open_browser(): from dtale.views import DtaleData with ExitStack() as stack: stack.enter_context( mock.patch("dtale.views.in_ipython_frontend", return_value=True) ) instance = DtaleData(9999, "user/root/proxy/9999") instance.started_with_open_browser = True assert instance.__str__() == "" assert instance.started_with_open_browser is False instance.started_with_open_browser = True assert instance.__repr__() == "" assert instance.started_with_open_browser is False
def test_settings_management(): from dtale.views import DtaleData with ExitStack() as stack: mock_get_settings = stack.enter_context( mock.patch("dtale.global_state.get_settings") ) mock_set_settings = stack.enter_context( mock.patch("dtale.global_state.set_settings") ) instance = DtaleData(9999, "user/root/proxy/9999") instance.update_settings(range_highlights={}) mock_get_settings.assert_called_once_with(9999) mock_set_settings.assert_called_once_with(9999, dict(rangeHighlight={})) mock_get_settings.reset_mock() instance.get_settings() mock_get_settings.assert_called_once_with(9999)
def show(data=None, host=None, port=None, name=None, debug=False, subprocess=True, data_loader=None, reaper_on=True, open_browser=False, notebook=False, force=False, context_vars=None, ignore_duplicate=False, app_root=None, **kwargs): """ Entry point for kicking off D-Tale :class:`flask:flask.Flask` process from python process :param data: data which D-Tale will display :type data: :class:`pandas:pandas.DataFrame` or :class:`pandas:pandas.Series` or :class:`pandas:pandas.DatetimeIndex` or :class:`pandas:pandas.MultiIndex`, optional :param host: hostname of D-Tale, defaults to 0.0.0.0 :type host: str, optional :param port: port number of D-Tale process, defaults to any open port on server :type port: str, optional :param name: optional label to assign a D-Tale process :type name: str, optional :param debug: will turn on :class:`flask:flask.Flask` debug functionality, defaults to False :type debug: bool, optional :param subprocess: run D-Tale as a subprocess of your current process, defaults to True :type subprocess: bool, optional :param data_loader: function to load your data :type data_loader: func, optional :param reaper_on: turn on subprocess which will terminate D-Tale after 1 hour of inactivity :type reaper_on: bool, optional :param open_browser: if true, this will try using the :mod:`python:webbrowser` package to automatically open your default browser to your D-Tale process :type open_browser: bool, optional :param notebook: if true, this will try displaying an :class:`ipython:IPython.display.IFrame` :type notebook: bool, optional :param force: if true, this will force the D-Tale instance to run on the specified host/port by killing any other process running at that location :type force: bool, optional :param context_vars: a dictionary of the variables that will be available for use in user-defined expressions, such as filters :type context_vars: dict, optional :param ignore_duplicate: if true, this will not check if this data matches any other data previously loaded to D-Tale :type ignore_duplicate: bool, optional :Example: >>> import dtale >>> import pandas as pd >>> df = pandas.DataFrame([dict(a=1,b=2,c=3)]) >>> dtale.show(df) D-Tale started at: http://hostname:port ..link displayed in logging can be copied and pasted into any browser """ global ACTIVE_HOST, ACTIVE_PORT, USE_NGROK, USE_COLAB, JUPYTER_SERVER_PROXY try: logfile, log_level, verbose = map(kwargs.get, ["logfile", "log_level", "verbose"]) setup_logging(logfile, log_level or "info", verbose) if USE_NGROK: if not PY3: raise Exception( "In order to use ngrok you must be using Python 3 or higher!" ) from flask_ngrok import _run_ngrok ACTIVE_HOST = _run_ngrok() ACTIVE_PORT = None else: initialize_process_props(host, port, force) app_url = build_url(ACTIVE_PORT, ACTIVE_HOST) startup_url, final_app_root = build_startup_url_and_app_root(app_root) instance = startup( startup_url, data=data, data_loader=data_loader, name=name, context_vars=context_vars, ignore_duplicate=ignore_duplicate, ) is_active = not running_with_flask_debug() and is_up(app_url) if is_active: def _start(): if open_browser: instance.open_browser() else: if USE_NGROK: thread = Timer(1, _run_ngrok) thread.setDaemon(True) thread.start() def _start(): app = build_app( app_url, reaper_on=reaper_on, host=ACTIVE_HOST, app_root=final_app_root, ) if debug and not USE_NGROK: app.jinja_env.auto_reload = True app.config["TEMPLATES_AUTO_RELOAD"] = True else: getLogger("werkzeug").setLevel(LOG_ERROR) if open_browser: instance.open_browser() # hide banner message in production environments cli = sys.modules.get("flask.cli") if cli is not None: cli.show_server_banner = lambda *x: None if USE_NGROK: app.run(threaded=True) else: app.run(host="0.0.0.0", port=ACTIVE_PORT, debug=debug, threaded=True) if subprocess: if is_active: _start() else: _thread.start_new_thread(_start, ()) if notebook: instance.notebook() else: logger.info("D-Tale started at: {}".format(app_url)) _start() return instance except DuplicateDataError as ex: print( "It looks like this data may have already been loaded to D-Tale based on shape and column names. Here is " "URL of the data that seems to match it:\n\n{}\n\nIf you still want to load this data please use the " "following command:\n\ndtale.show(df, ignore_duplicate=True)". format( DtaleData(ex.data_id, build_url(ACTIVE_PORT, ACTIVE_HOST)).main_url())) return None
def test_ipython_notebook_funcs(): from dtale.views import DtaleData getter = namedtuple("get", "ok") def mock_requests_get(url, verify=True): return getter(True) df = pd.DataFrame([1, 2, 3]) with ExitStack() as stack: mock_iframe = stack.enter_context( mock.patch("IPython.display.IFrame", mock.Mock())) stack.enter_context(mock.patch("requests.get", mock_requests_get)) stack.enter_context( mock.patch("dtale.views.in_ipython_frontend", return_value=True)) stack.enter_context( mock.patch("dtale.global_state.DATA", return_value={9999: df})) instance = DtaleData(9999, "http://localhost:9999") instance.notebook_correlations(col1="col1", col2="col2") mock_iframe.assert_called_once() url_parser = get_url_parser() [path, query] = mock_iframe.call_args[0][0].split("?") assert path == "http://localhost:9999/dtale/popup/correlations/9999" assert dict(url_parser(query)) == dict(col1="col1", col2="col2") instance.notebook_charts(x="col1", y="col2", group=["col3", "col4"], agg="count") [path, query] = mock_iframe.call_args[0][0].split("?") assert path == "http://localhost:9999/charts/9999" assert dict(url_parser(query)) == dict( chart_type="line", agg="count", group='["col3", "col4"]', x="col1", y='["col2"]', cpg="false", animate="false", ) instance.notebook_charts(x="col1", y="col2", agg="count") [_path, query] = mock_iframe.call_args[0][0].split("?") assert dict(url_parser(query)) == dict( chart_type="line", agg="count", x="col1", y='["col2"]', cpg="false", animate="false", ) instance.notebook_charts(x="col1", y="col2", group=["col3", "col4"]) [_path, query] = mock_iframe.call_args[0][0].split("?") assert dict(url_parser(query)) == dict( chart_type="line", x="col1", y='["col2"]', group='["col3", "col4"]', cpg="false", animate="false", )
def test_ipython_import_error(builtin_pkg): from dtale.views import DtaleData orig_import = __import__ def import_mock(name, *args, **kwargs): if name in ["IPython", "IPython.display"]: raise ImportError if name == "requests": raise ImportError return orig_import(name, *args, **kwargs) df = pd.DataFrame([1, 2, 3]) with ExitStack() as stack: stack.enter_context( mock.patch("{}.__import__".format(builtin_pkg), side_effect=import_mock)) stack.enter_context( mock.patch("dtale.views.in_ipython_frontend", return_value=False)) stack.enter_context(mock.patch("dtale.global_state.DATA", {9999: df})) instance = DtaleData(9999, "http://localhost:9999") assert not instance.is_up() assert instance._build_iframe() is None assert instance.notebook() == df.__repr__() assert str(instance) == str(df) assert instance.__repr__() == "http://localhost:9999/dtale/main/9999" instance.adjust_cell_dimensions(width=5, height=5) instance._notebook_handle = mock.Mock() instance._build_iframe = mock.Mock() instance.adjust_cell_dimensions(width=5, height=5) instance._notebook_handle.update.assert_called_once() instance._build_iframe.assert_called_once() assert {"width": 5, "height": 5} == instance._build_iframe.call_args[1] with ExitStack() as stack: stack.enter_context( mock.patch("{}.__import__".format(builtin_pkg), side_effect=import_mock)) stack.enter_context( mock.patch("dtale.views.in_ipython_frontend", return_value=True)) stack.enter_context( mock.patch("dtale.global_state.DATA", return_value={9999: df})) instance = DtaleData(9999, "http://localhost:9999") instance.notebook = mock.Mock() assert str(instance) == "" instance.notebook.assert_called_once() instance.notebook.reset_mock() assert instance.__repr__() is None instance.notebook.assert_called_once()
def _instance_msg(data_id): url = DtaleData(data_id, build_url(ACTIVE_PORT, ACTIVE_HOST)).main_url() return '{}:\t{}'.format(data_id, url)
def show(data=None, data_loader=None, name=None, context_vars=None, **options): """ Entry point for kicking off D-Tale :class:`flask:flask.Flask` process from python process :param data: data which D-Tale will display :type data: :class:`pandas:pandas.DataFrame` or :class:`pandas:pandas.Series` or :class:`pandas:pandas.DatetimeIndex` or :class:`pandas:pandas.MultiIndex`, optional :param host: hostname of D-Tale, defaults to 0.0.0.0 :type host: str, optional :param port: port number of D-Tale process, defaults to any open port on server :type port: str, optional :param name: optional label to assign a D-Tale process :type name: str, optional :param debug: will turn on :class:`flask:flask.Flask` debug functionality, defaults to False :type debug: bool, optional :param subprocess: run D-Tale as a subprocess of your current process, defaults to True :type subprocess: bool, optional :param data_loader: function to load your data :type data_loader: func, optional :param reaper_on: turn on subprocess which will terminate D-Tale after 1 hour of inactivity :type reaper_on: bool, optional :param open_browser: if true, this will try using the :mod:`python:webbrowser` package to automatically open your default browser to your D-Tale process :type open_browser: bool, optional :param notebook: if true, this will try displaying an :class:`ipython:IPython.display.IFrame` :type notebook: bool, optional :param force: if true, this will force the D-Tale instance to run on the specified host/port by killing any other process running at that location :type force: bool, optional :param context_vars: a dictionary of the variables that will be available for use in user-defined expressions, such as filters :type context_vars: dict, optional :param ignore_duplicate: if true, this will not check if this data matches any other data previously loaded to D-Tale :type ignore_duplicate: bool, optional :param app_root: Optional path to prepend to the routes of D-Tale. This is used when making use of Jupyterhub server proxy :type app_root: str, optional :param allow_cell_edits: If false, this will not allow users to edit cells directly in their D-Tale grid :type allow_cell_edits: bool, optional :param inplace: If true, this will call `reset_index(inplace=True)` on the dataframe used as a way to save memory. Otherwise this will create a brand new dataframe, thus doubling memory but leaving the dataframe input unchanged. :type inplace: bool, optional :param drop_index: If true, this will drop any pre-existing index on the dataframe input. :type drop_index: bool, optional :param hide_shutdown: If true, this will hide the "Shutdown" buton from users :type hide_shutdown: bool, optional :param github_fork: If true, this will display a "Fork me on GitHub" ribbon in the upper right-hand corner of the app :type github_fork: bool, optional :Example: >>> import dtale >>> import pandas as pd >>> df = pandas.DataFrame([dict(a=1,b=2,c=3)]) >>> dtale.show(df) D-Tale started at: http://hostname:port ..link displayed in logging can be copied and pasted into any browser """ global ACTIVE_HOST, ACTIVE_PORT, USE_NGROK try: final_options = dtale_config.build_show_options(options) logfile, log_level, verbose = map( final_options.get, ["logfile", "log_level", "verbose"] ) setup_logging(logfile, log_level or "info", verbose) if USE_NGROK: if not PY3: raise Exception( "In order to use ngrok you must be using Python 3 or higher!" ) from flask_ngrok import _run_ngrok ACTIVE_HOST = _run_ngrok() ACTIVE_PORT = None else: initialize_process_props( final_options["host"], final_options["port"], final_options["force"] ) app_url = build_url(ACTIVE_PORT, ACTIVE_HOST) startup_url, final_app_root = build_startup_url_and_app_root( final_options["app_root"] ) instance = startup( startup_url, data=data, data_loader=data_loader, name=name, context_vars=context_vars, ignore_duplicate=final_options["ignore_duplicate"], allow_cell_edits=final_options["allow_cell_edits"], inplace=final_options["inplace"], drop_index=final_options["drop_index"], precision=final_options["precision"], show_columns=final_options["show_columns"], hide_columns=final_options["hide_columns"], ) instance.started_with_open_browser = final_options["open_browser"] is_active = not running_with_flask_debug() and is_up(app_url) if is_active: def _start(): if final_options["open_browser"]: instance.open_browser() else: if USE_NGROK: thread = Timer(1, _run_ngrok) thread.setDaemon(True) thread.start() def _start(): app = build_app( app_url, reaper_on=final_options["reaper_on"], host=ACTIVE_HOST, app_root=final_app_root, ) if final_options["debug"] and not USE_NGROK: app.jinja_env.auto_reload = True app.config["TEMPLATES_AUTO_RELOAD"] = True else: getLogger("werkzeug").setLevel(LOG_ERROR) if final_options["open_browser"]: instance.open_browser() # hide banner message in production environments cli = sys.modules.get("flask.cli") if cli is not None: cli.show_server_banner = lambda *x: None if USE_NGROK: app.run(threaded=True) else: app.run( host="0.0.0.0", port=ACTIVE_PORT, debug=final_options["debug"], threaded=True, ) if final_options["subprocess"]: if is_active: _start() else: _thread.start_new_thread(_start, ()) if final_options["notebook"]: instance.notebook() else: logger.info("D-Tale started at: {}".format(app_url)) _start() return instance except DuplicateDataError as ex: print( "It looks like this data may have already been loaded to D-Tale based on shape and column names. Here is " "URL of the data that seems to match it:\n\n{}\n\nIf you still want to load this data please use the " "following command:\n\ndtale.show(df, ignore_duplicate=True)".format( DtaleData(ex.data_id, build_url(ACTIVE_PORT, ACTIVE_HOST)).main_url() ) ) return None
def test_ipython_import_error(): from dtale.views import DtaleData builtin_pkg = '__builtin__' if PY3: builtin_pkg = 'builtins' orig_import = __import__ def import_mock(name, *args, **kwargs): if name in ['IPython', 'IPython.display']: raise ImportError if name == 'requests': raise ImportError return orig_import(name, *args, **kwargs) df = pd.DataFrame([1, 2, 3]) with ExitStack() as stack: stack.enter_context( mock.patch('{}.__import__'.format(builtin_pkg), side_effect=import_mock)) stack.enter_context( mock.patch('dtale.views.in_ipython_frontend', return_value=False)) stack.enter_context(mock.patch('dtale.views.DATA', {9999: df})) instance = DtaleData(9999) assert not instance.is_up() assert instance._build_iframe() is None assert instance.notebook() == df.__repr__() assert str(instance) == str(df) assert instance.__repr__() == df.__repr__() instance.adjust_cell_dimensions(width=5, height=5) instance._notebook_handle = mock.Mock() instance._build_iframe = mock.Mock() instance.adjust_cell_dimensions(width=5, height=5) instance._notebook_handle.update.assert_called_once() instance._build_iframe.assert_called_once() assert {'width': 5, 'height': 5} == instance._build_iframe.call_args[1] with ExitStack() as stack: stack.enter_context( mock.patch('{}.__import__'.format(builtin_pkg), side_effect=import_mock)) stack.enter_context( mock.patch('dtale.views.in_ipython_frontend', return_value=True)) stack.enter_context( mock.patch('dtale.views.DATA', return_value={9999: df})) instance = DtaleData(9999) instance.notebook = mock.Mock() assert str(instance) == '' instance.notebook.assert_called_once() instance.notebook.reset_mock() assert instance.__repr__() == '' instance.notebook.assert_called_once()