Pass argument to Dash object

emher
emher Registered Posts: 32 ✭✭✭✭✭

I have just upgraded to dataiku 9.0, and I am trying out the new Dash integration. It's great! But since the Dash object is instantiated by dataiku, I am not sure how to pass arguments to the constructor, e.g. like this

app = dash.Dash(external_stylesheets=["some_stylesheet.css"], prevent_initial_callbacks=True)

What is the recommended way?

Answers

  • HenriC
    HenriC Dataiker Posts: 22 Dataiker
    edited July 17

    Hi @emher
    ,

    We are glad you like the new release

    The new Dash Webapp has been built for simple use cases running natively on our platform. To achieve what you want to do, you can use the following workaround:

    app.config.external_stylesheets =["some_stylesheet.css"]
    app.config.prevent_initial_callbacks = True

    However, some of the attributes can only be set through the constructor, and there are unfortunately no workaround to set them once the object has been initialised:

    [
       "name",
       "assets_folder",
       "assets_url_path",
       "eager_loading",
       "url_base_pathname",
       "routes_pathname_prefix",
       "requests_pathname_prefix",
       "serve_locally",
       "compress",
    ]

    Do not hesitate if you have more question about it!

    Have a nice day,

    Henri

  • emher
    emher Registered Posts: 32 ✭✭✭✭✭

    Hi @HenriC
    ,

    thank you for the answer! Unfortunately, one of the properties that I need to modify is the asserts folder (I didn't include it in my initial question to keep the example as simple as possible). Is there a reason why you don't allow editing these properties?

    In Dataiku 8.0 I was able to do it simply by binding the Dash app to the flask webserver of a "normal" web app. It required some hacking though, so I would prefer moving to the new native integration, which is much cleaner. But I need to be able to load my own assets

  • HenriC
    HenriC Dataiker Posts: 22 Dataiker

    Hi!

    The reason is quite simple. To make our app working out of the box, we intensiate `app = Dash(...)` just before running the user code. Once this app is created and linked to the flask server, well it can't be unregistered from it.

    The list of fields comes from Dash source code: dash.py:335. This list describes all fields that can't be set outside the constructor, and is unfortunately not up to us. Does it make sense?

    My guess would be for you to do as you were doing in DSS 8.0. We know it is not optimal and we will take your request in consideration for the coming releases

  • emher
    emher Registered Posts: 32 ✭✭✭✭✭

    Would it be possible to move that line,

    `app = Dash(...)`

    into the user code? If you make it part of the templates, it shouldn't make it more complex for "non-power user", and it would unleash the full power of Dash for "power users"?

  • emher
    emher Registered Posts: 32 ✭✭✭✭✭
    edited July 17

    I have now figured out a hack. So in dataiku 9.0, all Dash apps are linked to the same assets directory. The idea of the hack is to create a subdirectory within this director, and load only assets from this directory. The resulting syntax is,

    import my_dash_app
    from dash_extensions.dataiku import bind_assets_folder
    
    assets_folder = os.path.join(os.path.dirname(my_dash_app.__file__), "assets")
    bind_assets_folder(app, "my_dash_app", assets_folder)

    where my_dash_app is the module in which the app is defined, and where the app assets are located in an "assets" folder next to this file (which is the common pattern for dash applications). I think this more-or-less OK, but the hack itself is pretty ugly,

    def bind_assets_folder(app, app_id, assets_folder):
        import os
        import re
        from distutils.dir_util import copy_tree
        # Create assets container folder for the app.
        dst_assets_folder = os.path.join(app.config.assets_folder, app_id)
        os.makedirs(dst_assets_folder, exist_ok=True)
        # Copy assets.
        copy_tree(assets_folder, dst_assets_folder)
        
        def _walk_assets_directory(self):
            walk_dir = os.path.join(self.config.assets_folder, app_id)  # EMHER: Use application sub dir
            slash_splitter = re.compile(r"[\\/]+")
            ignore_str = self.config.assets_ignore
            ignore_filter = re.compile(ignore_str) if ignore_str else None
    
            for current, _, files in sorted(os.walk(walk_dir)):
                if current == walk_dir:
                    base = ""
                else:
                    s = current.replace(walk_dir, "").lstrip("\\").lstrip("/")
                    splitted = slash_splitter.split(s)
                    if len(splitted) > 1:
                        base = "/".join(slash_splitter.split(s))
                    else:
                        base = splitted[0]
                base = os.path.join(base, app_id)  # EMHER: Use application sub dir
                if ignore_filter:
                    files_gen = (x for x in files if not ignore_filter.search(x))
                else:
                    files_gen = files
    
                for f in sorted(files_gen):
                    path = "/".join([base, f]) if base else f
    
                    full = os.path.join(current, f)
    
                    if f.endswith("js"):
                        self.scripts.append_script(self._add_assets_resource(path, full))
                    elif f.endswith("css"):
                        self.css.append_css(self._add_assets_resource(path, full))
                    elif f == "favicon.ico":
                        self._favicon = path
    
        app._walk_assets_directory = lambda x=app: _walk_assets_directory(app)

  • emher
    emher Registered Posts: 32 ✭✭✭✭✭

    @HenriC
    As a side note, many of the features of [dash-extensions](https://github.com/thedirtyfew/dash-extensions) relies on the app object construction being part of the user code. So to be able to utilize these tools (without excessive hacking), moving the app construction into user code would also be a great benefit

  • williamwirono
    williamwirono Partner, Dataiku DSS Core Designer, Dataiku DSS ML Practitioner, Dataiku DSS Adv Designer, Registered Posts: 11 Partner
    edited July 17

    Hi @emher
    ,

    I am confused on what you meant by my_dash_app. What is that referring to? In addition, where are you placing this piece of code:

    import my_dash_app
    from dash_extensions.dataiku import bind_assets_folder
    
    assets_folder = os.path.join(os.path.dirname(my_dash_app.__file__), "assets")
    bind_assets_folder(app, "my_dash_app", assets_folder)

    Is it on the Dash webapp script?

    Similarly, where are you placing the CSS stuff in the /assets folder. Did you create an assets folder in the Code Library?

    Thanks in advance!

Setup Info
    Tags
      Help me…