11import logging
22import asyncio
33
4- from .types import DirectIOResponse , Block
4+ from .types import Metadata , Block
55from .credentials import KeyPair , Bearer
66from .crypto import decrypt_key , decrypt_block
77from .decompressor import decompress
@@ -32,7 +32,7 @@ async def retry(coro, retries=3, backoff=1):
3232 if attempts == retries :
3333 raise error
3434 wait = backoff * (2 ** (attempts - 1 ))
35- logger .debug ('Failed attempt number %s. Retrying in %s seconds.' , attempts , wait )
35+ logger .debug ('Download of block failed on attempt %s. Retrying in %s seconds.. .' , attempts , wait )
3636 await asyncio .sleep (wait )
3737
3838
@@ -46,23 +46,51 @@ async def get_object(client, file_id, chunk):
4646 :rtype: bytes
4747 """
4848 async def get_object_coro ():
49- parameters = {'file_id' : file_id , 'number' : chunk .index , 'offset' : chunk .offset }
50- logger .debug ('Downloading Block. %s' , parameters )
49+
50+ message = (
51+ f"Downloading block #{ chunk .index } "
52+ f"(offset={ chunk .offset } , length={ chunk .length } )"
53+ )
54+
55+ if file_id :
56+ message += f" for file ID { file_id } "
57+
58+ error_message , exception = None , None
59+
60+ logger .debug (message )
5161 try :
5262 response = await client .get (chunk .url )
5363 return await response .read ()
5464 except ConnectionError :
55- logger . error ( 'Failed to download block. Connection error. %s' , parameters )
56- raise DownloadConnectionError (file_id , chunk )
65+ error_message = 'connection'
66+ exception = DownloadConnectionError (file_id , chunk )
5767 except asyncio .TimeoutError :
58- logger . error ( 'Failed to download block. Timed out. %s' , parameters )
59- raise DownloadTimeout (file_id , chunk )
68+ error_message = 'timeout'
69+ exception = DownloadTimeout (file_id , chunk )
6070 except IOError as error :
61- logger . error ( 'Failed to download block. IO Error. %s' , parameters )
62- raise DownloadError (error , file_id , chunk )
71+ error_message = 'io'
72+ exception = DownloadError (error , file_id , chunk )
6373 except ClientResponseException as error :
64- logger .error ('Failed to download block. Error. %s' , parameters )
65- raise DownloadError (error .response , file_id , chunk )
74+ error_message = 'unknown'
75+ exception = DownloadError (error .response , file_id , chunk )
76+
77+ error_messages = {
78+ "connection" : "Connection error" ,
79+ "timeout" : "Timed out" ,
80+ "io" : "I/O error" ,
81+ "unknown" : "Unknown error"
82+ }
83+
84+ message = (
85+ f"Failed to download block #{ chunk .index } "
86+ f"(offset={ chunk .offset } , length={ chunk .length } )"
87+ )
88+ if file_id :
89+ message = message + f" for file ID { file_id } "
90+
91+ message = message + f": { error_messages .get (error_message , 'Unknown error' )} ."
92+ logger .error (message )
93+ raise exception
6694
6795 return await retry (get_object_coro )
6896
@@ -118,9 +146,13 @@ async def process_chunk(client, file_id, chunk, encryption_key, semaphore):
118146 :rtype: cterasdk.direct.types.Block
119147 """
120148 async def process (client , chunk , encryption_key ):
121- parameters = {'file_id' : file_id , 'number' : chunk .index , 'offset' : chunk .offset }
122- logger .debug ('Processing Block. %s' , parameters )
123-
149+ message = (
150+ f"Processing block { chunk .index } "
151+ f"(offset={ chunk .offset } , length={ chunk .length } )"
152+ )
153+ if file_id :
154+ message = message + f" for file ID { file_id } "
155+ logger .debug (message )
124156 encrypted_object = await get_object (client , file_id , chunk )
125157 decrypted_object = await decrypt_object (file_id , encrypted_object , encryption_key , chunk )
126158 decompressed_object = await decompress_object (file_id , decrypted_object , chunk )
@@ -144,10 +176,12 @@ async def process_chunks(client, file_id, chunks, encryption_key, semaphore=None
144176 :returns: List of futures.
145177 :rtype: list[asyncio.Task]
146178 """
147- parameters = {'file_id' : file_id , 'blocks' : len (chunks )}
179+ message = [f"Processing { len (chunks )} blocks" ]
180+ if file_id :
181+ message .append (f"for file ID { file_id } " )
148182 if semaphore :
149- parameters [ 'max_workers' ] = semaphore ._value # pylint: disable=protected-access
150- logger .debug ('Processing Blocks. %s' , parameters )
183+ message . append ( f"using up to { semaphore ._value } workers" ) # pylint: disable=protected-access
184+ logger .debug (' ' . join ( message ) )
151185 futures = []
152186 for chunk in chunks :
153187 futures .append (asyncio .create_task (process_chunk (client , file_id , chunk , encryption_key , semaphore )))
@@ -182,9 +216,11 @@ def create_authorization_header(credentials):
182216 authorization_header = None
183217
184218 if isinstance (credentials , Bearer ):
219+ logger .debug ('Initializing client using bearer token' )
185220 authorization_header = f'Bearer { credentials .bearer } '
186221
187222 elif isinstance (credentials , KeyPair ):
223+ logger .debug ('Initializing client using key pair.' )
188224 authorization_header = f'Bearer { credentials .access_key_id } '
189225
190226 return {'Authorization' : authorization_header }
@@ -197,17 +233,16 @@ async def get_chunks(api, credentials, file_id):
197233 :param cterasdk.clients.clients.AsyncJSON api: Asynchronous JSON Client.
198234 :param int file_id: File ID.
199235 :returns: Wrapped key and file chunks.
200- :rtype: cterasdk.direct.types.DirectIOResponse
236+ :rtype: cterasdk.direct.types.Metadata
201237 """
202238 async def get_chunks_coro ():
203- parameters = {'file_id' : file_id }
204- logger .debug ('Listing blocks. %s' , parameters )
239+ logger .debug ('Listing blocks for file ID: %s' , file_id )
205240 try :
206241 response = await api .get (f'{ file_id } ' , headers = create_authorization_header (credentials ))
207242 if not response .chunks :
208- logger .error ('Blocks not found. %s ' , parameters )
243+ logger .error ('Could not find blocks for file ID: %s. ' , file_id )
209244 raise BlocksNotFoundError (file_id )
210- return DirectIOResponse ( response )
245+ return Metadata ( file_id , response )
211246 except ClientResponseException as error :
212247 if error .response .status == 400 :
213248 raise NotFoundError (file_id )
@@ -217,10 +252,10 @@ async def get_chunks_coro():
217252 raise UnprocessableContent (file_id )
218253 raise error
219254 except ConnectionError :
220- logger .error ('Failed to list blocks. Connection error. %s ' , parameters )
255+ logger .error ('Failed to list blocks for file ID: %s due to a connection error. ' , file_id )
221256 raise BlockListConnectionError (file_id )
222257 except asyncio .TimeoutError :
223- logger .error ('Failed to list blocks. Timed out. %s ' , parameters )
258+ logger .error ('Timed out while listing blocks for file ID: %s. ' , file_id )
224259 raise BlockListTimeout (file_id )
225260
226261 return await retry (get_chunks_coro )
0 commit comments