📣 Announcing Dash Dev Tools

Dash Dev Tools is our latest effort to provide a pleasant and productive experience for Dash app developers :heart:

Dash DevTools is a built-in debugging UI that provides three main features for Dash developers:

  1. A visualization of the callback flow via a DAG visualization (directed acyclic graph)
  2. A central place to view both front-end and back-end errors
  3. Deep component property validation that bubbles up subtle, inconspicuous bugs :bug:

Getting Started

Try it out in the latest version:

pip install dash==0.42.0

When you run your apps, a new UI element is displayed in the bottom right corner. This element contains all the DevTools features:

Callback Graph

The callback DAG displays the relationships of inputs and outputs in your app. The green circles represent functions, the grey bounded boxes represent components, and their inner blue boxes are component properties.


Displaying Python Callback Exceptions

With Dash DevTools, we display the Python exceptions as a collapsable popup in the app. You’ll see the error right when it happens - no more context switching back and forth from to the terminal to the web browser.

The callback errors will tell you which output had the error. Crucially, the app itself will not crash - the output will simply not update. If multiple errors occur, they’ll accumulate.

No more “error loading dependencies” :tada:

If you’ve been working with Dash for a while, there’s no doubt that you’ve seen the dreaded “error loading dependencies” or “error loading layout” message.

This could happen for simple typos like setting children to html.Div(children=[['Hello Dash']]) instead of html.Div(['Hello Dash']).

With Dash DevTools, we’ve taken care to perform some extra validation on warmup and we’ll propagate any error up to the UI. Here’s what that error looks like now:

Much better :relieved:

:stop_sign: Deep property validation

Previously in Dash, if you supply the wrong value for a property, your app might silently fail or you might not never know that there is a runtime error waiting to be thrown :grimacing:. With Dash DevTools, we perform deep component validation on render and we do our best to display a helpful error message.

Here’s a quick example (quick - can you spot the error?)

dcc.Dropdown(
    id='my-dropdown',
    options=[
        {'label': 'New York City', 'value': 'NYC'},
        {'label': 'Montreal', 'value': 'MTL'},
        {'label': 'San Francisco', 'value': True}
    ],
    value='NYC'
)

With DevTools, you’ll see an error popup like this:
image

:wrench: Configuration

By default, Dash DevTools is enabled if you run your app with debug=True. There are two additional flags that can be used to turn on/off these features:

  • Hide the UI with dev_tools_ui=False
  • Turn off the component property validation with dev_tools_props_check=False.

You can mix-and-match. For example, the following configuration will keep the UI & the rest of the dev_tools_ features (like hot-reloading) but skip the property validation.

if __name__ == '__main__':
    app.run_server(debug=True, dev_tools_ui=True, dev_tools_props_check=False)

When you run your apps in production with e.g. gunicorn app:server, all of the dev_tools features are disabled.

And of course, do not use run_server in production environments!

:zap: For Component Authors

  • In DevTools, if your component raises an uncaught exception, that error message will bubble up to the DevTools UI and the app will no longer function.
  • Your propTypes definitions are important now. We use these definitions to perform the component property validation. Learn more about typechecking with PropTypes validations.
  • On that note, if you think you need the .shape prop type, you might actually be looking for the lesser-documented .exact prop type. exact will raise an error if an unspecified key is provided whereas shape will allow any arbitrary keys. We found ourselves using exact almost exclusively.
  • We recently upgraded dash-renderer to React 16 to enable these features. So, make sure that your components are React 16 compatible.
  • Previously, setProps was only provided if the component had a property that was an input/output/state. Now, setProps is always provided to your component. This should make component authoring much simpler: many components can be stateless & completely controlled by dash-renderer. For example, see the implementation of our dcc.Textarea component (only 30 lines of React code).

:clap: Credits

Dash DevTools was a 9 months effort involving all members of Dash team. Special shout out to @rnarren1 and @valentijnnieman who bravely paved the way in the early days of the project. Curious about the details? Check out the pull request.

Dash DevTools was sponsored by an organization. If your company is making use of Dash, reach out to our team to sponsor the roadmap or to get started with our production offerings.

As always, many thanks to everyone in the community for your feedback & support and let us know if you run into any snags :heart:

19 Likes

This is really really good. I just tried it out and instantly resolved a bug in one of my apps that was confusing me last night. Thanks Dash devs!

4 Likes

Great job, thank you guys!

1 Like

2 Likes
  • :mega: 0.43.0rc2 is now available: pip install dash==0.43.0rc3
  • :memo: I added a note about setProps for component authors in the announcement above.
1 Like

Thanks as ever! I will be trying this out this week, but I wanted to thank you all for thinking of mix and matching.

I have one app in particular that does not play well with Flasks debug mode, so being able to turn these features on without having to turn on Flask debug mode is really helpful!

1 Like

Thanks for this guys, hopefully it will be a great help to all the devs out there. I am however struggling to run it on my Dash app. I cannot run on localhost due to hosting on a cloud server so I have to expose the app to the public IP, maybe this is the issue?
Here is the error I get:

    Running on http://0.0.0.0:8050/
Debugger PIN: 925-302-811
 * Serving Flask app "test_app" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: on
Traceback (most recent call last):
  File "test_app.py", line 23, in <module>
    app.run_server(debug=True, dev_tools_ui=True, dev_tools_props_check=False, host='0.0.0.0')
  File "/home/lcm_fuelquality/web_app/venv/local/lib/python2.7/site-packages/dash/dash.py", line 1285, in run_server
    **flask_run_options)
  File "/home/lcm_fuelquality/web_app/venv/local/lib/python2.7/site-packages/flask/app.py", line 943, in run
    run_simple(host, port, self, **options)
TypeError: run_simple() got an unexpected keyword argument 'dev_tools_props_check'

Any ideas would be greatly appreciated,
Tom

@Berry

from the error, it seems the dash version is old, which doesn’t contain the latest code about two dev_tools flags.

cheers,
Byron

This stuff is amazing! Thanks a lot. :sunny:

Apologies Byron, I sudo pip installed the pre-release by accident.

It’s all working as expected now and looks great. A couple of points to note:

  1. Is there a way to copy an image of the callback graph? I had to screen grab multiple sections as my graph fills an A3 page
  2. Since upgrading to this Dash pre-release all my inline-style margins are not passing through to the browser. Other inline-styles are working as expected.

Regards,
Tom

1 Like

@Berry thanks for the feedbacks. could you be more specific about which component you had issue about inline-style, or a snippet of code would be more helpful. thanks

@byronz It is happening with buttons, inputs dropdowns and paragraphs.

Example code for button:

                html.Button( #Button to configure alerts
                id='alert-button',
                children=['Configure Alerts'],
                className='logout_button',
                style={
                    'float': 'top',
                    'position': 'relative',
                    'height': 'auto',
                    'width': '170',
                    'max-width': '100%',
                    'margin-top': '10'
                }
            ),

Button styles from within Chrome Dev Tools:

As you can see no margin-top styles are being applied.

If it helps I think I was on Dash 0.30.0 before this pre-release update.

@berry

the upgrade to React 16 has some breaking changes about the component props attributes, in short, it’s much more stricter than before.

if you change your margin-top: '10' into marginTop: 10 as specified here, it should fix your issue.

regarding the callback graph snapshot, we had some internal design discussion about this, it’s one of the further enhancement in the road map, but unfortunately it will be included in the next release.

Byron

Thanks for this note! I need to change a significant amount of my code base before updating.

While this isn’t directly relevant to plotly or dash, I thought I would point out that you can use a python script to do all the heavy lifting for you.

Here is a quick script I put together

import re

# Created a fairly specific pattern using your example code. 
# You might need to modify for alternative quoting cases.
# Also, afaik, there aren't css styles with more than one hyphen, are there? 
# No problem to add that but then the regex pattern gets ugly.

pat = re.compile(r"('\w+)(-)(\w+')(: '.*')") 

def reactStylesRepl(match):
    return f'{match.group(1)}{match.group(3).capitalize()}{match.group(4)}'

with open('your_file.py', 'rt') as f:
    replacedString = re.sub(pat, reactStylesRepl, f.read())

# Example:
string = """
html.Button( #Button to configure alerts
                id='alert-button',
                children=['Configure Alerts'],
                className='logout_button',
                style={
                    'float': 'top',
                    'position': 'relative',
                    'height': 'auto',
                    'width': '170',
                    'max-width': '100%',
                    'margin-top': '10'
                }
            ),
"""
print(re.sub(pat, reactStylesRepl, string))

# output
>>> html.Button( #Button to configure alerts
                id='alert-button',
                children=['Configure Alerts'],
                className='logout_button',
                style={
                    'float': 'top',
                    'position': 'relative',
                    'height': 'auto',
                    'width': '170',
                    'maxWidth': '100%',
                    'marginTop': '10'
                }
            ),

4 Likes

Thanks for the feedback everyone! 0.42.0 has been released :tada:

HI I have problem with visualizing app callback - I have like a lot of callbacks in my app and when I click on graph callback buton this is the message I get:

How can I fix this?

YIkes!

How many callbacks?

Around 270, some of which are multi output :wink: