11from __future__ import annotations
22
33import asyncio
4+ import contextlib
45from collections import defaultdict
56from collections .abc import Iterable
67from typing import TYPE_CHECKING , Any , TypedDict
@@ -70,17 +71,22 @@ async def get(
7071 return prototype .buffer .from_bytes (await resp .bytes_async ())
7172
7273 start , end = byte_range
74+ if (start is None or start == 0 ) and end is None :
75+ resp = await obs .get_async (self .store , key )
76+ return prototype .buffer .from_bytes (await resp .bytes_async ())
7377 if start is not None and end is not None :
7478 resp = await obs .get_range_async (self .store , key , start = start , end = end )
7579 return prototype .buffer .from_bytes (memoryview (resp ))
7680 elif start is not None :
77- if start >= 0 :
81+ if start > 0 :
7882 # Offset request
7983 resp = await obs .get_async (self .store , key , options = {"range" : {"offset" : start }})
8084 else :
8185 resp = await obs .get_async (self .store , key , options = {"range" : {"suffix" : start }})
82-
8386 return prototype .buffer .from_bytes (await resp .bytes_async ())
87+ elif end is not None :
88+ resp = await obs .get_range_async (self .store , key , start = 0 , end = end )
89+ return prototype .buffer .from_bytes (memoryview (resp ))
8490 else :
8591 raise ValueError (f"Unexpected input to `get`: { start = } , { end = } " )
8692
@@ -104,18 +110,22 @@ def supports_writes(self) -> bool:
104110 return True
105111
106112 async def set (self , key : str , value : Buffer ) -> None :
113+ self ._check_writable ()
107114 buf = value .to_bytes ()
108115 await obs .put_async (self .store , key , buf )
109116
110117 async def set_if_not_exists (self , key : str , value : Buffer ) -> None :
118+ self ._check_writable ()
111119 buf = value .to_bytes ()
112- await obs .put_async (self .store , key , buf , mode = "create" )
120+ with contextlib .suppress (obs .exceptions .AlreadyExistsError ):
121+ await obs .put_async (self .store , key , buf , mode = "create" )
113122
114123 @property
115124 def supports_deletes (self ) -> bool :
116125 return True
117126
118127 async def delete (self , key : str ) -> None :
128+ self ._check_writable ()
119129 await obs .delete_async (self .store , key )
120130
121131 @property
@@ -158,12 +168,13 @@ async def _transform_list_dir(
158168 # We assume that the underlying object-store implementation correctly handles the
159169 # prefix, so we don't double-check that the returned results actually start with the
160170 # given prefix.
161- prefix_len = len (prefix )
171+ prefix_len = len (prefix ) + 1 # If one is not added to the length, all items will contain "/"
162172 async for batch in list_stream :
163173 for item in batch :
164- # Yield this item if "/" does not exist after the prefix.
165- if "/" not in item ["path" ][prefix_len :]:
166- yield item ["path" ]
174+ # Yield this item if "/" does not exist after the prefix
175+ item_path = item ["path" ][prefix_len :]
176+ if "/" not in item_path :
177+ yield item_path
167178
168179
169180class _BoundedRequest (TypedDict ):
0 commit comments