@@ -103,6 +103,9 @@ def __init__(self, api_endpoint=API_ENDPOINT, username=USERNAME, password=PASSWO
103103 :param api_endpoint: base path to DSpace REST API, eg. http://localhost:8080/server/api
104104 :param username: username with appropriate privileges to perform operations on REST API
105105 :param password: password for the above username
106+ :param timeout: default per-request timeout in seconds, used by every request unless a
107+ method call overrides it (eg. create_bitstream's own timeout argument).
108+ None (default) falls back to DEFAULT_TIMEOUT (60s).
106109 """
107110 self .session = requests .Session ()
108111 self .API_ENDPOINT = api_endpoint
@@ -830,7 +833,7 @@ def get_bitstreams(self, uuid=None, bundle=None, page=0, size=20, sort=None):
830833 bitstreams .append (Bitstream (bitstream_resource ))
831834 return bitstreams
832835
833- def create_bitstream (self , bundle = None , name = None , path = None , mime = None , metadata = None , retry = False ):
836+ def create_bitstream (self , bundle = None , name = None , path = None , mime = None , metadata = None , retry = False , timeout = None ):
834837 """
835838 Upload a file and create a bitstream for a specified parent bundle, from the uploaded file and
836839 the supplied metadata.
@@ -845,6 +848,10 @@ def create_bitstream(self, bundle=None, name=None, path=None, mime=None, metadat
845848 @param metadata: Full metadata JSON
846849 @param retry: A 'retried' indicator. If the first attempt fails due to an expired or missing auth
847850 token, the request will retry once, after the token is refreshed. (default: False)
851+ @param timeout: Per-call timeout in seconds for this upload, overriding self.timeout - useful for
852+ large files that need longer than the client's default. None (default) falls back
853+ to self.timeout. Preserved across the CSRF-retry recursion, so it still applies
854+ to the retried request.
848855 @return: constructed Bitstream object from the API response, or None if the operation failed.
849856 """
850857 # TODO: It is probably wise to allow the bundle UUID to be simply passed as an alternative to having the full
@@ -865,19 +872,21 @@ def create_bitstream(self, bundle=None, name=None, path=None, mime=None, metadat
865872 h .update ({'Content-Encoding' : 'gzip' , 'User-Agent' : self .USER_AGENT })
866873 req = Request ('POST' , url , data = payload , headers = h , files = files )
867874 prepared_req = self .session .prepare_request (req )
868- r = self .session .send (prepared_req , proxies = self .proxies , timeout = self .timeout )
875+ r = self .session .send (prepared_req , proxies = self .proxies ,
876+ timeout = timeout if timeout is not None else self .timeout )
869877 if 'DSPACE-XSRF-TOKEN' in r .headers :
870878 t = r .headers ['DSPACE-XSRF-TOKEN' ]
871879 _logger .debug ('Updating token to ' + t )
872880 self .session .headers .update ({'X-XSRF-Token' : t })
873881 self .session .cookies .update ({'X-XSRF-Token' : t })
874882 if not retry and r .status_code in (401 , 403 ):
875883 r_json = parse_json (r )
876- if 'message' in r_json and 'CSRF token' in r_json ['message' ]:
884+ if 'message' in ( r_json or {}) and 'CSRF token' in r_json ['message' ]:
877885 _logger .debug ("Retrying request with updated CSRF token" )
878886 else :
879887 self .authenticate ()
880- return self .create_bitstream (bundle , name , path , mime , metadata , True )
888+ return self .create_bitstream (bundle = bundle , name = name , path = path , mime = mime ,
889+ metadata = metadata , retry = True , timeout = timeout )
881890
882891 if r .status_code == 201 or r .status_code == 200 :
883892 # Success
0 commit comments