@@ -55,8 +55,9 @@ def is_relative(url: str) -> bool:
5555 (len(parsed.path)==0 or parsed.path[0]!='/'))
5656
5757
58- def do_api_request(endpoint: str, method: str = 'GET', jsonData: dict = {},
59- data: dict = {}, files: dict = {}, decode: bool = True):
58+ def do_api_request(endpoint: str, method: str = 'GET', *,
59+ data: dict = {}, files: dict = {}, jsonData: dict = {},
60+ decode: bool = True, output_file: str = None):
6061 '''Perform an API call to the given endpoint and return its data.
6162
6263 Based on whether `domjudge_api_url` is set, this will call the DOMjudge
@@ -69,9 +70,12 @@ def do_api_request(endpoint: str, method: str = 'GET', jsonData: dict = {},
6970 jsonData (dict): the JSON data to PUT. Only used when method is PUT
7071 data (dict): data to pass in a POST request
7172 decode (bool): whether to decode the returned JSON data, default true
73+ output_file (str): write API response to file, e.g. for binary content;
74+ incompatible with decode=True.
7275
7376 Returns:
74- The endpoint contents, either as raw bytes or JSON decoded.
77+ The endpoint contents, either as raw bytes or JSON decoded, unless
78+ output_file is specified.
7579
7680 Raises:
7781 RuntimeError when the HTTP status code is non-2xx or the response
@@ -82,7 +86,7 @@ def do_api_request(endpoint: str, method: str = 'GET', jsonData: dict = {},
8286 orig_kwargs = locals()
8387
8488 if domjudge_api_url is None and is_relative(endpoint):
85- result = api_via_cli(endpoint, method, {}, {}, jsonData )
89+ result = api_via_cli(endpoint, method, jsonData=jsonData, output_file=output_file )
8690 else:
8791 if not is_relative(endpoint):
8892 raise RuntimeError(f'Cannot access non-relative URL {endpoint} without API base URL')
@@ -122,6 +126,10 @@ def do_api_request(endpoint: str, method: str = 'GET', jsonData: dict = {},
122126 raise RuntimeError(e)
123127 result = parse_api_response(endpoint, response)
124128
129+ if output_file is not None:
130+ with open(output_file, 'wb') as f:
131+ f.write(result)
132+
125133 if decode:
126134 try:
127135 result = json.loads(result)
@@ -141,7 +149,9 @@ def upload_file(endpoint: str, apifilename: str, file: str, data: dict = {}):
141149 do_api_request(endpoint, 'POST', data=data, files={apifilename: file})
142150
143151
144- def api_via_cli(endpoint: str, method: str = 'GET', data: dict = {}, files: dict = {}, jsonData: dict = {}):
152+ def api_via_cli(endpoint: str, method: str = 'GET', *,
153+ data: dict = {}, files: dict = {}, jsonData: dict = {},
154+ output_file: str = None):
145155 '''Perform the given API request using the CLI
146156
147157 Parameters:
@@ -150,6 +160,7 @@ def api_via_cli(endpoint: str, method: str = 'GET', data: dict = {}, files: dict
150160 data (dict): the POST data to use. Only used when method is POST or PUT
151161 files (dict): the files to use. Only used when method is POST or PUT
152162 jsonData (dict): the JSON data to use. Only used when method is POST or PUT
163+ output_file (str): write API response to file, e.g. for binary content
153164
154165 Returns:
155166 The raw endpoint contents.
@@ -174,6 +185,9 @@ def api_via_cli(endpoint: str, method: str = 'GET', data: dict = {}, files: dict
174185 if jsonData:
175186 command.extend(['-j', json.dumps(jsonData)])
176187
188+ if output_file:
189+ command.extend(['-o', output_file])
190+
177191 command.append(endpoint)
178192
179193 result = subprocess.run(command, capture_output=True)
0 commit comments