def main(host=None, port=None, debug=False, no_reaper=False, open_browser=False, name=None, **kwargs): """ Runs a local server for the D-Tale application. This local server is recommended when you have a pandas object stored in a CSV or retrievable from :class:`arctic.Arctic` data store. """ log_opts = get_log_options(kwargs) setup_logging(log_opts.get('logfile'), log_opts.get('log_level'), log_opts.get('verbose')) data_loader = check_loaders(kwargs) show(host=host, port=int(port or find_free_port()), debug=debug, subprocess=False, data_loader=data_loader, reaper_on=not no_reaper, open_browser=open_browser, name=name, **kwargs)
def test_setup_logging(): with ExitStack() as stack: mock_fh = stack.enter_context( mock.patch('logging.FileHandler', mock.Mock())) mock_lbc = stack.enter_context( mock.patch('logging.basicConfig', mock.Mock())) stack.enter_context(mock.patch('sys.argv', ['test'])) stack.enter_context( mock.patch('socket.gethostname', mock.Mock(return_value='test'))) mock_linf = stack.enter_context(mock.patch('logging.info', mock.Mock())) stack.enter_context(mock.patch('logging.getLogger', mock.Mock())) setup_logging(None, None) mock_fh.assert_not_called() mock_lbc.has_call( mock.call(format="%(asctime)s - %(levelname)-8s - %(message)s", level=logging.INFO)) mock_linf.has_call(mock.call('test')) mock_linf.has_call(mock.call('Hostname: test')) with ExitStack() as stack: mock_fh = stack.enter_context( mock.patch('logging.FileHandler', mock.Mock())) mock_lbc = stack.enter_context( mock.patch('logging.basicConfig', mock.Mock())) stack.enter_context(mock.patch('logging.getLogger', mock.Mock())) stack.enter_context(mock.patch('sys.argv', ['test'])) stack.enter_context( mock.patch('socket.gethostname', mock.Mock(return_value='test'))) setup_logging('test_log', None, verbose=True) mock_fh.assert_called_once() mock_lbc.has_call( mock.call(format="%(asctime)s - %(levelname)-8s - %(message)s", level=logging.DEBUG)) for level in ['debug', 'info', 'warning', 'error', 'critical'][::-1]: setup_logging(None, level) mock_lbc.has_call( mock.call(format="%(asctime)s - %(levelname)-8s - %(message)s", level=getattr(logging, level.upper()))) with ExitStack() as stack: mock_fh = stack.enter_context( mock.patch('logging.FileHandler', mock.Mock())) mock_lbc = stack.enter_context( mock.patch('logging.basicConfig', mock.Mock())) stack.enter_context(mock.patch('logging.getLogger', mock.Mock())) stack.enter_context(mock.patch('sys.argv', ['test'])) stack.enter_context( mock.patch('socket.gethostname', mock.Mock(side_effect=Exception('hostname exception')))) mock_linf = stack.enter_context(mock.patch('logging.info', mock.Mock())) setup_logging(None, None, verbose=True) mock_fh.assert_not_called() mock_lbc.has_call( mock.call(format="%(asctime)s - %(levelname)-8s - %(message)s", level=logging.DEBUG)) mock_linf.has_call(mock.call('hostname exception'))
def main(host=None, port=None, debug=None, no_reaper=None, open_browser=False, name=None, no_cell_edits=None, hide_shutdown=None, github_fork=None, app_root=None, hide_drop_rows=None, **kwargs): """ Runs a local server for the D-Tale application. This local server is recommended when you have a pandas object stored in a CSV or retrievable from :class:`arctic.Arctic` data store. """ log_opts = get_log_options(kwargs) setup_logging(log_opts.get("logfile"), log_opts.get("log_level"), log_opts.get("verbose")) data_loader = check_loaders(kwargs) # in order to handle the hierarchy of inputs if "--no-cell-edits" is not specified # then we'll update it to None allow_cell_edits = False if no_cell_edits is not None else None kwargs["show_columns"] = (kwargs["show_columns"].split(",") if kwargs.get("show_columns") else None) kwargs["hide_columns"] = (kwargs["hide_columns"].split(",") if kwargs.get("hide_columns") else None) kwargs["sort"] = ([ tuple(sort.split("|")) for sort in kwargs["sort"].split(",") ] if kwargs.get("sort") else None) kwargs["locked"] = kwargs["locked"].split(",") if kwargs.get( "locked") else None show(host=host, port=int(port or find_free_port()), debug=debug, subprocess=False, data_loader=data_loader, reaper_on=not no_reaper, open_browser=open_browser, name=name, allow_cell_edits=allow_cell_edits, hide_shutdown=hide_shutdown, github_fork=github_fork, app_root=app_root, hide_drop_rows=hide_drop_rows, **kwargs)
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_setup_logging(): with ExitStack() as stack: mock_fh = stack.enter_context(mock.patch("logging.FileHandler", mock.Mock())) mock_lbc = stack.enter_context(mock.patch("logging.basicConfig", mock.Mock())) stack.enter_context(mock.patch("sys.argv", ["test"])) stack.enter_context( mock.patch("socket.gethostname", mock.Mock(return_value="test")) ) mock_linf = stack.enter_context(mock.patch("logging.info", mock.Mock())) stack.enter_context(mock.patch("logging.getLogger", mock.Mock())) setup_logging(None, None) mock_fh.assert_not_called() mock_lbc.has_call( mock.call( format="%(asctime)s - %(levelname)-8s - %(message)s", level=logging.INFO ) ) mock_linf.has_call(mock.call("test")) mock_linf.has_call(mock.call("Hostname: test")) with ExitStack() as stack: mock_fh = stack.enter_context(mock.patch("logging.FileHandler", mock.Mock())) mock_lbc = stack.enter_context(mock.patch("logging.basicConfig", mock.Mock())) stack.enter_context(mock.patch("logging.getLogger", mock.Mock())) stack.enter_context(mock.patch("sys.argv", ["test"])) stack.enter_context( mock.patch("socket.gethostname", mock.Mock(return_value="test")) ) setup_logging("test_log", None, verbose=True) mock_fh.assert_called_once() mock_lbc.has_call( mock.call( format="%(asctime)s - %(levelname)-8s - %(message)s", level=logging.DEBUG, ) ) for level in ["debug", "info", "warning", "error", "critical"][::-1]: setup_logging(None, level) mock_lbc.has_call( mock.call( format="%(asctime)s - %(levelname)-8s - %(message)s", level=getattr(logging, level.upper()), ) ) with ExitStack() as stack: mock_fh = stack.enter_context(mock.patch("logging.FileHandler", mock.Mock())) mock_lbc = stack.enter_context(mock.patch("logging.basicConfig", mock.Mock())) stack.enter_context(mock.patch("logging.getLogger", mock.Mock())) stack.enter_context(mock.patch("sys.argv", ["test"])) stack.enter_context( mock.patch( "socket.gethostname", mock.Mock(side_effect=Exception("hostname exception")), ) ) mock_linf = stack.enter_context(mock.patch("logging.info", mock.Mock())) setup_logging(None, None, verbose=True) mock_fh.assert_not_called() mock_lbc.has_call( mock.call( format="%(asctime)s - %(levelname)-8s - %(message)s", level=logging.DEBUG, ) ) mock_linf.has_call(mock.call("hostname exception"))
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 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, **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 :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 """ logfile, log_level, verbose = map(kwargs.get, ['logfile', 'log_level', 'verbose']) setup_logging(logfile, log_level or 'info', verbose) initialize_process_props(host, port, force) url = build_url(ACTIVE_PORT, ACTIVE_HOST) instance = startup(url, data=data, data_loader=data_loader, name=name) is_active = not running_with_flask_debug() and is_up(url) if is_active: def _start(): if open_browser: instance.open_browser() else: def _start(): app = build_app(url, reaper_on=reaper_on, host=ACTIVE_HOST) if debug: 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 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(url)) _start() return instance
def show(data=None, host='0.0.0.0', port=None, name=None, debug=False, subprocess=True, data_loader=None, reaper_on=True, open_browser=False, notebook=False, **kwargs): """ Entry point for kicking off D-Tale 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 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 :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 """ logfile, log_level, verbose = map(kwargs.get, ['logfile', 'log_level', 'verbose']) setup_logging(logfile, log_level or 'info', verbose) selected_port = int(port or find_free_port()) instance = startup(data=data, data_loader=data_loader, port=selected_port, name=name) def _show(): app = build_app(reaper_on=reaper_on) if debug: app.jinja_env.auto_reload = True app.config['TEMPLATES_AUTO_RELOAD'] = True else: getLogger("werkzeug").setLevel(LOG_ERROR) url = build_url(selected_port) logger.info('D-Tale started at: {}'.format(url)) if open_browser: webbrowser.get().open(url) app.run(host=host, port=selected_port, debug=debug) if subprocess: _thread.start_new_thread(_show, ()) if notebook: instance.notebook() else: _show() return instance