TheR1sing3un opened a new pull request, #7746:
URL: https://github.com/apache/paimon/pull/7746

   ## Purpose
   
   `pypaimon`'s `Catalog` ABC has stubs for branch CRUD (`create_branch` / 
`drop_branch` / `list_branches` / `fast_forward`) but no tag methods at all — 
calling `catalog.create_tag(...)` on master raises `AttributeError`. Java's 
`Catalog` (`paimon-core/.../catalog/Catalog.java:914-985`) defines `createTag` 
/ `getTag` / `listTagsPaged` / `deleteTag`. This PR ports that surface to 
Python with a complete `RESTCatalog` implementation.
   
   `FilesystemCatalog` inherits the abstract `NotImplementedError` stubs 
(mirrors how it inherits the existing branch stubs). A concrete filesystem 
implementation requires a Python-side `TagManager` port and is tracked as a 
separate follow-up.
   
   ## Linked issue
   
   n/a — closing an API gap surfaced while auditing pypaimon's `Catalog` 
against the Java contract.
   
   ## Tests
   
   - `pypaimon/tests/api/test_tag_dto_serde.py` — 8 unit tests pinning the wire 
format to Java: exact JSON field names (`tagName` / `snapshotId` / 
`timeRetained` / `tagCreateTime` / `tagTimeRetained` / `tags` / 
`nextPageToken`), URL templates (`databases/{db}/tables/{tbl}/tags[/{tag}]`), 
and an explicit assertion that `ignoreIfExists` is **not** serialized.
   - `pypaimon/tests/rest/rest_tag_test.py` — 11 end-to-end tests against the 
in-process mock REST server mirroring Java `RESTCatalogTest::testTags` 
(`paimon-core/.../rest/RESTCatalogTest.java:2194`): create/get, list-paged with 
`max_results` and `tag_name_prefix`, create with `snapshot_id` / 
`time_retained`, already-exists with and without `ignore_if_exists`, table/tag 
not-found, delete, delete-not-exists. Plus 4 tests verifying 
`FilesystemCatalog` raises `NotImplementedError` (proves the abstract API gap 
is closed: master raises `AttributeError`).
   - Regression: `pypaimon/tests/rest/rest_simple_test.py rest_function_test.py 
rest_catalog_test.py` (52 tests) all pass unchanged.
   - All new files pass `flake8 --config=dev/cfg.ini`.
   
   ## API and format
   
   Adds new public methods on `Catalog`: `create_tag`, `delete_tag`, `get_tag`, 
`list_tags_paged`. Defaults raise `NotImplementedError` — non-breaking: any 
subclass that does not override behaves the same as before for users (their 
usage produces an explicit error instead of `AttributeError`).
   
   Wire format additions:
   
   | Endpoint | Method | DTO |
   |---|---|---|
   | `/v1/{prefix}/databases/{db}/tables/{tbl}/tags` | POST | `CreateTagRequest 
{ tagName, snapshotId?, timeRetained? }` |
   | `/v1/{prefix}/databases/{db}/tables/{tbl}/tags` | GET (paged) | query: 
`maxResults` / `pageToken` / `tagNamePrefix`; response: `ListTagsResponse { 
tags, nextPageToken }` |
   | `/v1/{prefix}/databases/{db}/tables/{tbl}/tags/{tag}` | GET | 
`GetTagResponse { tagName, snapshot, tagCreateTime?, tagTimeRetained? }` |
   | `/v1/{prefix}/databases/{db}/tables/{tbl}/tags/{tag}` | DELETE | — |
   
   These are wire-compatible with the existing Java REST server 
(`paimon-api/.../rest/requests/CreateTagRequest.java`, 
`responses/GetTagResponse.java`, `responses/ListTagsResponse.java`, 
`RESTApi.java:1062-1123`, `RESTCatalog.java:1056-1182`).
   
   New typed exception `TagAlreadyExistException` in `catalog_exception.py` 
(mirrors existing `BranchAlreadyExistException`).
   
   ## Documentation
   
   n/a — this is an API gap closure. Existing Java docs cover the semantics; 
the Python port mirrors Java behavior verbatim.
   
   ## Out of scope (separate PRs)
   
   - `FilesystemCatalog` tag implementation — needs a Python-side `TagManager` 
port (corresponds to Java `paimon-core/.../utils/TagManager.java`).
   - Branch REST gaps (`drop_branch` / `rename_branch` / `fast_forward` REST 
impls) — currently only `create_branch` / `list_branches` are usable; the rest 
still raise `NotImplementedError`.
   - CLI `pypaimon tag {create,list,delete}` — pypaimon CLI has no branch 
commands either; tag commands tracked separately.
   - Tag callbacks (Java `TagCallback`) — niche.
   - Typed `SnapshotNotExistException` — Java has it, pypaimon does not yet; 
the create_tag SNAPSHOT-not-exists branch raises plain `ValueError` with the 
same message until another caller demands the typed class.
   
   ## Strict-Java-alignment checklist
   
   - [x] `CreateTagRequest` has exactly three JSON fields: `tagName` / 
`snapshotId` / `timeRetained`. `grep -nE 'ignoreIfExists|ignore_if_exists' 
pypaimon/api/api_request.py pypaimon/api/api_response.py` returns no 
field-level hits (only an explanatory comment). `ignore_if_exists` lives only 
on `Catalog.create_tag` / `RESTCatalog.create_tag` parameters and is never 
serialized. Asserted by `test_to_json_minimal`.
   - [x] List-paged query keys (`maxResults` / `pageToken` / `tagNamePrefix`) 
match Java `RESTApi.java:157` constants exactly.
   - [x] URL builders produce 
`/v1/{prefix}/databases/{db}/tables/{tbl}/tags[/{tag}]` 
character-for-character; asserted by `test_resource_paths_tags_url`.
   - [x] JSON field names asserted by `test_to_json_full_uses_java_field_names` 
and `test_from_json_populates_all_fields`.
   - [x] HTTP-to-exception mapping mirrors Java `RESTCatalog.java:1100-1182` 
line-for-line; rebased comments in `rest_catalog.py` reference the Java line 
numbers.
   
   ## Generative AI disclosure
   
   Implementation, tests, and PR description were drafted with the assistance 
of Claude (Anthropic). Claude was supplied with the Java reference files 
(`Catalog.java`, `RESTCatalog.java`, `RESTApi.java`, `CreateTagRequest.java`, 
`GetTagResponse.java`, `ListTagsResponse.java`) and the existing pypaimon 
patterns (`list_partitions_paged`, `create_function`, `RESTBaseTest`); the 
design plan and code were reviewed and integrated by the author.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to