From 9c3fb2db360f3ad33e1ab7695fd672657788bb89 Mon Sep 17 00:00:00 2001 From: John Kerl Date: Tue, 19 Jul 2022 09:53:54 -0400 Subject: [PATCH] More REST-server call-avoidance (#223) * temp * narrow exception-type handling --- apis/python/src/tiledbsc/tiledb_group.py | 59 ++++++++++++++---------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/apis/python/src/tiledbsc/tiledb_group.py b/apis/python/src/tiledbsc/tiledb_group.py index fdcc4321ea..e377b842e7 100644 --- a/apis/python/src/tiledbsc/tiledb_group.py +++ b/apis/python/src/tiledbsc/tiledb_group.py @@ -88,9 +88,8 @@ def _open(self, mode: str = "r") -> tiledb.Group: It works asa `with self._open() as G:` as well as `G = self._open(); ...; G.close()`. """ assert mode in ("r", "w") - if mode == "r" and not self.exists(): - raise Exception(f"Does not exist: {self.uri}") # This works in with-open-as contexts because tiledb.Group has __enter__ and __exit__ methods. + # Raises an exception, as desired, if the group does not exist (or, doesn't exist _yet_). return tiledb.Group(self.uri, mode=mode, ctx=self._ctx) def _get_child_uris(self, member_names: Sequence[str]) -> Dict[str, str]: @@ -100,31 +99,43 @@ def _get_child_uris(self, member_names: Sequence[str]) -> Dict[str, str]: is reduced when we ask for all group-element name-to-URI mappings in a single request to the REST server. """ - if not self.exists(): - # Group not constructed yet. Here, appending "/" and name is appropriate in all - # cases: even for tiledb://... URIs, pre-construction URIs are of the form - # tiledb://namespace/s3://something/something/soma/membername. - return { - member_name: self.uri + "/" + member_name - for member_name in member_names - } - answer = {} + try: + # If the group exists, get URIs for elements. In local disk, S3, etc this is just + # concatenating a slash and the member name to the self URI; for TileDB Cloud, + # the member URIs involve UUIDs which are known to the server. + answer = {} - mapping = self._get_member_names_to_uris() - for member_name in member_names: - if member_name in mapping: - answer[member_name] = mapping[member_name] - else: - # Truly a slash, not os.path.join: - # * If the client is Linux/Un*x/Mac, it's the same of course - # * On Windows, os.path.sep is a backslash but backslashes are _not_ accepted for S3 or - # tiledb-cloud URIs, whereas in Windows versions for years now forward slashes _are_ - # accepted for local-disk paths. - # This means forward slash is acceptable in all cases. - answer[member_name] = self.uri + "/" + member_name + mapping = self._get_member_names_to_uris() + for member_name in member_names: + if member_name in mapping: + answer[member_name] = mapping[member_name] + else: + # Truly a slash, not os.path.join: + # * If the client is Linux/Un*x/Mac, it's the same of course + # * On Windows, os.path.sep is a backslash but backslashes are _not_ accepted for S3 or + # tiledb-cloud URIs, whereas in Windows versions for years now forward slashes _are_ + # accepted for local-disk paths. + # This means forward slash is acceptable in all cases. + answer[member_name] = self.uri + "/" + member_name + + return answer - return answer + except tiledb.cc.TileDBError as e: + stre = str(e) + # Local-disk/S3 does-not-exist exceptions say 'Group does not exist'; TileDB Cloud + # does-not-exist exceptions are worded less clearly. + if "Group does not exist" in stre or "HTTP code 401" in stre: + # Group not constructed yet, but we must return pre-creation URIs. Here, appending + # "/" and name is appropriate in all cases: even for tiledb://... URIs, + # pre-construction URIs are of the form + # tiledb://namespace/s3://something/something/soma/membername. + return { + member_name: self.uri + "/" + member_name + for member_name in member_names + } + else: + raise e def _get_child_uri(self, member_name: str) -> str: """