@@ -78,6 +78,69 @@ async def create_signed_upload_url(self, path: str) -> SignedUploadURL:
7878 "path" : path ,
7979 }
8080
81+ async def upload_to_signed_url (
82+ self ,
83+ path : str ,
84+ token : str ,
85+ file : Union [BufferedReader , bytes , FileIO , str , Path ],
86+ file_options : Optional [FileOptions ] = None ,
87+ ) -> Response :
88+ """
89+ Upload a file with a token generated from :meth:`.create_signed_url`
90+
91+ Parameters
92+ ----------
93+ path
94+ The file path, including the file name
95+ token
96+ The token generated from :meth:`.create_signed_url`
97+ file
98+ The file contents or a file-like object to upload
99+ file_options
100+ Additional options for the uploaded file
101+ """
102+ _path = self ._get_final_path (path )
103+ _url = urllib .parse .urlparse (f"/object/upload/sign/{ _path } " )
104+ query_params = urllib .parse .urlencode ({"token" : token })
105+ final_url = f"{ _url .geturl ()} ?{ query_params } "
106+
107+ if file_options is None :
108+ file_options = {}
109+
110+ cache_control = file_options .get ("cache-control" )
111+ if cache_control :
112+ file_options ["cache-control" ] = f"max-age={ cache_control } "
113+
114+ headers = {
115+ ** self ._client .headers ,
116+ ** DEFAULT_FILE_OPTIONS ,
117+ ** file_options ,
118+ }
119+ filename = path .rsplit ("/" , maxsplit = 1 )[- 1 ]
120+
121+ if (
122+ isinstance (file , BufferedReader )
123+ or isinstance (file , bytes )
124+ or isinstance (file , FileIO )
125+ ):
126+ # bytes or byte-stream-like object received
127+ _file = {"file" : (filename , file , headers .pop ("content-type" ))}
128+ else :
129+ # str or pathlib.path received
130+ _file = {
131+ "file" : (
132+ filename ,
133+ open (file , "rb" ),
134+ headers .pop ("content-type" ),
135+ )
136+ }
137+ return await self ._request (
138+ "PUT" ,
139+ final_url ,
140+ files = _file ,
141+ headers = headers ,
142+ )
143+
81144 async def create_signed_url (
82145 self , path : str , expires_in : int , options : CreateSignedURLOptions = {}
83146 ) -> dict [str , str ]:
@@ -281,13 +344,13 @@ async def upload(
281344 The File object to be stored in the bucket. or a async generator of chunks
282345 file_options
283346 HTTP headers.
284- The expected keys are:
285- `cache-control`: The number of seconds the asset is cached in the browser and in the Supabase CDN.
286- `content-type`: This SHOULD be set properly, otherwise the default value of text/plain will be used.
287- `x-upsert`: If set to true, the file will be updated if it already exists.
288347 """
289348 if file_options is None :
290349 file_options = {}
350+ cache_control = file_options .get ("cache-control" )
351+ if cache_control :
352+ file_options ["cache-control" ] = f"max-age={ cache_control } "
353+
291354 headers = {
292355 ** self ._client .headers ,
293356 ** DEFAULT_FILE_OPTIONS ,
0 commit comments