Skip to content

Commit f2d907c

Browse files
committed
address comments from kevin
1 parent 74562d1 commit f2d907c

File tree

2 files changed

+62
-174
lines changed

2 files changed

+62
-174
lines changed

pyiceberg/catalog/rest/__init__.py

Lines changed: 30 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,6 @@ class Endpoint(IcebergBaseModel):
9292
@field_validator("path", mode="before")
9393
@classmethod
9494
def _validate_path(cls, raw_path: str) -> str:
95-
if not raw_path:
96-
raise ValueError("Invalid path: empty")
9795
raw_path = raw_path.strip()
9896
if not raw_path:
9997
raise ValueError("Invalid path: empty")
@@ -104,10 +102,8 @@ def __str__(self) -> str:
104102
return f"{self.http_method.value} {self.path}"
105103

106104
@classmethod
107-
def from_string(cls, endpoint: str | None) -> "Endpoint":
108-
if endpoint is None:
109-
raise ValueError("Invalid endpoint (must consist of 'METHOD /path'): None")
110-
elements = endpoint.split(None, 1)
105+
def from_string(cls, endpoint: str) -> "Endpoint":
106+
elements = endpoint.strip().split(None, 1)
111107
if len(elements) != 2:
112108
raise ValueError(f"Invalid endpoint (must consist of two elements separated by a single space): {endpoint}")
113109
return cls(http_method=HttpMethod(elements[0].upper()), path=elements[1])
@@ -137,36 +133,31 @@ class Endpoints:
137133
fetch_scan_tasks: str = "namespaces/{namespace}/tables/{table}/tasks"
138134

139135

136+
API_PREFIX = "/v1/{prefix}"
137+
138+
140139
class Capability:
141-
V1_LIST_NAMESPACES = Endpoint(http_method=HttpMethod.GET, path="/v1/{prefix}/namespaces")
142-
V1_LOAD_NAMESPACE = Endpoint(http_method=HttpMethod.GET, path="/v1/{prefix}/namespaces/{namespace}")
143-
V1_NAMESPACE_EXISTS = Endpoint(http_method=HttpMethod.HEAD, path="/v1/{prefix}/namespaces/{namespace}")
144-
V1_UPDATE_NAMESPACE = Endpoint(http_method=HttpMethod.POST, path="/v1/{prefix}/namespaces/{namespace}/properties")
145-
V1_CREATE_NAMESPACE = Endpoint(http_method=HttpMethod.POST, path="/v1/{prefix}/namespaces")
146-
V1_DELETE_NAMESPACE = Endpoint(http_method=HttpMethod.DELETE, path="/v1/{prefix}/namespaces/{namespace}")
147-
148-
V1_LIST_TABLES = Endpoint(http_method=HttpMethod.GET, path="/v1/{prefix}/namespaces/{namespace}/tables")
149-
V1_LOAD_TABLE = Endpoint(http_method=HttpMethod.GET, path="/v1/{prefix}/namespaces/{namespace}/tables/{table}")
150-
V1_TABLE_EXISTS = Endpoint(http_method=HttpMethod.HEAD, path="/v1/{prefix}/namespaces/{namespace}/tables/{table}")
151-
V1_CREATE_TABLE = Endpoint(http_method=HttpMethod.POST, path="/v1/{prefix}/namespaces/{namespace}/tables")
152-
V1_UPDATE_TABLE = Endpoint(http_method=HttpMethod.POST, path="/v1/{prefix}/namespaces/{namespace}/tables/{table}")
153-
V1_DELETE_TABLE = Endpoint(http_method=HttpMethod.DELETE, path="/v1/{prefix}/namespaces/{namespace}/tables/{table}")
154-
V1_RENAME_TABLE = Endpoint(http_method=HttpMethod.POST, path="/v1/{prefix}/tables/rename")
155-
V1_REGISTER_TABLE = Endpoint(http_method=HttpMethod.POST, path="/v1/{prefix}/namespaces/{namespace}/register")
156-
157-
V1_LIST_VIEWS = Endpoint(http_method=HttpMethod.GET, path="/v1/{prefix}/namespaces/{namespace}/views")
158-
V1_LOAD_VIEW = Endpoint(http_method=HttpMethod.GET, path="/v1/{prefix}/namespaces/{namespace}/views/{view}")
159-
V1_VIEW_EXISTS = Endpoint(http_method=HttpMethod.HEAD, path="/v1/{prefix}/namespaces/{namespace}/views/{view}")
160-
V1_CREATE_VIEW = Endpoint(http_method=HttpMethod.POST, path="/v1/{prefix}/namespaces/{namespace}/views")
161-
V1_UPDATE_VIEW = Endpoint(http_method=HttpMethod.POST, path="/v1/{prefix}/namespaces/{namespace}/views/{view}")
162-
V1_DELETE_VIEW = Endpoint(http_method=HttpMethod.DELETE, path="/v1/{prefix}/namespaces/{namespace}/views/{view}")
163-
V1_RENAME_VIEW = Endpoint(http_method=HttpMethod.POST, path="/v1/{prefix}/views/rename")
164-
V1_SUBMIT_TABLE_SCAN_PLAN = Endpoint(
165-
http_method=HttpMethod.POST, path="/v1/{prefix}/namespaces/{namespace}/tables/{table}/plan"
166-
)
167-
V1_TABLE_SCAN_PLAN_TASKS = Endpoint(
168-
http_method=HttpMethod.POST, path="/v1/{prefix}/namespaces/{namespace}/tables/{table}/tasks"
169-
)
140+
V1_LIST_NAMESPACES = Endpoint(http_method=HttpMethod.GET, path=f"{API_PREFIX}/{Endpoints.list_namespaces}")
141+
V1_LOAD_NAMESPACE = Endpoint(http_method=HttpMethod.GET, path=f"{API_PREFIX}/{Endpoints.load_namespace_metadata}")
142+
V1_NAMESPACE_EXISTS = Endpoint(http_method=HttpMethod.HEAD, path=f"{API_PREFIX}/{Endpoints.namespace_exists}")
143+
V1_UPDATE_NAMESPACE = Endpoint(http_method=HttpMethod.POST, path=f"{API_PREFIX}/{Endpoints.update_namespace_properties}")
144+
V1_CREATE_NAMESPACE = Endpoint(http_method=HttpMethod.POST, path=f"{API_PREFIX}/{Endpoints.create_namespace}")
145+
V1_DELETE_NAMESPACE = Endpoint(http_method=HttpMethod.DELETE, path=f"{API_PREFIX}/{Endpoints.drop_namespace}")
146+
147+
V1_LIST_TABLES = Endpoint(http_method=HttpMethod.GET, path=f"{API_PREFIX}/{Endpoints.list_tables}")
148+
V1_LOAD_TABLE = Endpoint(http_method=HttpMethod.GET, path=f"{API_PREFIX}/{Endpoints.load_table}")
149+
V1_TABLE_EXISTS = Endpoint(http_method=HttpMethod.HEAD, path=f"{API_PREFIX}/{Endpoints.table_exists}")
150+
V1_CREATE_TABLE = Endpoint(http_method=HttpMethod.POST, path=f"{API_PREFIX}/{Endpoints.create_table}")
151+
V1_UPDATE_TABLE = Endpoint(http_method=HttpMethod.POST, path=f"{API_PREFIX}/{Endpoints.update_table}")
152+
V1_DELETE_TABLE = Endpoint(http_method=HttpMethod.DELETE, path=f"{API_PREFIX}/{Endpoints.drop_table}")
153+
V1_RENAME_TABLE = Endpoint(http_method=HttpMethod.POST, path=f"{API_PREFIX}/{Endpoints.rename_table}")
154+
V1_REGISTER_TABLE = Endpoint(http_method=HttpMethod.POST, path=f"{API_PREFIX}/{Endpoints.register_table}")
155+
156+
V1_LIST_VIEWS = Endpoint(http_method=HttpMethod.GET, path=f"{API_PREFIX}/{Endpoints.list_views}")
157+
V1_VIEW_EXISTS = Endpoint(http_method=HttpMethod.HEAD, path=f"{API_PREFIX}/{Endpoints.view_exists}")
158+
V1_DELETE_VIEW = Endpoint(http_method=HttpMethod.DELETE, path=f"{API_PREFIX}/{Endpoints.drop_view}")
159+
V1_SUBMIT_TABLE_SCAN_PLAN = Endpoint(http_method=HttpMethod.POST, path=f"{API_PREFIX}/{Endpoints.plan_table_scan}")
160+
V1_TABLE_SCAN_PLAN_TASKS = Endpoint(http_method=HttpMethod.POST, path=f"{API_PREFIX}/{Endpoints.fetch_scan_tasks}")
170161

171162

172163
# Default endpoints for backwards compatibility with legacy servers that don't return endpoints
@@ -231,6 +222,8 @@ class IdentifierKind(Enum):
231222
CUSTOM = "custom"
232223
REST_SCAN_PLANNING_ENABLED = "rest-scan-planning-enabled"
233224
REST_SCAN_PLANNING_ENABLED_DEFAULT = False
225+
# for backwards compatibility with older REST servers where it can be assumed that a particular
226+
# server supports view endpoints but doesn't send the "endpoints" field in the ConfigResponse
234227
VIEW_ENDPOINTS_SUPPORTED = "view-endpoints-supported"
235228
VIEW_ENDPOINTS_SUPPORTED_DEFAULT = False
236229

@@ -966,7 +959,7 @@ def update_namespace_properties(
966959
def namespace_exists(self, namespace: str | Identifier) -> bool:
967960
namespace_tuple = self._check_valid_namespace_identifier(namespace)
968961
namespace = NAMESPACE_SEPARATOR.join(namespace_tuple)
969-
962+
# fallback in order to work with older rest catalog implementations
970963
if Capability.V1_NAMESPACE_EXISTS not in self._supported_endpoints:
971964
try:
972965
self.load_namespace_properties(namespace_tuple)
@@ -998,6 +991,7 @@ def table_exists(self, identifier: str | Identifier) -> bool:
998991
Returns:
999992
bool: True if the table exists, False otherwise.
1000993
"""
994+
# fallback in order to work with older rest catalog implementations
1001995
if Capability.V1_TABLE_EXISTS not in self._supported_endpoints:
1002996
try:
1003997
self.load_table(identifier)

0 commit comments

Comments
 (0)