def test_build_show_options(unittest): final_options = build_show_options() assert final_options["allow_cell_edits"] options = dict(allow_cell_edits=False) final_options = build_show_options(options) assert not final_options["allow_cell_edits"] ini_path = os.path.join(os.path.dirname(__file__), "dtale.ini") os.environ["DTALE_CONFIG"] = ini_path final_options = build_show_options() assert final_options["allow_cell_edits"] assert final_options["precision"] == 6 unittest.assertEqual(final_options["show_columns"], ["a", "b"]) unittest.assertEqual(final_options["hide_columns"], ["c"]) unittest.assertEqual( final_options["column_formats"], {"a": {"fmt": {"html": True}}} ) unittest.assertEqual(final_options["sort"], [("a", "ASC")]) unittest.assertEqual(final_options["locked"], ["a", "b"]) final_options = build_show_options(options) assert not final_options["allow_cell_edits"] del os.environ["DTALE_CONFIG"] set_config(ini_path) final_options = build_show_options() assert final_options["allow_cell_edits"] set_config(None) final_options = build_show_options(options) assert not final_options["allow_cell_edits"]
def test_build_show_options_w_missing_ini_props(): final_options = build_show_options() assert final_options["allow_cell_edits"] options = dict(allow_cell_edits=False) final_options = build_show_options(options) assert not final_options["allow_cell_edits"] ini_path = os.path.join(os.path.dirname(__file__), "dtale_missing_props.ini") os.environ["DTALE_CONFIG"] = ini_path final_options = build_show_options() assert final_options["allow_cell_edits"] final_options = build_show_options(options) assert not final_options["allow_cell_edits"] del os.environ["DTALE_CONFIG"] set_config(ini_path) final_options = build_show_options() assert final_options["allow_cell_edits"] set_config(None) final_options = build_show_options(options) assert not final_options["allow_cell_edits"]
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