-
-
Notifications
You must be signed in to change notification settings - Fork 74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make it possible to resolve rx expressions recursively #918
Conversation
@@ -164,11 +164,13 @@ def eval_function_with_deps(function): | |||
kwargs = {n: getattr(dep.owner, dep.name) for n, dep in kw_deps.items()} | |||
return function(*args, **kwargs) | |||
|
|||
def resolve_value(value): | |||
def resolve_value(value, recursive=True): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was an oversight, it should not have recursively resolved values unless requested. Unfortunately changing the default behavior would cause potential regressions now since Panel and HoloViews both depend on it. So the migration plan will have to be for those libraries to explicitly set recursive=True/False
and then eventually we can consider changing the default.
Going to merge so I can cut an RC. If you have review comments please still leave them and I'll follow up before release. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have left some minor comments.
refs = resolve_ref(self.object, nested) | ||
value = resolve_value(self.object, nested) | ||
if self.recursive: | ||
new_refs = [r for r in resolve_ref(value, nested) if r not in refs] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
new_refs = [r for r in resolve_ref(value, nested) if r not in refs] | |
new_refs = [r for r in resolve_ref(value, recursive=nested) if r not in refs] |
Is clearer for me to understand by using keywords arguments here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, although it's also a little confusing, recursive
means something different in the context of resolve_ref
than it does in the context of the Resolver
.
new_refs = [r for r in resolve_ref(value, nested) if r not in refs] | ||
while new_refs: | ||
refs += new_refs | ||
value = resolve_value(value, nested) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
value = resolve_value(value, nested) | |
value = resolve_value(value, recursive=nested) |
while new_refs: | ||
refs += new_refs | ||
value = resolve_value(value, nested) | ||
new_refs = [r for r in resolve_ref(value, nested) if r not in refs] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
new_refs = [r for r in resolve_ref(value, nested) if r not in refs] | |
new_refs = [r for r in resolve_ref(value, recursive=nested) if r not in refs] |
value = resolve_value(self.object, nested) | ||
if self.recursive: | ||
new_refs = [r for r in resolve_ref(value, nested) if r not in refs] | ||
while new_refs: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
while new_refs: | |
while new_refs := [r for r in resolve_ref(value, recursive=nested) if r not in refs]: |
And delete the last line in the while-loop. (I know you like these walrus)
@@ -235,6 +287,27 @@ def pipe(self, func, /, *args, **kwargs): | |||
""" | |||
return self._as_rx()._apply_operator(func, *args, **kwargs) | |||
|
|||
def resolve(self, nested=True, recursive=False): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def resolve(self, nested=True, recursive=False): | |
def resolve(self, *, nested=True, recursive=False): |
So that we don't get a function call like this resolve(True, True)
Thanks, will make a new PR incorporating all your suggestions. |
Nice. Is the intention for this to be part of 1.4? |
I'm a little afraid at how "meta" this operation is but it allows doing some things which aren't otherwise possible with
.rx
(or rather extremely complicated). Specifically this allows writing expressions that themselves contain references and then recursively resolves them. The case where I encountered the need for this is a Panel ToDo app.Let us say we have a layout of tasks:
Each task is structured like this:
Now I can write a simple expression to gather up all checkboxes:
And if want to get the number of completed tasks I could do:
Unfortunately this only updates when the list of checkboxes changes, i.e. NOT when each individual checkbox is ticked or unticked.
What I really want to do is for the expression to resolve the references (i.e. in this case the widgets) and update when any of the references change. Using
.rx.resolve
I can count the number of completed tasks with: