From 494b33e4d9a6ffcbddcfe319bd2bc9383461ed09 Mon Sep 17 00:00:00 2001 From: Fangyin Cheng Date: Fri, 7 Nov 2025 13:38:02 +0800 Subject: [PATCH] fix(python): fix dot delimiter error --- .../lance_namespace/src/lance_namespace/rest.py | 17 ++++++++++++++--- python/lance_namespace/tests/test_rest.py | 5 +++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/python/lance_namespace/src/lance_namespace/rest.py b/python/lance_namespace/src/lance_namespace/rest.py index cd6c2c3c..e56da8b1 100644 --- a/python/lance_namespace/src/lance_namespace/rest.py +++ b/python/lance_namespace/src/lance_namespace/rest.py @@ -102,8 +102,14 @@ def object_id_str(id_list: list[str], delimiter: str = ".", obj: Any = None) -> object_type = type(obj).__name__ if obj is not None else "Unknown" raise ValueError(f"Object of type '{object_type}' must have an 'id' field") if len(id_list) == 0: - return delimiter - return delimiter.join(id_list) + id_str = delimiter + else: + id_str = delimiter.join(id_list) + if id_str == ".": + # https://github.com/lancedb/lance-namespace/issues/248 + # Escape single dot to avoid server path normalization issues + id_str = "%2E" + return id_str class LanceRestNamespace(LanceNamespace): @@ -111,14 +117,19 @@ class LanceRestNamespace(LanceNamespace): def __init__(self, **kwargs): configuration = Configuration() + config = RestNamespaceConfig(kwargs) if "uri" in kwargs: configuration.host = kwargs["uri"] + if "safe_chars_for_path_param" in kwargs: + configuration.safe_chars_for_path_param = kwargs["safe_chars_for_path_param"] + if config.delimiter() == "." and not configuration.safe_chars_for_path_param: + configuration.safe_chars_for_path_param = "%" self.api_client = ApiClient(configuration) self.namespace_api = NamespaceApi(self.api_client) self.table_api = TableApi(self.api_client) self.transaction_api = TransactionApi(self.api_client) - self.config = RestNamespaceConfig(kwargs) + self.config = config self.uri = kwargs.get("uri", "") def namespace_id(self) -> str: diff --git a/python/lance_namespace/tests/test_rest.py b/python/lance_namespace/tests/test_rest.py index f1475605..59fc1aab 100644 --- a/python/lance_namespace/tests/test_rest.py +++ b/python/lance_namespace/tests/test_rest.py @@ -93,10 +93,11 @@ def test_object_id_with_list_id(): assert object_id_str(obj.id, ".", obj) == "ns1.ns2.table1" def test_object_id_with_empty_list_id(): - """Test object with empty id list returns delimiter.""" + """Test object with empty id list returns delimiter. + Single dot will be escaped to %2E.""" obj = Mock() obj.id = [] - assert object_id_str(obj.id, ".", obj) == "." + assert object_id_str(obj.id, ".", obj) == "%2E" def test_object_id_with_string_id(): """Test object with id field as list containing single string."""