-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Add Patch callbacks #2414
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
Merged
Merged
Add Patch callbacks #2414
Changes from 23 commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
54f224b
Add patch API to partially update props from callbacks.
T4rk1n 967d20b
Add unit tests for patch API.
T4rk1n f9c29b1
Remove PatchOutput, add allow_duplicate argument to Output.
T4rk1n f77cef2
Fix DAG with allow_duplicate.
T4rk1n 5930963
Handle PMC patch outputs.
T4rk1n 8a90e23
Fix patch handling logic.
T4rk1n 7fbc630
Validate patch on undefined.
T4rk1n 4ceb35d
Add integration tests for patch callbacks.
T4rk1n 63466ec
Merge branch 'dev' into patch-update
T4rk1n 5ba249c
Clean DAG output id infobox.
T4rk1n 535c552
Merge branch 'dev' into patch-update
T4rk1n 6cbad7e
Merge branch 'dev' into patch-update
T4rk1n 88cdad4
Validate allow_duplicate with prevent_initial_call.
T4rk1n 0c45291
Add patch insert.
T4rk1n ea3fb07
list or tuple
T4rk1n 8610554
Merge branch 'dev' into patch-update
T4rk1n aefeb78
Error on patch with slice index.
T4rk1n 3f9723c
Validate slice on deletion.
T4rk1n 0c99886
Handle negative index in location.
T4rk1n 280e948
Fix negative location index + support insert.
T4rk1n 5b59c1c
Test array index deletion.
T4rk1n 5e6c3a6
Remove regular +-*/ operations.
T4rk1n a7cb1d8
iadd to extend lists & merge dicts
T4rk1n e127080
Add clear operation.
T4rk1n 1e5acb7
add ior to merge.
T4rk1n 9f55b3d
Fix selenium keys import.
T4rk1n c5d4dd6
Add reverse
T4rk1n 9ccc456
item->assigned
T4rk1n d4d8804
Rename merge to update
T4rk1n 1fc6b46
Add remove.
T4rk1n 9d4ae67
Add docstrings to patch methods.
T4rk1n d376745
Update dash/_patch.py
T4rk1n 3fae39e
Add sort stub
T4rk1n 2949b7b
Update changelog
T4rk1n File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
def _operation(name, location, **kwargs): | ||
return {"operation": name, "location": location, "params": dict(**kwargs)} | ||
|
||
|
||
_noop = object() | ||
|
||
|
||
def validate_slice(obj): | ||
if isinstance(obj, slice): | ||
raise TypeError("a slice is not a valid index for patch") | ||
|
||
|
||
class Patch: | ||
""" | ||
Patch a callback output value | ||
|
||
Act like a proxy of the output prop value on the frontend. | ||
|
||
Supported prop types: Dictionaries and lists. | ||
""" | ||
|
||
def __init__(self, location=None, parent=None): | ||
if location is not None: | ||
self._location = location | ||
else: | ||
# pylint: disable=consider-using-ternary | ||
self._location = (parent and parent._location) or [] | ||
if parent is not None: | ||
self._operations = parent._operations | ||
else: | ||
self._operations = [] | ||
|
||
def __getitem__(self, item): | ||
validate_slice(item) | ||
return Patch(location=self._location + [item], parent=self) | ||
|
||
def __getattr__(self, item): | ||
if item == "tolist": | ||
# to_json fix | ||
raise AttributeError | ||
if item == "_location": | ||
return self._location | ||
if item == "_operations": | ||
return self._operations | ||
return self.__getitem__(item) | ||
|
||
def __setattr__(self, key, value): | ||
if key in ("_location", "_operations"): | ||
self.__dict__[key] = value | ||
else: | ||
self.__setitem__(key, value) | ||
|
||
def __delattr__(self, item): | ||
self.__delitem__(item) | ||
|
||
def __setitem__(self, key, value): | ||
validate_slice(key) | ||
if value is _noop: | ||
# The += set themselves. | ||
return | ||
self._operations.append( | ||
_operation( | ||
"Assign", | ||
self._location + [key], | ||
value=value, | ||
) | ||
) | ||
|
||
def __delitem__(self, key): | ||
validate_slice(key) | ||
self._operations.append(_operation("Delete", self._location + [key])) | ||
alexcjohnson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
def __iadd__(self, other): | ||
if isinstance(other, (list, tuple)): | ||
self.extend(other) | ||
elif isinstance(other, dict): | ||
self.merge(other) | ||
alexcjohnson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
else: | ||
self._operations.append(_operation("Add", self._location, value=other)) | ||
return _noop | ||
|
||
def __isub__(self, other): | ||
self._operations.append(_operation("Sub", self._location, value=other)) | ||
return _noop | ||
|
||
def __imul__(self, other): | ||
self._operations.append(_operation("Mul", self._location, value=other)) | ||
alexcjohnson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return _noop | ||
|
||
def __itruediv__(self, other): | ||
self._operations.append(_operation("Div", self._location, value=other)) | ||
return _noop | ||
|
||
def append(self, item): | ||
self._operations.append(_operation("Append", self._location, value=item)) | ||
|
||
def prepend(self, item): | ||
self._operations.append(_operation("Prepend", self._location, value=item)) | ||
alexcjohnson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
def insert(self, index, item): | ||
self._operations.append( | ||
_operation("Insert", self._location, value=item, index=index) | ||
) | ||
|
||
def extend(self, item): | ||
if not isinstance(item, (list, tuple)): | ||
raise TypeError(f"{item} should be a list or tuple") | ||
self._operations.append(_operation("Extend", self._location, value=item)) | ||
|
||
def merge(self, item): | ||
alexcjohnson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if not isinstance(item, dict): | ||
raise TypeError(f"{item} should be a dictionary") | ||
self._operations.append(_operation("Merge", self._location, value=item)) | ||
|
||
def to_plotly_json(self): | ||
return { | ||
"__dash_patch_update": "__dash_patch_update", | ||
"operations": self._operations, | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.