Skip to content

Commit b2cd0fd

Browse files
fix(rest): refine S3-compatible scheme fallback
1 parent 807c554 commit b2cd0fd

2 files changed

Lines changed: 21 additions & 6 deletions

File tree

pyiceberg/catalog/rest/__init__.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,9 @@ class ListViewsResponse(IcebergBaseModel):
392392
_PLANNING_RESPONSE_ADAPTER = TypeAdapter(PlanningResponse)
393393

394394

395+
_S3_COMPATIBLE_SCHEMES = ("s3://", "s3a://", "s3n://", "oss://")
396+
397+
395398
def _is_hadoop_only_config(config: Properties) -> bool:
396399
"""Return True if every key is a Hadoop ``fs.*`` key — pyiceberg has no HadoopFileIO to consume them."""
397400
return bool(config) and all(k.startswith("fs.") for k in config)
@@ -483,10 +486,8 @@ def _resolve_storage_credentials(storage_credentials: list[StorageCredential], l
483486
if best_match is None or len(cred.prefix) > len(best_match.prefix):
484487
best_match = cred
485488

486-
# Java S3FileIO falls back to the "s3" ROOT_PREFIX credential; scope it to
487-
# schemes pyarrow's S3FileSystem handles so non-S3 schemes (gs://, abfs://,
488-
# etc.) don't get handed s3.* keys.
489-
if best_match is None and location.startswith(("s3://", "s3a://", "s3n://", "oss://")):
489+
# Mirrors Java S3FileIO.clientForStoragePath() ROOT_PREFIX fallback.
490+
if best_match is None and location.startswith(_S3_COMPATIBLE_SCHEMES):
490491
best_match = next((c for c in consumable if c.prefix == "s3"), None)
491492

492493
return best_match.config if best_match else {}

tests/catalog/test_rest.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2877,10 +2877,24 @@ def test_resolve_storage_credentials_all_hadoop_only_returns_empty() -> None:
28772877
assert RestCatalog._resolve_storage_credentials(credentials, "custom://bucket/path") == {}
28782878

28792879

2880-
def test_resolve_storage_credentials_root_prefix_fallback_for_s3_compatible_scheme() -> None:
2880+
def test_resolve_storage_credentials_s3a_s3n_match_root_prefix_directly() -> None:
28812881
from pyiceberg.catalog.rest.scan_planning import StorageCredential
28822882

2883-
# oss:// is routed through pyarrow's S3FileSystem, so ROOT_PREFIX "s3" applies.
2883+
# s3a:// and s3n:// start with "s3", so they match prefix="s3" via
2884+
# startswith at the normal matching stage — no fallback needed.
2885+
credentials = [
2886+
StorageCredential(prefix="s3", config={"s3.access-key-id": "native-k"}),
2887+
]
2888+
for scheme in ("s3a", "s3n"):
2889+
result = RestCatalog._resolve_storage_credentials(credentials, f"{scheme}://bucket/path")
2890+
assert result == {"s3.access-key-id": "native-k"}, f"{scheme}:// should match prefix='s3' directly"
2891+
2892+
2893+
def test_resolve_storage_credentials_root_prefix_fallback_for_oss() -> None:
2894+
from pyiceberg.catalog.rest.scan_planning import StorageCredential
2895+
2896+
# oss:// is S3-API-compatible; pyiceberg routes it through pyarrow's
2897+
# S3FileSystem, so the ROOT_PREFIX "s3" credential applies.
28842898
credentials = [
28852899
StorageCredential(prefix="s3", config={"s3.access-key-id": "native-k"}),
28862900
]

0 commit comments

Comments
 (0)