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

   ## Purpose
   
   PR #7746 added abstract tag stubs to `Catalog` and a complete `RESTCatalog` 
implementation, but left `FileSystemCatalog` inheriting `NotImplementedError`. 
The merge note said implementing filesystem tag CRUD required porting a Python 
`TagManager`. As it turns out, `pypaimon/tag/tag_manager.py::TagManager` and 
`FileStoreTable.create_tag` / `delete_tag` / `list_tags` / `tag_manager()` 
**already exist on master**, so this PR is a thin catalog-layer wrapper that 
delegates to those helpers and translates `ValueError` / return-value-`False` 
into the typed catalog exceptions used by the rest of the API.
   
   ## Linked issue
   
   Follow-up to #7746 — closes the FileSystemCatalog gap noted in that PR's 
"Out of scope" section.
   
   ## Tests
   
   - **`pypaimon/tests/filesystem_catalog_tag_test.py`** (12 new cases) — 
mirrors `RESTCatalogTagCRUDTest` on the local filesystem path:
     - `test_create_and_get_tag`, `test_create_tag_with_snapshot_id`
     - `test_create_tag_already_exists_raises`, 
`test_create_tag_already_exists_ignore`
     - `test_create_tag_with_time_retained_raises_not_implemented` 
(filesystem-only)
     - `test_create_tag_table_not_exists`
     - `test_get_tag_not_exists`
     - `test_delete_tag_happy`, `test_delete_tag_not_exists`
     - `test_list_tags_paged_basic` (paging via `max_results` + 
`next_page_token`)
     - `test_list_tags_paged_with_prefix`, `test_list_tags_paged_empty_table`
   - **`pypaimon/tests/rest/rest_tag_test.py`** — removed the now-stale 
`FilesystemCatalogTagInheritsNotImplementedTest` class (its assertions no 
longer hold; new behavior is covered by the new file). Cleaned up unused 
imports left behind.
   - Regression: `pypaimon/tests/api/test_tag_dto_serde.py` (8 cases) and the 
REST tag test matrix (11 cases) all still pass.
   - All edited files pass `flake8 --config=dev/cfg.ini`.
   
   ## API and format
   
   No new public Catalog method or wire format. This PR only **overrides** the 
four existing abstract stubs in `FileSystemCatalog`:
   
   | Method | Delegate / behavior |
   |---|---|
   | `create_tag` | `table.create_tag(tag_name, snapshot_id, 
ignore_if_exists)`. `ValueError("...already exists.")` → 
`TagAlreadyExistException` (only when `not ignore_if_exists`). |
   | `delete_tag` | `table.delete_tag(tag_name) -> bool`. `False` → 
`TagNotExistException`. |
   | `get_tag` | `table.tag_manager().get(tag_name) -> Optional[Tag]`. `None` → 
`TagNotExistException`. Result wrapped in `GetTagResponse` with 
`snapshot=tag.trim_to_snapshot()`. |
   | `list_tags_paged` | `table.list_tags() -> List[str]`. Client-side 
lexicographic sort + prefix filter + `page_token` continuation cursor (no Java 
equivalent of paged listing exists in `TagManager` itself). |
   
   ## Documentation
   
   n/a — this is a parity fix for an existing public API.
   
   ## Out of scope (separate PRs)
   
   - **`time_retained` real support** — Python's `Tag` dataclass currently 
inherits only `Snapshot` fields and has no place to store `tag_create_time` / 
`tag_time_retained`. This PR rejects `time_retained != None` with 
`NotImplementedError` rather than silently dropping it (which would mislead 
callers about TTL effects). Extending `Tag` + `TagManager.create_tag` to carry 
these fields requires a coordinated change to the on-disk tag JSON format and 
is tracked as a follow-up.
   - **`GetTagResponse.tag_create_time`** — for the same reason, this catalog 
returns `None` for `tag_create_time` and `tag_time_retained`. Cross-`FileIO` 
mtime extraction is not reliable (different `FileIO` implementations expose 
different metadata).
   - **Branch CRUD on FileSystemCatalog** — branch CRUD requires the abstract 
`rename_branch` stub and `BranchAlreadyExistException` handling introduced by 
#7747 (still under review). The sister PR for FileSystemCatalog branch CRUD 
will follow once #7747 lands.
   - **Tag callbacks** — Java has them; Python doesn't, and they're not needed 
for filesystem semantics.
   
   ## Verification
   
   ```bash
   # Targeted
   pytest pypaimon/tests/filesystem_catalog_tag_test.py -v
   
   # Regression
   pytest pypaimon/tests/rest/rest_tag_test.py 
pypaimon/tests/api/test_tag_dto_serde.py -v
   
   # Master-vs-fix
   git stash
   python -c "from pypaimon.catalog.filesystem_catalog import 
FileSystemCatalog; \
              print('create_tag in __dict__:', 'create_tag' in 
FileSystemCatalog.__dict__)"
   # Expected: False (master inherits NotImplementedError)
   git stash pop
   python -c "..."  # Expected: True (PR adds the override)
   
   # Lint
   flake8 --config=dev/cfg.ini pypaimon/catalog/filesystem_catalog.py \
                               pypaimon/tests/filesystem_catalog_tag_test.py \
                               pypaimon/tests/rest/rest_tag_test.py
   ```
   
   ## Generative AI disclosure
   
   Implementation, tests, and PR description were drafted with the assistance 
of Claude (Anthropic). Claude was supplied with the existing pypaimon helpers 
(`TagManager`, `FileStoreTable.create_tag` / `delete_tag` / `list_tags`, 
`RESTCatalog.create_tag`'s exception mapping pattern from #7746) and the REST 
tag test matrix; 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