caltechdata-api 1.7.1__tar.gz → 1.8.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.7.1 → caltechdata_api-1.8.1}/PKG-INFO +1 -1
- {caltechdata_api-1.7.1 → caltechdata_api-1.8.1}/caltechdata_api/caltechdata_write.py +3 -5
- {caltechdata_api-1.7.1 → caltechdata_api-1.8.1}/caltechdata_api/cli.py +141 -65
- {caltechdata_api-1.7.1 → caltechdata_api-1.8.1}/caltechdata_api/customize_schema.py +148 -1
- {caltechdata_api-1.7.1 → caltechdata_api-1.8.1}/caltechdata_api.egg-info/PKG-INFO +1 -1
- {caltechdata_api-1.7.1 → caltechdata_api-1.8.1}/LICENSE +0 -0
- {caltechdata_api-1.7.1 → caltechdata_api-1.8.1}/README.md +0 -0
- {caltechdata_api-1.7.1 → caltechdata_api-1.8.1}/caltechdata_api/__init__.py +0 -0
- {caltechdata_api-1.7.1 → caltechdata_api-1.8.1}/caltechdata_api/caltechdata_edit.py +0 -0
- {caltechdata_api-1.7.1 → caltechdata_api-1.8.1}/caltechdata_api/download_file.py +0 -0
- {caltechdata_api-1.7.1 → caltechdata_api-1.8.1}/caltechdata_api/get_files.py +0 -0
- {caltechdata_api-1.7.1 → caltechdata_api-1.8.1}/caltechdata_api/get_metadata.py +0 -0
- {caltechdata_api-1.7.1 → caltechdata_api-1.8.1}/caltechdata_api/md_to_json.py +0 -0
- {caltechdata_api-1.7.1 → caltechdata_api-1.8.1}/caltechdata_api/utils.py +0 -0
- {caltechdata_api-1.7.1 → caltechdata_api-1.8.1}/caltechdata_api.egg-info/SOURCES.txt +0 -0
- {caltechdata_api-1.7.1 → caltechdata_api-1.8.1}/caltechdata_api.egg-info/dependency_links.txt +0 -0
- {caltechdata_api-1.7.1 → caltechdata_api-1.8.1}/caltechdata_api.egg-info/entry_points.txt +0 -0
- {caltechdata_api-1.7.1 → caltechdata_api-1.8.1}/caltechdata_api.egg-info/requires.txt +0 -0
- {caltechdata_api-1.7.1 → caltechdata_api-1.8.1}/caltechdata_api.egg-info/top_level.txt +0 -0
- {caltechdata_api-1.7.1 → caltechdata_api-1.8.1}/setup.cfg +0 -0
- {caltechdata_api-1.7.1 → caltechdata_api-1.8.1}/setup.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import copy
|
|
2
2
|
import json
|
|
3
|
-
import os
|
|
4
|
-
|
|
3
|
+
import os
|
|
4
|
+
import requests
|
|
5
5
|
import s3fs
|
|
6
6
|
from requests import session
|
|
7
7
|
from json.decoder import JSONDecodeError
|
|
@@ -49,8 +49,6 @@ def write_files_rdm(files, file_link, headers, f_headers, s3=None, keepfiles=Fal
|
|
|
49
49
|
infile = open(name, "rb")
|
|
50
50
|
else:
|
|
51
51
|
infile = open(f_list[name], "rb")
|
|
52
|
-
# size = infile.seek(0, 2)
|
|
53
|
-
# infile.seek(0, 0) # reset at beginning
|
|
54
52
|
result = requests.put(link, headers=f_headers, data=infile)
|
|
55
53
|
if result.status_code != 200:
|
|
56
54
|
raise Exception(result.text)
|
|
@@ -68,7 +66,7 @@ def write_files_rdm(files, file_link, headers, f_headers, s3=None, keepfiles=Fal
|
|
|
68
66
|
def add_file_links(
|
|
69
67
|
metadata, file_links, file_descriptions=[], additional_descriptions="", s3_link=None
|
|
70
68
|
):
|
|
71
|
-
# Currently configured for S3 links, assuming all are at same endpoint
|
|
69
|
+
# Currently configured for S3 links, assuming all are at the same endpoint
|
|
72
70
|
link_string = ""
|
|
73
71
|
endpoint = "https://" + file_links[0].split("/")[2]
|
|
74
72
|
s3 = s3fs.S3FileSystem(anon=True, client_kwargs={"endpoint_url": endpoint})
|
|
@@ -59,11 +59,14 @@ def decrypt_token(encrypted_token, key):
|
|
|
59
59
|
return f.decrypt(encrypted_token).decode()
|
|
60
60
|
|
|
61
61
|
|
|
62
|
-
# Function to get or set token
|
|
63
|
-
def get_or_set_token():
|
|
64
|
-
|
|
62
|
+
# Function to get or set token with support for test system
|
|
63
|
+
def get_or_set_token(production=True):
|
|
65
64
|
key = load_or_generate_key()
|
|
66
|
-
|
|
65
|
+
|
|
66
|
+
# Use different token files for production and test environments
|
|
67
|
+
token_filename = "token.txt" if production else "token_test.txt"
|
|
68
|
+
token_file = os.path.join(caltechdata_directory, token_filename)
|
|
69
|
+
|
|
67
70
|
try:
|
|
68
71
|
with open(token_file, "rb") as f:
|
|
69
72
|
encrypted_token = f.read()
|
|
@@ -71,8 +74,12 @@ def get_or_set_token():
|
|
|
71
74
|
return token
|
|
72
75
|
except FileNotFoundError:
|
|
73
76
|
while True:
|
|
74
|
-
token = input(
|
|
75
|
-
|
|
77
|
+
token = input(
|
|
78
|
+
f"Enter your {'Production' if production else 'Test'} CaltechDATA token: "
|
|
79
|
+
).strip()
|
|
80
|
+
confirm_token = input(
|
|
81
|
+
f"Confirm your {'Production' if production else 'Test'} CaltechDATA token: "
|
|
82
|
+
).strip()
|
|
76
83
|
if token == confirm_token:
|
|
77
84
|
encrypted_token = encrypt_token(token, key)
|
|
78
85
|
with open(token_file, "wb") as f:
|
|
@@ -133,7 +140,7 @@ def get_funding_entries():
|
|
|
133
140
|
def validate_funder_identifier(funder_identifier):
|
|
134
141
|
response = requests.get(f"https://api.ror.org/organizations/{funder_identifier}")
|
|
135
142
|
if response.status_code == 200:
|
|
136
|
-
return
|
|
143
|
+
return response.json().get("name")
|
|
137
144
|
else:
|
|
138
145
|
return False
|
|
139
146
|
|
|
@@ -150,7 +157,8 @@ def get_funding_details():
|
|
|
150
157
|
award_title = get_user_input("Enter the award title for funding: ")
|
|
151
158
|
while True:
|
|
152
159
|
funder_identifier = get_user_input("Enter the funder ROR (https://ror.org): ")
|
|
153
|
-
|
|
160
|
+
name = validate_funder_identifier(funder_identifier)
|
|
161
|
+
if name:
|
|
154
162
|
break
|
|
155
163
|
else:
|
|
156
164
|
print(
|
|
@@ -162,6 +170,7 @@ def get_funding_details():
|
|
|
162
170
|
return {
|
|
163
171
|
"awardNumber": award_number,
|
|
164
172
|
"awardTitle": award_title,
|
|
173
|
+
"funderName": name,
|
|
165
174
|
"funderIdentifier": funder_identifier,
|
|
166
175
|
"funderIdentifierType": "ROR",
|
|
167
176
|
}
|
|
@@ -187,9 +196,18 @@ def parse_arguments():
|
|
|
187
196
|
if license_number.isdigit() and 1 <= int(license_number) <= 8:
|
|
188
197
|
# Valid license number selected
|
|
189
198
|
args["license"] = {
|
|
190
|
-
"1":
|
|
191
|
-
|
|
192
|
-
|
|
199
|
+
"1": {
|
|
200
|
+
"rights": "Creative Commons Zero v1.0 Universal",
|
|
201
|
+
"rightsIdentifier": "cc0-1.0",
|
|
202
|
+
},
|
|
203
|
+
"2": {
|
|
204
|
+
"rights": "Creative Commons Attribution v4.0 Universal",
|
|
205
|
+
"rightsIdentifier": "cc-by-4.0",
|
|
206
|
+
},
|
|
207
|
+
"3": {
|
|
208
|
+
"rights": "Creative Commons Attribution Non-Commercial v4.0 Universal",
|
|
209
|
+
"rightsIdentifier": "cc-by-nc-4.0",
|
|
210
|
+
},
|
|
193
211
|
}[license_number]
|
|
194
212
|
break
|
|
195
213
|
else:
|
|
@@ -252,9 +270,11 @@ def get_names(orcid):
|
|
|
252
270
|
return family_name, given_name
|
|
253
271
|
|
|
254
272
|
|
|
255
|
-
def write_s3cmd_config(
|
|
273
|
+
def write_s3cmd_config(endpoint):
|
|
256
274
|
configf = os.path.join(home_directory, ".s3cfg")
|
|
257
275
|
if not os.path.exists(configf):
|
|
276
|
+
access_key = get_user_input("Enter the access key: ")
|
|
277
|
+
secret_key = get_user_input("Enter the secret key: ")
|
|
258
278
|
with open(configf, "w") as file:
|
|
259
279
|
file.write(
|
|
260
280
|
f"""[default]
|
|
@@ -279,9 +299,7 @@ def upload_supporting_file(record_id=None):
|
|
|
279
299
|
endpoint = "sdsc.osn.xsede.org"
|
|
280
300
|
path = "ini230004-bucket01/"
|
|
281
301
|
if not record_id:
|
|
282
|
-
|
|
283
|
-
secret_key = get_user_input("Enter the secret key: ")
|
|
284
|
-
write_s3cmd_config(access_key, secret_key, endpoint)
|
|
302
|
+
write_s3cmd_config(endpoint)
|
|
285
303
|
print("""S3 connection configured.""")
|
|
286
304
|
break
|
|
287
305
|
endpoint = f"https://{endpoint}/"
|
|
@@ -376,20 +394,35 @@ def upload_data_from_file():
|
|
|
376
394
|
print(f"Error: Invalid JSON format in the file '{filename}'. {str(e)}")
|
|
377
395
|
|
|
378
396
|
|
|
397
|
+
def parse_args():
|
|
398
|
+
"""Parse command-line arguments."""
|
|
399
|
+
parser = argparse.ArgumentParser(description="CaltechDATA CLI tool.")
|
|
400
|
+
parser.add_argument(
|
|
401
|
+
"-test", action="store_true", help="Use test mode, sets production to False"
|
|
402
|
+
)
|
|
403
|
+
args = parser.parse_args()
|
|
404
|
+
return args
|
|
405
|
+
|
|
406
|
+
|
|
379
407
|
def main():
|
|
408
|
+
args = parse_args()
|
|
409
|
+
|
|
410
|
+
production = not args.test # Set production to False if -test flag is provided
|
|
411
|
+
|
|
380
412
|
choice = get_user_input(
|
|
381
413
|
"Do you want to create or edit a CaltechDATA record? (create/edit): "
|
|
382
414
|
).lower()
|
|
383
415
|
if choice == "create":
|
|
384
|
-
create_record()
|
|
416
|
+
create_record(production)
|
|
385
417
|
elif choice == "edit":
|
|
386
|
-
edit_record()
|
|
418
|
+
edit_record(production)
|
|
387
419
|
else:
|
|
388
420
|
print("Invalid choice. Please enter 'create' or 'edit'.")
|
|
389
421
|
|
|
390
422
|
|
|
391
|
-
def create_record():
|
|
392
|
-
token = get_or_set_token()
|
|
423
|
+
def create_record(production):
|
|
424
|
+
token = get_or_set_token(production)
|
|
425
|
+
# keep_file = input("Do you want to keep your existing files? (yes/no): ").lower() == "yes"
|
|
393
426
|
print("Using CaltechDATA token:", token)
|
|
394
427
|
while True:
|
|
395
428
|
choice = get_user_input(
|
|
@@ -401,7 +434,11 @@ def create_record():
|
|
|
401
434
|
if existing_data:
|
|
402
435
|
if filepath != "":
|
|
403
436
|
response = caltechdata_write(
|
|
404
|
-
existing_data,
|
|
437
|
+
existing_data,
|
|
438
|
+
token,
|
|
439
|
+
filepath,
|
|
440
|
+
production=production,
|
|
441
|
+
publish=False,
|
|
405
442
|
)
|
|
406
443
|
elif file_link != "":
|
|
407
444
|
response = caltechdata_write(
|
|
@@ -414,15 +451,10 @@ def create_record():
|
|
|
414
451
|
)
|
|
415
452
|
else:
|
|
416
453
|
response = caltechdata_write(
|
|
417
|
-
existing_data, token, production=
|
|
454
|
+
existing_data, token, production=production, publish=False
|
|
418
455
|
)
|
|
419
456
|
rec_id = response
|
|
420
|
-
|
|
421
|
-
f"""You can view and publish this record at
|
|
422
|
-
https://data.caltech.edu/uploads/{rec_id}
|
|
423
|
-
If you need to upload large files to S3, you can type
|
|
424
|
-
`s3cmd put DATA_FILE s3://ini230004-bucket01/{rec_id}/"""
|
|
425
|
-
)
|
|
457
|
+
print_upload_message(rec_id, production)
|
|
426
458
|
break
|
|
427
459
|
else:
|
|
428
460
|
print("Going back to the main menu.")
|
|
@@ -457,9 +489,7 @@ def create_record():
|
|
|
457
489
|
],
|
|
458
490
|
"types": {"resourceType": "", "resourceTypeGeneral": "Dataset"},
|
|
459
491
|
"rightsList": [
|
|
460
|
-
|
|
461
|
-
"rightsIdentifier": args["license"],
|
|
462
|
-
}
|
|
492
|
+
args["license"],
|
|
463
493
|
],
|
|
464
494
|
"fundingReferences": args["fundingReferences"],
|
|
465
495
|
"schemaVersion": "http://datacite.org/schema/kernel-4",
|
|
@@ -468,27 +498,23 @@ def create_record():
|
|
|
468
498
|
if confirm_upload():
|
|
469
499
|
if filepath != "":
|
|
470
500
|
response = caltechdata_write(
|
|
471
|
-
metadata, token, filepath, production=
|
|
501
|
+
metadata, token, filepath, production=production, publish=False
|
|
472
502
|
)
|
|
473
503
|
elif file_link != "":
|
|
474
504
|
response = caltechdata_write(
|
|
475
505
|
metadata,
|
|
476
506
|
token,
|
|
477
507
|
file_links=[file_link],
|
|
478
|
-
production=
|
|
508
|
+
production=production,
|
|
479
509
|
publish=False,
|
|
480
510
|
)
|
|
481
511
|
else:
|
|
482
512
|
response = caltechdata_write(
|
|
483
|
-
metadata, token, production=
|
|
513
|
+
metadata, token, production=production, publish=False
|
|
484
514
|
)
|
|
485
515
|
rec_id = response
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
https://data.caltech.edu/uploads/{rec_id}
|
|
489
|
-
If you need to upload large files to S3, you can type
|
|
490
|
-
`s3cmd put DATA_FILE s3://ini230004-bucket01/{rec_id}/"""
|
|
491
|
-
)
|
|
516
|
+
|
|
517
|
+
print_upload_message(rec_id, production)
|
|
492
518
|
with open(response + ".json", "w") as file:
|
|
493
519
|
json.dump(metadata, file, indent=2)
|
|
494
520
|
break
|
|
@@ -498,17 +524,32 @@ def create_record():
|
|
|
498
524
|
print("Invalid choice. Please enter 'existing' or 'create'.")
|
|
499
525
|
|
|
500
526
|
|
|
501
|
-
def
|
|
527
|
+
def print_upload_message(rec_id, production):
|
|
528
|
+
base_url = (
|
|
529
|
+
"https://data.caltech.edu/uploads/"
|
|
530
|
+
if production
|
|
531
|
+
else "https://data.caltechlibrary.dev/uploads/"
|
|
532
|
+
)
|
|
533
|
+
print(
|
|
534
|
+
f"""You can view and publish this record at
|
|
535
|
+
{base_url}{rec_id}
|
|
536
|
+
If you need to upload large files to S3, you can type
|
|
537
|
+
`s3cmd put DATA_FILE s3://ini230004-bucket01/{rec_id}/`"""
|
|
538
|
+
)
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
def edit_record(production):
|
|
502
542
|
record_id = input("Enter the CaltechDATA record ID: ")
|
|
503
|
-
token = get_or_set_token()
|
|
543
|
+
token = get_or_set_token(production)
|
|
504
544
|
file_name = download_file_by_id(record_id, token)
|
|
545
|
+
|
|
505
546
|
if file_name:
|
|
506
547
|
try:
|
|
507
548
|
# Read the edited metadata file
|
|
508
549
|
with open(file_name, "r") as file:
|
|
509
550
|
metadata = json.load(file)
|
|
510
551
|
response = caltechdata_edit(
|
|
511
|
-
record_id, metadata, token, production=
|
|
552
|
+
record_id, metadata, token, production=production, publish=False
|
|
512
553
|
)
|
|
513
554
|
if response:
|
|
514
555
|
print("Metadata edited successfully.")
|
|
@@ -520,31 +561,54 @@ def edit_record():
|
|
|
520
561
|
print("No metadata file found.")
|
|
521
562
|
choice = get_user_input("Do you want to add files? (y/n): ").lower()
|
|
522
563
|
if choice == "y":
|
|
523
|
-
|
|
564
|
+
if production:
|
|
565
|
+
API_URL_TEMPLATE = "https://data.caltech.edu/api/records/{record_id}/files"
|
|
566
|
+
API_URL_TEMPLATE_DRAFT = (
|
|
567
|
+
"https://data.caltech.edu/api/records/{record_id}/draft/files"
|
|
568
|
+
)
|
|
569
|
+
else:
|
|
570
|
+
API_URL_TEMPLATE = (
|
|
571
|
+
"https://data.caltechlibrary.dev/api/records/{record_id}/files"
|
|
572
|
+
)
|
|
573
|
+
API_URL_TEMPLATE_DRAFT = (
|
|
574
|
+
"https://data.caltechlibrary.dev/api/records/{record_id}/draft/files"
|
|
575
|
+
)
|
|
576
|
+
|
|
524
577
|
url = API_URL_TEMPLATE.format(record_id=record_id)
|
|
578
|
+
url_draft = API_URL_TEMPLATE_DRAFT.format(record_id=record_id)
|
|
525
579
|
|
|
526
|
-
|
|
527
|
-
"
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
580
|
+
headers = {
|
|
581
|
+
"accept": "application/json",
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
if token:
|
|
585
|
+
headers["Authorization"] = "Bearer %s" % token
|
|
586
|
+
|
|
587
|
+
response = requests.get(url, headers=headers)
|
|
588
|
+
response_draft = requests.get(url_draft, headers=headers)
|
|
589
|
+
data = response.json()
|
|
590
|
+
data_draft = response_draft.json()
|
|
591
|
+
# Check if 'entries' exists and its length
|
|
592
|
+
if (
|
|
593
|
+
len(data.get("entries", [])) == 0
|
|
594
|
+
and len(data_draft.get("entries", [])) == 0
|
|
595
|
+
):
|
|
535
596
|
keepfile = False
|
|
536
597
|
else:
|
|
537
|
-
keepfile =
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
598
|
+
keepfile = (
|
|
599
|
+
input("Do you want to keep existing files? (y/n): ").lower() == "y"
|
|
600
|
+
)
|
|
601
|
+
|
|
602
|
+
filepath, file_link = upload_supporting_file(record_id)
|
|
603
|
+
if file_link:
|
|
604
|
+
print(file_link)
|
|
605
|
+
|
|
542
606
|
if filepath != "":
|
|
543
607
|
response = caltechdata_edit(
|
|
544
608
|
record_id,
|
|
545
609
|
token=token,
|
|
546
610
|
files=filepath,
|
|
547
|
-
production=
|
|
611
|
+
production=production,
|
|
548
612
|
publish=False,
|
|
549
613
|
keepfiles=keepfile,
|
|
550
614
|
)
|
|
@@ -554,14 +618,13 @@ def edit_record():
|
|
|
554
618
|
metadata,
|
|
555
619
|
token=token,
|
|
556
620
|
file_links=file_link,
|
|
557
|
-
production=
|
|
621
|
+
production=production,
|
|
558
622
|
publish=False,
|
|
559
|
-
|
|
623
|
+
keepfiles=keepfile,
|
|
560
624
|
)
|
|
625
|
+
|
|
561
626
|
rec_id = response
|
|
562
|
-
|
|
563
|
-
f"You can view and publish this record at https://data.caltech.edu/uploads/{rec_id}\n"
|
|
564
|
-
)
|
|
627
|
+
print_upload_message(rec_id, production)
|
|
565
628
|
|
|
566
629
|
|
|
567
630
|
def download_file_by_id(record_id, token=None):
|
|
@@ -576,7 +639,6 @@ def download_file_by_id(record_id, token=None):
|
|
|
576
639
|
|
|
577
640
|
try:
|
|
578
641
|
response = requests.get(url, headers=headers)
|
|
579
|
-
|
|
580
642
|
if response.status_code != 200:
|
|
581
643
|
# Might have a draft
|
|
582
644
|
response = requests.get(
|
|
@@ -584,7 +646,21 @@ def download_file_by_id(record_id, token=None):
|
|
|
584
646
|
headers=headers,
|
|
585
647
|
)
|
|
586
648
|
if response.status_code != 200:
|
|
587
|
-
|
|
649
|
+
url = f"https://data.caltechlibrary.dev/api/records/{record_id}"
|
|
650
|
+
response = requests.get(
|
|
651
|
+
url,
|
|
652
|
+
headers=headers,
|
|
653
|
+
)
|
|
654
|
+
if response.status_code != 200:
|
|
655
|
+
# Might have a draft
|
|
656
|
+
response = requests.get(
|
|
657
|
+
url + "/draft",
|
|
658
|
+
headers=headers,
|
|
659
|
+
)
|
|
660
|
+
if response.status_code != 200:
|
|
661
|
+
raise Exception(
|
|
662
|
+
f"Record {record_id} does not exist, cannot edit"
|
|
663
|
+
)
|
|
588
664
|
file_content = response.content
|
|
589
665
|
file_name = f"downloaded_data_{record_id}.json"
|
|
590
666
|
with open(file_name, "wb") as file:
|
|
@@ -134,8 +134,9 @@ def rdm_creators_contributors(person_list, peopleroles):
|
|
|
134
134
|
|
|
135
135
|
def customize_schema_rdm(json_record):
|
|
136
136
|
# Get vocabularies used in InvenioRDM
|
|
137
|
-
vocabularies = get_vocabularies()
|
|
138
137
|
|
|
138
|
+
vocabularies = get_vocabularies()
|
|
139
|
+
validate_metadata(json_record)
|
|
139
140
|
peopleroles = vocabularies["crr"]
|
|
140
141
|
resourcetypes = vocabularies["rsrct"]
|
|
141
142
|
descriptiontypes = vocabularies["dty"]
|
|
@@ -386,6 +387,152 @@ def customize_schema_rdm(json_record):
|
|
|
386
387
|
return final
|
|
387
388
|
|
|
388
389
|
|
|
390
|
+
def validate_metadata(json_record):
|
|
391
|
+
"""
|
|
392
|
+
Validates the presence and structure of required fields in a CaltechDATA JSON record.
|
|
393
|
+
Raises an exception if any required field is missing or structured incorrectly.
|
|
394
|
+
"""
|
|
395
|
+
errors = []
|
|
396
|
+
|
|
397
|
+
# Check for 'types' and 'resourceTypeGeneral'
|
|
398
|
+
if "types" not in json_record:
|
|
399
|
+
errors.append("'types' field is missing.")
|
|
400
|
+
elif not isinstance(json_record["types"], dict):
|
|
401
|
+
errors.append("'types' field should be a dictionary.")
|
|
402
|
+
elif "resourceTypeGeneral" not in json_record["types"]:
|
|
403
|
+
errors.append("'resourceTypeGeneral' field is missing in 'types'.")
|
|
404
|
+
|
|
405
|
+
# Check for 'title'
|
|
406
|
+
if "titles" not in json_record:
|
|
407
|
+
errors.append("'titles' field is missing.")
|
|
408
|
+
elif not isinstance(json_record["titles"], list) or len(json_record["titles"]) == 0:
|
|
409
|
+
errors.append("'titles' should be a non-empty list.")
|
|
410
|
+
else:
|
|
411
|
+
# Ensure each title is a dictionary with 'title' field
|
|
412
|
+
for title in json_record["titles"]:
|
|
413
|
+
if not isinstance(title, dict) or "title" not in title:
|
|
414
|
+
errors.append(
|
|
415
|
+
"Each entry in 'titles' must be a dictionary with a 'title' key."
|
|
416
|
+
)
|
|
417
|
+
|
|
418
|
+
# Publication date is handled by customize function
|
|
419
|
+
|
|
420
|
+
# Check for 'creators'
|
|
421
|
+
if "creators" not in json_record:
|
|
422
|
+
errors.append("'creators' field is missing.")
|
|
423
|
+
elif (
|
|
424
|
+
not isinstance(json_record["creators"], list)
|
|
425
|
+
or len(json_record["creators"]) == 0
|
|
426
|
+
):
|
|
427
|
+
errors.append("'creators' should be a non-empty list.")
|
|
428
|
+
else:
|
|
429
|
+
for creator in json_record["creators"]:
|
|
430
|
+
if not isinstance(creator, dict) or "name" not in creator:
|
|
431
|
+
errors.append(
|
|
432
|
+
"Each creator in 'creators' must be a dictionary with a 'name' key."
|
|
433
|
+
)
|
|
434
|
+
|
|
435
|
+
# Check for 'contributors'
|
|
436
|
+
if "contributors" in json_record:
|
|
437
|
+
if not isinstance(json_record["contributors"], list):
|
|
438
|
+
errors.append("'contributors' should be a list.")
|
|
439
|
+
else:
|
|
440
|
+
for contributor in json_record["contributors"]:
|
|
441
|
+
if not isinstance(contributor, dict) or "name" not in contributor:
|
|
442
|
+
errors.append(
|
|
443
|
+
"Each contributor must be a dictionary with a 'name' key."
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
# Check for 'resourceType'
|
|
447
|
+
if "resourceType" not in json_record["types"]:
|
|
448
|
+
errors.append("'resourceType' field is missing in 'types'.")
|
|
449
|
+
elif not isinstance(json_record["types"]["resourceType"], str):
|
|
450
|
+
errors.append("'resourceType' should be a string.")
|
|
451
|
+
|
|
452
|
+
# Check for 'identifiers'
|
|
453
|
+
if "identifiers" in json_record:
|
|
454
|
+
if not isinstance(json_record["identifiers"], list):
|
|
455
|
+
errors.append("'identifiers' should be a list.")
|
|
456
|
+
else:
|
|
457
|
+
for identifier in json_record["identifiers"]:
|
|
458
|
+
if (
|
|
459
|
+
not isinstance(identifier, dict)
|
|
460
|
+
or "identifier" not in identifier
|
|
461
|
+
or "identifierType" not in identifier
|
|
462
|
+
):
|
|
463
|
+
errors.append(
|
|
464
|
+
"Each identifier must be a dictionary with 'identifier' and 'identifierType' keys."
|
|
465
|
+
)
|
|
466
|
+
|
|
467
|
+
# Check for 'subjects'
|
|
468
|
+
if "subjects" in json_record:
|
|
469
|
+
if not isinstance(json_record["subjects"], list):
|
|
470
|
+
errors.append("'subjects' should be a list.")
|
|
471
|
+
else:
|
|
472
|
+
for subject in json_record["subjects"]:
|
|
473
|
+
if not isinstance(subject, dict) or "subject" not in subject:
|
|
474
|
+
errors.append(
|
|
475
|
+
"Each subject must be a dictionary with a 'subject' key."
|
|
476
|
+
)
|
|
477
|
+
|
|
478
|
+
# Check for 'relatedIdentifiers'
|
|
479
|
+
if "relatedIdentifiers" in json_record:
|
|
480
|
+
if not isinstance(json_record["relatedIdentifiers"], list):
|
|
481
|
+
errors.append("'relatedIdentifiers' should be a list.")
|
|
482
|
+
else:
|
|
483
|
+
for related_id in json_record["relatedIdentifiers"]:
|
|
484
|
+
if (
|
|
485
|
+
not isinstance(related_id, dict)
|
|
486
|
+
or "relatedIdentifier" not in related_id
|
|
487
|
+
):
|
|
488
|
+
errors.append(
|
|
489
|
+
"Each relatedIdentifier must be a dictionary with a 'relatedIdentifier' key."
|
|
490
|
+
)
|
|
491
|
+
|
|
492
|
+
# Check for 'rightsList'
|
|
493
|
+
if "rightsList" in json_record:
|
|
494
|
+
if not isinstance(json_record["rightsList"], list):
|
|
495
|
+
errors.append("'rightsList' should be a list.")
|
|
496
|
+
else:
|
|
497
|
+
for rights in json_record["rightsList"]:
|
|
498
|
+
if not isinstance(rights, dict) or "rights" not in rights:
|
|
499
|
+
errors.append(
|
|
500
|
+
"Each entry in 'rightsList' must be a dictionary with a 'rights' key."
|
|
501
|
+
)
|
|
502
|
+
|
|
503
|
+
# Check for 'geoLocations'
|
|
504
|
+
if "geoLocations" in json_record:
|
|
505
|
+
if not isinstance(json_record["geoLocations"], list):
|
|
506
|
+
errors.append("'geoLocations' should be a list.")
|
|
507
|
+
else:
|
|
508
|
+
for location in json_record["geoLocations"]:
|
|
509
|
+
if not isinstance(location, dict):
|
|
510
|
+
errors.append("Each entry in 'geoLocations' must be a dictionary.")
|
|
511
|
+
elif (
|
|
512
|
+
"geoLocationPoint" not in location
|
|
513
|
+
and "geoLocationBox" not in location
|
|
514
|
+
and "geoLocationPlace" not in location
|
|
515
|
+
):
|
|
516
|
+
errors.append(
|
|
517
|
+
"Each geoLocation entry must contain at least one of 'geoLocationPoint', 'geoLocationBox', or 'geoLocationPlace'."
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
# Check for 'fundingReferences'
|
|
521
|
+
if "fundingReferences" in json_record:
|
|
522
|
+
if not isinstance(json_record["fundingReferences"], list):
|
|
523
|
+
errors.append("'fundingReferences' should be a list.")
|
|
524
|
+
else:
|
|
525
|
+
for funding in json_record["fundingReferences"]:
|
|
526
|
+
if not isinstance(funding, dict):
|
|
527
|
+
errors.append("Each funding reference must be a dictionary.")
|
|
528
|
+
if "funderName" not in funding:
|
|
529
|
+
errors.append("Each funding reference must contain 'funderName'.")
|
|
530
|
+
|
|
531
|
+
# Return errors if any are found
|
|
532
|
+
if errors:
|
|
533
|
+
raise ValueError(f"Validation errors in metadata: {', '.join(errors)}")
|
|
534
|
+
|
|
535
|
+
|
|
389
536
|
if __name__ == "__main__":
|
|
390
537
|
# Read in from file for demo purposes
|
|
391
538
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{caltechdata_api-1.7.1 → caltechdata_api-1.8.1}/caltechdata_api.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|