-
Notifications
You must be signed in to change notification settings - Fork 53
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
Add support for patching, merging, replacing metadata #688
Conversation
hyperrealist
commented
Mar 11, 2024
•
edited
Loading
edited
- patch_metadata uses a http patch request with application/json-patch+json content type
- merge_metadata can be triggered with a http patch request and application/merge-patch+json
- update_metadata uses a similar approach to merge_metadata, but constructs a json-patch on the client-side
- add jsonpatch and json-merge-patch to requirements
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.
Looks good. I think the main thing that's missing is implementing the new adapters methods on the SQL-backed adapter in Tiled itself.
tiled/tiled/catalog/adapter.py
Line 814 in 3b07e5f
async def update_metadata(self, metadata=None, specs=None): |
In a later PR, we could even look into pushing the patch representation all the way into SQL, but to start I think applying the path in Python and doing a full replace in SQL is the way to go.
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.
Looked at this earlier on a call with Dan, not seeing anything too out of the ordinary that he hasn't already touched on.
2f1a0a7
to
709812f
Compare
@danielballan, @Kezzsim this PR is ready for another review. Changes since your last review are minimal, though it took me an obscene amount of time to figure this out. |
tiled/server/schemas.py
Outdated
specs: Optional[Specs] | ||
|
||
# Wait for fix https://github.com/pydantic/pydantic/issues/3957 | ||
# to do this with `unique_items` parameters to `pydantic.constr`. |
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.
Looks like they've fixed it already in ver 1.10.12 (we use 1.10.13). Would it be worthwhile just uncommenting line 86?
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.
or maybe in a separate PR?
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 marked this one as resolved by mistake. This came from a part of code I copied from @danielballan. Not exactly sure what needs to be done here, but I agree maybe it should be a separate PR.
I pushed a couple of commits addressing suggestions from @danielballan and @genematx. Also added an option in |
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.
One note in line on the latest changes.
Also:
- @skarakuzu recently added a CHANGELOG. Can you add a line item for this?
- Can these methods be added to the API reference? It looks like
update_metadata
was never added, and the new methods should be added too.
I’ve asked @Kezzsim to test drive this locally a bit before we merge. Merge away when you are satisfied, Kari! |
24ecb57
to
7af28d1
Compare
Rebased and force-pushed to resolve merge conflicts with #695 |
Tests failed due to an incompatibility with pydantic 2.x, introduced by #695. I have pushed a commit with a fix. |
This looks good, however I'm noticing a break from convention when it comes to how HTTP is implemented. Pulling up swagger docs on http://127.0.0.1:8000/docs reveals that Example of current request body [dict]: {
"patch": [
{
"op": "replace",
"path": "/test",
"value": "testing"
}
],
"specs": null
} Proposed json patch implementation of body [list]:
Fixing this to have it be within spec would require one of two potential changes:
@danielballan mentioned pulling in @dylanmcreynolds since he has a good eye for making similar API design decisions that are both conforming to spec and aesthetically pleasing. I'd like to see what his suggestion is. |
Thanks @Kezzsim, this is something that had been bothering me in the background at times. I appreciate your attention to detail!
{
"type": "application/json-patch+json", # could default to this. may also support aliases "json-patch"
"metadata": [
{
"op": "replace",
"path": "/test",
"value": "testing"
}
],
"specs": [],
} and {
"type": "application/merge-patch+json", # or "merge-patch" / "merge"
"metadata": {"test": "testing"},
"specs": [],
} All these solutions would conform to http spec, but I am leaning toward solutions 1 or 4 for their conceptual simplicity and ease of implementation. Anyway, I am completely open to other ideas and design considerations. |
Yes, good catch @Kezzsim! And thanks for presenting some additional options @hyperrealist. Some additional design considerations: Option (1) would break symmetry between GET and PATCH, as I can foresee adding support for patching data sources, alongside metadata and specs, which would make the downsides with (2) and (3) even more salient. I can see no problems with (4). There was something appealing about specifying the patch format in the If we go that way, it is worth considering options for what to name the key. Is it |
I very much intentionally wanted to avoid calling it |
Seeing 👍s from @Kezzsim and myself, I think going ahead with (4) with name |
I'm not sure I understand the hesitance about calling it |
CI errors for Python 3.11 are coming from dask's incompatibility with 3.11.9 (fixed in 2024.4.1). Github CI uses 3.11.9, so it is broken at the moment. I pinned python<3.11.9 for now [on second thought, let me actually remove the pin so that you can see the errors], but I am not sure if I should attempt to resolve this issue in this PR. We should probably update to dask 2024.4.1. With that note, I think this ready for another review, @danielballan @Kezzsim @genematx. I did not implement patch for specs, but just for metadata. If you think patching specs makes sense I can add that. |
tiled/server/router.py
Outdated
detail="This node does not support update of metadata.", | ||
) | ||
|
||
if body.content_type in [ |
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.
In the spirit of, "Adhere to standards wherever possible," I would prefer to start with strictly accepting application/json-patch+json
and application/merge-patch+json
here. The use case for aliases seems narrow to me. The MIME type are unambiguous, Google-able, and easy enough to copy/paste from examples, or achieve through tooling like the Tiled Python client.
At least, I would wait to add aliases until/unless there is demonstrated demand for it that cannot be easily addressed another way. It's easy to add this later if we need to, but hard to remove once supported.
|
||
class HyphenizedBaseModel(pydantic.BaseModel): | ||
# This model configuration allows aliases like "content-type" | ||
model_config = ConfigDict(alias_generator=lambda f: f.replace("_", "-")) |
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.
Clever!
FYI, @hyperrealist, you may have seen this go by already but in case not, the CI failures on Python 3.11 are not the fault of this PR and can be ignored. See #715. |
fbaa3f2
to
3bdfe03
Compare
Co-authored-by: Dan Allan <[email protected]>
a9d7a09
to
471c097
Compare
I played with this locally. It works as advertised. I really like the ease of use of I took the liberty of rebasing on Will merge when CI passes. |