caltechdata-api 1.11.0__tar.gz → 2.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/PKG-INFO +31 -14
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/README.md +17 -5
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api/caltechdata_edit.py +57 -64
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api/caltechdata_write.py +52 -53
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api/cli.py +2 -2
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api/customize_schema.py +6 -35
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api/get_metadata.py +4 -4
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api.egg-info/PKG-INFO +31 -14
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api.egg-info/SOURCES.txt +0 -2
- caltechdata_api-2.1.0/pyproject.toml +69 -0
- caltechdata_api-2.1.0/setup.cfg +4 -0
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/tests/test_rdm.py +8 -6
- caltechdata_api-2.1.0/tests/test_unit.py +76 -0
- caltechdata_api-1.11.0/pyproject.toml +0 -3
- caltechdata_api-1.11.0/setup.cfg +0 -55
- caltechdata_api-1.11.0/setup.py +0 -3
- caltechdata_api-1.11.0/tests/test_unit.py +0 -166
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/LICENSE +0 -0
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api/__init__.py +0 -0
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api/download_file.py +0 -0
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api/get_files.py +0 -0
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api/md_to_json.py +0 -0
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api/utils.py +0 -0
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api/vocabularies/date_types.yaml +0 -0
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api/vocabularies/description_types.yaml +0 -0
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api/vocabularies/identifier_types.yaml +0 -0
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api/vocabularies/licenses.csv +0 -0
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api/vocabularies/relation_types.yaml +0 -0
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api/vocabularies/resource_types.yaml +0 -0
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api/vocabularies/roles.yaml +0 -0
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api/vocabularies/title_types.yaml +0 -0
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api/vocabularies.yaml +0 -0
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api.egg-info/dependency_links.txt +0 -0
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api.egg-info/entry_points.txt +0 -0
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api.egg-info/requires.txt +0 -0
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api.egg-info/top_level.txt +0 -0
- {caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/tests/test_download.py +0 -0
|
@@ -1,20 +1,25 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: caltechdata_api
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: Python wrapper for CaltechDATA API.
|
|
5
|
-
|
|
6
|
-
Author: Thomas E Morrell
|
|
7
|
-
|
|
8
|
-
License:
|
|
9
|
-
|
|
5
|
+
Author: Rohan Bhattarai, Elizabeth Won
|
|
6
|
+
Author-email: Thomas E Morrell <tmorrell@caltech.edu>, Alexander A Abakah <aabakah@caltech.edu>, Kshemaahna Nagi <knagi@caltech.edu>
|
|
7
|
+
Maintainer-email: Thomas E Morrell <tmorrell@caltech.edu>
|
|
8
|
+
License-Expression: BSD-3-Clause
|
|
9
|
+
Project-URL: Homepage, https://github.com/caltechlibrary/caltechdata_api
|
|
10
|
+
Project-URL: Repository, https://github.com/caltechlibrary/caltechdata_api
|
|
11
|
+
Project-URL: Issues, https://github.com/caltechlibrary/caltechdata_api/issues
|
|
12
|
+
Keywords: metadata,software,InvenioRDM
|
|
10
13
|
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
13
14
|
Classifier: Programming Language :: Python :: 3.9
|
|
14
15
|
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
15
20
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
16
21
|
Classifier: Operating System :: OS Independent
|
|
17
|
-
Requires-Python: >=3.
|
|
22
|
+
Requires-Python: >=3.9
|
|
18
23
|
Description-Content-Type: text/markdown
|
|
19
24
|
License-File: LICENSE
|
|
20
25
|
Requires-Dist: requests
|
|
@@ -44,7 +49,7 @@ The `caltechdata_api` Python library provides a convenient interface for interac
|
|
|
44
49
|
|
|
45
50
|
## Requirements
|
|
46
51
|
|
|
47
|
-
- Python 3.
|
|
52
|
+
- Python 3.9+
|
|
48
53
|
|
|
49
54
|
## Installation
|
|
50
55
|
|
|
@@ -54,6 +59,18 @@ Install the library via pip:
|
|
|
54
59
|
pip install caltechdata_api
|
|
55
60
|
```
|
|
56
61
|
|
|
62
|
+
Or add it to a [uv](https://docs.astral.sh/uv/) project:
|
|
63
|
+
|
|
64
|
+
```shell
|
|
65
|
+
uv add caltechdata_api
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
You can also run a script using uv:
|
|
69
|
+
|
|
70
|
+
```shell
|
|
71
|
+
uv run write.py
|
|
72
|
+
```
|
|
73
|
+
|
|
57
74
|
## Examples
|
|
58
75
|
|
|
59
76
|
There are some example python scripts in the GitHub repository.
|
|
@@ -61,7 +78,7 @@ There are some example python scripts in the GitHub repository.
|
|
|
61
78
|
### Create a record:
|
|
62
79
|
|
|
63
80
|
```shell
|
|
64
|
-
|
|
81
|
+
uv run write.py example.json -fnames logo.gif
|
|
65
82
|
# Output: pbkn6-m9y63 (unique identifier)
|
|
66
83
|
```
|
|
67
84
|
> The response will be the unique identifier for the record. You can put this at
|
|
@@ -71,7 +88,7 @@ https://data.caltechlibrary.dev/records/pbkn6-m9y63)
|
|
|
71
88
|
### Edit a record
|
|
72
89
|
Make changes to the example.json file to see a change)
|
|
73
90
|
```
|
|
74
|
-
|
|
91
|
+
uv run edit.py example.json -id pbkn6-m9y63
|
|
75
92
|
10.33569/pbkn6-m9y63
|
|
76
93
|
```
|
|
77
94
|
> The response is the DOI for the record, which includes the unique identifier
|
|
@@ -82,13 +99,13 @@ Some groups have worked with the library to create custom DOIs. These can be
|
|
|
82
99
|
passed in the metadata like:
|
|
83
100
|
|
|
84
101
|
```shell
|
|
85
|
-
|
|
102
|
+
uv run write.py example_custom.json -fnames logo.gif
|
|
86
103
|
m6zxz-p4j22
|
|
87
104
|
```
|
|
88
105
|
|
|
89
106
|
And then you can edit with
|
|
90
107
|
```
|
|
91
|
-
|
|
108
|
+
uv run edit.py example_custom.json -id m6zxz-p4j22
|
|
92
109
|
10.5281/inveniordm.1234
|
|
93
110
|
```
|
|
94
111
|
|
|
@@ -15,7 +15,7 @@ The `caltechdata_api` Python library provides a convenient interface for interac
|
|
|
15
15
|
|
|
16
16
|
## Requirements
|
|
17
17
|
|
|
18
|
-
- Python 3.
|
|
18
|
+
- Python 3.9+
|
|
19
19
|
|
|
20
20
|
## Installation
|
|
21
21
|
|
|
@@ -25,6 +25,18 @@ Install the library via pip:
|
|
|
25
25
|
pip install caltechdata_api
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
Or add it to a [uv](https://docs.astral.sh/uv/) project:
|
|
29
|
+
|
|
30
|
+
```shell
|
|
31
|
+
uv add caltechdata_api
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
You can also run a script using uv:
|
|
35
|
+
|
|
36
|
+
```shell
|
|
37
|
+
uv run write.py
|
|
38
|
+
```
|
|
39
|
+
|
|
28
40
|
## Examples
|
|
29
41
|
|
|
30
42
|
There are some example python scripts in the GitHub repository.
|
|
@@ -32,7 +44,7 @@ There are some example python scripts in the GitHub repository.
|
|
|
32
44
|
### Create a record:
|
|
33
45
|
|
|
34
46
|
```shell
|
|
35
|
-
|
|
47
|
+
uv run write.py example.json -fnames logo.gif
|
|
36
48
|
# Output: pbkn6-m9y63 (unique identifier)
|
|
37
49
|
```
|
|
38
50
|
> The response will be the unique identifier for the record. You can put this at
|
|
@@ -42,7 +54,7 @@ https://data.caltechlibrary.dev/records/pbkn6-m9y63)
|
|
|
42
54
|
### Edit a record
|
|
43
55
|
Make changes to the example.json file to see a change)
|
|
44
56
|
```
|
|
45
|
-
|
|
57
|
+
uv run edit.py example.json -id pbkn6-m9y63
|
|
46
58
|
10.33569/pbkn6-m9y63
|
|
47
59
|
```
|
|
48
60
|
> The response is the DOI for the record, which includes the unique identifier
|
|
@@ -53,13 +65,13 @@ Some groups have worked with the library to create custom DOIs. These can be
|
|
|
53
65
|
passed in the metadata like:
|
|
54
66
|
|
|
55
67
|
```shell
|
|
56
|
-
|
|
68
|
+
uv run write.py example_custom.json -fnames logo.gif
|
|
57
69
|
m6zxz-p4j22
|
|
58
70
|
```
|
|
59
71
|
|
|
60
72
|
And then you can edit with
|
|
61
73
|
```
|
|
62
|
-
|
|
74
|
+
uv run edit.py example_custom.json -id m6zxz-p4j22
|
|
63
75
|
10.5281/inveniordm.1234
|
|
64
76
|
```
|
|
65
77
|
|
|
@@ -7,7 +7,6 @@ from caltechdata_api import (
|
|
|
7
7
|
customize_schema,
|
|
8
8
|
write_files_rdm,
|
|
9
9
|
add_file_links,
|
|
10
|
-
send_to_community,
|
|
11
10
|
)
|
|
12
11
|
|
|
13
12
|
|
|
@@ -16,7 +15,8 @@ def caltechdata_unembargo(token, ids, production=False):
|
|
|
16
15
|
|
|
17
16
|
|
|
18
17
|
def caltechdata_accept(ids, token=None, production=False):
|
|
19
|
-
# Accept a record into a community
|
|
18
|
+
# Accept a record into a community. Only accepts the first community
|
|
19
|
+
# request
|
|
20
20
|
|
|
21
21
|
# If no token is provided, get from RDMTOK environment variable
|
|
22
22
|
if not token:
|
|
@@ -36,8 +36,15 @@ def caltechdata_accept(ids, token=None, production=False):
|
|
|
36
36
|
result = requests.get(
|
|
37
37
|
url + "/api/records/" + idv + "/draft/review", headers=headers
|
|
38
38
|
)
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
if result.status_code != 200:
|
|
40
|
+
result = requests.get(
|
|
41
|
+
url + "/api/records/" + idv + "/requests", headers=headers
|
|
42
|
+
)
|
|
43
|
+
if result.status_code != 200:
|
|
44
|
+
raise Exception(result.text)
|
|
45
|
+
accept_link = result.json()["hits"]["hits"][0]["links"]["actions"]["accept"]
|
|
46
|
+
else:
|
|
47
|
+
accept_link = result.json()["links"]["actions"]["accept"]
|
|
41
48
|
data = comment = {
|
|
42
49
|
"payload": {
|
|
43
50
|
"content": "This record is accepted automatically with the CaltechDATA API",
|
|
@@ -97,7 +104,7 @@ def caltechdata_edit(
|
|
|
97
104
|
token=None,
|
|
98
105
|
files={},
|
|
99
106
|
production=False,
|
|
100
|
-
schema=
|
|
107
|
+
schema=None,
|
|
101
108
|
publish=False,
|
|
102
109
|
file_links=[],
|
|
103
110
|
s3=None,
|
|
@@ -122,41 +129,6 @@ def caltechdata_edit(
|
|
|
122
129
|
if isinstance(files, str) == True:
|
|
123
130
|
files = [files]
|
|
124
131
|
|
|
125
|
-
# Check if file links were provided in the metadata
|
|
126
|
-
descriptions = []
|
|
127
|
-
ex_file_links = []
|
|
128
|
-
ex_file_descriptions = []
|
|
129
|
-
if "descriptions" in metadata:
|
|
130
|
-
for d in metadata["descriptions"]:
|
|
131
|
-
if d["description"].startswith("Files available via S3"):
|
|
132
|
-
file_text = d["description"]
|
|
133
|
-
file_list = file_text.split('href="')
|
|
134
|
-
# Check if we have file_descriptions
|
|
135
|
-
split_comma = file_list[0].split(", ")
|
|
136
|
-
if len(split_comma) == 3:
|
|
137
|
-
ex_file_descriptions.append(split_comma[1])
|
|
138
|
-
# Loop over links in description, skip header text
|
|
139
|
-
for file in file_list[1:]:
|
|
140
|
-
ex_file_links.append(file.split('"\n')[0])
|
|
141
|
-
split_comma = file.split(", ")
|
|
142
|
-
if len(split_comma) == 3:
|
|
143
|
-
ex_file_descriptions.append(split_comma[1])
|
|
144
|
-
else:
|
|
145
|
-
descriptions.append(d)
|
|
146
|
-
# We remove file link descriptions, and re-add below
|
|
147
|
-
metadata["descriptions"] = descriptions
|
|
148
|
-
|
|
149
|
-
# If user has provided file links as a cli option, we add those
|
|
150
|
-
if file_links:
|
|
151
|
-
metadata = add_file_links(
|
|
152
|
-
metadata, file_links, file_descriptions, s3_link=s3_link
|
|
153
|
-
)
|
|
154
|
-
# Otherwise we add file links found in the mtadata file
|
|
155
|
-
elif ex_file_links:
|
|
156
|
-
metadata = add_file_links(
|
|
157
|
-
metadata, ex_file_links, ex_file_descriptions, s3_link=s3_link
|
|
158
|
-
)
|
|
159
|
-
|
|
160
132
|
if authors == False:
|
|
161
133
|
if production == True:
|
|
162
134
|
url = "https://data.caltech.edu/"
|
|
@@ -181,6 +153,18 @@ def caltechdata_edit(
|
|
|
181
153
|
"Content-type": "application/octet-stream",
|
|
182
154
|
}
|
|
183
155
|
|
|
156
|
+
# Add to community if provided:
|
|
157
|
+
if community:
|
|
158
|
+
result = requests.post(
|
|
159
|
+
url + "/api/records/" + idv + "/communities",
|
|
160
|
+
headers=headers,
|
|
161
|
+
data=json.dumps({"communities": [{"id": community}]}),
|
|
162
|
+
)
|
|
163
|
+
if result.status_code != 200:
|
|
164
|
+
print(result.url)
|
|
165
|
+
raise Exception(result.text)
|
|
166
|
+
caltechdata_accept([idv], token, production)
|
|
167
|
+
|
|
184
168
|
# Check status
|
|
185
169
|
existing = requests.get(
|
|
186
170
|
url + "/api/records/" + idv,
|
|
@@ -294,10 +278,19 @@ def caltechdata_edit(
|
|
|
294
278
|
# We want to have the system set new DOIs
|
|
295
279
|
data["pids"] = {}
|
|
296
280
|
else:
|
|
297
|
-
if authors == False:
|
|
281
|
+
if authors == False and schema == "43":
|
|
298
282
|
metadata["pids"] = pids
|
|
299
283
|
data = customize_schema.customize_schema(metadata, schema=schema)
|
|
300
|
-
|
|
284
|
+
elif authors == False:
|
|
285
|
+
# Data using RDM schema, force oai PID
|
|
286
|
+
if "pids" not in metadata:
|
|
287
|
+
metadata["pids"] = {}
|
|
288
|
+
metadata["pids"]["oai"] = {
|
|
289
|
+
"identifier": f"oai:data.caltech.edu:{idv}",
|
|
290
|
+
"provider": "oai",
|
|
291
|
+
}
|
|
292
|
+
data = metadata
|
|
293
|
+
if authors == True:
|
|
301
294
|
# Authors, force oai PID
|
|
302
295
|
if "pids" not in metadata:
|
|
303
296
|
metadata["pids"] = {}
|
|
@@ -307,7 +300,21 @@ def caltechdata_edit(
|
|
|
307
300
|
}
|
|
308
301
|
data = metadata
|
|
309
302
|
|
|
310
|
-
|
|
303
|
+
# Check for existing draft
|
|
304
|
+
result = requests.get(
|
|
305
|
+
url + "/api/records/" + idv + "/draft",
|
|
306
|
+
headers=headers,
|
|
307
|
+
)
|
|
308
|
+
if result.status_code != 200:
|
|
309
|
+
# We make a draft
|
|
310
|
+
result = requests.post(
|
|
311
|
+
url + "/api/records/" + idv + "/draft",
|
|
312
|
+
headers=headers,
|
|
313
|
+
)
|
|
314
|
+
if result.status_code != 201:
|
|
315
|
+
raise Exception(result.text)
|
|
316
|
+
|
|
317
|
+
if files or file_links:
|
|
311
318
|
if default_preview:
|
|
312
319
|
data["files"] = {"enabled": True, "default_preview": default_preview}
|
|
313
320
|
else:
|
|
@@ -320,29 +327,15 @@ def caltechdata_edit(
|
|
|
320
327
|
)
|
|
321
328
|
if result.status_code != 200:
|
|
322
329
|
raise Exception(result.text)
|
|
323
|
-
|
|
324
|
-
|
|
330
|
+
file_upload_link = result.json()["links"]["files"]
|
|
331
|
+
if files:
|
|
332
|
+
write_files_rdm(
|
|
333
|
+
files, file_upload_link, headers, f_headers, keepfiles=keepfiles
|
|
334
|
+
)
|
|
335
|
+
if file_links:
|
|
336
|
+
add_file_links(file_upload_link, file_links, headers, keepfiles=keepfiles)
|
|
325
337
|
|
|
326
338
|
else:
|
|
327
|
-
# Check for existing draft
|
|
328
|
-
result = requests.get(
|
|
329
|
-
url + "/api/records/" + idv + "/draft",
|
|
330
|
-
headers=headers,
|
|
331
|
-
)
|
|
332
|
-
if result.status_code != 200:
|
|
333
|
-
# We make a draft
|
|
334
|
-
result = requests.post(
|
|
335
|
-
url + "/api/records/" + idv + "/draft",
|
|
336
|
-
headers=headers,
|
|
337
|
-
)
|
|
338
|
-
if result.status_code != 201:
|
|
339
|
-
time.sleep(3)
|
|
340
|
-
result = requests.post(
|
|
341
|
-
url + "/api/records/" + idv + "/draft",
|
|
342
|
-
headers=headers,
|
|
343
|
-
)
|
|
344
|
-
if result.status_code != 201:
|
|
345
|
-
raise Exception(result.text)
|
|
346
339
|
# We want files to stay the same as the existing record
|
|
347
340
|
data["files"] = existing["files"]
|
|
348
341
|
if default_preview:
|
|
@@ -67,45 +67,40 @@ def write_files_rdm(
|
|
|
67
67
|
raise Exception(result.text)
|
|
68
68
|
|
|
69
69
|
|
|
70
|
-
def add_file_links(
|
|
71
|
-
metadata, file_links, file_descriptions=[], additional_descriptions="", s3_link=None
|
|
72
|
-
):
|
|
70
|
+
def add_file_links(file_upload_link, file_links, headers, keepfiles=False):
|
|
73
71
|
# Currently configured for S3 links, assuming all are at the same endpoint
|
|
74
72
|
link_string = ""
|
|
75
73
|
endpoint = "https://" + file_links[0].split("/")[2]
|
|
76
74
|
s3 = s3fs.S3FileSystem(anon=True, client_kwargs={"endpoint_url": endpoint})
|
|
77
75
|
index = 0
|
|
76
|
+
file_json = []
|
|
77
|
+
f_list = []
|
|
78
78
|
for link in file_links:
|
|
79
79
|
file = link.split("/")[-1]
|
|
80
|
+
f_list.append(file)
|
|
80
81
|
path = link.split(endpoint)[1]
|
|
81
82
|
size = s3.info(path)["size"]
|
|
82
|
-
size = humanbytes(size)
|
|
83
|
-
try:
|
|
84
|
-
description = file_descriptions[index]
|
|
85
|
-
if description != " ":
|
|
86
|
-
desc = description + ","
|
|
87
|
-
else:
|
|
88
|
-
desc = ""
|
|
89
|
-
except IndexError:
|
|
90
|
-
desc = ""
|
|
91
|
-
if link_string == "":
|
|
92
|
-
if s3_link:
|
|
93
|
-
link_string = f"Files available via S3 at {s3_link}</p></p>"
|
|
94
|
-
else:
|
|
95
|
-
cleaned = link.strip(file)
|
|
96
|
-
link_string = f"Files available via S3 at {cleaned}</p></p>"
|
|
97
|
-
link_string += f"""{file}, {desc} {size}
|
|
98
|
-
<p><a role="button" class="ui compact mini button" href="{link}"
|
|
99
|
-
> <i class="download icon"></i> Download </a></p></p></p>
|
|
100
|
-
"""
|
|
101
|
-
index += 1
|
|
102
|
-
# Tack on any additional descriptions
|
|
103
|
-
if additional_descriptions != "":
|
|
104
|
-
link_string += additional_descriptions
|
|
105
83
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
84
|
+
file_json.append(
|
|
85
|
+
{"key": file, "size": size, "transfer": {"type": "R", "url": link}}
|
|
86
|
+
)
|
|
87
|
+
# Now we see if any existing files need to be replaced
|
|
88
|
+
result = requests.get(file_upload_link, headers=headers)
|
|
89
|
+
if result.status_code == 200:
|
|
90
|
+
ex_files = result.json()["entries"]
|
|
91
|
+
for ex in ex_files:
|
|
92
|
+
if ex["key"] in f_list:
|
|
93
|
+
result = requests.delete(ex["links"]["self"], headers=headers)
|
|
94
|
+
if result.status_code != 204:
|
|
95
|
+
raise Exception(result.text)
|
|
96
|
+
else:
|
|
97
|
+
if keepfiles == False:
|
|
98
|
+
result = requests.delete(ex["links"]["self"], headers=headers)
|
|
99
|
+
if result.status_code != 204:
|
|
100
|
+
raise Exception(result.text)
|
|
101
|
+
result = requests.post(file_upload_link, headers=headers, json=file_json)
|
|
102
|
+
if result.status_code != 201:
|
|
103
|
+
raise Exception(result.text)
|
|
109
104
|
|
|
110
105
|
|
|
111
106
|
def send_to_community(
|
|
@@ -155,14 +150,13 @@ def caltechdata_write(
|
|
|
155
150
|
token=None,
|
|
156
151
|
files=[],
|
|
157
152
|
production=False,
|
|
158
|
-
schema=
|
|
153
|
+
schema=None,
|
|
159
154
|
publish=False,
|
|
160
155
|
file_links=[],
|
|
161
156
|
s3=None,
|
|
162
157
|
community=None,
|
|
163
158
|
authors=False,
|
|
164
159
|
file_descriptions=[],
|
|
165
|
-
s3_link=None,
|
|
166
160
|
default_preview=None,
|
|
167
161
|
review_message=None,
|
|
168
162
|
verify=True,
|
|
@@ -181,15 +175,25 @@ def caltechdata_write(
|
|
|
181
175
|
if not token:
|
|
182
176
|
token = os.environ["RDMTOK"]
|
|
183
177
|
|
|
178
|
+
if authors == False:
|
|
179
|
+
if production == True:
|
|
180
|
+
url = "https://data.caltech.edu/"
|
|
181
|
+
elif local == True:
|
|
182
|
+
url = "https://127.0.0.1:5000/"
|
|
183
|
+
else:
|
|
184
|
+
url = "https://data.caltechlibrary.dev/"
|
|
185
|
+
else:
|
|
186
|
+
if production == True:
|
|
187
|
+
url = "https://authors.library.caltech.edu/"
|
|
188
|
+
elif local == True:
|
|
189
|
+
url = "https://127.0.0.1:5000/"
|
|
190
|
+
else:
|
|
191
|
+
url = "https://authors.caltechlibrary.dev/"
|
|
192
|
+
|
|
184
193
|
# If files is a string - change to single value array
|
|
185
194
|
if isinstance(files, str) == True:
|
|
186
195
|
files = [files]
|
|
187
196
|
|
|
188
|
-
if file_links:
|
|
189
|
-
metadata = add_file_links(
|
|
190
|
-
metadata, file_links, file_descriptions, s3_link=s3_link
|
|
191
|
-
)
|
|
192
|
-
|
|
193
197
|
# Pull out pid information
|
|
194
198
|
if production == True:
|
|
195
199
|
repo_prefix = "10.22002"
|
|
@@ -235,22 +239,11 @@ def caltechdata_write(
|
|
|
235
239
|
if "pids" not in metadata:
|
|
236
240
|
metadata["pids"] = pids
|
|
237
241
|
|
|
238
|
-
if authors == False:
|
|
242
|
+
if authors == False and schema == "43":
|
|
239
243
|
data = customize_schema.customize_schema(metadata, schema=schema)
|
|
240
|
-
if production == True:
|
|
241
|
-
url = "https://data.caltech.edu/"
|
|
242
|
-
elif local == True:
|
|
243
|
-
url = "https://127.0.0.1:5000/"
|
|
244
|
-
else:
|
|
245
|
-
url = "https://data.caltechlibrary.dev/"
|
|
246
244
|
else:
|
|
245
|
+
# Using RDM schema, no customization
|
|
247
246
|
data = metadata
|
|
248
|
-
if production == True:
|
|
249
|
-
url = "https://authors.library.caltech.edu/"
|
|
250
|
-
elif local == True:
|
|
251
|
-
url = "https://127.0.0.1:5000/"
|
|
252
|
-
else:
|
|
253
|
-
url = "https://authors.caltechlibrary.dev/"
|
|
254
247
|
|
|
255
248
|
headers = {
|
|
256
249
|
"Authorization": "Bearer %s" % token,
|
|
@@ -261,10 +254,13 @@ def caltechdata_write(
|
|
|
261
254
|
"Content-type": "application/octet-stream",
|
|
262
255
|
}
|
|
263
256
|
|
|
264
|
-
if
|
|
257
|
+
if files or file_links:
|
|
258
|
+
if default_preview:
|
|
259
|
+
data["files"] = {"enabled": True, "default_preview": default_preview}
|
|
260
|
+
else:
|
|
261
|
+
data["files"] = {"enabled": True}
|
|
262
|
+
else:
|
|
265
263
|
data["files"] = {"enabled": False}
|
|
266
|
-
elif default_preview:
|
|
267
|
-
data["files"] = {"enabled": True, "default_preview": default_preview}
|
|
268
264
|
|
|
269
265
|
# Make draft and publish
|
|
270
266
|
result = requests.post(
|
|
@@ -277,11 +273,14 @@ def caltechdata_write(
|
|
|
277
273
|
raise Exception(result.text)
|
|
278
274
|
idv = result.json()["id"]
|
|
279
275
|
publish_link = result.json()["links"]["publish"]
|
|
276
|
+
file_link = result.json()["links"]["files"]
|
|
280
277
|
|
|
281
278
|
if files:
|
|
282
|
-
file_link = result.json()["links"]["files"]
|
|
283
279
|
write_files_rdm(files, file_link, headers, f_headers, s3, verify=verify)
|
|
284
280
|
|
|
281
|
+
if file_links:
|
|
282
|
+
add_file_links(file_link, file_links, headers)
|
|
283
|
+
|
|
285
284
|
if community:
|
|
286
285
|
review_link = result.json()["links"]["review"]
|
|
287
286
|
send_to_community(
|
|
@@ -364,8 +364,8 @@ def upload_supporting_file(record_id=None):
|
|
|
364
364
|
"Do you want to upload or link data files? (upload/link/n): "
|
|
365
365
|
).lower()
|
|
366
366
|
if choice == "link":
|
|
367
|
-
endpoint = "
|
|
368
|
-
path = "
|
|
367
|
+
endpoint = "caltech2.osn.mghpcc.org"
|
|
368
|
+
path = "caltechdata-public/"
|
|
369
369
|
if not record_id:
|
|
370
370
|
write_s3cmd_config(endpoint)
|
|
371
371
|
print("""S3 connection configured.""")
|
|
@@ -7,28 +7,6 @@ from pathlib import Path
|
|
|
7
7
|
import requests
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
def grid_to_ror(grid):
|
|
11
|
-
# Temporary until InvenioRDM stops spitting out GRIDS
|
|
12
|
-
# We manually handle some incorrect/redundant GRID Ids
|
|
13
|
-
if grid == "grid.451078.f":
|
|
14
|
-
ror = "00hm6j694"
|
|
15
|
-
elif grid == "grid.5805.8":
|
|
16
|
-
ror = "02en5vm52"
|
|
17
|
-
elif grid == "grid.465477.3":
|
|
18
|
-
ror = "00em52312"
|
|
19
|
-
else:
|
|
20
|
-
url = (
|
|
21
|
-
f"https://api.ror.org/organizations?query.advanced=external_ids.all:{grid}"
|
|
22
|
-
)
|
|
23
|
-
results = requests.get(url).json()
|
|
24
|
-
if len(results["items"]) == 0:
|
|
25
|
-
print(url + "doesn't have a valid ROR")
|
|
26
|
-
exit()
|
|
27
|
-
ror = results["items"][0]["id"]
|
|
28
|
-
ror = ror.split("ror.org/")[1]
|
|
29
|
-
return ror
|
|
30
|
-
|
|
31
|
-
|
|
32
10
|
def get_vocabularies():
|
|
33
11
|
"""Returns dictionary of vocabularies"""
|
|
34
12
|
path = Path(__file__).parent
|
|
@@ -297,7 +275,7 @@ def customize_schema_rdm(json_record):
|
|
|
297
275
|
if "geoLocationPoint" in location:
|
|
298
276
|
lat = location["geoLocationPoint"]["pointLatitude"]
|
|
299
277
|
lon = location["geoLocationPoint"]["pointLongitude"]
|
|
300
|
-
new["geometry"] = {"type": "Point", "coordinates": [
|
|
278
|
+
new["geometry"] = {"type": "Point", "coordinates": [lon, lat]}
|
|
301
279
|
if "geoLocationBox" in location:
|
|
302
280
|
south = float(location["geoLocationBox"]["southBoundLatitude"])
|
|
303
281
|
north = float(location["geoLocationBox"]["northBoundLatitude"])
|
|
@@ -307,11 +285,11 @@ def customize_schema_rdm(json_record):
|
|
|
307
285
|
"type": "Polygon",
|
|
308
286
|
"coordinates": [
|
|
309
287
|
[
|
|
310
|
-
[
|
|
311
|
-
[
|
|
312
|
-
[
|
|
313
|
-
[
|
|
314
|
-
[
|
|
288
|
+
[east, north],
|
|
289
|
+
[west, north],
|
|
290
|
+
[west, south],
|
|
291
|
+
[east, south],
|
|
292
|
+
[east, north],
|
|
315
293
|
]
|
|
316
294
|
],
|
|
317
295
|
}
|
|
@@ -335,11 +313,6 @@ def customize_schema_rdm(json_record):
|
|
|
335
313
|
ror = ror.split("ror.org/")[1]
|
|
336
314
|
funder["id"] = ror
|
|
337
315
|
fund.pop("funderIdentifierType")
|
|
338
|
-
elif fund["funderIdentifierType"] == "GRID":
|
|
339
|
-
# We need this temporarily to round-trip data
|
|
340
|
-
ror = grid_to_ror(fund.pop("funderIdentifier"))
|
|
341
|
-
funder["id"] = ror
|
|
342
|
-
fund.pop("funderIdentifierType")
|
|
343
316
|
else:
|
|
344
317
|
print(f'Unknown Type mapping {fund["funderIdentifierType"]}')
|
|
345
318
|
if "awardTitle" in fund:
|
|
@@ -568,8 +541,6 @@ def validate_metadata(json_record):
|
|
|
568
541
|
else:
|
|
569
542
|
|
|
570
543
|
for geo_loc in json_record["geoLocations"]:
|
|
571
|
-
if not isinstance(geo_loc, dict) or "geoLocationPlace" not in geo_loc:
|
|
572
|
-
errors.append("Each 'geoLocation' must have 'geoLocationPlace'.")
|
|
573
544
|
if "geoLocationPoint" in geo_loc:
|
|
574
545
|
point = geo_loc["geoLocationPoint"]
|
|
575
546
|
if (
|
|
@@ -12,11 +12,11 @@ def get_metadata(
|
|
|
12
12
|
production=True,
|
|
13
13
|
validate=True,
|
|
14
14
|
emails=False,
|
|
15
|
-
schema=
|
|
15
|
+
schema=None,
|
|
16
16
|
token=False,
|
|
17
17
|
authors=False,
|
|
18
18
|
):
|
|
19
|
-
# Returns just DataCite metadata or DataCite metadata with emails
|
|
19
|
+
# Returns InvenioRDM metadata, or just DataCite metadata, or DataCite metadata with emails
|
|
20
20
|
|
|
21
21
|
if production == True:
|
|
22
22
|
if authors:
|
|
@@ -35,7 +35,7 @@ def get_metadata(
|
|
|
35
35
|
"accept": "application/json",
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
if authors:
|
|
38
|
+
if authors or schema == None:
|
|
39
39
|
headers = base_headers
|
|
40
40
|
validate = False
|
|
41
41
|
else:
|
|
@@ -114,7 +114,7 @@ if __name__ == "__main__":
|
|
|
114
114
|
action="store_true",
|
|
115
115
|
help="skip validation of metadata",
|
|
116
116
|
)
|
|
117
|
-
parser.add_argument("-schema", default=
|
|
117
|
+
parser.add_argument("-schema", default=None, help="Schema Version")
|
|
118
118
|
|
|
119
119
|
args = parser.parse_args()
|
|
120
120
|
|
|
@@ -1,20 +1,25 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: caltechdata_api
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: Python wrapper for CaltechDATA API.
|
|
5
|
-
|
|
6
|
-
Author: Thomas E Morrell
|
|
7
|
-
|
|
8
|
-
License:
|
|
9
|
-
|
|
5
|
+
Author: Rohan Bhattarai, Elizabeth Won
|
|
6
|
+
Author-email: Thomas E Morrell <tmorrell@caltech.edu>, Alexander A Abakah <aabakah@caltech.edu>, Kshemaahna Nagi <knagi@caltech.edu>
|
|
7
|
+
Maintainer-email: Thomas E Morrell <tmorrell@caltech.edu>
|
|
8
|
+
License-Expression: BSD-3-Clause
|
|
9
|
+
Project-URL: Homepage, https://github.com/caltechlibrary/caltechdata_api
|
|
10
|
+
Project-URL: Repository, https://github.com/caltechlibrary/caltechdata_api
|
|
11
|
+
Project-URL: Issues, https://github.com/caltechlibrary/caltechdata_api/issues
|
|
12
|
+
Keywords: metadata,software,InvenioRDM
|
|
10
13
|
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
13
14
|
Classifier: Programming Language :: Python :: 3.9
|
|
14
15
|
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
15
20
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
16
21
|
Classifier: Operating System :: OS Independent
|
|
17
|
-
Requires-Python: >=3.
|
|
22
|
+
Requires-Python: >=3.9
|
|
18
23
|
Description-Content-Type: text/markdown
|
|
19
24
|
License-File: LICENSE
|
|
20
25
|
Requires-Dist: requests
|
|
@@ -44,7 +49,7 @@ The `caltechdata_api` Python library provides a convenient interface for interac
|
|
|
44
49
|
|
|
45
50
|
## Requirements
|
|
46
51
|
|
|
47
|
-
- Python 3.
|
|
52
|
+
- Python 3.9+
|
|
48
53
|
|
|
49
54
|
## Installation
|
|
50
55
|
|
|
@@ -54,6 +59,18 @@ Install the library via pip:
|
|
|
54
59
|
pip install caltechdata_api
|
|
55
60
|
```
|
|
56
61
|
|
|
62
|
+
Or add it to a [uv](https://docs.astral.sh/uv/) project:
|
|
63
|
+
|
|
64
|
+
```shell
|
|
65
|
+
uv add caltechdata_api
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
You can also run a script using uv:
|
|
69
|
+
|
|
70
|
+
```shell
|
|
71
|
+
uv run write.py
|
|
72
|
+
```
|
|
73
|
+
|
|
57
74
|
## Examples
|
|
58
75
|
|
|
59
76
|
There are some example python scripts in the GitHub repository.
|
|
@@ -61,7 +78,7 @@ There are some example python scripts in the GitHub repository.
|
|
|
61
78
|
### Create a record:
|
|
62
79
|
|
|
63
80
|
```shell
|
|
64
|
-
|
|
81
|
+
uv run write.py example.json -fnames logo.gif
|
|
65
82
|
# Output: pbkn6-m9y63 (unique identifier)
|
|
66
83
|
```
|
|
67
84
|
> The response will be the unique identifier for the record. You can put this at
|
|
@@ -71,7 +88,7 @@ https://data.caltechlibrary.dev/records/pbkn6-m9y63)
|
|
|
71
88
|
### Edit a record
|
|
72
89
|
Make changes to the example.json file to see a change)
|
|
73
90
|
```
|
|
74
|
-
|
|
91
|
+
uv run edit.py example.json -id pbkn6-m9y63
|
|
75
92
|
10.33569/pbkn6-m9y63
|
|
76
93
|
```
|
|
77
94
|
> The response is the DOI for the record, which includes the unique identifier
|
|
@@ -82,13 +99,13 @@ Some groups have worked with the library to create custom DOIs. These can be
|
|
|
82
99
|
passed in the metadata like:
|
|
83
100
|
|
|
84
101
|
```shell
|
|
85
|
-
|
|
102
|
+
uv run write.py example_custom.json -fnames logo.gif
|
|
86
103
|
m6zxz-p4j22
|
|
87
104
|
```
|
|
88
105
|
|
|
89
106
|
And then you can edit with
|
|
90
107
|
```
|
|
91
|
-
|
|
108
|
+
uv run edit.py example_custom.json -id m6zxz-p4j22
|
|
92
109
|
10.5281/inveniordm.1234
|
|
93
110
|
```
|
|
94
111
|
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "caltechdata_api"
|
|
7
|
+
version = "2.1.0"
|
|
8
|
+
description = "Python wrapper for CaltechDATA API."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = "BSD-3-Clause"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
authors = [
|
|
14
|
+
{name = "Thomas E Morrell", email = "tmorrell@caltech.edu"},
|
|
15
|
+
{name = "Rohan Bhattarai"},
|
|
16
|
+
{name = "Elizabeth Won"},
|
|
17
|
+
{name = "Alexander A Abakah", email = "aabakah@caltech.edu"},
|
|
18
|
+
{name = "Kshemaahna Nagi", email = "knagi@caltech.edu"},
|
|
19
|
+
]
|
|
20
|
+
maintainers = [
|
|
21
|
+
{name = "Thomas E Morrell", email = "tmorrell@caltech.edu"},
|
|
22
|
+
]
|
|
23
|
+
keywords = ["metadata", "software", "InvenioRDM"]
|
|
24
|
+
classifiers = [
|
|
25
|
+
"Programming Language :: Python :: 3",
|
|
26
|
+
"Programming Language :: Python :: 3.9",
|
|
27
|
+
"Programming Language :: Python :: 3.10",
|
|
28
|
+
"Programming Language :: Python :: 3.11",
|
|
29
|
+
"Programming Language :: Python :: 3.12",
|
|
30
|
+
"Programming Language :: Python :: 3.13",
|
|
31
|
+
"Programming Language :: Python :: 3.14",
|
|
32
|
+
"Programming Language :: Python :: Implementation :: CPython",
|
|
33
|
+
"Operating System :: OS Independent",
|
|
34
|
+
]
|
|
35
|
+
dependencies = [
|
|
36
|
+
"requests",
|
|
37
|
+
"datacite>1.1.0",
|
|
38
|
+
"tqdm>=4.62.3",
|
|
39
|
+
"pyyaml",
|
|
40
|
+
"s3fs",
|
|
41
|
+
"cryptography",
|
|
42
|
+
"s3cmd",
|
|
43
|
+
"jsonschema-specifications",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
[project.urls]
|
|
47
|
+
Homepage = "https://github.com/caltechlibrary/caltechdata_api"
|
|
48
|
+
Repository = "https://github.com/caltechlibrary/caltechdata_api"
|
|
49
|
+
Issues = "https://github.com/caltechlibrary/caltechdata_api/issues"
|
|
50
|
+
|
|
51
|
+
[project.scripts]
|
|
52
|
+
caltechdata_api = "caltechdata_api.cli:main"
|
|
53
|
+
|
|
54
|
+
[dependency-groups]
|
|
55
|
+
dev = [
|
|
56
|
+
"pytest>=7.0",
|
|
57
|
+
"black",
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
[tool.setuptools.packages.find]
|
|
61
|
+
include = ["caltechdata_api*"]
|
|
62
|
+
|
|
63
|
+
[tool.setuptools.package-data]
|
|
64
|
+
caltechdata_api = ["vocabularies.yaml", "vocabularies/*"]
|
|
65
|
+
|
|
66
|
+
[tool.pytest.ini_options]
|
|
67
|
+
addopts = "--verbose"
|
|
68
|
+
testpaths = ["tests"]
|
|
69
|
+
pythonpath = ["tests"]
|
|
@@ -7,6 +7,10 @@ from caltechdata_api import (
|
|
|
7
7
|
import json
|
|
8
8
|
import os
|
|
9
9
|
|
|
10
|
+
# Any file will do here, we just need something to attach to the test records
|
|
11
|
+
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
12
|
+
UPLOAD_FILE = os.path.join(BASE_DIR, "helpers.py")
|
|
13
|
+
|
|
10
14
|
|
|
11
15
|
def test_datacite_rdm_conversion(full_datacite43_record, full_rdm_record):
|
|
12
16
|
|
|
@@ -48,7 +52,7 @@ def test_datacite_rdm_create_edit(full_datacite43_record):
|
|
|
48
52
|
full_datacite43_record,
|
|
49
53
|
schema="43",
|
|
50
54
|
production=False,
|
|
51
|
-
files=[
|
|
55
|
+
files=[UPLOAD_FILE],
|
|
52
56
|
publish=True,
|
|
53
57
|
token=env_token,
|
|
54
58
|
)
|
|
@@ -68,8 +72,7 @@ def test_datacite_rdm_create_edit(full_datacite43_record):
|
|
|
68
72
|
|
|
69
73
|
assert doi.startswith("10.33569")
|
|
70
74
|
|
|
71
|
-
|
|
72
|
-
new_metadata = get_metadata(recid, production=False, validate=False)
|
|
75
|
+
new_metadata = get_metadata(recid, production=False, schema="43")
|
|
73
76
|
|
|
74
77
|
assert new_metadata["publisher"] == "Edited"
|
|
75
78
|
|
|
@@ -78,7 +81,7 @@ def test_datacite_rdm_create_edit(full_datacite43_record):
|
|
|
78
81
|
new_doi = caltechdata_edit(
|
|
79
82
|
recid,
|
|
80
83
|
full_datacite43_record,
|
|
81
|
-
files=[
|
|
84
|
+
files=[UPLOAD_FILE],
|
|
82
85
|
schema="43",
|
|
83
86
|
production=False,
|
|
84
87
|
publish=True,
|
|
@@ -89,7 +92,6 @@ def test_datacite_rdm_create_edit(full_datacite43_record):
|
|
|
89
92
|
|
|
90
93
|
recid = new_doi.split("/")[1]
|
|
91
94
|
|
|
92
|
-
|
|
93
|
-
new_metadata = get_metadata(recid, production=False, validate=False)
|
|
95
|
+
new_metadata = get_metadata(recid, production=False, schema="43")
|
|
94
96
|
|
|
95
97
|
assert new_metadata["publisher"] == "Again!"
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import pytest
|
|
3
|
+
import logging
|
|
4
|
+
from caltechdata_api import validate_metadata as validator43
|
|
5
|
+
from helpers import load_json_path
|
|
6
|
+
|
|
7
|
+
# Configure logging
|
|
8
|
+
logging.basicConfig(level=logging.DEBUG)
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
# Dynamically determine the base path
|
|
12
|
+
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
13
|
+
INVALID_DATACITE43_DIR = os.path.join(BASE_DIR, "data", "invalid_datacite43")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# Function to get all JSON files in the directory
|
|
17
|
+
def get_all_json_files(directory):
|
|
18
|
+
return [
|
|
19
|
+
os.path.join(directory, f) for f in os.listdir(directory) if f.endswith(".json")
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# Get list of all valid and invalid JSON files
|
|
24
|
+
VALID_DATACITE43_FILES = get_all_json_files(
|
|
25
|
+
os.path.join(BASE_DIR, "data", "datacite43")
|
|
26
|
+
)
|
|
27
|
+
INVALID_DATACITE43_FILES = get_all_json_files(INVALID_DATACITE43_DIR)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@pytest.mark.parametrize("valid_file", VALID_DATACITE43_FILES)
|
|
31
|
+
def test_valid_json(valid_file):
|
|
32
|
+
"""Test that valid example files validate successfully."""
|
|
33
|
+
print(f"\nValidating file: {valid_file}")
|
|
34
|
+
json_data = load_json_path(valid_file)
|
|
35
|
+
validation_errors = None
|
|
36
|
+
try:
|
|
37
|
+
validation_errors = validator43(json_data)
|
|
38
|
+
except ValueError as e:
|
|
39
|
+
pytest.fail(f"Validation failed for: {valid_file}\nErrors: {str(e)}")
|
|
40
|
+
|
|
41
|
+
assert (
|
|
42
|
+
not validation_errors
|
|
43
|
+
), f"Validation failed for: {valid_file}\nErrors: {validation_errors}"
|
|
44
|
+
print(f"Validation passed for: {valid_file}")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@pytest.mark.parametrize("invalid_file", INVALID_DATACITE43_FILES)
|
|
48
|
+
def test_invalid_json(invalid_file):
|
|
49
|
+
"""Test that invalid example files do not validate successfully."""
|
|
50
|
+
logger.debug(f"Attempting to validate invalid file: {invalid_file}")
|
|
51
|
+
|
|
52
|
+
json_data = load_json_path(invalid_file)
|
|
53
|
+
|
|
54
|
+
def validate_wrapper():
|
|
55
|
+
try:
|
|
56
|
+
validation_errors = validator43(json_data)
|
|
57
|
+
|
|
58
|
+
logger.debug(f"Validation result for {invalid_file}: {validation_errors}")
|
|
59
|
+
|
|
60
|
+
if validation_errors:
|
|
61
|
+
logger.debug(f"Found validation errors in {invalid_file}")
|
|
62
|
+
return
|
|
63
|
+
|
|
64
|
+
logger.error(
|
|
65
|
+
f"No validation errors found for supposedly invalid file: {invalid_file}"
|
|
66
|
+
)
|
|
67
|
+
raise ValueError(
|
|
68
|
+
f"Validation did not fail for invalid file: {invalid_file}"
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
except Exception as e:
|
|
72
|
+
logger.error(f"Validation exception for {invalid_file}: {str(e)}")
|
|
73
|
+
raise
|
|
74
|
+
|
|
75
|
+
with pytest.raises((ValueError, KeyError, AssertionError, TypeError)):
|
|
76
|
+
validate_wrapper()
|
caltechdata_api-1.11.0/setup.cfg
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
[build-system]
|
|
2
|
-
requires = ["setuptools>=64.0","wheel"]
|
|
3
|
-
build-backend = "setuptools.build_meta"
|
|
4
|
-
|
|
5
|
-
[metadata]
|
|
6
|
-
name = caltechdata_api
|
|
7
|
-
version = 1.11.0
|
|
8
|
-
author = Thomas E Morrell, Rohan Bhattarai, Elizabeth Won, Alexander A Abakah, Kshemaahna Nagi
|
|
9
|
-
author_email = tmorrell@caltech.edu, aabakah@caltech.edu, knagi@caltech.edu
|
|
10
|
-
description = Python wrapper for CaltechDATA API.
|
|
11
|
-
long_description = file: README.md
|
|
12
|
-
long_description_content_type = text/markdown
|
|
13
|
-
url = https://github.com/caltechlibrary/caltechdata_api
|
|
14
|
-
license = MIT
|
|
15
|
-
classifiers =
|
|
16
|
-
License :: OSI Approved :: MIT License
|
|
17
|
-
Programming Language :: Python :: 3
|
|
18
|
-
Programming Language :: Python :: 3.7
|
|
19
|
-
Programming Language :: Python :: 3.8
|
|
20
|
-
Programming Language :: Python :: 3.9
|
|
21
|
-
Programming Language :: Python :: 3.10
|
|
22
|
-
Programming Language :: Python :: Implementation :: CPython
|
|
23
|
-
Operating System :: OS Independent
|
|
24
|
-
|
|
25
|
-
[options]
|
|
26
|
-
packages = find:
|
|
27
|
-
python_requires = >=3.6.0
|
|
28
|
-
install_requires =
|
|
29
|
-
requests
|
|
30
|
-
datacite>1.1.0
|
|
31
|
-
tqdm>=4.62.3
|
|
32
|
-
pyyaml
|
|
33
|
-
s3fs
|
|
34
|
-
cryptography
|
|
35
|
-
s3cmd
|
|
36
|
-
jsonschema-specifications
|
|
37
|
-
include_package_data = True
|
|
38
|
-
|
|
39
|
-
[options.packages.find]
|
|
40
|
-
exclude = tests
|
|
41
|
-
|
|
42
|
-
[options.package_data]
|
|
43
|
-
caltechdata_api = vocabularies.yaml, vocabularies/*
|
|
44
|
-
|
|
45
|
-
[options.entry_points]
|
|
46
|
-
console_scripts =
|
|
47
|
-
caltechdata_api=caltechdata_api.cli:main
|
|
48
|
-
|
|
49
|
-
[tool:pytest]
|
|
50
|
-
addopts = --verbose
|
|
51
|
-
|
|
52
|
-
[egg_info]
|
|
53
|
-
tag_build =
|
|
54
|
-
tag_date = 0
|
|
55
|
-
|
caltechdata_api-1.11.0/setup.py
DELETED
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import pytest
|
|
3
|
-
import logging
|
|
4
|
-
from caltechdata_api import validate_metadata as validator43
|
|
5
|
-
from helpers import load_json_path
|
|
6
|
-
|
|
7
|
-
# Configure logging
|
|
8
|
-
logging.basicConfig(level=logging.DEBUG)
|
|
9
|
-
logger = logging.getLogger(__name__)
|
|
10
|
-
|
|
11
|
-
# Dynamically determine the base path
|
|
12
|
-
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
13
|
-
INVALID_DATACITE43_DIR = os.path.join(BASE_DIR, "data", "invalid_datacite43")
|
|
14
|
-
DATACITE43_DIR = os.path.join(BASE_DIR, "data")
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
# Function to get all JSON files in the directory
|
|
18
|
-
def get_all_json_files(directory):
|
|
19
|
-
return [
|
|
20
|
-
os.path.join(directory, f) for f in os.listdir(directory) if f.endswith(".json")
|
|
21
|
-
]
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
# Get list of all valid and invalid JSON files
|
|
25
|
-
VALID_DATACITE43_FILES = get_all_json_files(
|
|
26
|
-
os.path.join(BASE_DIR, "data", "datacite43")
|
|
27
|
-
)
|
|
28
|
-
INVALID_DATACITE43_FILES = get_all_json_files(INVALID_DATACITE43_DIR)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
@pytest.mark.parametrize("valid_file", VALID_DATACITE43_FILES)
|
|
32
|
-
def test_valid_json(valid_file):
|
|
33
|
-
"""Test that valid example files validate successfully."""
|
|
34
|
-
print(f"\nValidating file: {valid_file}")
|
|
35
|
-
json_data = load_json_path(valid_file)
|
|
36
|
-
validation_errors = None
|
|
37
|
-
try:
|
|
38
|
-
validation_errors = validator43(json_data)
|
|
39
|
-
except ValueError as e:
|
|
40
|
-
pytest.fail(f"Validation failed for: {valid_file}\nErrors: {str(e)}")
|
|
41
|
-
|
|
42
|
-
assert (
|
|
43
|
-
not validation_errors
|
|
44
|
-
), f"Validation failed for: {valid_file}\nErrors: {validation_errors}"
|
|
45
|
-
print(f"Validation passed for: {valid_file}")
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
@pytest.mark.parametrize("invalid_file", INVALID_DATACITE43_FILES)
|
|
49
|
-
def test_invalid_json(invalid_file):
|
|
50
|
-
"""Test that invalid example files do not validate successfully."""
|
|
51
|
-
logger.debug(f"Attempting to validate invalid file: {invalid_file}")
|
|
52
|
-
|
|
53
|
-
json_data = load_json_path(invalid_file)
|
|
54
|
-
|
|
55
|
-
def validate_wrapper():
|
|
56
|
-
try:
|
|
57
|
-
validation_errors = validator43(json_data)
|
|
58
|
-
|
|
59
|
-
logger.debug(f"Validation result for {invalid_file}: {validation_errors}")
|
|
60
|
-
|
|
61
|
-
if validation_errors:
|
|
62
|
-
logger.debug(f"Found validation errors in {invalid_file}")
|
|
63
|
-
return
|
|
64
|
-
|
|
65
|
-
logger.error(
|
|
66
|
-
f"No validation errors found for supposedly invalid file: {invalid_file}"
|
|
67
|
-
)
|
|
68
|
-
raise ValueError(
|
|
69
|
-
f"Validation did not fail for invalid file: {invalid_file}"
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
except Exception as e:
|
|
73
|
-
logger.error(f"Validation exception for {invalid_file}: {str(e)}")
|
|
74
|
-
raise
|
|
75
|
-
|
|
76
|
-
with pytest.raises((ValueError, KeyError, AssertionError, TypeError)):
|
|
77
|
-
validate_wrapper()
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
@pytest.mark.parametrize(
|
|
81
|
-
"missing_field_file",
|
|
82
|
-
[
|
|
83
|
-
{
|
|
84
|
-
"file": os.path.join(DATACITE43_DIR, "missing_creators.json"),
|
|
85
|
-
"missing_field": "creators",
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
"file": os.path.join(DATACITE43_DIR, "missing_titles.json"),
|
|
89
|
-
"missing_field": "titles",
|
|
90
|
-
},
|
|
91
|
-
],
|
|
92
|
-
)
|
|
93
|
-
def test_missing_required_fields(missing_field_file):
|
|
94
|
-
"""Test that JSON files missing required fields fail validation."""
|
|
95
|
-
print(
|
|
96
|
-
f"\nTesting missing field: {missing_field_file['missing_field']} in file: {missing_field_file['file']}"
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
# Skip the test if the file doesn't exist
|
|
100
|
-
if not os.path.exists(missing_field_file["file"]):
|
|
101
|
-
pytest.skip(f"Test file not found: {missing_field_file['file']}")
|
|
102
|
-
|
|
103
|
-
json_data = load_json_path(missing_field_file["file"])
|
|
104
|
-
with pytest.raises(
|
|
105
|
-
ValueError,
|
|
106
|
-
match=f"Missing required metadata field: {missing_field_file['missing_field']}",
|
|
107
|
-
):
|
|
108
|
-
validator43(json_data)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
@pytest.mark.parametrize(
|
|
112
|
-
"type_error_file",
|
|
113
|
-
[
|
|
114
|
-
{
|
|
115
|
-
"file": os.path.join(DATACITE43_DIR, "type_error_creators.json"),
|
|
116
|
-
"field": "creators",
|
|
117
|
-
},
|
|
118
|
-
{
|
|
119
|
-
"file": os.path.join(DATACITE43_DIR, "type_error_dates.json"),
|
|
120
|
-
"field": "dates",
|
|
121
|
-
},
|
|
122
|
-
],
|
|
123
|
-
)
|
|
124
|
-
def test_incorrect_field_types(type_error_file):
|
|
125
|
-
"""Test that JSON files with incorrect field types fail validation."""
|
|
126
|
-
print(
|
|
127
|
-
f"\nTesting incorrect type in field: {type_error_file['field']} for file: {type_error_file['file']}"
|
|
128
|
-
)
|
|
129
|
-
|
|
130
|
-
# Skip the test if the file doesn't exist
|
|
131
|
-
if not os.path.exists(type_error_file["file"]):
|
|
132
|
-
pytest.skip(f"Test file not found: {type_error_file['file']}")
|
|
133
|
-
|
|
134
|
-
json_data = load_json_path(type_error_file["file"])
|
|
135
|
-
with pytest.raises(
|
|
136
|
-
ValueError, match=f"Incorrect type for field: {type_error_file['field']}"
|
|
137
|
-
):
|
|
138
|
-
validator43(json_data)
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
def test_multiple_errors():
|
|
142
|
-
"""Test JSON file with multiple issues to check all errors are raised."""
|
|
143
|
-
multiple_errors_file = os.path.join(DATACITE43_DIR, "multiple_errors.json")
|
|
144
|
-
|
|
145
|
-
# Skip the test if the file doesn't exist
|
|
146
|
-
if not os.path.exists(multiple_errors_file):
|
|
147
|
-
pytest.skip(f"Test file not found: {multiple_errors_file}")
|
|
148
|
-
|
|
149
|
-
json_data = load_json_path(multiple_errors_file)
|
|
150
|
-
with pytest.raises(ValueError, match="Multiple validation errors"):
|
|
151
|
-
validator43(json_data)
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
def test_error_logging(caplog):
|
|
155
|
-
"""Test that errors are logged correctly during validation."""
|
|
156
|
-
some_invalid_file = os.path.join(INVALID_DATACITE43_DIR, "some_invalid_file.json")
|
|
157
|
-
|
|
158
|
-
# Skip the test if the file doesn't exist
|
|
159
|
-
if not os.path.exists(some_invalid_file):
|
|
160
|
-
pytest.skip(f"Test file not found: {some_invalid_file}")
|
|
161
|
-
|
|
162
|
-
json_data = load_json_path(some_invalid_file)
|
|
163
|
-
with caplog.at_level(logging.ERROR):
|
|
164
|
-
with pytest.raises(ValueError):
|
|
165
|
-
validator43(json_data)
|
|
166
|
-
assert "Validation failed" in caplog.text
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api/vocabularies/date_types.yaml
RENAMED
|
File without changes
|
{caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api/vocabularies/description_types.yaml
RENAMED
|
File without changes
|
{caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api/vocabularies/identifier_types.yaml
RENAMED
|
File without changes
|
|
File without changes
|
{caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api/vocabularies/relation_types.yaml
RENAMED
|
File without changes
|
{caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api/vocabularies/resource_types.yaml
RENAMED
|
File without changes
|
|
File without changes
|
{caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api/vocabularies/title_types.yaml
RENAMED
|
File without changes
|
|
File without changes
|
{caltechdata_api-1.11.0 → caltechdata_api-2.1.0}/caltechdata_api.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|