Prevent initial call - #1228

Merged
alexcjohnson merged 4 commits into
devfrom
prevent-initial-call
May 4, 2020
Merged

Prevent initial call#1228
alexcjohnson merged 4 commits into
devfrom
prevent-initial-call

Conversation

@alexcjohnson

@alexcjohnsonalexcjohnson commented May 4, 2020

Copy link
Copy Markdown
Collaborator

Closes#1225
Supersedes #1123

Adds the ability to control whether or not callbacks fire when the page or layout chunk first loads. This can simplify a lot of code like if n_clicks is None: raise PreventUpdate, and it can improve loading performance, particularly for pattern-matching callbacks, where a page can easily generate hundreds of callback invocations, since there is no longer even a server call for these callbacks.

This option is off by default, but can either be turned on for each callback independently:

@app.callback(outputs, inputs, prevent_initial_call=True)defcb(...):
...
app.clientside_callback(func, outputs, inputs, prevent_initial_call=True)

or app-wide, in which case it can be turned off for individual callbacks:

app=dash.Dash(prevent_initial_callbacks=True)
@app.callback(outputs, inputs, prevent_initial_call=False)defcb(...)
...
  • I have run the tests locally and they passed. (refer to testing section in contributing)
  • 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
  • Docs follow-up issue: https://github.com/plotly/dash-docs/issues/874

@alexcjohnsonalexcjohnson added this to the Dash v1.12 milestone May 4, 2020

@Marc-Andre-RivetMarc-Andre-Rivet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💃

pluck('path', flatten(cb.getOutputs(paths)))
)
) {
cb.changedPropIds = {};

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I'm not sure what I was thinking here with clearing out changedPropIds, but in this case (we've found a callback by its inputs due to a layout change, and just determined that all its outputs are in the same layout chunk) we know the callback is already included in the queue via its outputs so the best thing to do is simply not re-include it at all. This extra addCallback was harmless before prevent_initial_call, just a slight bit of extra work; but now that we have prevent_initial_call it's possible this callback would not be added based on its outputs.

If this condition isn't met, there are outputs outside the new layout chunk and it's not in fact an initial call anyway - so it's appropriate to add the callback and that's what the new logic does.

{"clientside": False, "content": True, "global": False},
{"clientside": True, "content": True, "global": True},
{"clientside": False, "content": False, "global": True},
]

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

pytest does a nice job logging dictionary test parametrizations (flavor0, flavor1 etc):
Screen Shot 2020-05-04 at 5 15 44 PM

@alexcjohnson
alexcjohnson merged commit 7961611 into devMay 4, 2020
@alexcjohnson
alexcjohnson deleted the prevent-initial-call branch May 4, 2020 21:26
@maartenbreddels

Copy link
Copy Markdown

Initial impression is really good! Together with #832 we can avoid any unneeded calls, and have a very fast page load.

@alexcjohnsonalexcjohnson mentioned this pull request May 13, 2020
5 tasks
nightsailer added a commit to o3cloud/dash that referenced this pull request Jun 13, 2020
@chriddypchriddyp mentioned this pull request Jun 25, 2020
Sign up for freeto 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.

Ability to prevent initial callback from firing

4 participants

@alexcjohnson@maartenbreddels@Marc-Andre-Rivet@chriddyp
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Prevent initial call - #1228

Merged
alexcjohnson merged 4 commits into
devfrom
prevent-initial-call
May 4, 2020
Merged

Prevent initial call#1228
alexcjohnson merged 4 commits into
devfrom
prevent-initial-call

Conversation

@alexcjohnson

@alexcjohnsonalexcjohnson commented May 4, 2020

Copy link
Copy Markdown
Collaborator

Closes#1225
Supersedes #1123

Adds the ability to control whether or not callbacks fire when the page or layout chunk first loads. This can simplify a lot of code like if n_clicks is None: raise PreventUpdate, and it can improve loading performance, particularly for pattern-matching callbacks, where a page can easily generate hundreds of callback invocations, since there is no longer even a server call for these callbacks.

This option is off by default, but can either be turned on for each callback independently:

@app.callback(outputs, inputs, prevent_initial_call=True)defcb(...):
...
app.clientside_callback(func, outputs, inputs, prevent_initial_call=True)

or app-wide, in which case it can be turned off for individual callbacks:

app=dash.Dash(prevent_initial_callbacks=True)
@app.callback(outputs, inputs, prevent_initial_call=False)defcb(...)
...
  • I have run the tests locally and they passed. (refer to testing section in contributing)
  • 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
  • Docs follow-up issue: https://github.com/plotly/dash-docs/issues/874

@alexcjohnsonalexcjohnson added this to the Dash v1.12 milestone May 4, 2020

@Marc-Andre-RivetMarc-Andre-Rivet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💃

pluck('path', flatten(cb.getOutputs(paths)))
)
) {
cb.changedPropIds = {};

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I'm not sure what I was thinking here with clearing out changedPropIds, but in this case (we've found a callback by its inputs due to a layout change, and just determined that all its outputs are in the same layout chunk) we know the callback is already included in the queue via its outputs so the best thing to do is simply not re-include it at all. This extra addCallback was harmless before prevent_initial_call, just a slight bit of extra work; but now that we have prevent_initial_call it's possible this callback would not be added based on its outputs.

If this condition isn't met, there are outputs outside the new layout chunk and it's not in fact an initial call anyway - so it's appropriate to add the callback and that's what the new logic does.

{"clientside": False, "content": True, "global": False},
{"clientside": True, "content": True, "global": True},
{"clientside": False, "content": False, "global": True},
]

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

pytest does a nice job logging dictionary test parametrizations (flavor0, flavor1 etc):
Screen Shot 2020-05-04 at 5 15 44 PM

@alexcjohnson
alexcjohnson merged commit 7961611 into devMay 4, 2020
@alexcjohnson
alexcjohnson deleted the prevent-initial-call branch May 4, 2020 21:26
@maartenbreddels

Copy link
Copy Markdown

Initial impression is really good! Together with #832 we can avoid any unneeded calls, and have a very fast page load.

@alexcjohnsonalexcjohnson mentioned this pull request May 13, 2020
5 tasks
nightsailer added a commit to o3cloud/dash that referenced this pull request Jun 13, 2020
@chriddypchriddyp mentioned this pull request Jun 25, 2020
Sign up for freeto 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.

Ability to prevent initial callback from firing

4 participants

@alexcjohnson@maartenbreddels@Marc-Andre-Rivet@chriddyp
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Prevent initial call - #1228

Merged
alexcjohnson merged 4 commits into
devfrom
prevent-initial-call
May 4, 2020
Merged

Prevent initial call#1228
alexcjohnson merged 4 commits into
devfrom
prevent-initial-call

Conversation

@alexcjohnson

@alexcjohnsonalexcjohnson commented May 4, 2020

Copy link
Copy Markdown
Collaborator

Closes#1225
Supersedes #1123

Adds the ability to control whether or not callbacks fire when the page or layout chunk first loads. This can simplify a lot of code like if n_clicks is None: raise PreventUpdate, and it can improve loading performance, particularly for pattern-matching callbacks, where a page can easily generate hundreds of callback invocations, since there is no longer even a server call for these callbacks.

This option is off by default, but can either be turned on for each callback independently:

@app.callback(outputs, inputs, prevent_initial_call=True)defcb(...):
...
app.clientside_callback(func, outputs, inputs, prevent_initial_call=True)

or app-wide, in which case it can be turned off for individual callbacks:

app=dash.Dash(prevent_initial_callbacks=True)
@app.callback(outputs, inputs, prevent_initial_call=False)defcb(...)
...
  • I have run the tests locally and they passed. (refer to testing section in contributing)
  • 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
  • Docs follow-up issue: https://github.com/plotly/dash-docs/issues/874

@alexcjohnsonalexcjohnson added this to the Dash v1.12 milestone May 4, 2020

@Marc-Andre-RivetMarc-Andre-Rivet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💃

pluck('path', flatten(cb.getOutputs(paths)))
)
) {
cb.changedPropIds = {};

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I'm not sure what I was thinking here with clearing out changedPropIds, but in this case (we've found a callback by its inputs due to a layout change, and just determined that all its outputs are in the same layout chunk) we know the callback is already included in the queue via its outputs so the best thing to do is simply not re-include it at all. This extra addCallback was harmless before prevent_initial_call, just a slight bit of extra work; but now that we have prevent_initial_call it's possible this callback would not be added based on its outputs.

If this condition isn't met, there are outputs outside the new layout chunk and it's not in fact an initial call anyway - so it's appropriate to add the callback and that's what the new logic does.

{"clientside": False, "content": True, "global": False},
{"clientside": True, "content": True, "global": True},
{"clientside": False, "content": False, "global": True},
]

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

pytest does a nice job logging dictionary test parametrizations (flavor0, flavor1 etc):
Screen Shot 2020-05-04 at 5 15 44 PM

@alexcjohnson
alexcjohnson merged commit 7961611 into devMay 4, 2020
@alexcjohnson
alexcjohnson deleted the prevent-initial-call branch May 4, 2020 21:26
@maartenbreddels

Copy link
Copy Markdown

Initial impression is really good! Together with #832 we can avoid any unneeded calls, and have a very fast page load.

@alexcjohnsonalexcjohnson mentioned this pull request May 13, 2020
5 tasks
nightsailer added a commit to o3cloud/dash that referenced this pull request Jun 13, 2020
@chriddypchriddyp mentioned this pull request Jun 25, 2020
Sign up for freeto 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.

Ability to prevent initial callback from firing

4 participants

@alexcjohnson@maartenbreddels@Marc-Andre-Rivet@chriddyp
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Prevent initial call - #1228

Merged
alexcjohnson merged 4 commits into
devfrom
prevent-initial-call
May 4, 2020
Merged

Prevent initial call#1228
alexcjohnson merged 4 commits into
devfrom
prevent-initial-call

Conversation

@alexcjohnson

@alexcjohnsonalexcjohnson commented May 4, 2020

Copy link
Copy Markdown
Collaborator

Closes#1225
Supersedes #1123

Adds the ability to control whether or not callbacks fire when the page or layout chunk first loads. This can simplify a lot of code like if n_clicks is None: raise PreventUpdate, and it can improve loading performance, particularly for pattern-matching callbacks, where a page can easily generate hundreds of callback invocations, since there is no longer even a server call for these callbacks.

This option is off by default, but can either be turned on for each callback independently:

@app.callback(outputs, inputs, prevent_initial_call=True)defcb(...):
...
app.clientside_callback(func, outputs, inputs, prevent_initial_call=True)

or app-wide, in which case it can be turned off for individual callbacks:

app=dash.Dash(prevent_initial_callbacks=True)
@app.callback(outputs, inputs, prevent_initial_call=False)defcb(...)
...
  • I have run the tests locally and they passed. (refer to testing section in contributing)
  • 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
  • Docs follow-up issue: https://github.com/plotly/dash-docs/issues/874

@alexcjohnsonalexcjohnson added this to the Dash v1.12 milestone May 4, 2020

@Marc-Andre-RivetMarc-Andre-Rivet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💃

pluck('path', flatten(cb.getOutputs(paths)))
)
) {
cb.changedPropIds = {};

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I'm not sure what I was thinking here with clearing out changedPropIds, but in this case (we've found a callback by its inputs due to a layout change, and just determined that all its outputs are in the same layout chunk) we know the callback is already included in the queue via its outputs so the best thing to do is simply not re-include it at all. This extra addCallback was harmless before prevent_initial_call, just a slight bit of extra work; but now that we have prevent_initial_call it's possible this callback would not be added based on its outputs.

If this condition isn't met, there are outputs outside the new layout chunk and it's not in fact an initial call anyway - so it's appropriate to add the callback and that's what the new logic does.

{"clientside": False, "content": True, "global": False},
{"clientside": True, "content": True, "global": True},
{"clientside": False, "content": False, "global": True},
]

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

pytest does a nice job logging dictionary test parametrizations (flavor0, flavor1 etc):
Screen Shot 2020-05-04 at 5 15 44 PM

@alexcjohnson
alexcjohnson merged commit 7961611 into devMay 4, 2020
@alexcjohnson
alexcjohnson deleted the prevent-initial-call branch May 4, 2020 21:26
@maartenbreddels

Copy link
Copy Markdown

Initial impression is really good! Together with #832 we can avoid any unneeded calls, and have a very fast page load.

@alexcjohnsonalexcjohnson mentioned this pull request May 13, 2020
5 tasks
nightsailer added a commit to o3cloud/dash that referenced this pull request Jun 13, 2020
@chriddypchriddyp mentioned this pull request Jun 25, 2020
Sign up for freeto 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.

Ability to prevent initial callback from firing

4 participants

@alexcjohnson@maartenbreddels@Marc-Andre-Rivet@chriddyp
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Prevent initial call - #1228

Merged
alexcjohnson merged 4 commits into
devfrom
prevent-initial-call
May 4, 2020
Merged

Prevent initial call#1228
alexcjohnson merged 4 commits into
devfrom
prevent-initial-call

Conversation

@alexcjohnson

@alexcjohnsonalexcjohnson commented May 4, 2020

Copy link
Copy Markdown
Collaborator

Closes#1225
Supersedes #1123

Adds the ability to control whether or not callbacks fire when the page or layout chunk first loads. This can simplify a lot of code like if n_clicks is None: raise PreventUpdate, and it can improve loading performance, particularly for pattern-matching callbacks, where a page can easily generate hundreds of callback invocations, since there is no longer even a server call for these callbacks.

This option is off by default, but can either be turned on for each callback independently:

@app.callback(outputs, inputs, prevent_initial_call=True)defcb(...):
...
app.clientside_callback(func, outputs, inputs, prevent_initial_call=True)

or app-wide, in which case it can be turned off for individual callbacks:

app=dash.Dash(prevent_initial_callbacks=True)
@app.callback(outputs, inputs, prevent_initial_call=False)defcb(...)
...
  • I have run the tests locally and they passed. (refer to testing section in contributing)
  • 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
  • Docs follow-up issue: https://github.com/plotly/dash-docs/issues/874

@alexcjohnsonalexcjohnson added this to the Dash v1.12 milestone May 4, 2020

@Marc-Andre-RivetMarc-Andre-Rivet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💃

pluck('path', flatten(cb.getOutputs(paths)))
)
) {
cb.changedPropIds = {};

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I'm not sure what I was thinking here with clearing out changedPropIds, but in this case (we've found a callback by its inputs due to a layout change, and just determined that all its outputs are in the same layout chunk) we know the callback is already included in the queue via its outputs so the best thing to do is simply not re-include it at all. This extra addCallback was harmless before prevent_initial_call, just a slight bit of extra work; but now that we have prevent_initial_call it's possible this callback would not be added based on its outputs.

If this condition isn't met, there are outputs outside the new layout chunk and it's not in fact an initial call anyway - so it's appropriate to add the callback and that's what the new logic does.

{"clientside": False, "content": True, "global": False},
{"clientside": True, "content": True, "global": True},
{"clientside": False, "content": False, "global": True},
]

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

pytest does a nice job logging dictionary test parametrizations (flavor0, flavor1 etc):
Screen Shot 2020-05-04 at 5 15 44 PM

@alexcjohnson
alexcjohnson merged commit 7961611 into devMay 4, 2020
@alexcjohnson
alexcjohnson deleted the prevent-initial-call branch May 4, 2020 21:26
@maartenbreddels

Copy link
Copy Markdown

Initial impression is really good! Together with #832 we can avoid any unneeded calls, and have a very fast page load.

@alexcjohnsonalexcjohnson mentioned this pull request May 13, 2020
5 tasks
nightsailer added a commit to o3cloud/dash that referenced this pull request Jun 13, 2020
@chriddypchriddyp mentioned this pull request Jun 25, 2020
Sign up for freeto 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.

Ability to prevent initial callback from firing

4 participants

@alexcjohnson@maartenbreddels@Marc-Andre-Rivet@chriddyp
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Prevent initial call - #1228

Merged
alexcjohnson merged 4 commits into
devfrom
prevent-initial-call
May 4, 2020
Merged

Prevent initial call#1228
alexcjohnson merged 4 commits into
devfrom
prevent-initial-call

Conversation

@alexcjohnson

@alexcjohnsonalexcjohnson commented May 4, 2020

Copy link
Copy Markdown
Collaborator

Closes#1225
Supersedes #1123

Adds the ability to control whether or not callbacks fire when the page or layout chunk first loads. This can simplify a lot of code like if n_clicks is None: raise PreventUpdate, and it can improve loading performance, particularly for pattern-matching callbacks, where a page can easily generate hundreds of callback invocations, since there is no longer even a server call for these callbacks.

This option is off by default, but can either be turned on for each callback independently:

@app.callback(outputs, inputs, prevent_initial_call=True)defcb(...):
...
app.clientside_callback(func, outputs, inputs, prevent_initial_call=True)

or app-wide, in which case it can be turned off for individual callbacks:

app=dash.Dash(prevent_initial_callbacks=True)
@app.callback(outputs, inputs, prevent_initial_call=False)defcb(...)
...
  • I have run the tests locally and they passed. (refer to testing section in contributing)
  • 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
  • Docs follow-up issue: https://github.com/plotly/dash-docs/issues/874

@alexcjohnsonalexcjohnson added this to the Dash v1.12 milestone May 4, 2020

@Marc-Andre-RivetMarc-Andre-Rivet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💃

pluck('path', flatten(cb.getOutputs(paths)))
)
) {
cb.changedPropIds = {};

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I'm not sure what I was thinking here with clearing out changedPropIds, but in this case (we've found a callback by its inputs due to a layout change, and just determined that all its outputs are in the same layout chunk) we know the callback is already included in the queue via its outputs so the best thing to do is simply not re-include it at all. This extra addCallback was harmless before prevent_initial_call, just a slight bit of extra work; but now that we have prevent_initial_call it's possible this callback would not be added based on its outputs.

If this condition isn't met, there are outputs outside the new layout chunk and it's not in fact an initial call anyway - so it's appropriate to add the callback and that's what the new logic does.

{"clientside": False, "content": True, "global": False},
{"clientside": True, "content": True, "global": True},
{"clientside": False, "content": False, "global": True},
]

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

pytest does a nice job logging dictionary test parametrizations (flavor0, flavor1 etc):
Screen Shot 2020-05-04 at 5 15 44 PM

@alexcjohnson
alexcjohnson merged commit 7961611 into devMay 4, 2020
@alexcjohnson
alexcjohnson deleted the prevent-initial-call branch May 4, 2020 21:26
@maartenbreddels

Copy link
Copy Markdown

Initial impression is really good! Together with #832 we can avoid any unneeded calls, and have a very fast page load.

@alexcjohnsonalexcjohnson mentioned this pull request May 13, 2020
5 tasks
nightsailer added a commit to o3cloud/dash that referenced this pull request Jun 13, 2020
@chriddypchriddyp mentioned this pull request Jun 25, 2020
Sign up for freeto 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.

Ability to prevent initial callback from firing

4 participants

@alexcjohnson@maartenbreddels@Marc-Andre-Rivet@chriddyp
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Prevent initial call - #1228

Merged
alexcjohnson merged 4 commits into
devfrom
prevent-initial-call
May 4, 2020
Merged

Prevent initial call#1228
alexcjohnson merged 4 commits into
devfrom
prevent-initial-call

Conversation

@alexcjohnson

@alexcjohnsonalexcjohnson commented May 4, 2020

Copy link
Copy Markdown
Collaborator

Closes#1225
Supersedes #1123

Adds the ability to control whether or not callbacks fire when the page or layout chunk first loads. This can simplify a lot of code like if n_clicks is None: raise PreventUpdate, and it can improve loading performance, particularly for pattern-matching callbacks, where a page can easily generate hundreds of callback invocations, since there is no longer even a server call for these callbacks.

This option is off by default, but can either be turned on for each callback independently:

@app.callback(outputs, inputs, prevent_initial_call=True)defcb(...):
...
app.clientside_callback(func, outputs, inputs, prevent_initial_call=True)

or app-wide, in which case it can be turned off for individual callbacks:

app=dash.Dash(prevent_initial_callbacks=True)
@app.callback(outputs, inputs, prevent_initial_call=False)defcb(...)
...
  • I have run the tests locally and they passed. (refer to testing section in contributing)
  • 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
  • Docs follow-up issue: https://github.com/plotly/dash-docs/issues/874

@alexcjohnsonalexcjohnson added this to the Dash v1.12 milestone May 4, 2020

@Marc-Andre-RivetMarc-Andre-Rivet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💃

pluck('path', flatten(cb.getOutputs(paths)))
)
) {
cb.changedPropIds = {};

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I'm not sure what I was thinking here with clearing out changedPropIds, but in this case (we've found a callback by its inputs due to a layout change, and just determined that all its outputs are in the same layout chunk) we know the callback is already included in the queue via its outputs so the best thing to do is simply not re-include it at all. This extra addCallback was harmless before prevent_initial_call, just a slight bit of extra work; but now that we have prevent_initial_call it's possible this callback would not be added based on its outputs.

If this condition isn't met, there are outputs outside the new layout chunk and it's not in fact an initial call anyway - so it's appropriate to add the callback and that's what the new logic does.

{"clientside": False, "content": True, "global": False},
{"clientside": True, "content": True, "global": True},
{"clientside": False, "content": False, "global": True},
]

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

pytest does a nice job logging dictionary test parametrizations (flavor0, flavor1 etc):
Screen Shot 2020-05-04 at 5 15 44 PM

@alexcjohnson
alexcjohnson merged commit 7961611 into devMay 4, 2020
@alexcjohnson
alexcjohnson deleted the prevent-initial-call branch May 4, 2020 21:26
@maartenbreddels

Copy link
Copy Markdown

Initial impression is really good! Together with #832 we can avoid any unneeded calls, and have a very fast page load.

@alexcjohnsonalexcjohnson mentioned this pull request May 13, 2020
5 tasks
nightsailer added a commit to o3cloud/dash that referenced this pull request Jun 13, 2020
@chriddypchriddyp mentioned this pull request Jun 25, 2020
Sign up for freeto 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.

Ability to prevent initial callback from firing

4 participants

@alexcjohnson@maartenbreddels@Marc-Andre-Rivet@chriddyp
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Prevent initial call - #1228

Merged
alexcjohnson merged 4 commits into
devfrom
prevent-initial-call
May 4, 2020
Merged

Prevent initial call#1228
alexcjohnson merged 4 commits into
devfrom
prevent-initial-call

Conversation

@alexcjohnson

@alexcjohnsonalexcjohnson commented May 4, 2020

Copy link
Copy Markdown
Collaborator

Closes#1225
Supersedes #1123

Adds the ability to control whether or not callbacks fire when the page or layout chunk first loads. This can simplify a lot of code like if n_clicks is None: raise PreventUpdate, and it can improve loading performance, particularly for pattern-matching callbacks, where a page can easily generate hundreds of callback invocations, since there is no longer even a server call for these callbacks.

This option is off by default, but can either be turned on for each callback independently:

@app.callback(outputs, inputs, prevent_initial_call=True)defcb(...):
...
app.clientside_callback(func, outputs, inputs, prevent_initial_call=True)

or app-wide, in which case it can be turned off for individual callbacks:

app=dash.Dash(prevent_initial_callbacks=True)
@app.callback(outputs, inputs, prevent_initial_call=False)defcb(...)
...
  • I have run the tests locally and they passed. (refer to testing section in contributing)
  • 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
  • Docs follow-up issue: https://github.com/plotly/dash-docs/issues/874

@alexcjohnsonalexcjohnson added this to the Dash v1.12 milestone May 4, 2020

@Marc-Andre-RivetMarc-Andre-Rivet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💃

pluck('path', flatten(cb.getOutputs(paths)))
)
) {
cb.changedPropIds = {};

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I'm not sure what I was thinking here with clearing out changedPropIds, but in this case (we've found a callback by its inputs due to a layout change, and just determined that all its outputs are in the same layout chunk) we know the callback is already included in the queue via its outputs so the best thing to do is simply not re-include it at all. This extra addCallback was harmless before prevent_initial_call, just a slight bit of extra work; but now that we have prevent_initial_call it's possible this callback would not be added based on its outputs.

If this condition isn't met, there are outputs outside the new layout chunk and it's not in fact an initial call anyway - so it's appropriate to add the callback and that's what the new logic does.

{"clientside": False, "content": True, "global": False},
{"clientside": True, "content": True, "global": True},
{"clientside": False, "content": False, "global": True},
]

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

pytest does a nice job logging dictionary test parametrizations (flavor0, flavor1 etc):
Screen Shot 2020-05-04 at 5 15 44 PM

@alexcjohnson
alexcjohnson merged commit 7961611 into devMay 4, 2020
@alexcjohnson
alexcjohnson deleted the prevent-initial-call branch May 4, 2020 21:26
@maartenbreddels

Copy link
Copy Markdown

Initial impression is really good! Together with #832 we can avoid any unneeded calls, and have a very fast page load.

@alexcjohnsonalexcjohnson mentioned this pull request May 13, 2020
5 tasks
nightsailer added a commit to o3cloud/dash that referenced this pull request Jun 13, 2020
@chriddypchriddyp mentioned this pull request Jun 25, 2020
Sign up for freeto 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.

Ability to prevent initial callback from firing

4 participants

@alexcjohnson@maartenbreddels@Marc-Andre-Rivet@chriddyp