Make it possible to resolve rx expressions recursively#918
Conversation
| return function(*args, **kwargs) | ||
|
|
||
| def resolve_value(value): | ||
| def resolve_value(value, recursive=True): |
There was a problem hiding this comment.
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. |
hoxbro
left a comment
There was a problem hiding this comment.
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.
| 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.
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.
| 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.
| 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.
| 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)
| """ | ||
| return self._as_rx()._apply_operator(func, *args, **kwargs) | ||
|
|
||
| def resolve(self, nested=True, recursive=False): |
There was a problem hiding this comment.
| 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.resolveI can count the number of completed tasks with: