-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapi.py
More file actions
104 lines (84 loc) · 3.77 KB
/
Copy pathapi.py
File metadata and controls
104 lines (84 loc) · 3.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
"""
Provides low-level access to the TIND API.
"""
import os.path
import re
from typing import Tuple
import requests
from .errors import AuthorizationError, TINDError, TooManyRequestsError
TIMEOUT: int = 30
"""The number of seconds to wait for an HTTP connection to respond."""
def _auth_header(api_key: str) -> dict[str, str]:
"""Returns the Authorization header needed for TIND API calls.
:param str api_key: The TIND API key
:raises AuthorizationError: If no TIND API key is provided
:returns dict: The ``Authorization`` header to use for the HTTP request.
"""
if not api_key:
raise AuthorizationError("No TIND API key provided")
return {"Authorization": f"Token {api_key}"}
def tind_get(
endpoint: str, api_key: str, api_url: str, params: dict[str, str] | None = None
) -> Tuple[int, str]:
"""Run a GET API request, returning its response.
:param str endpoint: The TIND API endpoint to query.
For example, ``'record/1/'``.
:param str api_key: The TIND API token.
:param str api_url: The base URL of the TIND instance, e.g. ``https://digicoll.berkeley.edu``.
:param dict|None params: Extra query parameters to send.
For example, ``{'of': 'xm'}``.
:raises AuthorizationError: If an invalid TIND API key is provided.
:raises TooManyRequestsError: If the TIND server is overloaded with requests.
:raises TINDError: If an internal server error occurs during request processing.
:returns: A tuple of the HTTP status code and response text (if any).
:rtype: Tuple[int, str]
"""
if params is None:
params = {}
api_base = api_url.rstrip("/")
resp = requests.get(
f"{api_base}/{endpoint}",
headers=_auth_header(api_key),
params=params,
timeout=TIMEOUT,
)
if resp.status_code == 401:
raise AuthorizationError("Invalid TIND API key provided")
if resp.status_code == 429:
raise TooManyRequestsError("Enhance your calm")
if resp.status_code >= 500:
raise TINDError.from_json(resp.status_code, resp.text)
return resp.status_code, resp.text
def tind_download(url: str, output_dir: str, api_key: str) -> Tuple[int, str]:
"""Download a file from TIND.
:param str url: The TIND file download URL.
:param str output_dir: The path to the directory in which to save the file.
:param str api_key: The TIND API token.
:raises AuthorizationError: If an invalid TIND API key is provided.
:raises TooManyRequestsError: If the TIND server is overloaded with requests.
:raises TINDError: If an internal server error occurs during request processing.
:returns: A tuple of the HTTP status code and the path to the downloaded file (if successful).
:rtype: Tuple[int, str]
"""
resp = requests.get(url, headers=_auth_header(api_key), timeout=TIMEOUT)
status = resp.status_code
if status == 401:
raise AuthorizationError("Invalid TIND API key provided")
if status == 429:
raise TooManyRequestsError("Enhance your calm")
if status >= 500:
raise TINDError.from_json(status, resp.text)
if status != 200:
return status, ""
# Fall-back to the file name in the URL if it isn't included in the response.
output_filename = url.split("?")[0].rstrip("/").split("/")[-2]
# See if we can extract the filename from the response headers.
if "Content-Disposition" in resp.headers:
match = re.findall('filename="(.+)"', resp.headers["Content-Disposition"])
if len(match) == 1:
output_filename = match[0]
output_path = os.path.join(output_dir, output_filename)
with open(output_path, "wb") as out_f:
for chunk in resp.iter_content():
out_f.write(chunk)
return status, output_path