Skip to content

Adding dispatch decorator that simplifies common dispatch patterns - #69

Open
cfarrow wants to merge 4 commits into
mainfrom
enh-dispatch-decorator
Open

Adding dispatch decorator that simplifies common dispatch patterns#69
cfarrow wants to merge 4 commits into
mainfrom
enh-dispatch-decorator

Conversation

@cfarrow

Copy link
Copy Markdown

This decorator is meant to eliminate some of the boilerplate associated with effectively using executors and work schedulers like here. The decorator also handles dispatch with callables (e.g. ui_dispatch, deferred_call).

Feedback on the functionality and API is much appreciated (@sjagoe, @mdickinson, @prabhuramachandran). If this is determined to be merge-worthy, I'll write up some documentation and examples.

@cfarrow

Copy link
Copy Markdown
Author

The test runs are not relevant to this PR. We might want something like this soon on a consulting project. @mdickinson do you mind taking a look?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd much prefer to see two separate decorators here. We might even drop the call option altogether: did you have specific use-cases in mind for this? If not, can we wait until those use-cases exist?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I'd much prefer to see two separate decorators here.

No problem. Now to name them...

We might even drop the call option altogether: did you have specific use-cases in mind for this?

I had traits.trait_notifiers.ui_dispatch in mind for call. I would be happy to drop it if we had a UIExecutor that dispatched to a UI thread. (That can get pretty hairy, though.)

@mdickinson

Copy link
Copy Markdown
Member

I agree this looks potentially useful. I'm looking for actual places I'd use it, and haven't found any yet. I'll keep you posted.

I'd strongly prefer to see two separate decorators rather than one multi-purpose decorator with a horrible signature. :-)

What happens if you try to combine the @dispatch decorator with an @on_trait_change decorator? There's at least one ordering of the decorators that won't work (because the dispatch decorator will hide the signature of the decorated method). Is there an ordering that does work, or do we just avoid mixing the two?

@cfarrow

Copy link
Copy Markdown
Author

Originally I had planned on migrating the 'dispatch' argument of the on_trait_change method to the on_trait_change decorator, and adding the ability to specify an arbitrary dispatcher like in the decorator here. I went with this solution because it is more general.

Here is an example of where I would use this.

I want the decorators to play nicely, and I forgot about the traits call signature issue. I want that to work before merging this. I'll need more tests, but they should not live in encore.

@mdickinson

Copy link
Copy Markdown
Member

So in the example you linked to, you wouldn't want to decorate the @on_trait_change method anyway: it's the _blur_and_notify_plot method that you'd put the dispatch decorator on, right? And this seems to me as though it would be the normal case: it would be rare for the method signature for the on_trait_change-decorated method to coincide with that of the thing you're trying to redispatch.

I did find examples where I'd use this, and they look similar: I didn't find any cases where I'd want to apply the dispatch decorator and the on_trait_change decorator simultaneously.

@cfarrow

Copy link
Copy Markdown
Author

Image you do not have the option to turn off asynchronous updates in that example. In that case, you want all changes to a given trait to trigger a state update that goes through the asynchronizer. It would look something like...

@on_trait_change('blur_level, image', post_init=True)@dispatch("_asynchronizer")def_recalculate_blurred_image(self):
""" Blur the image asynchronously """self.blurred_image=blur_image(self.image, self.blur_level)
ui_dispatch(self.plot_data.set_data, "blurred_image", self.blurred_image)

@mdickinson

Copy link
Copy Markdown
Member

Hmm. That example makes me a bit nervous, because rather than using the new values of blur_level and image that the trait change notifier could have provided for you, you're looking up image and blur_level on the object again. And in a multithreaded situation those values might have changed in the meantime. There are places where we'd care about that sort of thing.

@cfarrow

Copy link
Copy Markdown
Author

That is true. This is a bad idea in general, and for that reason, we may not want the decorators to play nicely together (with a good set of documentation explaining why).

So, we're at a point where we're trading off a call to an executor-like object for a decorator that references that object by name. The latter is more declarative, but doesn't save much work.

I'll tinker around with this more later.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If this is meant to be sugar, then can't dispatcher handle either a string, or callable or real dispatcher instance? If you want this to be explicit, then it seems more consistent to have dispatcher=None, dispatcher_trait=None, callback=None.

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.

3 participants

@cfarrow@mdickinson@prabhuramachandran
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
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;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Adding dispatch decorator that simplifies common dispatch patterns by cfarrow · Pull Request #69 · enthought/encore · GitHub
Skip to content

Adding dispatch decorator that simplifies common dispatch patterns - #69

Open
cfarrow wants to merge 4 commits into
mainfrom
enh-dispatch-decorator
Open

Adding dispatch decorator that simplifies common dispatch patterns#69
cfarrow wants to merge 4 commits into
mainfrom
enh-dispatch-decorator

Conversation

@cfarrow

Copy link
Copy Markdown

This decorator is meant to eliminate some of the boilerplate associated with effectively using executors and work schedulers like here. The decorator also handles dispatch with callables (e.g. ui_dispatch, deferred_call).

Feedback on the functionality and API is much appreciated (@sjagoe, @mdickinson, @prabhuramachandran). If this is determined to be merge-worthy, I'll write up some documentation and examples.

@cfarrow

Copy link
Copy Markdown
Author

The test runs are not relevant to this PR. We might want something like this soon on a consulting project. @mdickinson do you mind taking a look?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd much prefer to see two separate decorators here. We might even drop the call option altogether: did you have specific use-cases in mind for this? If not, can we wait until those use-cases exist?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I'd much prefer to see two separate decorators here.

No problem. Now to name them...

We might even drop the call option altogether: did you have specific use-cases in mind for this?

I had traits.trait_notifiers.ui_dispatch in mind for call. I would be happy to drop it if we had a UIExecutor that dispatched to a UI thread. (That can get pretty hairy, though.)

@mdickinson

Copy link
Copy Markdown
Member

I agree this looks potentially useful. I'm looking for actual places I'd use it, and haven't found any yet. I'll keep you posted.

I'd strongly prefer to see two separate decorators rather than one multi-purpose decorator with a horrible signature. :-)

What happens if you try to combine the @dispatch decorator with an @on_trait_change decorator? There's at least one ordering of the decorators that won't work (because the dispatch decorator will hide the signature of the decorated method). Is there an ordering that does work, or do we just avoid mixing the two?

@cfarrow

Copy link
Copy Markdown
Author

Originally I had planned on migrating the 'dispatch' argument of the on_trait_change method to the on_trait_change decorator, and adding the ability to specify an arbitrary dispatcher like in the decorator here. I went with this solution because it is more general.

Here is an example of where I would use this.

I want the decorators to play nicely, and I forgot about the traits call signature issue. I want that to work before merging this. I'll need more tests, but they should not live in encore.

@mdickinson

Copy link
Copy Markdown
Member

So in the example you linked to, you wouldn't want to decorate the @on_trait_change method anyway: it's the _blur_and_notify_plot method that you'd put the dispatch decorator on, right? And this seems to me as though it would be the normal case: it would be rare for the method signature for the on_trait_change-decorated method to coincide with that of the thing you're trying to redispatch.

I did find examples where I'd use this, and they look similar: I didn't find any cases where I'd want to apply the dispatch decorator and the on_trait_change decorator simultaneously.

@cfarrow

Copy link
Copy Markdown
Author

Image you do not have the option to turn off asynchronous updates in that example. In that case, you want all changes to a given trait to trigger a state update that goes through the asynchronizer. It would look something like...

@on_trait_change('blur_level, image', post_init=True)@dispatch("_asynchronizer")def_recalculate_blurred_image(self):
""" Blur the image asynchronously """self.blurred_image=blur_image(self.image, self.blur_level)
ui_dispatch(self.plot_data.set_data, "blurred_image", self.blurred_image)

@mdickinson

Copy link
Copy Markdown
Member

Hmm. That example makes me a bit nervous, because rather than using the new values of blur_level and image that the trait change notifier could have provided for you, you're looking up image and blur_level on the object again. And in a multithreaded situation those values might have changed in the meantime. There are places where we'd care about that sort of thing.

@cfarrow

Copy link
Copy Markdown
Author

That is true. This is a bad idea in general, and for that reason, we may not want the decorators to play nicely together (with a good set of documentation explaining why).

So, we're at a point where we're trading off a call to an executor-like object for a decorator that references that object by name. The latter is more declarative, but doesn't save much work.

I'll tinker around with this more later.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If this is meant to be sugar, then can't dispatcher handle either a string, or callable or real dispatcher instance? If you want this to be explicit, then it seems more consistent to have dispatcher=None, dispatcher_trait=None, callback=None.

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.

3 participants

@cfarrow@mdickinson@prabhuramachandran
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Adding dispatch decorator that simplifies common dispatch patterns by cfarrow · Pull Request #69 · enthought/encore · GitHub
Skip to content

Adding dispatch decorator that simplifies common dispatch patterns - #69

Open
cfarrow wants to merge 4 commits into
mainfrom
enh-dispatch-decorator
Open

Adding dispatch decorator that simplifies common dispatch patterns#69
cfarrow wants to merge 4 commits into
mainfrom
enh-dispatch-decorator

Conversation

@cfarrow

Copy link
Copy Markdown

This decorator is meant to eliminate some of the boilerplate associated with effectively using executors and work schedulers like here. The decorator also handles dispatch with callables (e.g. ui_dispatch, deferred_call).

Feedback on the functionality and API is much appreciated (@sjagoe, @mdickinson, @prabhuramachandran). If this is determined to be merge-worthy, I'll write up some documentation and examples.

@cfarrow

Copy link
Copy Markdown
Author

The test runs are not relevant to this PR. We might want something like this soon on a consulting project. @mdickinson do you mind taking a look?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd much prefer to see two separate decorators here. We might even drop the call option altogether: did you have specific use-cases in mind for this? If not, can we wait until those use-cases exist?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I'd much prefer to see two separate decorators here.

No problem. Now to name them...

We might even drop the call option altogether: did you have specific use-cases in mind for this?

I had traits.trait_notifiers.ui_dispatch in mind for call. I would be happy to drop it if we had a UIExecutor that dispatched to a UI thread. (That can get pretty hairy, though.)

@mdickinson

Copy link
Copy Markdown
Member

I agree this looks potentially useful. I'm looking for actual places I'd use it, and haven't found any yet. I'll keep you posted.

I'd strongly prefer to see two separate decorators rather than one multi-purpose decorator with a horrible signature. :-)

What happens if you try to combine the @dispatch decorator with an @on_trait_change decorator? There's at least one ordering of the decorators that won't work (because the dispatch decorator will hide the signature of the decorated method). Is there an ordering that does work, or do we just avoid mixing the two?

@cfarrow

Copy link
Copy Markdown
Author

Originally I had planned on migrating the 'dispatch' argument of the on_trait_change method to the on_trait_change decorator, and adding the ability to specify an arbitrary dispatcher like in the decorator here. I went with this solution because it is more general.

Here is an example of where I would use this.

I want the decorators to play nicely, and I forgot about the traits call signature issue. I want that to work before merging this. I'll need more tests, but they should not live in encore.

@mdickinson

Copy link
Copy Markdown
Member

So in the example you linked to, you wouldn't want to decorate the @on_trait_change method anyway: it's the _blur_and_notify_plot method that you'd put the dispatch decorator on, right? And this seems to me as though it would be the normal case: it would be rare for the method signature for the on_trait_change-decorated method to coincide with that of the thing you're trying to redispatch.

I did find examples where I'd use this, and they look similar: I didn't find any cases where I'd want to apply the dispatch decorator and the on_trait_change decorator simultaneously.

@cfarrow

Copy link
Copy Markdown
Author

Image you do not have the option to turn off asynchronous updates in that example. In that case, you want all changes to a given trait to trigger a state update that goes through the asynchronizer. It would look something like...

@on_trait_change('blur_level, image', post_init=True)@dispatch("_asynchronizer")def_recalculate_blurred_image(self):
""" Blur the image asynchronously """self.blurred_image=blur_image(self.image, self.blur_level)
ui_dispatch(self.plot_data.set_data, "blurred_image", self.blurred_image)

@mdickinson

Copy link
Copy Markdown
Member

Hmm. That example makes me a bit nervous, because rather than using the new values of blur_level and image that the trait change notifier could have provided for you, you're looking up image and blur_level on the object again. And in a multithreaded situation those values might have changed in the meantime. There are places where we'd care about that sort of thing.

@cfarrow

Copy link
Copy Markdown
Author

That is true. This is a bad idea in general, and for that reason, we may not want the decorators to play nicely together (with a good set of documentation explaining why).

So, we're at a point where we're trading off a call to an executor-like object for a decorator that references that object by name. The latter is more declarative, but doesn't save much work.

I'll tinker around with this more later.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If this is meant to be sugar, then can't dispatcher handle either a string, or callable or real dispatcher instance? If you want this to be explicit, then it seems more consistent to have dispatcher=None, dispatcher_trait=None, callback=None.

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.

3 participants

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

Adding dispatch decorator that simplifies common dispatch patterns - #69

Open
cfarrow wants to merge 4 commits into
mainfrom
enh-dispatch-decorator
Open

Adding dispatch decorator that simplifies common dispatch patterns#69
cfarrow wants to merge 4 commits into
mainfrom
enh-dispatch-decorator

Conversation

@cfarrow

Copy link
Copy Markdown

This decorator is meant to eliminate some of the boilerplate associated with effectively using executors and work schedulers like here. The decorator also handles dispatch with callables (e.g. ui_dispatch, deferred_call).

Feedback on the functionality and API is much appreciated (@sjagoe, @mdickinson, @prabhuramachandran). If this is determined to be merge-worthy, I'll write up some documentation and examples.

@cfarrow

Copy link
Copy Markdown
Author

The test runs are not relevant to this PR. We might want something like this soon on a consulting project. @mdickinson do you mind taking a look?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd much prefer to see two separate decorators here. We might even drop the call option altogether: did you have specific use-cases in mind for this? If not, can we wait until those use-cases exist?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I'd much prefer to see two separate decorators here.

No problem. Now to name them...

We might even drop the call option altogether: did you have specific use-cases in mind for this?

I had traits.trait_notifiers.ui_dispatch in mind for call. I would be happy to drop it if we had a UIExecutor that dispatched to a UI thread. (That can get pretty hairy, though.)

@mdickinson

Copy link
Copy Markdown
Member

I agree this looks potentially useful. I'm looking for actual places I'd use it, and haven't found any yet. I'll keep you posted.

I'd strongly prefer to see two separate decorators rather than one multi-purpose decorator with a horrible signature. :-)

What happens if you try to combine the @dispatch decorator with an @on_trait_change decorator? There's at least one ordering of the decorators that won't work (because the dispatch decorator will hide the signature of the decorated method). Is there an ordering that does work, or do we just avoid mixing the two?

@cfarrow

Copy link
Copy Markdown
Author

Originally I had planned on migrating the 'dispatch' argument of the on_trait_change method to the on_trait_change decorator, and adding the ability to specify an arbitrary dispatcher like in the decorator here. I went with this solution because it is more general.

Here is an example of where I would use this.

I want the decorators to play nicely, and I forgot about the traits call signature issue. I want that to work before merging this. I'll need more tests, but they should not live in encore.

@mdickinson

Copy link
Copy Markdown
Member

So in the example you linked to, you wouldn't want to decorate the @on_trait_change method anyway: it's the _blur_and_notify_plot method that you'd put the dispatch decorator on, right? And this seems to me as though it would be the normal case: it would be rare for the method signature for the on_trait_change-decorated method to coincide with that of the thing you're trying to redispatch.

I did find examples where I'd use this, and they look similar: I didn't find any cases where I'd want to apply the dispatch decorator and the on_trait_change decorator simultaneously.

@cfarrow

Copy link
Copy Markdown
Author

Image you do not have the option to turn off asynchronous updates in that example. In that case, you want all changes to a given trait to trigger a state update that goes through the asynchronizer. It would look something like...

@on_trait_change('blur_level, image', post_init=True)@dispatch("_asynchronizer")def_recalculate_blurred_image(self):
""" Blur the image asynchronously """self.blurred_image=blur_image(self.image, self.blur_level)
ui_dispatch(self.plot_data.set_data, "blurred_image", self.blurred_image)

@mdickinson

Copy link
Copy Markdown
Member

Hmm. That example makes me a bit nervous, because rather than using the new values of blur_level and image that the trait change notifier could have provided for you, you're looking up image and blur_level on the object again. And in a multithreaded situation those values might have changed in the meantime. There are places where we'd care about that sort of thing.

@cfarrow

Copy link
Copy Markdown
Author

That is true. This is a bad idea in general, and for that reason, we may not want the decorators to play nicely together (with a good set of documentation explaining why).

So, we're at a point where we're trading off a call to an executor-like object for a decorator that references that object by name. The latter is more declarative, but doesn't save much work.

I'll tinker around with this more later.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If this is meant to be sugar, then can't dispatcher handle either a string, or callable or real dispatcher instance? If you want this to be explicit, then it seems more consistent to have dispatcher=None, dispatcher_trait=None, callback=None.

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.

3 participants

@cfarrow@mdickinson@prabhuramachandran
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Adding dispatch decorator that simplifies common dispatch patterns by cfarrow · Pull Request #69 · enthought/encore · GitHub
Skip to content

Adding dispatch decorator that simplifies common dispatch patterns - #69

Open
cfarrow wants to merge 4 commits into
mainfrom
enh-dispatch-decorator
Open

Adding dispatch decorator that simplifies common dispatch patterns#69
cfarrow wants to merge 4 commits into
mainfrom
enh-dispatch-decorator

Conversation

@cfarrow

Copy link
Copy Markdown

This decorator is meant to eliminate some of the boilerplate associated with effectively using executors and work schedulers like here. The decorator also handles dispatch with callables (e.g. ui_dispatch, deferred_call).

Feedback on the functionality and API is much appreciated (@sjagoe, @mdickinson, @prabhuramachandran). If this is determined to be merge-worthy, I'll write up some documentation and examples.

@cfarrow

Copy link
Copy Markdown
Author

The test runs are not relevant to this PR. We might want something like this soon on a consulting project. @mdickinson do you mind taking a look?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd much prefer to see two separate decorators here. We might even drop the call option altogether: did you have specific use-cases in mind for this? If not, can we wait until those use-cases exist?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I'd much prefer to see two separate decorators here.

No problem. Now to name them...

We might even drop the call option altogether: did you have specific use-cases in mind for this?

I had traits.trait_notifiers.ui_dispatch in mind for call. I would be happy to drop it if we had a UIExecutor that dispatched to a UI thread. (That can get pretty hairy, though.)

@mdickinson

Copy link
Copy Markdown
Member

I agree this looks potentially useful. I'm looking for actual places I'd use it, and haven't found any yet. I'll keep you posted.

I'd strongly prefer to see two separate decorators rather than one multi-purpose decorator with a horrible signature. :-)

What happens if you try to combine the @dispatch decorator with an @on_trait_change decorator? There's at least one ordering of the decorators that won't work (because the dispatch decorator will hide the signature of the decorated method). Is there an ordering that does work, or do we just avoid mixing the two?

@cfarrow

Copy link
Copy Markdown
Author

Originally I had planned on migrating the 'dispatch' argument of the on_trait_change method to the on_trait_change decorator, and adding the ability to specify an arbitrary dispatcher like in the decorator here. I went with this solution because it is more general.

Here is an example of where I would use this.

I want the decorators to play nicely, and I forgot about the traits call signature issue. I want that to work before merging this. I'll need more tests, but they should not live in encore.

@mdickinson

Copy link
Copy Markdown
Member

So in the example you linked to, you wouldn't want to decorate the @on_trait_change method anyway: it's the _blur_and_notify_plot method that you'd put the dispatch decorator on, right? And this seems to me as though it would be the normal case: it would be rare for the method signature for the on_trait_change-decorated method to coincide with that of the thing you're trying to redispatch.

I did find examples where I'd use this, and they look similar: I didn't find any cases where I'd want to apply the dispatch decorator and the on_trait_change decorator simultaneously.

@cfarrow

Copy link
Copy Markdown
Author

Image you do not have the option to turn off asynchronous updates in that example. In that case, you want all changes to a given trait to trigger a state update that goes through the asynchronizer. It would look something like...

@on_trait_change('blur_level, image', post_init=True)@dispatch("_asynchronizer")def_recalculate_blurred_image(self):
""" Blur the image asynchronously """self.blurred_image=blur_image(self.image, self.blur_level)
ui_dispatch(self.plot_data.set_data, "blurred_image", self.blurred_image)

@mdickinson

Copy link
Copy Markdown
Member

Hmm. That example makes me a bit nervous, because rather than using the new values of blur_level and image that the trait change notifier could have provided for you, you're looking up image and blur_level on the object again. And in a multithreaded situation those values might have changed in the meantime. There are places where we'd care about that sort of thing.

@cfarrow

Copy link
Copy Markdown
Author

That is true. This is a bad idea in general, and for that reason, we may not want the decorators to play nicely together (with a good set of documentation explaining why).

So, we're at a point where we're trading off a call to an executor-like object for a decorator that references that object by name. The latter is more declarative, but doesn't save much work.

I'll tinker around with this more later.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If this is meant to be sugar, then can't dispatcher handle either a string, or callable or real dispatcher instance? If you want this to be explicit, then it seems more consistent to have dispatcher=None, dispatcher_trait=None, callback=None.

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.

3 participants

@cfarrow@mdickinson@prabhuramachandran
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Adding dispatch decorator that simplifies common dispatch patterns by cfarrow · Pull Request #69 · enthought/encore · GitHub
Skip to content

Adding dispatch decorator that simplifies common dispatch patterns - #69

Open
cfarrow wants to merge 4 commits into
mainfrom
enh-dispatch-decorator
Open

Adding dispatch decorator that simplifies common dispatch patterns#69
cfarrow wants to merge 4 commits into
mainfrom
enh-dispatch-decorator

Conversation

@cfarrow

Copy link
Copy Markdown

This decorator is meant to eliminate some of the boilerplate associated with effectively using executors and work schedulers like here. The decorator also handles dispatch with callables (e.g. ui_dispatch, deferred_call).

Feedback on the functionality and API is much appreciated (@sjagoe, @mdickinson, @prabhuramachandran). If this is determined to be merge-worthy, I'll write up some documentation and examples.

@cfarrow

Copy link
Copy Markdown
Author

The test runs are not relevant to this PR. We might want something like this soon on a consulting project. @mdickinson do you mind taking a look?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd much prefer to see two separate decorators here. We might even drop the call option altogether: did you have specific use-cases in mind for this? If not, can we wait until those use-cases exist?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I'd much prefer to see two separate decorators here.

No problem. Now to name them...

We might even drop the call option altogether: did you have specific use-cases in mind for this?

I had traits.trait_notifiers.ui_dispatch in mind for call. I would be happy to drop it if we had a UIExecutor that dispatched to a UI thread. (That can get pretty hairy, though.)

@mdickinson

Copy link
Copy Markdown
Member

I agree this looks potentially useful. I'm looking for actual places I'd use it, and haven't found any yet. I'll keep you posted.

I'd strongly prefer to see two separate decorators rather than one multi-purpose decorator with a horrible signature. :-)

What happens if you try to combine the @dispatch decorator with an @on_trait_change decorator? There's at least one ordering of the decorators that won't work (because the dispatch decorator will hide the signature of the decorated method). Is there an ordering that does work, or do we just avoid mixing the two?

@cfarrow

Copy link
Copy Markdown
Author

Originally I had planned on migrating the 'dispatch' argument of the on_trait_change method to the on_trait_change decorator, and adding the ability to specify an arbitrary dispatcher like in the decorator here. I went with this solution because it is more general.

Here is an example of where I would use this.

I want the decorators to play nicely, and I forgot about the traits call signature issue. I want that to work before merging this. I'll need more tests, but they should not live in encore.

@mdickinson

Copy link
Copy Markdown
Member

So in the example you linked to, you wouldn't want to decorate the @on_trait_change method anyway: it's the _blur_and_notify_plot method that you'd put the dispatch decorator on, right? And this seems to me as though it would be the normal case: it would be rare for the method signature for the on_trait_change-decorated method to coincide with that of the thing you're trying to redispatch.

I did find examples where I'd use this, and they look similar: I didn't find any cases where I'd want to apply the dispatch decorator and the on_trait_change decorator simultaneously.

@cfarrow

Copy link
Copy Markdown
Author

Image you do not have the option to turn off asynchronous updates in that example. In that case, you want all changes to a given trait to trigger a state update that goes through the asynchronizer. It would look something like...

@on_trait_change('blur_level, image', post_init=True)@dispatch("_asynchronizer")def_recalculate_blurred_image(self):
""" Blur the image asynchronously """self.blurred_image=blur_image(self.image, self.blur_level)
ui_dispatch(self.plot_data.set_data, "blurred_image", self.blurred_image)

@mdickinson

Copy link
Copy Markdown
Member

Hmm. That example makes me a bit nervous, because rather than using the new values of blur_level and image that the trait change notifier could have provided for you, you're looking up image and blur_level on the object again. And in a multithreaded situation those values might have changed in the meantime. There are places where we'd care about that sort of thing.

@cfarrow

Copy link
Copy Markdown
Author

That is true. This is a bad idea in general, and for that reason, we may not want the decorators to play nicely together (with a good set of documentation explaining why).

So, we're at a point where we're trading off a call to an executor-like object for a decorator that references that object by name. The latter is more declarative, but doesn't save much work.

I'll tinker around with this more later.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If this is meant to be sugar, then can't dispatcher handle either a string, or callable or real dispatcher instance? If you want this to be explicit, then it seems more consistent to have dispatcher=None, dispatcher_trait=None, callback=None.

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.

3 participants

@cfarrow@mdickinson@prabhuramachandran
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Adding dispatch decorator that simplifies common dispatch patterns by cfarrow · Pull Request #69 · enthought/encore · GitHub
Skip to content

Adding dispatch decorator that simplifies common dispatch patterns - #69

Open
cfarrow wants to merge 4 commits into
mainfrom
enh-dispatch-decorator
Open

Adding dispatch decorator that simplifies common dispatch patterns#69
cfarrow wants to merge 4 commits into
mainfrom
enh-dispatch-decorator

Conversation

@cfarrow

Copy link
Copy Markdown

This decorator is meant to eliminate some of the boilerplate associated with effectively using executors and work schedulers like here. The decorator also handles dispatch with callables (e.g. ui_dispatch, deferred_call).

Feedback on the functionality and API is much appreciated (@sjagoe, @mdickinson, @prabhuramachandran). If this is determined to be merge-worthy, I'll write up some documentation and examples.

@cfarrow

Copy link
Copy Markdown
Author

The test runs are not relevant to this PR. We might want something like this soon on a consulting project. @mdickinson do you mind taking a look?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd much prefer to see two separate decorators here. We might even drop the call option altogether: did you have specific use-cases in mind for this? If not, can we wait until those use-cases exist?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I'd much prefer to see two separate decorators here.

No problem. Now to name them...

We might even drop the call option altogether: did you have specific use-cases in mind for this?

I had traits.trait_notifiers.ui_dispatch in mind for call. I would be happy to drop it if we had a UIExecutor that dispatched to a UI thread. (That can get pretty hairy, though.)

@mdickinson

Copy link
Copy Markdown
Member

I agree this looks potentially useful. I'm looking for actual places I'd use it, and haven't found any yet. I'll keep you posted.

I'd strongly prefer to see two separate decorators rather than one multi-purpose decorator with a horrible signature. :-)

What happens if you try to combine the @dispatch decorator with an @on_trait_change decorator? There's at least one ordering of the decorators that won't work (because the dispatch decorator will hide the signature of the decorated method). Is there an ordering that does work, or do we just avoid mixing the two?

@cfarrow

Copy link
Copy Markdown
Author

Originally I had planned on migrating the 'dispatch' argument of the on_trait_change method to the on_trait_change decorator, and adding the ability to specify an arbitrary dispatcher like in the decorator here. I went with this solution because it is more general.

Here is an example of where I would use this.

I want the decorators to play nicely, and I forgot about the traits call signature issue. I want that to work before merging this. I'll need more tests, but they should not live in encore.

@mdickinson

Copy link
Copy Markdown
Member

So in the example you linked to, you wouldn't want to decorate the @on_trait_change method anyway: it's the _blur_and_notify_plot method that you'd put the dispatch decorator on, right? And this seems to me as though it would be the normal case: it would be rare for the method signature for the on_trait_change-decorated method to coincide with that of the thing you're trying to redispatch.

I did find examples where I'd use this, and they look similar: I didn't find any cases where I'd want to apply the dispatch decorator and the on_trait_change decorator simultaneously.

@cfarrow

Copy link
Copy Markdown
Author

Image you do not have the option to turn off asynchronous updates in that example. In that case, you want all changes to a given trait to trigger a state update that goes through the asynchronizer. It would look something like...

@on_trait_change('blur_level, image', post_init=True)@dispatch("_asynchronizer")def_recalculate_blurred_image(self):
""" Blur the image asynchronously """self.blurred_image=blur_image(self.image, self.blur_level)
ui_dispatch(self.plot_data.set_data, "blurred_image", self.blurred_image)

@mdickinson

Copy link
Copy Markdown
Member

Hmm. That example makes me a bit nervous, because rather than using the new values of blur_level and image that the trait change notifier could have provided for you, you're looking up image and blur_level on the object again. And in a multithreaded situation those values might have changed in the meantime. There are places where we'd care about that sort of thing.

@cfarrow

Copy link
Copy Markdown
Author

That is true. This is a bad idea in general, and for that reason, we may not want the decorators to play nicely together (with a good set of documentation explaining why).

So, we're at a point where we're trading off a call to an executor-like object for a decorator that references that object by name. The latter is more declarative, but doesn't save much work.

I'll tinker around with this more later.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If this is meant to be sugar, then can't dispatcher handle either a string, or callable or real dispatcher instance? If you want this to be explicit, then it seems more consistent to have dispatcher=None, dispatcher_trait=None, callback=None.

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.

3 participants

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

Adding dispatch decorator that simplifies common dispatch patterns - #69

Open
cfarrow wants to merge 4 commits into
mainfrom
enh-dispatch-decorator
Open

Adding dispatch decorator that simplifies common dispatch patterns#69
cfarrow wants to merge 4 commits into
mainfrom
enh-dispatch-decorator

Conversation

@cfarrow

Copy link
Copy Markdown

This decorator is meant to eliminate some of the boilerplate associated with effectively using executors and work schedulers like here. The decorator also handles dispatch with callables (e.g. ui_dispatch, deferred_call).

Feedback on the functionality and API is much appreciated (@sjagoe, @mdickinson, @prabhuramachandran). If this is determined to be merge-worthy, I'll write up some documentation and examples.

@cfarrow

Copy link
Copy Markdown
Author

The test runs are not relevant to this PR. We might want something like this soon on a consulting project. @mdickinson do you mind taking a look?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd much prefer to see two separate decorators here. We might even drop the call option altogether: did you have specific use-cases in mind for this? If not, can we wait until those use-cases exist?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I'd much prefer to see two separate decorators here.

No problem. Now to name them...

We might even drop the call option altogether: did you have specific use-cases in mind for this?

I had traits.trait_notifiers.ui_dispatch in mind for call. I would be happy to drop it if we had a UIExecutor that dispatched to a UI thread. (That can get pretty hairy, though.)

@mdickinson

Copy link
Copy Markdown
Member

I agree this looks potentially useful. I'm looking for actual places I'd use it, and haven't found any yet. I'll keep you posted.

I'd strongly prefer to see two separate decorators rather than one multi-purpose decorator with a horrible signature. :-)

What happens if you try to combine the @dispatch decorator with an @on_trait_change decorator? There's at least one ordering of the decorators that won't work (because the dispatch decorator will hide the signature of the decorated method). Is there an ordering that does work, or do we just avoid mixing the two?

@cfarrow

Copy link
Copy Markdown
Author

Originally I had planned on migrating the 'dispatch' argument of the on_trait_change method to the on_trait_change decorator, and adding the ability to specify an arbitrary dispatcher like in the decorator here. I went with this solution because it is more general.

Here is an example of where I would use this.

I want the decorators to play nicely, and I forgot about the traits call signature issue. I want that to work before merging this. I'll need more tests, but they should not live in encore.

@mdickinson

Copy link
Copy Markdown
Member

So in the example you linked to, you wouldn't want to decorate the @on_trait_change method anyway: it's the _blur_and_notify_plot method that you'd put the dispatch decorator on, right? And this seems to me as though it would be the normal case: it would be rare for the method signature for the on_trait_change-decorated method to coincide with that of the thing you're trying to redispatch.

I did find examples where I'd use this, and they look similar: I didn't find any cases where I'd want to apply the dispatch decorator and the on_trait_change decorator simultaneously.

@cfarrow

Copy link
Copy Markdown
Author

Image you do not have the option to turn off asynchronous updates in that example. In that case, you want all changes to a given trait to trigger a state update that goes through the asynchronizer. It would look something like...

@on_trait_change('blur_level, image', post_init=True)@dispatch("_asynchronizer")def_recalculate_blurred_image(self):
""" Blur the image asynchronously """self.blurred_image=blur_image(self.image, self.blur_level)
ui_dispatch(self.plot_data.set_data, "blurred_image", self.blurred_image)

@mdickinson

Copy link
Copy Markdown
Member

Hmm. That example makes me a bit nervous, because rather than using the new values of blur_level and image that the trait change notifier could have provided for you, you're looking up image and blur_level on the object again. And in a multithreaded situation those values might have changed in the meantime. There are places where we'd care about that sort of thing.

@cfarrow

Copy link
Copy Markdown
Author

That is true. This is a bad idea in general, and for that reason, we may not want the decorators to play nicely together (with a good set of documentation explaining why).

So, we're at a point where we're trading off a call to an executor-like object for a decorator that references that object by name. The latter is more declarative, but doesn't save much work.

I'll tinker around with this more later.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If this is meant to be sugar, then can't dispatcher handle either a string, or callable or real dispatcher instance? If you want this to be explicit, then it seems more consistent to have dispatcher=None, dispatcher_trait=None, callback=None.

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.

3 participants

@cfarrow@mdickinson@prabhuramachandran