caltechdata-api 1.7.0__tar.gz → 1.8.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.7.0 → caltechdata_api-1.8.0}/PKG-INFO +2 -3
- {caltechdata_api-1.7.0 → caltechdata_api-1.8.0}/README.md +1 -2
- {caltechdata_api-1.7.0 → caltechdata_api-1.8.0}/caltechdata_api/caltechdata_edit.py +11 -0
- {caltechdata_api-1.7.0 → caltechdata_api-1.8.0}/caltechdata_api/caltechdata_write.py +3 -5
- {caltechdata_api-1.7.0 → caltechdata_api-1.8.0}/caltechdata_api/cli.py +121 -54
- {caltechdata_api-1.7.0 → caltechdata_api-1.8.0}/caltechdata_api/customize_schema.py +165 -1
- {caltechdata_api-1.7.0 → caltechdata_api-1.8.0}/caltechdata_api.egg-info/PKG-INFO +2 -3
- {caltechdata_api-1.7.0 → caltechdata_api-1.8.0}/LICENSE +0 -0
- {caltechdata_api-1.7.0 → caltechdata_api-1.8.0}/caltechdata_api/__init__.py +0 -0
- {caltechdata_api-1.7.0 → caltechdata_api-1.8.0}/caltechdata_api/download_file.py +0 -0
- {caltechdata_api-1.7.0 → caltechdata_api-1.8.0}/caltechdata_api/get_files.py +0 -0
- {caltechdata_api-1.7.0 → caltechdata_api-1.8.0}/caltechdata_api/get_metadata.py +0 -0
- {caltechdata_api-1.7.0 → caltechdata_api-1.8.0}/caltechdata_api/md_to_json.py +0 -0
- {caltechdata_api-1.7.0 → caltechdata_api-1.8.0}/caltechdata_api/utils.py +0 -0
- {caltechdata_api-1.7.0 → caltechdata_api-1.8.0}/caltechdata_api.egg-info/SOURCES.txt +0 -0
- {caltechdata_api-1.7.0 → caltechdata_api-1.8.0}/caltechdata_api.egg-info/dependency_links.txt +0 -0
- {caltechdata_api-1.7.0 → caltechdata_api-1.8.0}/caltechdata_api.egg-info/entry_points.txt +0 -0
- {caltechdata_api-1.7.0 → caltechdata_api-1.8.0}/caltechdata_api.egg-info/requires.txt +0 -0
- {caltechdata_api-1.7.0 → caltechdata_api-1.8.0}/caltechdata_api.egg-info/top_level.txt +0 -0
- {caltechdata_api-1.7.0 → caltechdata_api-1.8.0}/setup.cfg +0 -0
- {caltechdata_api-1.7.0 → caltechdata_api-1.8.0}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: caltechdata_api
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.8.0
|
|
4
4
|
Summary: Python wrapper for CaltechDATA API.
|
|
5
5
|
Home-page: https://github.com/caltechlibrary/caltechdata_api
|
|
6
6
|
Author: Thomas E Morrell, Bhattarai Rohan , Won Elizabeth
|
|
@@ -33,8 +33,7 @@ The `caltechdata_api` Python library provides a convenient interface for interac
|
|
|
33
33
|
|
|
34
34
|
## Requirements
|
|
35
35
|
|
|
36
|
-
- Python 3
|
|
37
|
-
- `requests` library
|
|
36
|
+
- Python 3.6+
|
|
38
37
|
|
|
39
38
|
## Installation
|
|
40
39
|
|
|
@@ -211,6 +211,17 @@ def caltechdata_edit(
|
|
|
211
211
|
"provider": "datacite",
|
|
212
212
|
"client": "datacite",
|
|
213
213
|
}
|
|
214
|
+
# If we are making a new version, we only want to look for custom DOIs
|
|
215
|
+
if version == True and "identifiers" in metadata:
|
|
216
|
+
for identifier in metadata["identifiers"]:
|
|
217
|
+
if identifier["identifierType"] == "DOI":
|
|
218
|
+
doi = identifier["identifier"]
|
|
219
|
+
prefix = doi.split("/")[0]
|
|
220
|
+
if prefix != repo_prefix:
|
|
221
|
+
pids["doi"] = {
|
|
222
|
+
"identifier": doi,
|
|
223
|
+
"provider": "external",
|
|
224
|
+
}
|
|
214
225
|
|
|
215
226
|
# If no metadata is provided, use existing. Otherwise customize provided
|
|
216
227
|
# metadata
|
|
@@ -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:
|
|
@@ -254,7 +261,7 @@ def get_names(orcid):
|
|
|
254
261
|
|
|
255
262
|
def write_s3cmd_config(access_key, secret_key, endpoint):
|
|
256
263
|
configf = os.path.join(home_directory, ".s3cfg")
|
|
257
|
-
if not os.path.exists(
|
|
264
|
+
if not os.path.exists(configf):
|
|
258
265
|
with open(configf, "w") as file:
|
|
259
266
|
file.write(
|
|
260
267
|
f"""[default]
|
|
@@ -376,20 +383,35 @@ def upload_data_from_file():
|
|
|
376
383
|
print(f"Error: Invalid JSON format in the file '{filename}'. {str(e)}")
|
|
377
384
|
|
|
378
385
|
|
|
386
|
+
def parse_args():
|
|
387
|
+
"""Parse command-line arguments."""
|
|
388
|
+
parser = argparse.ArgumentParser(description="CaltechDATA CLI tool.")
|
|
389
|
+
parser.add_argument(
|
|
390
|
+
"-test", action="store_true", help="Use test mode, sets production to False"
|
|
391
|
+
)
|
|
392
|
+
args = parser.parse_args()
|
|
393
|
+
return args
|
|
394
|
+
|
|
395
|
+
|
|
379
396
|
def main():
|
|
397
|
+
args = parse_args()
|
|
398
|
+
|
|
399
|
+
production = not args.test # Set production to False if -test flag is provided
|
|
400
|
+
|
|
380
401
|
choice = get_user_input(
|
|
381
402
|
"Do you want to create or edit a CaltechDATA record? (create/edit): "
|
|
382
403
|
).lower()
|
|
383
404
|
if choice == "create":
|
|
384
|
-
create_record()
|
|
405
|
+
create_record(production)
|
|
385
406
|
elif choice == "edit":
|
|
386
|
-
edit_record()
|
|
407
|
+
edit_record(production)
|
|
387
408
|
else:
|
|
388
409
|
print("Invalid choice. Please enter 'create' or 'edit'.")
|
|
389
410
|
|
|
390
411
|
|
|
391
|
-
def create_record():
|
|
392
|
-
token = get_or_set_token()
|
|
412
|
+
def create_record(production):
|
|
413
|
+
token = get_or_set_token(production)
|
|
414
|
+
# keep_file = input("Do you want to keep your existing files? (yes/no): ").lower() == "yes"
|
|
393
415
|
print("Using CaltechDATA token:", token)
|
|
394
416
|
while True:
|
|
395
417
|
choice = get_user_input(
|
|
@@ -401,7 +423,11 @@ def create_record():
|
|
|
401
423
|
if existing_data:
|
|
402
424
|
if filepath != "":
|
|
403
425
|
response = caltechdata_write(
|
|
404
|
-
existing_data,
|
|
426
|
+
existing_data,
|
|
427
|
+
token,
|
|
428
|
+
filepath,
|
|
429
|
+
production=production,
|
|
430
|
+
publish=False,
|
|
405
431
|
)
|
|
406
432
|
elif file_link != "":
|
|
407
433
|
response = caltechdata_write(
|
|
@@ -414,15 +440,10 @@ def create_record():
|
|
|
414
440
|
)
|
|
415
441
|
else:
|
|
416
442
|
response = caltechdata_write(
|
|
417
|
-
existing_data, token, production=
|
|
443
|
+
existing_data, token, production=production, publish=False
|
|
418
444
|
)
|
|
419
445
|
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
|
-
)
|
|
446
|
+
print_upload_message(rec_id, production)
|
|
426
447
|
break
|
|
427
448
|
else:
|
|
428
449
|
print("Going back to the main menu.")
|
|
@@ -468,27 +489,23 @@ def create_record():
|
|
|
468
489
|
if confirm_upload():
|
|
469
490
|
if filepath != "":
|
|
470
491
|
response = caltechdata_write(
|
|
471
|
-
metadata, token, filepath, production=
|
|
492
|
+
metadata, token, filepath, production=production, publish=False
|
|
472
493
|
)
|
|
473
494
|
elif file_link != "":
|
|
474
495
|
response = caltechdata_write(
|
|
475
496
|
metadata,
|
|
476
497
|
token,
|
|
477
498
|
file_links=[file_link],
|
|
478
|
-
production=
|
|
499
|
+
production=production,
|
|
479
500
|
publish=False,
|
|
480
501
|
)
|
|
481
502
|
else:
|
|
482
503
|
response = caltechdata_write(
|
|
483
|
-
metadata, token, production=
|
|
504
|
+
metadata, token, production=production, publish=False
|
|
484
505
|
)
|
|
485
506
|
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
|
-
)
|
|
507
|
+
|
|
508
|
+
print_upload_message(rec_id, production)
|
|
492
509
|
with open(response + ".json", "w") as file:
|
|
493
510
|
json.dump(metadata, file, indent=2)
|
|
494
511
|
break
|
|
@@ -498,17 +515,32 @@ def create_record():
|
|
|
498
515
|
print("Invalid choice. Please enter 'existing' or 'create'.")
|
|
499
516
|
|
|
500
517
|
|
|
501
|
-
def
|
|
518
|
+
def print_upload_message(rec_id, production):
|
|
519
|
+
base_url = (
|
|
520
|
+
"https://data.caltech.edu/uploads/"
|
|
521
|
+
if production
|
|
522
|
+
else "https://data.caltechlibrary.dev/uploads/"
|
|
523
|
+
)
|
|
524
|
+
print(
|
|
525
|
+
f"""You can view and publish this record at
|
|
526
|
+
{base_url}{rec_id}
|
|
527
|
+
If you need to upload large files to S3, you can type
|
|
528
|
+
`s3cmd put DATA_FILE s3://ini230004-bucket01/{rec_id}/`"""
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
def edit_record(production):
|
|
502
533
|
record_id = input("Enter the CaltechDATA record ID: ")
|
|
503
|
-
token = get_or_set_token()
|
|
534
|
+
token = get_or_set_token(production)
|
|
504
535
|
file_name = download_file_by_id(record_id, token)
|
|
536
|
+
|
|
505
537
|
if file_name:
|
|
506
538
|
try:
|
|
507
539
|
# Read the edited metadata file
|
|
508
540
|
with open(file_name, "r") as file:
|
|
509
541
|
metadata = json.load(file)
|
|
510
542
|
response = caltechdata_edit(
|
|
511
|
-
record_id, metadata, token, production=
|
|
543
|
+
record_id, metadata, token, production=production, publish=False
|
|
512
544
|
)
|
|
513
545
|
if response:
|
|
514
546
|
print("Metadata edited successfully.")
|
|
@@ -520,31 +552,54 @@ def edit_record():
|
|
|
520
552
|
print("No metadata file found.")
|
|
521
553
|
choice = get_user_input("Do you want to add files? (y/n): ").lower()
|
|
522
554
|
if choice == "y":
|
|
523
|
-
|
|
555
|
+
if production:
|
|
556
|
+
API_URL_TEMPLATE = "https://data.caltech.edu/api/records/{record_id}/files"
|
|
557
|
+
API_URL_TEMPLATE_DRAFT = (
|
|
558
|
+
"https://data.caltech.edu/api/records/{record_id}/draft/files"
|
|
559
|
+
)
|
|
560
|
+
else:
|
|
561
|
+
API_URL_TEMPLATE = (
|
|
562
|
+
"https://data.caltechlibrary.dev/api/records/{record_id}/files"
|
|
563
|
+
)
|
|
564
|
+
API_URL_TEMPLATE_DRAFT = (
|
|
565
|
+
"https://data.caltechlibrary.dev/api/records/{record_id}/draft/files"
|
|
566
|
+
)
|
|
567
|
+
|
|
524
568
|
url = API_URL_TEMPLATE.format(record_id=record_id)
|
|
569
|
+
url_draft = API_URL_TEMPLATE_DRAFT.format(record_id=record_id)
|
|
525
570
|
|
|
526
|
-
|
|
527
|
-
"
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
571
|
+
headers = {
|
|
572
|
+
"accept": "application/json",
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
if token:
|
|
576
|
+
headers["Authorization"] = "Bearer %s" % token
|
|
577
|
+
|
|
578
|
+
response = requests.get(url, headers=headers)
|
|
579
|
+
response_draft = requests.get(url_draft, headers=headers)
|
|
580
|
+
data = response.json()
|
|
581
|
+
data_draft = response_draft.json()
|
|
582
|
+
# Check if 'entries' exists and its length
|
|
583
|
+
if (
|
|
584
|
+
len(data.get("entries", [])) == 0
|
|
585
|
+
and len(data_draft.get("entries", [])) == 0
|
|
586
|
+
):
|
|
535
587
|
keepfile = False
|
|
536
588
|
else:
|
|
537
|
-
keepfile =
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
589
|
+
keepfile = (
|
|
590
|
+
input("Do you want to keep existing files? (y/n): ").lower() == "y"
|
|
591
|
+
)
|
|
592
|
+
|
|
593
|
+
filepath, file_link = upload_supporting_file(record_id)
|
|
594
|
+
if file_link:
|
|
595
|
+
print(file_link)
|
|
596
|
+
|
|
542
597
|
if filepath != "":
|
|
543
598
|
response = caltechdata_edit(
|
|
544
599
|
record_id,
|
|
545
600
|
token=token,
|
|
546
601
|
files=filepath,
|
|
547
|
-
production=
|
|
602
|
+
production=production,
|
|
548
603
|
publish=False,
|
|
549
604
|
keepfiles=keepfile,
|
|
550
605
|
)
|
|
@@ -554,14 +609,13 @@ def edit_record():
|
|
|
554
609
|
metadata,
|
|
555
610
|
token=token,
|
|
556
611
|
file_links=file_link,
|
|
557
|
-
production=
|
|
612
|
+
production=production,
|
|
558
613
|
publish=False,
|
|
559
|
-
|
|
614
|
+
keepfiles=keepfile,
|
|
560
615
|
)
|
|
616
|
+
|
|
561
617
|
rec_id = response
|
|
562
|
-
|
|
563
|
-
f"You can view and publish this record at https://data.caltech.edu/uploads/{rec_id}\n"
|
|
564
|
-
)
|
|
618
|
+
print_upload_message(rec_id, production)
|
|
565
619
|
|
|
566
620
|
|
|
567
621
|
def download_file_by_id(record_id, token=None):
|
|
@@ -576,7 +630,6 @@ def download_file_by_id(record_id, token=None):
|
|
|
576
630
|
|
|
577
631
|
try:
|
|
578
632
|
response = requests.get(url, headers=headers)
|
|
579
|
-
|
|
580
633
|
if response.status_code != 200:
|
|
581
634
|
# Might have a draft
|
|
582
635
|
response = requests.get(
|
|
@@ -584,7 +637,21 @@ def download_file_by_id(record_id, token=None):
|
|
|
584
637
|
headers=headers,
|
|
585
638
|
)
|
|
586
639
|
if response.status_code != 200:
|
|
587
|
-
|
|
640
|
+
url = f"https://data.caltechlibrary.dev/api/records/{record_id}"
|
|
641
|
+
response = requests.get(
|
|
642
|
+
url,
|
|
643
|
+
headers=headers,
|
|
644
|
+
)
|
|
645
|
+
if response.status_code != 200:
|
|
646
|
+
# Might have a draft
|
|
647
|
+
response = requests.get(
|
|
648
|
+
url + "/draft",
|
|
649
|
+
headers=headers,
|
|
650
|
+
)
|
|
651
|
+
if response.status_code != 200:
|
|
652
|
+
raise Exception(
|
|
653
|
+
f"Record {record_id} does not exist, cannot edit"
|
|
654
|
+
)
|
|
588
655
|
file_content = response.content
|
|
589
656
|
file_name = f"downloaded_data_{record_id}.json"
|
|
590
657
|
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,169 @@ 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
|
+
# Check for 'publication_date'
|
|
419
|
+
if "publicationYear" not in json_record and "dates" not in json_record:
|
|
420
|
+
errors.append(
|
|
421
|
+
"A publication date is required ('publicationYear' or 'dates' field is missing)."
|
|
422
|
+
)
|
|
423
|
+
if "dates" in json_record:
|
|
424
|
+
if not isinstance(json_record["dates"], list):
|
|
425
|
+
errors.append("'dates' should be a list.")
|
|
426
|
+
else:
|
|
427
|
+
for date_entry in json_record["dates"]:
|
|
428
|
+
if (
|
|
429
|
+
not isinstance(date_entry, dict)
|
|
430
|
+
or "dateType" not in date_entry
|
|
431
|
+
or "date" not in date_entry
|
|
432
|
+
):
|
|
433
|
+
errors.append(
|
|
434
|
+
"Each entry in 'dates' must be a dictionary with 'dateType' and 'date' keys."
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
# Check for 'creators'
|
|
438
|
+
if "creators" not in json_record:
|
|
439
|
+
errors.append("'creators' field is missing.")
|
|
440
|
+
elif (
|
|
441
|
+
not isinstance(json_record["creators"], list)
|
|
442
|
+
or len(json_record["creators"]) == 0
|
|
443
|
+
):
|
|
444
|
+
errors.append("'creators' should be a non-empty list.")
|
|
445
|
+
else:
|
|
446
|
+
for creator in json_record["creators"]:
|
|
447
|
+
if not isinstance(creator, dict) or "name" not in creator:
|
|
448
|
+
errors.append(
|
|
449
|
+
"Each creator in 'creators' must be a dictionary with a 'name' key."
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
# Check for 'contributors'
|
|
453
|
+
if "contributors" in json_record:
|
|
454
|
+
if not isinstance(json_record["contributors"], list):
|
|
455
|
+
errors.append("'contributors' should be a list.")
|
|
456
|
+
else:
|
|
457
|
+
for contributor in json_record["contributors"]:
|
|
458
|
+
if not isinstance(contributor, dict) or "name" not in contributor:
|
|
459
|
+
errors.append(
|
|
460
|
+
"Each contributor must be a dictionary with a 'name' key."
|
|
461
|
+
)
|
|
462
|
+
|
|
463
|
+
# Check for 'resourceType'
|
|
464
|
+
if "resourceType" not in json_record["types"]:
|
|
465
|
+
errors.append("'resourceType' field is missing in 'types'.")
|
|
466
|
+
elif not isinstance(json_record["types"]["resourceType"], str):
|
|
467
|
+
errors.append("'resourceType' should be a string.")
|
|
468
|
+
|
|
469
|
+
# Check for 'identifiers'
|
|
470
|
+
if "identifiers" in json_record:
|
|
471
|
+
if not isinstance(json_record["identifiers"], list):
|
|
472
|
+
errors.append("'identifiers' should be a list.")
|
|
473
|
+
else:
|
|
474
|
+
for identifier in json_record["identifiers"]:
|
|
475
|
+
if (
|
|
476
|
+
not isinstance(identifier, dict)
|
|
477
|
+
or "identifier" not in identifier
|
|
478
|
+
or "identifierType" not in identifier
|
|
479
|
+
):
|
|
480
|
+
errors.append(
|
|
481
|
+
"Each identifier must be a dictionary with 'identifier' and 'identifierType' keys."
|
|
482
|
+
)
|
|
483
|
+
|
|
484
|
+
# Check for 'subjects'
|
|
485
|
+
if "subjects" in json_record:
|
|
486
|
+
if not isinstance(json_record["subjects"], list):
|
|
487
|
+
errors.append("'subjects' should be a list.")
|
|
488
|
+
else:
|
|
489
|
+
for subject in json_record["subjects"]:
|
|
490
|
+
if not isinstance(subject, dict) or "subject" not in subject:
|
|
491
|
+
errors.append(
|
|
492
|
+
"Each subject must be a dictionary with a 'subject' key."
|
|
493
|
+
)
|
|
494
|
+
|
|
495
|
+
# Check for 'relatedIdentifiers'
|
|
496
|
+
if "relatedIdentifiers" in json_record:
|
|
497
|
+
if not isinstance(json_record["relatedIdentifiers"], list):
|
|
498
|
+
errors.append("'relatedIdentifiers' should be a list.")
|
|
499
|
+
else:
|
|
500
|
+
for related_id in json_record["relatedIdentifiers"]:
|
|
501
|
+
if (
|
|
502
|
+
not isinstance(related_id, dict)
|
|
503
|
+
or "relatedIdentifier" not in related_id
|
|
504
|
+
):
|
|
505
|
+
errors.append(
|
|
506
|
+
"Each relatedIdentifier must be a dictionary with a 'relatedIdentifier' key."
|
|
507
|
+
)
|
|
508
|
+
|
|
509
|
+
# Check for 'rightsList'
|
|
510
|
+
if "rightsList" in json_record:
|
|
511
|
+
if not isinstance(json_record["rightsList"], list):
|
|
512
|
+
errors.append("'rightsList' should be a list.")
|
|
513
|
+
else:
|
|
514
|
+
for rights in json_record["rightsList"]:
|
|
515
|
+
if not isinstance(rights, dict) or "rights" not in rights:
|
|
516
|
+
errors.append(
|
|
517
|
+
"Each entry in 'rightsList' must be a dictionary with a 'rights' key."
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
# Check for 'geoLocations'
|
|
521
|
+
if "geoLocations" in json_record:
|
|
522
|
+
if not isinstance(json_record["geoLocations"], list):
|
|
523
|
+
errors.append("'geoLocations' should be a list.")
|
|
524
|
+
else:
|
|
525
|
+
for location in json_record["geoLocations"]:
|
|
526
|
+
if not isinstance(location, dict):
|
|
527
|
+
errors.append("Each entry in 'geoLocations' must be a dictionary.")
|
|
528
|
+
elif (
|
|
529
|
+
"geoLocationPoint" not in location
|
|
530
|
+
and "geoLocationBox" not in location
|
|
531
|
+
and "geoLocationPlace" not in location
|
|
532
|
+
):
|
|
533
|
+
errors.append(
|
|
534
|
+
"Each geoLocation entry must contain at least one of 'geoLocationPoint', 'geoLocationBox', or 'geoLocationPlace'."
|
|
535
|
+
)
|
|
536
|
+
|
|
537
|
+
# Check for 'fundingReferences'
|
|
538
|
+
if "fundingReferences" in json_record:
|
|
539
|
+
if not isinstance(json_record["fundingReferences"], list):
|
|
540
|
+
errors.append("'fundingReferences' should be a list.")
|
|
541
|
+
else:
|
|
542
|
+
for funding in json_record["fundingReferences"]:
|
|
543
|
+
if not isinstance(funding, dict):
|
|
544
|
+
errors.append("Each funding reference must be a dictionary.")
|
|
545
|
+
if "funderName" not in funding:
|
|
546
|
+
errors.append("Each funding reference must contain 'funderName'.")
|
|
547
|
+
|
|
548
|
+
# Return errors if any are found
|
|
549
|
+
if errors:
|
|
550
|
+
raise ValueError(f"Validation errors in metadata: {', '.join(errors)}")
|
|
551
|
+
|
|
552
|
+
|
|
389
553
|
if __name__ == "__main__":
|
|
390
554
|
# Read in from file for demo purposes
|
|
391
555
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: caltechdata-api
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.8.0
|
|
4
4
|
Summary: Python wrapper for CaltechDATA API.
|
|
5
5
|
Home-page: https://github.com/caltechlibrary/caltechdata_api
|
|
6
6
|
Author: Thomas E Morrell, Bhattarai Rohan , Won Elizabeth
|
|
@@ -33,8 +33,7 @@ The `caltechdata_api` Python library provides a convenient interface for interac
|
|
|
33
33
|
|
|
34
34
|
## Requirements
|
|
35
35
|
|
|
36
|
-
- Python 3
|
|
37
|
-
- `requests` library
|
|
36
|
+
- Python 3.6+
|
|
38
37
|
|
|
39
38
|
## Installation
|
|
40
39
|
|
|
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.0 → caltechdata_api-1.8.0}/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
|