Skip to content

Commit cd2cfce

Browse files
committed
Add initial invenio class hierarchy
1 parent 93b9f9c commit cd2cfce

File tree

1 file changed

+344
-0
lines changed

1 file changed

+344
-0
lines changed

janus_core/repository/invenio.py

Lines changed: 344 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,344 @@
1+
"""Repository data structure."""
2+
import json
3+
from abc import ABC
4+
from pathlib import Path
5+
from functools import cached_property
6+
7+
import requests
8+
9+
10+
def _check(request: requests.Request, proc: str):
11+
try:
12+
request.raise_for_status()
13+
except requests.HTTPError as err:
14+
raise requests.HTTPError(
15+
f"Error while {proc}, info: {request.json()['message']}"
16+
) from err
17+
18+
return request
19+
20+
class _SubCommandHandler(ABC):
21+
def __init__(self, parent):
22+
self.parent = parent
23+
24+
@property
25+
def url(self):
26+
return self.parent.url
27+
28+
@property
29+
def api_key(self):
30+
return self.parent.api_key
31+
32+
33+
class _File(_SubCommandHandler):
34+
def __init__(self, parent, name):
35+
super.__init__(self, parent)
36+
self.name = name
37+
38+
@property
39+
def dep_id(self):
40+
return self.parent.dep_id
41+
42+
@property
43+
def bucket_url(self):
44+
return self.parent.bucket_url
45+
46+
def info(self, **params):
47+
return _check(
48+
requests.get(
49+
f"{self.url}/deposit/depositions/{self.dep_id}/files/{self.name}",
50+
params={**params, "access_token": self.api_key},
51+
),
52+
f"getting {self.name} file info from deposition {self.dep_id}",
53+
)
54+
55+
def update(self, file: Path, **params):
56+
data = {"name": f"{file.name}"}
57+
header = {"Content-Type": "application/json"}
58+
return _check(
59+
requests.put(
60+
f"{self.url}/deposit/depositions/{self.dep_id}/files/{self.name}",
61+
params={**params, "access_token": self.api_key},
62+
data=json.dumps(data),
63+
headers=header,
64+
),
65+
f"updating {self.name} in deposition {self.dep_id}",
66+
)
67+
68+
def download(self, dest: Path = Path(), **params):
69+
info = self.info().json()
70+
link = info["links"]["download"]
71+
filename = info["filename"]
72+
73+
request = _check(
74+
requests.get(link, params={**params, "access_token": self.api_key}),
75+
f"downloading file {self.name} from deposition {self.dep_id}",
76+
)
77+
78+
dest = Path(dest)
79+
if dest.is_file():
80+
raise OSError(f"{dest} is a file which exists. Must be a directory.")
81+
82+
if not dest.isdir():
83+
dest.mkdir(parents=True, exist_ok=True)
84+
85+
with (dest / filename).open("wb") as out_file:
86+
out_file.write(request.content)
87+
88+
return request
89+
90+
def delete(self, **params):
91+
return _check(
92+
requests.delete(
93+
f"{self.url}/deposit/depositions/{self.dep_id}/files/{self.file_id}",
94+
params={**params, "access_token": self.api_key},
95+
),
96+
f"deleting file {self.name} from deposition {self.dep_id}",
97+
)
98+
99+
100+
def upload(self, file: Path, **params):
101+
file = Path(file)
102+
103+
with file.open("rb") as in_file:
104+
return _check(
105+
requests.put(
106+
f"{self.bucket_url}/{self.name}",
107+
params={**params, "access_token": self.api_key},
108+
data=in_file,
109+
),
110+
f"Uploading file {self.name} to deposition {self.dep_id}"
111+
)
112+
113+
class _Files(_SubCommandHandler):
114+
def __init__(self, parent):
115+
super.__init__(self, parent)
116+
117+
@property
118+
def dep_id(self):
119+
return self.parent.dep_id
120+
121+
@property
122+
def bucket_url(self):
123+
return self.parent.bucket_url
124+
125+
def __getitem__(self, name) -> _File:
126+
return _File(self, name)
127+
128+
def list(self, **params):
129+
return _check(
130+
requests.get(
131+
f"{self.url}/deposit/depositions/{self.dep_id}/files",
132+
params={**params, "access_token": self.api_key},
133+
),
134+
f"listing deposition {self.dep_id} files",
135+
)
136+
137+
def sort(self, sorted_ids, **params):
138+
return _check(
139+
requests.put(
140+
f"{self.url}/deposit/depositions/{self.dep_id}/files",
141+
params={**params, "access_token": self.api_key},
142+
data=json.dumps(sorted_ids),
143+
headers={"Content-Type": "application/json"},
144+
),
145+
f"sorting files for deposition {self.dep_id}"
146+
)
147+
148+
def upload(self, files: dict[str, Path], **params):
149+
request_list = []
150+
for name, file in files.items():
151+
file = Path(file)
152+
153+
with file.open("rb") as curr_file:
154+
request_list.append(
155+
_check(
156+
requests.put(
157+
f"{self.bucket_url}/{name}",
158+
params={**params, "access_token": self.api_key},
159+
data=curr_file,
160+
),
161+
f"Uploading file {self.name} to deposition {self.dep_id}"
162+
)
163+
)
164+
165+
return request_list
166+
167+
def download(self, dest, **params):
168+
request = self.list(**params).json()
169+
files = {file["id"]: file["filename"] for file in request}
170+
171+
for file in files.values():
172+
self[file].download(dest, **params)
173+
174+
175+
class _Deposition(_SubCommandHandler):
176+
def __init__(self, parent, dep_id):
177+
super().__init__(self, parent)
178+
self.dep_id = dep_id
179+
180+
@property
181+
def files(self) -> _Files:
182+
return _Files(self)
183+
184+
@cached_property
185+
def bucket_url(self):
186+
return self.get().json()["links"]["bucket"]
187+
188+
def get(self, **params):
189+
request = _check(
190+
requests.get(
191+
f"{self.url}/deposit/depositions/{self.dep_id}",
192+
params={**params, "access_token": self.api_key},
193+
),
194+
f"getting deposition {self.dep_id}"
195+
)
196+
self.bucket_url = request.json()["links"]["bucket"]
197+
return request
198+
199+
200+
def create(self, **params):
201+
return _check(
202+
requests.post(
203+
f"{self.url}/deposit/depositions",
204+
params={**params, "access_token": self.api_key},
205+
json={},
206+
headers={"Content-Type": "application/json"},
207+
),
208+
"creating deposition"
209+
)
210+
211+
def update(self, data, **params):
212+
return _check(
213+
requests.put(
214+
f"{self.url}/deposit/depositions/{self.dep_id}",
215+
params={**params, "access_token": self.api_key},
216+
data=json.dumps(data),
217+
headers={"Content-Type": "application/json"},
218+
),
219+
f"updating deposition {self.dep_id}"
220+
)
221+
222+
def delete(self, **params):
223+
return _check(
224+
requests.delete(
225+
f"{self.url}/deposit/depositions/{self.dep_id}",
226+
params={**params, "access_token": self.api_key},
227+
),
228+
f"deleting deposition {self.dep_id}"
229+
)
230+
231+
def publish(self, **params):
232+
return _check(
233+
requests.post(
234+
f"{self.url}/deposit/depositions/{self.dep_id}/actions/publish",
235+
params={**params, "access_token": self.api_key},
236+
),
237+
f"publishing deposition {self.dep_id}",
238+
)
239+
240+
def edit(self, **params):
241+
return _check(
242+
requests.post(
243+
f"{self.url}/deposit/depositions/{self.dep_id}/actions/edit",
244+
params={**params, "access_token": self.api_key},
245+
),
246+
f"editing deposition {self.dep_id}",
247+
)
248+
249+
def discard(self, **params):
250+
return _check(
251+
requests.post(
252+
f"{self.url}/deposit/depositions/{self.dep_id}/actions/discard",
253+
params={**params, "access_token": self.api_key},
254+
),
255+
f"discarding deposition {self.dep_id}",
256+
)
257+
258+
def new_version(self, **params):
259+
return _check(
260+
requests.post(
261+
f"{self.url}/deposit/depositions/{self.dep_id}/actions/newversion",
262+
params={**params, "access_token": self.api_key},
263+
),
264+
f"setting new version for deposition {self.dep_id}",
265+
)
266+
267+
class _Repository(_SubCommandHandler):
268+
def __getitem__(self, dep_id):
269+
return _Deposition(self, dep_id)
270+
271+
def list(self, **params):
272+
return _check(
273+
requests.get(
274+
f"{self.url}/deposit/depositions",
275+
params={**params, "access_token": self.api_key},
276+
),
277+
"listing depositions"
278+
)
279+
280+
281+
class _Records(_SubCommandHandler):
282+
def get(self, rec_id, **params):
283+
return _check(
284+
requests.get(
285+
f"{self.url}/records/{rec_id}",
286+
params={**params, "access_token": self.api_key},
287+
),
288+
f"getting record {rec_id}",
289+
)
290+
291+
def list(self, **params):
292+
return _check(
293+
requests.get(
294+
f"{self.url}/records", params={**params, "access_token": self.api_key}
295+
),
296+
"listing records",
297+
)
298+
299+
class _Licenses(_SubCommandHandler):
300+
def get(self, lic_id, **params):
301+
return _check(
302+
requests.get(
303+
f"{self.url}/licenses/{lic_id}",
304+
params={**params, "access_token": self.api_key},
305+
),
306+
f"getting license {lic_id}",
307+
)
308+
309+
def list(self, **params):
310+
return _check(
311+
requests.get(
312+
f"{self.url}/licenses/", params={**params, "access_token": self.api_key}
313+
),
314+
"listing licenses",
315+
)
316+
317+
318+
class InvenioRepository:
319+
"""Handler for Invenio-like repositories.
320+
321+
Handles pushing info to e.g. Zenodo
322+
323+
Parameters
324+
----------
325+
url
326+
Repository URL.
327+
api_key : str
328+
API key with appropriate permissions.
329+
330+
Examples
331+
--------
332+
.. code-block::
333+
my_repo = InvenioRepository("abc123", "companyname.website")
334+
my_repo.depositions["my_repo"].files["file"].upload(my_file)
335+
my_repo.records.get()
336+
my_repo.liceses.list()
337+
"""
338+
def __init__(self, url: str, api_key: str):
339+
self.url = url
340+
self.api_key = api_key
341+
342+
self.depositions = _Repository(self)
343+
self.records = _Records(self)
344+
self.licenses = _Licenses(self)

0 commit comments

Comments
 (0)