caltechdata-api 1.9.1__tar.gz → 1.10.1__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.9.1 → caltechdata_api-1.10.1}/PKG-INFO +14 -10
- {caltechdata_api-1.9.1 → caltechdata_api-1.10.1}/README.md +5 -2
- {caltechdata_api-1.9.1 → caltechdata_api-1.10.1}/caltechdata_api/__init__.py +2 -1
- {caltechdata_api-1.9.1 → caltechdata_api-1.10.1}/caltechdata_api/caltechdata_edit.py +8 -4
- {caltechdata_api-1.9.1 → caltechdata_api-1.10.1}/caltechdata_api/cli.py +140 -35
- {caltechdata_api-1.9.1 → caltechdata_api-1.10.1}/caltechdata_api/customize_schema.py +26 -27
- {caltechdata_api-1.9.1 → caltechdata_api-1.10.1}/caltechdata_api.egg-info/PKG-INFO +14 -10
- {caltechdata_api-1.9.1 → caltechdata_api-1.10.1}/caltechdata_api.egg-info/SOURCES.txt +2 -0
- caltechdata_api-1.10.1/pyproject.toml +3 -0
- caltechdata_api-1.10.1/setup.cfg +54 -0
- caltechdata_api-1.10.1/setup.py +3 -0
- caltechdata_api-1.9.1/setup.cfg +0 -4
- caltechdata_api-1.9.1/setup.py +0 -179
- {caltechdata_api-1.9.1 → caltechdata_api-1.10.1}/LICENSE +0 -0
- {caltechdata_api-1.9.1 → caltechdata_api-1.10.1}/caltechdata_api/caltechdata_write.py +0 -0
- {caltechdata_api-1.9.1 → caltechdata_api-1.10.1}/caltechdata_api/download_file.py +0 -0
- {caltechdata_api-1.9.1 → caltechdata_api-1.10.1}/caltechdata_api/get_files.py +0 -0
- {caltechdata_api-1.9.1 → caltechdata_api-1.10.1}/caltechdata_api/get_metadata.py +0 -0
- {caltechdata_api-1.9.1 → caltechdata_api-1.10.1}/caltechdata_api/md_to_json.py +0 -0
- {caltechdata_api-1.9.1 → caltechdata_api-1.10.1}/caltechdata_api/utils.py +0 -0
- {caltechdata_api-1.9.1 → caltechdata_api-1.10.1}/caltechdata_api.egg-info/dependency_links.txt +0 -0
- {caltechdata_api-1.9.1 → caltechdata_api-1.10.1}/caltechdata_api.egg-info/entry_points.txt +0 -0
- {caltechdata_api-1.9.1 → caltechdata_api-1.10.1}/caltechdata_api.egg-info/requires.txt +0 -0
- {caltechdata_api-1.9.1 → caltechdata_api-1.10.1}/caltechdata_api.egg-info/top_level.txt +0 -0
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: caltechdata_api
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.10.1
|
|
4
4
|
Summary: Python wrapper for CaltechDATA API.
|
|
5
5
|
Home-page: https://github.com/caltechlibrary/caltechdata_api
|
|
6
|
-
Author: Thomas E Morrell,
|
|
7
|
-
Author-email: tmorrell@caltech.edu, ,
|
|
8
|
-
License:
|
|
6
|
+
Author: Thomas E Morrell, Rohan Bhattarai, Elizabeth Won, Alexander A Abakah, Kshemaahna Nagi
|
|
7
|
+
Author-email: tmorrell@caltech.edu, aabakah@caltech.edu, knagi@caltech.edu
|
|
8
|
+
License: MIT
|
|
9
9
|
Platform: UNKNOWN
|
|
10
|
-
Classifier: License :: OSI Approved ::
|
|
11
|
-
Classifier: Programming Language :: Python
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
11
|
Classifier: Programming Language :: Python :: 3
|
|
13
12
|
Classifier: Programming Language :: Python :: 3.7
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
16
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
15
|
-
Classifier:
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
16
18
|
Requires-Python: >=3.6.0
|
|
17
19
|
Description-Content-Type: text/markdown
|
|
18
20
|
License-File: LICENSE
|
|
19
21
|
|
|
20
|
-
|
|
21
22
|
# CaltechDATA API Python Library
|
|
22
23
|
|
|
23
24
|
[](https://data.caltech.edu/records/wfjr5-kw507/latest)
|
|
@@ -49,7 +50,7 @@ pip install caltechdata_api
|
|
|
49
50
|
|
|
50
51
|
There are some example python scripts in the GitHub repository.
|
|
51
52
|
|
|
52
|
-
###Create a record:
|
|
53
|
+
### Create a record:
|
|
53
54
|
|
|
54
55
|
```shell
|
|
55
56
|
python write.py example.json -fnames logo.gif
|
|
@@ -59,7 +60,7 @@ python write.py example.json -fnames logo.gif
|
|
|
59
60
|
the end of a url to visit the record (e.g.
|
|
60
61
|
https://data.caltechlibrary.dev/records/pbkn6-m9y63)
|
|
61
62
|
|
|
62
|
-
###Edit a record
|
|
63
|
+
### Edit a record
|
|
63
64
|
Make changes to the example.json file to see a change)
|
|
64
65
|
```
|
|
65
66
|
python edit.py example.json -id pbkn6-m9y63
|
|
@@ -97,5 +98,8 @@ This returns the custom DOI of the record if it is successful.
|
|
|
97
98
|
Only test your application on the test repository (`data.caltechlibrary.dev`). Testing the API on the public
|
|
98
99
|
repository will generate junk records that are annoying to delete.
|
|
99
100
|
|
|
101
|
+
## Using the Command Line Interface
|
|
102
|
+
|
|
103
|
+
If you would like to interact with the CaltechDATA API using the Command line Interface (CLI), please [see the detailed documentation](https://caltechlibrary.github.io/caltechdata_api/caltechdata_api/cli-documentation-for-users).
|
|
100
104
|
|
|
101
105
|
|
|
@@ -29,7 +29,7 @@ pip install caltechdata_api
|
|
|
29
29
|
|
|
30
30
|
There are some example python scripts in the GitHub repository.
|
|
31
31
|
|
|
32
|
-
###Create a record:
|
|
32
|
+
### Create a record:
|
|
33
33
|
|
|
34
34
|
```shell
|
|
35
35
|
python write.py example.json -fnames logo.gif
|
|
@@ -39,7 +39,7 @@ python write.py example.json -fnames logo.gif
|
|
|
39
39
|
the end of a url to visit the record (e.g.
|
|
40
40
|
https://data.caltechlibrary.dev/records/pbkn6-m9y63)
|
|
41
41
|
|
|
42
|
-
###Edit a record
|
|
42
|
+
### Edit a record
|
|
43
43
|
Make changes to the example.json file to see a change)
|
|
44
44
|
```
|
|
45
45
|
python edit.py example.json -id pbkn6-m9y63
|
|
@@ -77,3 +77,6 @@ This returns the custom DOI of the record if it is successful.
|
|
|
77
77
|
Only test your application on the test repository (`data.caltechlibrary.dev`). Testing the API on the public
|
|
78
78
|
repository will generate junk records that are annoying to delete.
|
|
79
79
|
|
|
80
|
+
## Using the Command Line Interface
|
|
81
|
+
|
|
82
|
+
If you would like to interact with the CaltechDATA API using the Command line Interface (CLI), please [see the detailed documentation](https://caltechlibrary.github.io/caltechdata_api/caltechdata_api/cli-documentation-for-users).
|
|
@@ -9,7 +9,8 @@ from .caltechdata_edit import (
|
|
|
9
9
|
caltechdata_unembargo,
|
|
10
10
|
caltechdata_accept,
|
|
11
11
|
)
|
|
12
|
-
from .customize_schema import customize_schema
|
|
12
|
+
from .customize_schema import customize_schema, validate_metadata
|
|
13
13
|
from .get_metadata import get_metadata
|
|
14
14
|
from .download_file import download_file, download_url
|
|
15
15
|
from .utils import humanbytes
|
|
16
|
+
from .md_to_json import parse_readme_to_json
|
|
@@ -66,6 +66,7 @@ def caltechdata_edit(
|
|
|
66
66
|
default_preview=None,
|
|
67
67
|
authors=False,
|
|
68
68
|
keepfiles=False,
|
|
69
|
+
return_id=False,
|
|
69
70
|
):
|
|
70
71
|
# Make a copy of the metadata to make sure our local changes don't leak
|
|
71
72
|
metadata = copy.deepcopy(metadata)
|
|
@@ -299,10 +300,13 @@ def caltechdata_edit(
|
|
|
299
300
|
result = requests.post(publish_link, headers=headers)
|
|
300
301
|
if result.status_code != 202:
|
|
301
302
|
raise Exception(result.text)
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
return pids["doi"]["identifier"]
|
|
303
|
+
if return_id:
|
|
304
|
+
return result.json()["id"]
|
|
305
305
|
else:
|
|
306
|
-
|
|
306
|
+
pids = result.json()["pids"]
|
|
307
|
+
if "doi" in pids:
|
|
308
|
+
return pids["doi"]["identifier"]
|
|
309
|
+
else:
|
|
310
|
+
return pids["oai"]["identifier"]
|
|
307
311
|
else:
|
|
308
312
|
return idv
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import argparse
|
|
2
2
|
import requests
|
|
3
3
|
import s3fs
|
|
4
|
-
from caltechdata_api import caltechdata_write, caltechdata_edit
|
|
5
|
-
from md_to_json import parse_readme_to_json
|
|
4
|
+
from caltechdata_api import caltechdata_write, caltechdata_edit, parse_readme_to_json
|
|
6
5
|
import json
|
|
7
6
|
import os
|
|
8
7
|
from cryptography.fernet import Fernet
|
|
@@ -59,11 +58,17 @@ def decrypt_token(encrypted_token, key):
|
|
|
59
58
|
return f.decrypt(encrypted_token).decode()
|
|
60
59
|
|
|
61
60
|
|
|
62
|
-
# Function to get or set token with support for test system
|
|
61
|
+
# Function to get or set token with support for test system.
|
|
63
62
|
def get_or_set_token(production=True):
|
|
63
|
+
# First check for environment variable
|
|
64
|
+
env_token = os.environ.get("CALTECHDATA_TOKEN")
|
|
65
|
+
if env_token:
|
|
66
|
+
print("Using token from environment variable")
|
|
67
|
+
return env_token
|
|
68
|
+
|
|
64
69
|
key = load_or_generate_key()
|
|
65
70
|
|
|
66
|
-
# Use different token files for production and test
|
|
71
|
+
# Use different token files for production and test environment.
|
|
67
72
|
token_filename = "token.txt" if production else "token_test.txt"
|
|
68
73
|
token_file = os.path.join(caltechdata_directory, token_filename)
|
|
69
74
|
|
|
@@ -94,6 +99,16 @@ def get_or_set_token(production=True):
|
|
|
94
99
|
print("Tokens do not match. Please try again.")
|
|
95
100
|
|
|
96
101
|
|
|
102
|
+
# Delete the saved token file.
|
|
103
|
+
def delete_saved_token():
|
|
104
|
+
token_file = os.path.join(caltechdata_directory, "token.txt")
|
|
105
|
+
if os.path.exists(token_file):
|
|
106
|
+
os.remove(token_file)
|
|
107
|
+
print("Token deleted successfully.")
|
|
108
|
+
else:
|
|
109
|
+
print("No token found to delete.")
|
|
110
|
+
|
|
111
|
+
|
|
97
112
|
def welcome_message():
|
|
98
113
|
print("Welcome to CaltechDATA CLI")
|
|
99
114
|
|
|
@@ -181,6 +196,61 @@ def get_funding_details():
|
|
|
181
196
|
}
|
|
182
197
|
|
|
183
198
|
|
|
199
|
+
# Add profile handling functions
|
|
200
|
+
def save_profile():
|
|
201
|
+
profile_file = os.path.join(caltechdata_directory, "profile.json")
|
|
202
|
+
|
|
203
|
+
# Get ORCID
|
|
204
|
+
while True:
|
|
205
|
+
orcid = get_user_input("Enter your ORCID identifier: ")
|
|
206
|
+
orcid = normalize_orcid(orcid)
|
|
207
|
+
family_name, given_name = get_names(orcid)
|
|
208
|
+
if family_name is not None and given_name is not None:
|
|
209
|
+
break
|
|
210
|
+
retry = input("Do you want to try again? (y/n): ")
|
|
211
|
+
if retry.lower() != "y":
|
|
212
|
+
return None
|
|
213
|
+
|
|
214
|
+
# Get funding details
|
|
215
|
+
funding_references = []
|
|
216
|
+
num_funding_entries = get_funding_entries()
|
|
217
|
+
for _ in range(num_funding_entries):
|
|
218
|
+
funding_references.append(get_funding_details())
|
|
219
|
+
|
|
220
|
+
profile_data = {
|
|
221
|
+
"orcid": orcid,
|
|
222
|
+
"family_name": family_name,
|
|
223
|
+
"given_name": given_name,
|
|
224
|
+
"funding_references": funding_references,
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
with open(profile_file, "w") as f:
|
|
228
|
+
json.dump(profile_data, f, indent=2)
|
|
229
|
+
|
|
230
|
+
print("Profile saved successfully!")
|
|
231
|
+
return profile_data
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def load_profile():
|
|
235
|
+
profile_file = os.path.join(caltechdata_directory, "profile.json")
|
|
236
|
+
try:
|
|
237
|
+
with open(profile_file, "r") as f:
|
|
238
|
+
return json.load(f)
|
|
239
|
+
except FileNotFoundError:
|
|
240
|
+
return None
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def get_or_create_profile():
|
|
244
|
+
profile = load_profile()
|
|
245
|
+
if profile:
|
|
246
|
+
use_saved = input("Use saved profile? (y/n): ").lower()
|
|
247
|
+
if use_saved == "y":
|
|
248
|
+
return profile
|
|
249
|
+
|
|
250
|
+
print("Creating new profile...")
|
|
251
|
+
return save_profile()
|
|
252
|
+
|
|
253
|
+
|
|
184
254
|
def parse_arguments():
|
|
185
255
|
welcome_message()
|
|
186
256
|
args = {}
|
|
@@ -217,23 +287,17 @@ def parse_arguments():
|
|
|
217
287
|
break
|
|
218
288
|
else:
|
|
219
289
|
print("Invalid input. Please enter a number between 1 and 8.")
|
|
290
|
+
# Load or create profile
|
|
291
|
+
profile = get_or_create_profile()
|
|
292
|
+
if profile:
|
|
293
|
+
args["orcid"] = profile["orcid"]
|
|
294
|
+
args["family_name"] = profile["family_name"]
|
|
295
|
+
args["given_name"] = profile["given_name"]
|
|
296
|
+
args["fundingReferences"] = profile["funding_references"]
|
|
297
|
+
else:
|
|
298
|
+
print("Failed to load or create profile. Exiting.")
|
|
299
|
+
return None
|
|
220
300
|
|
|
221
|
-
while True:
|
|
222
|
-
orcid = get_user_input("Enter your ORCID identifier: ")
|
|
223
|
-
family_name, given_name = get_names(orcid)
|
|
224
|
-
if family_name is not None and given_name is not None:
|
|
225
|
-
args["orcid"] = orcid
|
|
226
|
-
break # Break out of the loop if names are successfully retrieved
|
|
227
|
-
retry = input("Do you want to try again? (y/n): ")
|
|
228
|
-
if retry.lower() != "y":
|
|
229
|
-
print("Exiting program.")
|
|
230
|
-
return
|
|
231
|
-
# Optional arguments
|
|
232
|
-
num_funding_entries = get_funding_entries()
|
|
233
|
-
funding_references = []
|
|
234
|
-
for _ in range(num_funding_entries):
|
|
235
|
-
funding_references.append(get_funding_details())
|
|
236
|
-
args["fundingReferences"] = funding_references
|
|
237
301
|
return args
|
|
238
302
|
|
|
239
303
|
|
|
@@ -296,6 +360,7 @@ def upload_supporting_file(record_id=None):
|
|
|
296
360
|
filepaths = []
|
|
297
361
|
file_link = ""
|
|
298
362
|
file_links = []
|
|
363
|
+
idx = 0
|
|
299
364
|
while True:
|
|
300
365
|
choice = get_user_input(
|
|
301
366
|
"Do you want to upload or link data files? (upload/link/n): "
|
|
@@ -338,14 +403,28 @@ def upload_supporting_file(record_id=None):
|
|
|
338
403
|
files = [
|
|
339
404
|
f for f in os.listdir() if not f.endswith(".json") and os.path.isfile(f)
|
|
340
405
|
]
|
|
341
|
-
|
|
406
|
+
idx += 1
|
|
407
|
+
print((f"{idx}/ \n").join(files))
|
|
342
408
|
while True:
|
|
343
409
|
filename = get_user_input(
|
|
344
|
-
"Enter the filename to upload as a supporting file (or 'n' to finish): "
|
|
410
|
+
"Enter the filename to upload as a supporting file (or '*' to get all files currently in this directory, or the index number of the file as displayed followed by a /, otherwise 'n' to finish): "
|
|
345
411
|
)
|
|
346
|
-
if filename == "
|
|
412
|
+
if filename == "*":
|
|
413
|
+
for files_name in files:
|
|
414
|
+
filepath = os.path.abspath(files_name)
|
|
415
|
+
filepaths.append(filepath)
|
|
416
|
+
print("All files added successfully")
|
|
417
|
+
elif filename == "n":
|
|
347
418
|
break
|
|
348
|
-
|
|
419
|
+
elif (not len(filename) == 0) and (filename[len(filename) - 1] == "/"):
|
|
420
|
+
try:
|
|
421
|
+
files_name = files[int(filename[0]) - 1]
|
|
422
|
+
filepath = os.path.abspath(files_name)
|
|
423
|
+
filepaths.append(filepath)
|
|
424
|
+
print("File added successfully")
|
|
425
|
+
except ValueError:
|
|
426
|
+
continue
|
|
427
|
+
elif filename in files:
|
|
349
428
|
file_size = os.path.getsize(filename)
|
|
350
429
|
if file_size > 1024 * 1024 * 1024:
|
|
351
430
|
print(
|
|
@@ -356,6 +435,7 @@ def upload_supporting_file(record_id=None):
|
|
|
356
435
|
else:
|
|
357
436
|
filepath = os.path.abspath(filename)
|
|
358
437
|
filepaths.append(filepath)
|
|
438
|
+
print("File added successfully")
|
|
359
439
|
else:
|
|
360
440
|
print(
|
|
361
441
|
f"Error: File '{filename}' not found. Please enter a valid filename."
|
|
@@ -405,24 +485,48 @@ def parse_args():
|
|
|
405
485
|
parser.add_argument(
|
|
406
486
|
"-test", action="store_true", help="Use test mode, sets production to False"
|
|
407
487
|
)
|
|
488
|
+
parser.add_argument(
|
|
489
|
+
"--delete-token", action="store_true", help="Delete the saved token."
|
|
490
|
+
)
|
|
408
491
|
args = parser.parse_args()
|
|
409
492
|
return args
|
|
410
493
|
|
|
411
494
|
|
|
495
|
+
def normalize_orcid(val):
|
|
496
|
+
orcid_urls = ["https://orcid.org/", "http://orcid.org/", "orcid.org/"]
|
|
497
|
+
for orcid_url in orcid_urls:
|
|
498
|
+
if val.startswith(orcid_url):
|
|
499
|
+
val = val[len(orcid_url) :]
|
|
500
|
+
break
|
|
501
|
+
|
|
502
|
+
val = val.replace("-", "").replace(" ", "")
|
|
503
|
+
if len(val) != 16 or not val.isdigit():
|
|
504
|
+
raise ValueError(f"Invalid ORCID identifier: {val}")
|
|
505
|
+
return "-".join([val[0:4], val[4:8], val[8:12], val[12:16]])
|
|
506
|
+
|
|
507
|
+
|
|
412
508
|
def main():
|
|
413
509
|
args = parse_args()
|
|
510
|
+
production = not args.test
|
|
511
|
+
if args.delete_token:
|
|
512
|
+
delete_saved_token()
|
|
513
|
+
while True:
|
|
514
|
+
choice = get_user_input(
|
|
515
|
+
"What would you like to do? (create/edit/profile/exit): "
|
|
516
|
+
).lower()
|
|
414
517
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
518
|
+
if choice == "create":
|
|
519
|
+
create_record(production)
|
|
520
|
+
elif choice == "edit":
|
|
521
|
+
edit_record(production)
|
|
522
|
+
elif choice == "profile":
|
|
523
|
+
save_profile()
|
|
524
|
+
elif choice == "exit":
|
|
525
|
+
break
|
|
526
|
+
else:
|
|
527
|
+
print(
|
|
528
|
+
"Invalid choice. Please enter 'create', 'edit', 'profile', or 'exit'."
|
|
529
|
+
)
|
|
426
530
|
|
|
427
531
|
|
|
428
532
|
def create_record(production):
|
|
@@ -521,6 +625,7 @@ def create_record(production):
|
|
|
521
625
|
print_upload_message(rec_id, production)
|
|
522
626
|
with open(response + ".json", "w") as file:
|
|
523
627
|
json.dump(metadata, file, indent=2)
|
|
628
|
+
exit()
|
|
524
629
|
break
|
|
525
630
|
else:
|
|
526
631
|
break
|
|
@@ -373,7 +373,8 @@ def customize_schema_rdm(json_record):
|
|
|
373
373
|
if "community" in json_record:
|
|
374
374
|
com = json_record.pop("community")
|
|
375
375
|
parent["communities"] = {"ids": [com], "default": com}
|
|
376
|
-
|
|
376
|
+
if parent != {}:
|
|
377
|
+
final["parent"] = parent
|
|
377
378
|
# Not technically datacite, but transfer pids information
|
|
378
379
|
if "pids" in json_record:
|
|
379
380
|
final["pids"] = json_record.pop("pids")
|
|
@@ -408,11 +409,11 @@ def validate_metadata(json_record):
|
|
|
408
409
|
|
|
409
410
|
# Publication date is handled by customize function
|
|
410
411
|
|
|
411
|
-
# Check for '
|
|
412
|
-
if "
|
|
413
|
-
errors.append("'
|
|
414
|
-
elif not isinstance(json_record["types"]["
|
|
415
|
-
errors.append("'
|
|
412
|
+
# Check for 'resourceTypeGeneral'
|
|
413
|
+
if "resourceTypeGeneral" not in json_record["types"]:
|
|
414
|
+
errors.append("'resourceTypeGeneral' field is missing in 'types'.")
|
|
415
|
+
elif not isinstance(json_record["types"]["resourceTypeGeneral"], str):
|
|
416
|
+
errors.append("'resourceTypeGeneral' should be a string.")
|
|
416
417
|
|
|
417
418
|
# Check for 'identifiers'
|
|
418
419
|
if "identifiers" in json_record:
|
|
@@ -480,18 +481,17 @@ def validate_metadata(json_record):
|
|
|
480
481
|
errors.append("Each 'subject' must have a 'subject' key.")
|
|
481
482
|
|
|
482
483
|
# Check for 'dates'
|
|
483
|
-
if "dates"
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
errors.append("Each 'date' must have 'date' and 'dateType'.")
|
|
484
|
+
if "dates" in json_record:
|
|
485
|
+
if not isinstance(json_record["dates"], list) or len(json_record["dates"]) == 0:
|
|
486
|
+
errors.append("'dates' should be a non-empty list.")
|
|
487
|
+
else:
|
|
488
|
+
for date in json_record["dates"]:
|
|
489
|
+
if (
|
|
490
|
+
not isinstance(date, dict)
|
|
491
|
+
or "date" not in date
|
|
492
|
+
or "dateType" not in date
|
|
493
|
+
):
|
|
494
|
+
errors.append("Each 'date' must have 'date' and 'dateType'.")
|
|
495
495
|
|
|
496
496
|
# Check for 'creators'
|
|
497
497
|
if "creators" not in json_record:
|
|
@@ -509,11 +509,11 @@ def validate_metadata(json_record):
|
|
|
509
509
|
if creator["nameType"] == "Organizational":
|
|
510
510
|
if "name" not in creator:
|
|
511
511
|
errors.append("Each organizational 'creator' must have 'name'.")
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
512
|
+
else:
|
|
513
|
+
if "familyName" not in creator:
|
|
514
|
+
errors.append(
|
|
515
|
+
"Each 'creator' must have a 'familyName' or have type Organizational"
|
|
516
|
+
)
|
|
517
517
|
if "affiliation" in creator:
|
|
518
518
|
if not isinstance(creator["affiliation"], list):
|
|
519
519
|
errors.append("'affiliation' in 'creators' should be a list.")
|
|
@@ -601,10 +601,9 @@ def validate_metadata(json_record):
|
|
|
601
601
|
errors.append("'publisher' should be a string.")
|
|
602
602
|
|
|
603
603
|
# Check for 'publicationYear'
|
|
604
|
-
if "publicationYear"
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
errors.append("'publicationYear' should be a string.")
|
|
604
|
+
if "publicationYear" in json_record:
|
|
605
|
+
if not isinstance(json_record["publicationYear"], str):
|
|
606
|
+
errors.append("'publicationYear' should be a string.")
|
|
608
607
|
|
|
609
608
|
# Check for 'types'
|
|
610
609
|
if "types" not in json_record:
|
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: caltechdata-api
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.10.1
|
|
4
4
|
Summary: Python wrapper for CaltechDATA API.
|
|
5
5
|
Home-page: https://github.com/caltechlibrary/caltechdata_api
|
|
6
|
-
Author: Thomas E Morrell,
|
|
7
|
-
Author-email: tmorrell@caltech.edu, ,
|
|
8
|
-
License:
|
|
6
|
+
Author: Thomas E Morrell, Rohan Bhattarai, Elizabeth Won, Alexander A Abakah, Kshemaahna Nagi
|
|
7
|
+
Author-email: tmorrell@caltech.edu, aabakah@caltech.edu, knagi@caltech.edu
|
|
8
|
+
License: MIT
|
|
9
9
|
Platform: UNKNOWN
|
|
10
|
-
Classifier: License :: OSI Approved ::
|
|
11
|
-
Classifier: Programming Language :: Python
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
11
|
Classifier: Programming Language :: Python :: 3
|
|
13
12
|
Classifier: Programming Language :: Python :: 3.7
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
16
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
15
|
-
Classifier:
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
16
18
|
Requires-Python: >=3.6.0
|
|
17
19
|
Description-Content-Type: text/markdown
|
|
18
20
|
License-File: LICENSE
|
|
19
21
|
|
|
20
|
-
|
|
21
22
|
# CaltechDATA API Python Library
|
|
22
23
|
|
|
23
24
|
[](https://data.caltech.edu/records/wfjr5-kw507/latest)
|
|
@@ -49,7 +50,7 @@ pip install caltechdata_api
|
|
|
49
50
|
|
|
50
51
|
There are some example python scripts in the GitHub repository.
|
|
51
52
|
|
|
52
|
-
###Create a record:
|
|
53
|
+
### Create a record:
|
|
53
54
|
|
|
54
55
|
```shell
|
|
55
56
|
python write.py example.json -fnames logo.gif
|
|
@@ -59,7 +60,7 @@ python write.py example.json -fnames logo.gif
|
|
|
59
60
|
the end of a url to visit the record (e.g.
|
|
60
61
|
https://data.caltechlibrary.dev/records/pbkn6-m9y63)
|
|
61
62
|
|
|
62
|
-
###Edit a record
|
|
63
|
+
### Edit a record
|
|
63
64
|
Make changes to the example.json file to see a change)
|
|
64
65
|
```
|
|
65
66
|
python edit.py example.json -id pbkn6-m9y63
|
|
@@ -97,5 +98,8 @@ This returns the custom DOI of the record if it is successful.
|
|
|
97
98
|
Only test your application on the test repository (`data.caltechlibrary.dev`). Testing the API on the public
|
|
98
99
|
repository will generate junk records that are annoying to delete.
|
|
99
100
|
|
|
101
|
+
## Using the Command Line Interface
|
|
102
|
+
|
|
103
|
+
If you would like to interact with the CaltechDATA API using the Command line Interface (CLI), please [see the detailed documentation](https://caltechlibrary.github.io/caltechdata_api/caltechdata_api/cli-documentation-for-users).
|
|
100
104
|
|
|
101
105
|
|
|
@@ -0,0 +1,54 @@
|
|
|
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.10.1
|
|
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
|
+
include_package_data = True
|
|
37
|
+
|
|
38
|
+
[options.packages.find]
|
|
39
|
+
exclude = tests
|
|
40
|
+
|
|
41
|
+
[options.package_data]
|
|
42
|
+
caltechdata_api = vocabularies.yaml, vocabularies/*
|
|
43
|
+
|
|
44
|
+
[options.entry_points]
|
|
45
|
+
console_scripts =
|
|
46
|
+
caltechdata_api=caltechdata_api.cli:main
|
|
47
|
+
|
|
48
|
+
[tool:pytest]
|
|
49
|
+
addopts = --verbose
|
|
50
|
+
|
|
51
|
+
[egg_info]
|
|
52
|
+
tag_build =
|
|
53
|
+
tag_date = 0
|
|
54
|
+
|
caltechdata_api-1.9.1/setup.cfg
DELETED
caltechdata_api-1.9.1/setup.py
DELETED
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
|
|
4
|
-
# Note: To use the 'upload' functionality of this file, you must:
|
|
5
|
-
# $ pip install twine
|
|
6
|
-
|
|
7
|
-
import io, json
|
|
8
|
-
import os
|
|
9
|
-
import sys
|
|
10
|
-
import glob
|
|
11
|
-
from shutil import rmtree
|
|
12
|
-
|
|
13
|
-
from setuptools import find_packages, setup, Command
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def read(fname):
|
|
17
|
-
with open(fname, mode="r", encoding="utf-8") as f:
|
|
18
|
-
src = f.read()
|
|
19
|
-
return src
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def package_files(package, directory):
|
|
23
|
-
os.chdir(package)
|
|
24
|
-
paths = glob.glob(directory + "/**", recursive=True)
|
|
25
|
-
os.chdir("..")
|
|
26
|
-
return paths
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
codemeta_json = "codemeta.json"
|
|
30
|
-
|
|
31
|
-
# Let's pickup as much metadata as we need from codemeta.json
|
|
32
|
-
with open(codemeta_json, mode="r", encoding="utf-8") as f:
|
|
33
|
-
src = f.read()
|
|
34
|
-
meta = json.loads(src)
|
|
35
|
-
|
|
36
|
-
# Let's make our symvar string
|
|
37
|
-
version = meta["version"]
|
|
38
|
-
|
|
39
|
-
# Now we need to pull and format our author, author_email strings.
|
|
40
|
-
author = ""
|
|
41
|
-
author_email = ""
|
|
42
|
-
for obj in meta["author"]:
|
|
43
|
-
given = obj.get("givenName", "")
|
|
44
|
-
family = obj.get("familyName", "")
|
|
45
|
-
email = obj.get("email", "")
|
|
46
|
-
if len(author) == 0:
|
|
47
|
-
author = given + " " + family
|
|
48
|
-
else:
|
|
49
|
-
author = author + ", " + given + " " + family
|
|
50
|
-
if len(author_email) == 0:
|
|
51
|
-
author_email = email
|
|
52
|
-
else:
|
|
53
|
-
author_email = author_email + ", " + email
|
|
54
|
-
description = meta["description"]
|
|
55
|
-
url = meta["codeRepository"]
|
|
56
|
-
download = meta["downloadUrl"]
|
|
57
|
-
license = meta["license"]
|
|
58
|
-
name = meta["name"]
|
|
59
|
-
|
|
60
|
-
REQUIRES_PYTHON = ">=3.6.0"
|
|
61
|
-
|
|
62
|
-
# What packages are required for this module to be executed?
|
|
63
|
-
REQUIRED = [
|
|
64
|
-
"requests",
|
|
65
|
-
"datacite>1.1.0",
|
|
66
|
-
"tqdm>=4.62.3",
|
|
67
|
-
"pyyaml",
|
|
68
|
-
"s3fs",
|
|
69
|
-
"cryptography",
|
|
70
|
-
"s3cmd",
|
|
71
|
-
]
|
|
72
|
-
|
|
73
|
-
# What packages are optional?
|
|
74
|
-
EXTRAS = {
|
|
75
|
-
# 'fancy feature': ['django'],
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
files = package_files("caltechdata_api", "vocabularies")
|
|
79
|
-
files.append("vocabularies.yaml")
|
|
80
|
-
|
|
81
|
-
# The rest you shouldn't have to touch too much :)
|
|
82
|
-
# ------------------------------------------------
|
|
83
|
-
# Except, perhaps the License and Trove Classifiers!
|
|
84
|
-
# If you do change the License, remember to change the Trove Classifier for that!
|
|
85
|
-
|
|
86
|
-
here = os.path.abspath(os.path.dirname(__file__))
|
|
87
|
-
|
|
88
|
-
# Import the README and use it as the long-description.
|
|
89
|
-
# Note: this will only work if 'README.md' is present in your MANIFEST.in file!
|
|
90
|
-
try:
|
|
91
|
-
with io.open(os.path.join(here, "README.md"), encoding="utf-8") as f:
|
|
92
|
-
long_description = "\n" + f.read()
|
|
93
|
-
except FileNotFoundError:
|
|
94
|
-
long_description = description
|
|
95
|
-
|
|
96
|
-
# Load the package's __version__.py module as a dictionary.
|
|
97
|
-
about = {}
|
|
98
|
-
if not version:
|
|
99
|
-
with open(os.path.join(here, NAME, "__version__.py")) as f:
|
|
100
|
-
exec(f.read(), about)
|
|
101
|
-
else:
|
|
102
|
-
about["__version__"] = version
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
class UploadCommand(Command):
|
|
106
|
-
"""Support setup.py upload."""
|
|
107
|
-
|
|
108
|
-
description = "Build and publish the package."
|
|
109
|
-
user_options = []
|
|
110
|
-
|
|
111
|
-
@staticmethod
|
|
112
|
-
def status(s):
|
|
113
|
-
"""Prints things in bold."""
|
|
114
|
-
print("\033[1m{0}\033[0m".format(s))
|
|
115
|
-
|
|
116
|
-
def initialize_options(self):
|
|
117
|
-
pass
|
|
118
|
-
|
|
119
|
-
def finalize_options(self):
|
|
120
|
-
pass
|
|
121
|
-
|
|
122
|
-
def run(self):
|
|
123
|
-
try:
|
|
124
|
-
self.status("Removing previous builds…")
|
|
125
|
-
rmtree(os.path.join(here, "dist"))
|
|
126
|
-
except OSError:
|
|
127
|
-
pass
|
|
128
|
-
|
|
129
|
-
self.status("Building Source and Wheel distribution…")
|
|
130
|
-
os.system("{0} setup.py sdist bdist_wheel ".format(sys.executable))
|
|
131
|
-
|
|
132
|
-
self.status("Uploading the package to PyPI via Twine…")
|
|
133
|
-
os.system("twine upload dist/*")
|
|
134
|
-
|
|
135
|
-
sys.exit()
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
# Where the magic happens:
|
|
139
|
-
setup(
|
|
140
|
-
name=name,
|
|
141
|
-
version=about["__version__"],
|
|
142
|
-
description=description,
|
|
143
|
-
long_description=long_description,
|
|
144
|
-
long_description_content_type="text/markdown",
|
|
145
|
-
author=author,
|
|
146
|
-
author_email=author_email,
|
|
147
|
-
python_requires=REQUIRES_PYTHON,
|
|
148
|
-
url=url,
|
|
149
|
-
packages=find_packages(exclude=("tests",)),
|
|
150
|
-
# If your package is a single module, use this instead of 'packages':
|
|
151
|
-
# py_modules=['mypackage'],
|
|
152
|
-
# entry_points={
|
|
153
|
-
# 'console_scripts': ['mycli=mymodule:cli'],
|
|
154
|
-
# },
|
|
155
|
-
install_requires=REQUIRED,
|
|
156
|
-
extras_require=EXTRAS,
|
|
157
|
-
include_package_data=True,
|
|
158
|
-
package_data={name: files},
|
|
159
|
-
license=license,
|
|
160
|
-
classifiers=[
|
|
161
|
-
# Trove classifiers
|
|
162
|
-
# Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers
|
|
163
|
-
"License :: OSI Approved :: BSD License",
|
|
164
|
-
"Programming Language :: Python",
|
|
165
|
-
"Programming Language :: Python :: 3",
|
|
166
|
-
"Programming Language :: Python :: 3.7",
|
|
167
|
-
"Programming Language :: Python :: Implementation :: CPython",
|
|
168
|
-
"Programming Language :: Python :: Implementation :: PyPy",
|
|
169
|
-
],
|
|
170
|
-
# $ setup.py publish support.
|
|
171
|
-
cmdclass={
|
|
172
|
-
"upload": UploadCommand,
|
|
173
|
-
},
|
|
174
|
-
entry_points={
|
|
175
|
-
"console_scripts": [
|
|
176
|
-
"caltechdata_api=caltechdata_api.cli:main",
|
|
177
|
-
],
|
|
178
|
-
},
|
|
179
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{caltechdata_api-1.9.1 → caltechdata_api-1.10.1}/caltechdata_api.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|