Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Config cleanup #761

Merged
merged 36 commits into from
Jun 11, 2019
Merged

Config cleanup #761

merged 36 commits into from
Jun 11, 2019

Conversation

alexcjohnson
Copy link
Collaborator

@alexcjohnson alexcjohnson commented Jun 7, 2019

closes #746

Some breaking changes to the dash.Dash API

Constructor / config breaking changes:

  • Removed two obsolete constructor kwargs: static_folder (assets_folder is much smarter) and components_cache_max_age (all files have cache-busting URLs)
  • Removed the very old misspelled supress_callback_exceptions fallback
  • Removed the unused resources.config.infer_from_layout
  • Revamped app.config: ALL constructor args are now stored in config (and none are stored in any other instance attributes anymore), with three exceptions:
    • server - app.init_app(server) is the right way to set this
    • index_string - it has a special setter method
    • plugins - You could add more plugins by calling my_plugin.plug(app) but not by modifying a config entry

Dev tools breaking changes:

  • Changed hot_reload_interval from msec to seconds, for consistency with hot_reload_watch_interval
  • When called from enable_dev_tools, debug=True by default. It's still False by default from run_server.

Non-breaking changes:

  • The expanded app.config prevents you from adding new (ie misspelled or obsolete) items and makes some items read-only - the ones that will not take effect if changed after the constructor (and init_app, since that can happen in the constructor) have finished.
  • The default assets_url_path is now just 'assets', not '/assets'. Since in actual usage we always strip the leading '/' and prepend the requests prefix, it's misleading as well as harder to explain with the slash there.
  • New constructor kwarg serve_locally - default True as per serve_locally by default #722 - sets both JS and CSS config
  • Added a docstring for the dash.Dash constructor and improved docstrings for the run_server and enable_dev_tools methods

Not implemented:

I looked into the name parameter and seems to me we should NOT make it mandatory, but would be interested to hear what others think about this. The only time this seems to matter is if the file that was run (python run.py in our common usage, or the gunicorn equivalent) is in a different directory from the one that defines app (let's call it app.py). All it seems to affect is where Flask looks for other files specified by relative paths, the key one being assets_folder.

  • Our default, '__main__', says these are relative to run.py.
  • Our recommended usage, name=__name__, says they're relative to app.py
  • You can specify something else with a package path (dotted, like package.sub.path as in import package.sub.path, and it will be resolved exactly as that import would be)
  • AFAICT it does NOT matter what the working dir was, relative to run.py, when you ran Python

Most of the time this doesn't matter, as run.py and app.py, if they're even separate files, are usually in the same dir. __name__ is nice in that you get the same assets folder no matter where you import app.py from, but on the other hand I suspect the more likely situation is that you set up your project and then at some point decide to move app.py into a subdirectory, without moving assets or run.py. In that case __name__ would cause problems, and the current default '__main__' is probably correct. That to me is a sufficient reason to leave the default behavior as it is.

Contributor Checklist

  • I have added tests, or extended existing tests, to cover any new features or bugs fixed in this PR
  • I have added entry in the CHANGELOG.md
  • If this PR needs a follow-up in dash docs, community thread, I have mentioned the relevant URLS as follow
    • this github #PR number updates the dash docs
    • here is the show and tell thread in plotly dash community

@@ -1,5 +1,13 @@
## Unreleased
### Changed
- [#761](https://github.com/plotly/dash/pull/761) Several breaking changes to the `dash.Dash` API:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a 💥 here?

@@ -86,106 +86,223 @@ class _NoUpdate(object):
# pylint: disable=too-many-instance-attributes
# pylint: disable=too-many-arguments, too-many-locals
class Dash(object):
"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😸 nice docstring.

tangential question, do we have an agreed reference to follow? I feel like it's not very helpful to use super-long-detailed-sphinx-style; chris is also building sth in the house.

but from our users' perspective, data scientists might feel this more familiar https://sphinxcontrib-napoleon.readthedocs.io/en/latest/

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be up for changing to a cleaner style, I was just copying the style we already had for run_server and enable_dev_tools.

Feels to me like we should have a decent level of detail here, and then use this to generate the corresponding page in dash-docs. Let's keep this format until we decide how we want to do that, so we only need to alter it once. @chriddyp I'm not aware if you're working on something else to fill this gap.

dash/dash.py Outdated
Dash is a framework for building analytical web applications.
No JavaScript required.

If a parameter can be set by an environment variable, that is listed too.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that is listed with env: prefix?

dash/dash.py Outdated
:type server: boolean or flask.Flask

:param assets_folder: a path, relative to the current working directory,
for extra files to be used in the browser. Default ``'assets'`` By
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the Default 'asset' By default needs a better split.

dash/dash.py Outdated
Default ``'assets'``.
:type asset_url_path: string

:param assets_ignore: A regexp, as a string to pass to ``re.compile``, for
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

regexp is js flavor, pythonic name should be regex

dash/dash.py Outdated
be called after the Flask server is attached.
:type plugins: list of objects

:param **kwargs: Do not use. Gives error messages for obsolete arguments.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it be more intuitive if we add an example section e.g. man lsof for less experienced users?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean rather than the errors on providing old kwargs? I was thinking of those just as helpers for experienced users of old dash versions. This documentation of **kwargs is just intended for people who see **kwargs in the function signature and wonder why it's there. Perhaps I can omit this documentation and just rename it to **obsolete, and assume that's sufficiently self-documenting?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the confusion, I meant for all the docstring. Just happened to leave the comment at this line. Nothing wrong with kwargs.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the confusion, I meant for all the docstring. Just happened to leave the comment at this line. Nothing wrong with kwargs.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. I feel like once people get here they've seen examples already elsewhere in the docs, so this docstring is just about enumerating all the options.

Anyway I will change **kwargs to **obsolete and remove it from the docstring.

@@ -1164,7 +1164,7 @@ def test_removing_component_while_its_getting_updated(self):
),
html.Div(id='body')
])
app.config.supress_callback_exceptions = True
app.config.suppress_callback_exceptions = True
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

predicted merge conflicts here

@@ -870,6 +871,40 @@ def failure2(children):
context.exception.args[0]
)

def test_callback_dep_types(self):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexcjohnson do you want to migrate this with new style?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not too hard to migrate -> 4052507

return self._wait_for(
EC.presence_of_element_located,
((By.CSS_SELECTOR, selector),),
timeout,
"timeout {} => waiting for selector {}".format(timeout, selector),
"timeout {}s => waiting for selector {}".format(_time, selector),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice fix on the timeout
🐄 minor, I would use more pythonic way format (timeout if timeout else self._wait_timeout, selector)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐄 in 55274be

Copy link
Contributor

@byronz byronz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💃 nice job! the two new comments are good to have, feel free to merge without the change

input_.send_keys('xyz')
dash_duo.wait_for_text_to_equal('#input', 'initial inputxyz')

# callback1 runs 4x (initial page load and 3x through send_keys)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would put the comment as an assert msg, so you can see that directly in the assertion exception. the comment does show up too with the code snippet.

with self.assertRaises(InvalidCallbackReturnValue):
multi('aaa')
btn_elements = [
dash_duo.find_element('#' + x) for x in btns
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: prefer btn than x here

app = Dash(__name__)
btn = dash_duo.find_element('#btn')
for _ in range(10):
btn.click()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can use this API dash_duo.multiple_click(). yep the API reference is coming soon

        for _ in range(clicks):
            self.find_element(css_selector).click()

])

with pytest.raises(IncorrectTypeException):
@app.callback([[Output('out', 'children')]], # extra nesting
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment can be set as message='' inside raises

# Remove those
comment_regex = r'<!--[^\[](.*?)-->' # noqa: W605

# Somehow the html attributes are unordered.
Copy link
Contributor

@byronz byronz Jun 11, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this permutation was a bad idea, I did similar clean up with beautiful soup parser for the initial state test case

# Note: this .html file shows there's no undo/redo button by default
with open(
os.path.join(
os.path.dirname(__file__), "initial_state_dash_app_content.html"
)
) as fp:
expected_dom = BeautifulSoup(fp.read().strip(), "lxml")
fetched_dom = dash_duo.dash_outerhtml_dom
assert (
fetched_dom.decode() == expected_dom.decode()
), "the fetching rendered dom is expected"

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah I noticed that - BeautifulSoup is a nice idea, I'll try it here.

@byronz byronz merged commit 558047f into master Jun 11, 2019
@alexcjohnson alexcjohnson deleted the config-cleanup branch June 11, 2019 17:59
HammadTheOne pushed a commit to HammadTheOne/dash that referenced this pull request May 28, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Clean up kwargs and config
2 participants