caltechdata-api 1.5.0__tar.gz → 1.6.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.5.0 → caltechdata_api-1.6.0}/PKG-INFO +36 -20
- caltechdata_api-1.6.0/README.md +78 -0
- {caltechdata_api-1.5.0 → caltechdata_api-1.6.0}/caltechdata_api/caltechdata_edit.py +0 -1
- {caltechdata_api-1.5.0 → caltechdata_api-1.6.0}/caltechdata_api/caltechdata_write.py +2 -3
- caltechdata_api-1.6.0/caltechdata_api/cli.py +608 -0
- {caltechdata_api-1.5.0 → caltechdata_api-1.6.0}/caltechdata_api/customize_schema.py +0 -2
- caltechdata_api-1.6.0/caltechdata_api/md_to_json.py +139 -0
- {caltechdata_api-1.5.0 → caltechdata_api-1.6.0}/caltechdata_api/utils.py +0 -1
- {caltechdata_api-1.5.0 → caltechdata_api-1.6.0}/caltechdata_api.egg-info/PKG-INFO +36 -20
- {caltechdata_api-1.5.0 → caltechdata_api-1.6.0}/caltechdata_api.egg-info/SOURCES.txt +3 -0
- caltechdata_api-1.6.0/caltechdata_api.egg-info/entry_points.txt +3 -0
- {caltechdata_api-1.5.0 → caltechdata_api-1.6.0}/caltechdata_api.egg-info/requires.txt +2 -0
- {caltechdata_api-1.5.0 → caltechdata_api-1.6.0}/setup.py +14 -1
- caltechdata_api-1.5.0/README.md +0 -62
- {caltechdata_api-1.5.0 → caltechdata_api-1.6.0}/LICENSE +0 -0
- {caltechdata_api-1.5.0 → caltechdata_api-1.6.0}/caltechdata_api/__init__.py +0 -0
- {caltechdata_api-1.5.0 → caltechdata_api-1.6.0}/caltechdata_api/download_file.py +0 -0
- {caltechdata_api-1.5.0 → caltechdata_api-1.6.0}/caltechdata_api/get_files.py +0 -0
- {caltechdata_api-1.5.0 → caltechdata_api-1.6.0}/caltechdata_api/get_metadata.py +0 -0
- {caltechdata_api-1.5.0 → caltechdata_api-1.6.0}/caltechdata_api.egg-info/dependency_links.txt +0 -0
- {caltechdata_api-1.5.0 → caltechdata_api-1.6.0}/caltechdata_api.egg-info/top_level.txt +0 -0
- {caltechdata_api-1.5.0 → caltechdata_api-1.6.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: caltechdata_api
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.6.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
|
|
@@ -18,38 +18,56 @@ Description-Content-Type: text/markdown
|
|
|
18
18
|
License-File: LICENSE
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
#
|
|
21
|
+
# CaltechDATA API Python Library
|
|
22
22
|
|
|
23
|
-
Python library for
|
|
23
|
+
The `caltechdata_api` Python library provides a convenient interface for interacting with the CaltechDATA API. It allows users to write files, create DataCite 4 standard JSON records, edit existing records, and retrieve metadata from the CaltechDATA repository.
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
- caltechdata_edit edits records in CaltechDATA
|
|
27
|
-
- get_metadata gets metadata from CaltechDATA records
|
|
25
|
+
## Features
|
|
28
26
|
|
|
29
|
-
|
|
27
|
+
### Writing and Editing Records
|
|
28
|
+
- `caltechdata_write`: Writes files and a DataCite 4 standard JSON record to the CaltechDATA repository.
|
|
29
|
+
- `caltechdata_edit`: Edits existing records in CaltechDATA.
|
|
30
|
+
|
|
31
|
+
### Metadata Operations
|
|
32
|
+
- `get_metadata`: Retrieves metadata from CaltechDATA records.
|
|
33
|
+
|
|
34
|
+
## Requirements
|
|
35
|
+
|
|
36
|
+
- Python 3 (Anaconda is recommended)
|
|
37
|
+
- `requests` library
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
Install the library via pip:
|
|
42
|
+
|
|
43
|
+
```shell
|
|
44
|
+
pip install caltechdata_api
|
|
45
|
+
```
|
|
30
46
|
|
|
31
47
|
## Examples
|
|
32
48
|
|
|
33
49
|
There are some example python scripts in the GitHub repository.
|
|
34
50
|
|
|
35
|
-
Create a record:
|
|
51
|
+
###Create a record:
|
|
36
52
|
|
|
37
53
|
```shell
|
|
38
54
|
python write.py example.json -fnames logo.gif
|
|
39
|
-
pbkn6-m9y63
|
|
55
|
+
# Output: pbkn6-m9y63 (unique identifier)
|
|
40
56
|
```
|
|
41
|
-
The response will be the unique identifier for the record. You can put this at
|
|
57
|
+
> The response will be the unique identifier for the record. You can put this at
|
|
42
58
|
the end of a url to visit the record (e.g.
|
|
43
59
|
https://data.caltechlibrary.dev/records/pbkn6-m9y63)
|
|
44
60
|
|
|
45
|
-
Edit a record
|
|
61
|
+
###Edit a record
|
|
62
|
+
Make changes to the example.json file to see a change)
|
|
46
63
|
```
|
|
47
64
|
python edit.py example.json -id pbkn6-m9y63
|
|
48
65
|
10.33569/pbkn6-m9y63
|
|
49
66
|
```
|
|
50
|
-
The response is the DOI for the record, which includes the unique identifier
|
|
67
|
+
> The response is the DOI for the record, which includes the unique identifier
|
|
51
68
|
for the record in the default configuration.
|
|
52
69
|
|
|
70
|
+
## Using Custom DOIs
|
|
53
71
|
Some groups have worked with the library to create custom DOIs. These can be
|
|
54
72
|
passed in the metadata like:
|
|
55
73
|
|
|
@@ -66,18 +84,16 @@ python edit.py example_custom.json -id m6zxz-p4j22
|
|
|
66
84
|
|
|
67
85
|
This returns the custom DOI of the record if it is successful.
|
|
68
86
|
|
|
69
|
-
## Setup
|
|
70
87
|
|
|
71
|
-
|
|
88
|
+
## Setup and Authentication
|
|
72
89
|
|
|
73
|
-
|
|
90
|
+
1. Acquire a personal access token from your CaltechDATA account (found under "Applications" at the top right of your screen).
|
|
91
|
+
2. Copy the token to a file named token.bash.
|
|
92
|
+
3. Load the token in the command line using source token.bash.
|
|
74
93
|
|
|
75
|
-
|
|
76
|
-
(find it at the top right of your screen under "Applications").
|
|
77
|
-
Then copy the token to token.bash. Type `source token.bash` in
|
|
78
|
-
the command line to load the token.
|
|
94
|
+
## Note on Testing
|
|
79
95
|
|
|
80
|
-
Only test your application on the test repository (data.caltechlibrary.dev). Testing the API on the public
|
|
96
|
+
Only test your application on the test repository (`data.caltechlibrary.dev`). Testing the API on the public
|
|
81
97
|
repository will generate junk records that are annoying to delete.
|
|
82
98
|
|
|
83
99
|
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# CaltechDATA API Python Library
|
|
2
|
+
|
|
3
|
+
The `caltechdata_api` Python library provides a convenient interface for interacting with the CaltechDATA API. It allows users to write files, create DataCite 4 standard JSON records, edit existing records, and retrieve metadata from the CaltechDATA repository.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
### Writing and Editing Records
|
|
8
|
+
- `caltechdata_write`: Writes files and a DataCite 4 standard JSON record to the CaltechDATA repository.
|
|
9
|
+
- `caltechdata_edit`: Edits existing records in CaltechDATA.
|
|
10
|
+
|
|
11
|
+
### Metadata Operations
|
|
12
|
+
- `get_metadata`: Retrieves metadata from CaltechDATA records.
|
|
13
|
+
|
|
14
|
+
## Requirements
|
|
15
|
+
|
|
16
|
+
- Python 3 (Anaconda is recommended)
|
|
17
|
+
- `requests` library
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
Install the library via pip:
|
|
22
|
+
|
|
23
|
+
```shell
|
|
24
|
+
pip install caltechdata_api
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Examples
|
|
28
|
+
|
|
29
|
+
There are some example python scripts in the GitHub repository.
|
|
30
|
+
|
|
31
|
+
###Create a record:
|
|
32
|
+
|
|
33
|
+
```shell
|
|
34
|
+
python write.py example.json -fnames logo.gif
|
|
35
|
+
# Output: pbkn6-m9y63 (unique identifier)
|
|
36
|
+
```
|
|
37
|
+
> The response will be the unique identifier for the record. You can put this at
|
|
38
|
+
the end of a url to visit the record (e.g.
|
|
39
|
+
https://data.caltechlibrary.dev/records/pbkn6-m9y63)
|
|
40
|
+
|
|
41
|
+
###Edit a record
|
|
42
|
+
Make changes to the example.json file to see a change)
|
|
43
|
+
```
|
|
44
|
+
python edit.py example.json -id pbkn6-m9y63
|
|
45
|
+
10.33569/pbkn6-m9y63
|
|
46
|
+
```
|
|
47
|
+
> The response is the DOI for the record, which includes the unique identifier
|
|
48
|
+
for the record in the default configuration.
|
|
49
|
+
|
|
50
|
+
## Using Custom DOIs
|
|
51
|
+
Some groups have worked with the library to create custom DOIs. These can be
|
|
52
|
+
passed in the metadata like:
|
|
53
|
+
|
|
54
|
+
```shell
|
|
55
|
+
python write.py example_custom.json -fnames logo.gif
|
|
56
|
+
m6zxz-p4j22
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
And then you can edit with
|
|
60
|
+
```
|
|
61
|
+
python edit.py example_custom.json -id m6zxz-p4j22
|
|
62
|
+
10.5281/inveniordm.1234
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
This returns the custom DOI of the record if it is successful.
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
## Setup and Authentication
|
|
69
|
+
|
|
70
|
+
1. Acquire a personal access token from your CaltechDATA account (found under "Applications" at the top right of your screen).
|
|
71
|
+
2. Copy the token to a file named token.bash.
|
|
72
|
+
3. Load the token in the command line using source token.bash.
|
|
73
|
+
|
|
74
|
+
## Note on Testing
|
|
75
|
+
|
|
76
|
+
Only test your application on the test repository (`data.caltechlibrary.dev`). Testing the API on the public
|
|
77
|
+
repository will generate junk records that are annoying to delete.
|
|
78
|
+
|
|
@@ -67,9 +67,9 @@ def write_files_rdm(files, file_link, headers, f_headers, s3=None):
|
|
|
67
67
|
def add_file_links(
|
|
68
68
|
metadata, file_links, file_descriptions=[], additional_descriptions="", s3_link=None
|
|
69
69
|
):
|
|
70
|
-
# Currently configured for
|
|
70
|
+
# Currently configured for S3 links, assuming all are at same endpoint
|
|
71
71
|
link_string = ""
|
|
72
|
-
endpoint = "https://
|
|
72
|
+
endpoint = "https://" + file_links[0].split("/")[2]
|
|
73
73
|
s3 = s3fs.S3FileSystem(anon=True, client_kwargs={"endpoint_url": endpoint})
|
|
74
74
|
index = 0
|
|
75
75
|
for link in file_links:
|
|
@@ -102,7 +102,6 @@ def add_file_links(
|
|
|
102
102
|
|
|
103
103
|
|
|
104
104
|
def send_to_community(review_link, data, headers, publish, community, message=None):
|
|
105
|
-
|
|
106
105
|
if not message:
|
|
107
106
|
message = "This record is submitted automatically with the CaltechDATA API"
|
|
108
107
|
|
|
@@ -0,0 +1,608 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import requests
|
|
3
|
+
import s3fs
|
|
4
|
+
from caltechdata_api import caltechdata_write, caltechdata_edit
|
|
5
|
+
from .md_to_json import parse_readme_to_json
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
import configparser
|
|
9
|
+
|
|
10
|
+
CALTECHDATA_API = "https://data.caltech.edu/api/names?q=identifiers.identifier:{}"
|
|
11
|
+
ORCID_API = "https://orcid.org/"
|
|
12
|
+
HEADERS = {"Accept": "application/json"}
|
|
13
|
+
|
|
14
|
+
name = ""
|
|
15
|
+
affiliationIdentifierScheme = ""
|
|
16
|
+
affiliation_identifier = ""
|
|
17
|
+
|
|
18
|
+
awardNumber = ""
|
|
19
|
+
awardTitle = ""
|
|
20
|
+
funderIdentifier = ""
|
|
21
|
+
funderIdentifierType = ""
|
|
22
|
+
funderName = ""
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
CONFIG_FILE = "caltechdata_config.ini"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def get_or_set_token():
|
|
29
|
+
config = configparser.ConfigParser()
|
|
30
|
+
|
|
31
|
+
if os.path.isfile(CONFIG_FILE):
|
|
32
|
+
config.read(CONFIG_FILE)
|
|
33
|
+
if "CaltechDATA" in config and "token" in config["CaltechDATA"]:
|
|
34
|
+
return config["CaltechDATA"]["token"]
|
|
35
|
+
else:
|
|
36
|
+
while True:
|
|
37
|
+
token = get_user_input("Enter your CaltechDATA token: ")
|
|
38
|
+
confirm_token = get_user_input("Confirm your CaltechDATA token: ")
|
|
39
|
+
if token == confirm_token:
|
|
40
|
+
config.add_section("CaltechDATA")
|
|
41
|
+
config.set("CaltechDATA", "token", token)
|
|
42
|
+
with open(CONFIG_FILE, "w") as configfile:
|
|
43
|
+
config.write(configfile)
|
|
44
|
+
return token
|
|
45
|
+
else:
|
|
46
|
+
print("Tokens do not match. Please try again.")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def welcome_message():
|
|
50
|
+
print("Welcome to CaltechDATA CLI")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def get_user_input(prompt, required=True):
|
|
54
|
+
while True:
|
|
55
|
+
user_input = input(prompt)
|
|
56
|
+
if required and not user_input:
|
|
57
|
+
print("This field is required. Please provide a value.")
|
|
58
|
+
else:
|
|
59
|
+
return user_input
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def confirm_upload():
|
|
63
|
+
while True:
|
|
64
|
+
user_input = input("Do you want to send this record to CaltechDATA? (y/n): ")
|
|
65
|
+
if user_input.lower() == "y":
|
|
66
|
+
return True
|
|
67
|
+
elif user_input.lower() == "n":
|
|
68
|
+
print("Upload canceled.")
|
|
69
|
+
return False
|
|
70
|
+
else:
|
|
71
|
+
print("Invalid input. Please enter 'y' or 'n'.")
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def check_award_number(award_number):
|
|
75
|
+
response = requests.get(
|
|
76
|
+
f"https://data.caltech.edu/api/awards?q=number:{award_number}"
|
|
77
|
+
)
|
|
78
|
+
data = response.json()
|
|
79
|
+
total_hits = data.get("hits", {}).get("total", 0)
|
|
80
|
+
return total_hits > 0
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def get_funding_entries():
|
|
84
|
+
while True:
|
|
85
|
+
try:
|
|
86
|
+
num_entries = int(
|
|
87
|
+
input("How many funding entries do you want to provide? ")
|
|
88
|
+
)
|
|
89
|
+
if num_entries >= 0:
|
|
90
|
+
return num_entries
|
|
91
|
+
else:
|
|
92
|
+
print("Please enter a non-negative integer.")
|
|
93
|
+
except ValueError:
|
|
94
|
+
print("Please enter a valid integer.")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def validate_funder_identifier(funder_identifier):
|
|
98
|
+
response = requests.get(f"https://api.ror.org/organizations/{funder_identifier}")
|
|
99
|
+
if response.status_code == 200:
|
|
100
|
+
return True
|
|
101
|
+
else:
|
|
102
|
+
return False
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def get_funding_details():
|
|
106
|
+
award_number = get_user_input("Enter the award number for funding: ")
|
|
107
|
+
award_exists = check_award_number(award_number)
|
|
108
|
+
if not award_exists:
|
|
109
|
+
print(
|
|
110
|
+
f"""Error: No award with number '{award_number}' found in
|
|
111
|
+
CaltechDATA. You will need to provide more details about the
|
|
112
|
+
funding."""
|
|
113
|
+
)
|
|
114
|
+
award_title = get_user_input("Enter the award title for funding: ")
|
|
115
|
+
while True:
|
|
116
|
+
funder_identifier = get_user_input("Enter the funder ROR (https://ror.org): ")
|
|
117
|
+
if validate_funder_identifier(funder_identifier):
|
|
118
|
+
break
|
|
119
|
+
else:
|
|
120
|
+
print(
|
|
121
|
+
"""This funder identifier is not a ROR. Please enter a valid
|
|
122
|
+
ROR identifier (without the url). For example the ROR for the
|
|
123
|
+
NSF is 021nxhr62."""
|
|
124
|
+
)
|
|
125
|
+
print("-" * 10)
|
|
126
|
+
return {
|
|
127
|
+
"awardNumber": award_number,
|
|
128
|
+
"awardTitle": award_title,
|
|
129
|
+
"funderIdentifier": funder_identifier,
|
|
130
|
+
"funderIdentifierType": "ROR",
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def parse_arguments():
|
|
135
|
+
welcome_message()
|
|
136
|
+
args = {}
|
|
137
|
+
args["title"] = get_user_input("Enter the title of the dataset: ")
|
|
138
|
+
args["description"] = get_user_input(
|
|
139
|
+
"Enter the abstract or description of the dataset: "
|
|
140
|
+
)
|
|
141
|
+
print("License options:")
|
|
142
|
+
print("1. Creative Commons Zero Waiver (cc-zero)")
|
|
143
|
+
print("2. Creative Commons Attribution (cc-by)")
|
|
144
|
+
print("3. Creative Commons Attribution Non Commercial (cc-by-nc)")
|
|
145
|
+
|
|
146
|
+
# Prompt user to select a license
|
|
147
|
+
while True:
|
|
148
|
+
license_number = input(
|
|
149
|
+
"Enter the number corresponding to the desired license: "
|
|
150
|
+
)
|
|
151
|
+
if license_number.isdigit() and 1 <= int(license_number) <= 8:
|
|
152
|
+
# Valid license number selected
|
|
153
|
+
args["license"] = {
|
|
154
|
+
"1": "cc0-1.0",
|
|
155
|
+
"2": "cc-by-4.0",
|
|
156
|
+
"3": "cc-by-nc-4.0",
|
|
157
|
+
}[license_number]
|
|
158
|
+
break
|
|
159
|
+
else:
|
|
160
|
+
print("Invalid input. Please enter a number between 1 and 8.")
|
|
161
|
+
|
|
162
|
+
while True:
|
|
163
|
+
orcid = get_user_input("Enter your ORCID identifier: ")
|
|
164
|
+
family_name, given_name = get_names(orcid)
|
|
165
|
+
if family_name is not None and given_name is not None:
|
|
166
|
+
args["orcid"] = orcid
|
|
167
|
+
break # Break out of the loop if names are successfully retrieved
|
|
168
|
+
retry = input("Do you want to try again? (y/n): ")
|
|
169
|
+
if retry.lower() != "y":
|
|
170
|
+
print("Exiting program.")
|
|
171
|
+
return
|
|
172
|
+
# Optional arguments
|
|
173
|
+
num_funding_entries = get_funding_entries()
|
|
174
|
+
funding_references = []
|
|
175
|
+
for _ in range(num_funding_entries):
|
|
176
|
+
funding_references.append(get_funding_details())
|
|
177
|
+
args["fundingReferences"] = funding_references
|
|
178
|
+
return args
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def query_caltechdata_api(orcid):
|
|
182
|
+
response = requests.get(CALTECHDATA_API.format(orcid), headers=HEADERS)
|
|
183
|
+
return response.json()
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def query_orcid_api(orcid):
|
|
187
|
+
response = requests.get(ORCID_API + orcid, headers=HEADERS)
|
|
188
|
+
return response.json()
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def get_names(orcid):
|
|
192
|
+
caltechdata_response = query_caltechdata_api(orcid)
|
|
193
|
+
global affiliationIdentifierScheme, affiliation_identifier, name
|
|
194
|
+
if caltechdata_response.get("hits", {}).get("hits"):
|
|
195
|
+
hit = caltechdata_response["hits"]["hits"][0]
|
|
196
|
+
family_name = hit.get("family_name", "")
|
|
197
|
+
given_name = hit.get("given_name", "")
|
|
198
|
+
affiliation_identifier = "05dxps055"
|
|
199
|
+
affiliationIdentifierScheme = "ROR"
|
|
200
|
+
name = "California Institute of Technology"
|
|
201
|
+
|
|
202
|
+
else:
|
|
203
|
+
orcid_link = "https://orcid.org/"
|
|
204
|
+
headers = {"Accept": "application/json"}
|
|
205
|
+
orcid_response = requests.get(orcid_link + orcid, headers=headers)
|
|
206
|
+
try:
|
|
207
|
+
orcid_data = orcid_response.json()
|
|
208
|
+
name_info = orcid_data.get("person", {}).get("name", {})
|
|
209
|
+
family_name = name_info.get("family-name", {}).get("value", "")
|
|
210
|
+
given_name = name_info.get("given-names", {}).get("value", "")
|
|
211
|
+
except json.decoder.JSONDecodeError:
|
|
212
|
+
print(
|
|
213
|
+
f"Error: ORCID identifier not found or invalid. Please check the ORCID identifier and try again."
|
|
214
|
+
)
|
|
215
|
+
return None, None
|
|
216
|
+
return family_name, given_name
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def upload_supporting_file(record_id=None):
|
|
220
|
+
filepath = ""
|
|
221
|
+
file_link = ""
|
|
222
|
+
while True:
|
|
223
|
+
choice = get_user_input(
|
|
224
|
+
"Do you want to upload or link data files? (upload/link/n): "
|
|
225
|
+
).lower()
|
|
226
|
+
if choice == "link":
|
|
227
|
+
endpoint = "https://sdsc.osn.xsede.org/"
|
|
228
|
+
path = "ini230004-bucket01/"
|
|
229
|
+
|
|
230
|
+
if not record_id:
|
|
231
|
+
record_id = get_user_input("Folder where OSN files are uploaded")
|
|
232
|
+
|
|
233
|
+
s3 = s3fs.S3FileSystem(anon=True, client_kwargs={"endpoint_url": endpoint})
|
|
234
|
+
# Find the files
|
|
235
|
+
files = s3.glob(path + record_id + "/*")
|
|
236
|
+
|
|
237
|
+
file_links = []
|
|
238
|
+
|
|
239
|
+
for link in files:
|
|
240
|
+
fname = link.split("/")[-1]
|
|
241
|
+
if "." not in fname:
|
|
242
|
+
# If there is a directory, get files
|
|
243
|
+
folder_files = s3.glob(link + "/*")
|
|
244
|
+
for file in folder_files:
|
|
245
|
+
name = file.split("/")[-1]
|
|
246
|
+
if "." not in name:
|
|
247
|
+
level_2_files = s3.glob(file + "/*")
|
|
248
|
+
for f in level_2_files:
|
|
249
|
+
name = f.split("/")[-1]
|
|
250
|
+
if "." not in name:
|
|
251
|
+
level_3_files = s3.glob(f + "/*")
|
|
252
|
+
for l3 in level_3_files:
|
|
253
|
+
file_links.append(endpoint + l3)
|
|
254
|
+
else:
|
|
255
|
+
file_links.append(endpoint + f)
|
|
256
|
+
else:
|
|
257
|
+
file_links.append(endpoint + file)
|
|
258
|
+
else:
|
|
259
|
+
file_links.append(endpoint + link)
|
|
260
|
+
return filepath, file_links
|
|
261
|
+
elif choice == "upload":
|
|
262
|
+
print("Current files in the directory:")
|
|
263
|
+
files = [
|
|
264
|
+
f for f in os.listdir() if not f.endswith(".json") and os.path.isfile(f)
|
|
265
|
+
]
|
|
266
|
+
print("\n".join(files))
|
|
267
|
+
filename = get_user_input(
|
|
268
|
+
"Enter the filename to upload as a supporting file: "
|
|
269
|
+
)
|
|
270
|
+
if filename in files:
|
|
271
|
+
file_size = os.path.getsize(filename)
|
|
272
|
+
if file_size > 1024 * 1024 * 1024:
|
|
273
|
+
file_link = get_user_input(
|
|
274
|
+
"Enter the S3 link to the file (File size is more than 1GB): "
|
|
275
|
+
)
|
|
276
|
+
if file_link:
|
|
277
|
+
return filepath, file_link
|
|
278
|
+
else:
|
|
279
|
+
print("Link is required for files larger than 1GB.")
|
|
280
|
+
continue
|
|
281
|
+
else:
|
|
282
|
+
filepath = os.path.abspath(filename)
|
|
283
|
+
break
|
|
284
|
+
else:
|
|
285
|
+
print(
|
|
286
|
+
f"Error: File '{filename}' not found. Please enter a valid filename."
|
|
287
|
+
)
|
|
288
|
+
elif choice == "n":
|
|
289
|
+
break
|
|
290
|
+
else:
|
|
291
|
+
print("Invalid input. Please enter 'link' or 'upload' or 'n'.")
|
|
292
|
+
|
|
293
|
+
return filepath, file_link
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def upload_data_from_file():
|
|
297
|
+
while True:
|
|
298
|
+
print("Current JSON files in the directory:")
|
|
299
|
+
files = [f for f in os.listdir() if f.endswith(".json") and os.path.isfile(f)]
|
|
300
|
+
print("\n".join(files))
|
|
301
|
+
|
|
302
|
+
filename = get_user_input(
|
|
303
|
+
"Enter a README.md or JSON filename to upload to CaltechDATA (or type 'exit' to go back): "
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
if filename.lower() == "exit":
|
|
307
|
+
return None
|
|
308
|
+
|
|
309
|
+
if filename == "README.md":
|
|
310
|
+
data = parse_readme_to_json(filename)
|
|
311
|
+
return data
|
|
312
|
+
else:
|
|
313
|
+
try:
|
|
314
|
+
with open(filename, "r") as file:
|
|
315
|
+
data = json.load(file)
|
|
316
|
+
return data
|
|
317
|
+
|
|
318
|
+
except json.JSONDecodeError as e:
|
|
319
|
+
print(f"Error: Invalid JSON format in the file '{filename}'. {str(e)}")
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
def main():
|
|
323
|
+
choice = get_user_input(
|
|
324
|
+
"Do you want to create or edit a CaltechDATA record? (create/edit): "
|
|
325
|
+
).lower()
|
|
326
|
+
if choice == "create":
|
|
327
|
+
create_record()
|
|
328
|
+
elif choice == "edit":
|
|
329
|
+
edit_record()
|
|
330
|
+
else:
|
|
331
|
+
print("Invalid choice. Please enter 'create' or 'edit'.")
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
def create_record():
|
|
335
|
+
token = get_or_set_token()
|
|
336
|
+
print("Using CaltechDATA token:", token)
|
|
337
|
+
while True:
|
|
338
|
+
choice = get_user_input(
|
|
339
|
+
"Do you want to use metadata from an existing file or create new metadata? (existing/create): "
|
|
340
|
+
).lower()
|
|
341
|
+
if choice == "existing":
|
|
342
|
+
existing_data = upload_data_from_file()
|
|
343
|
+
filepath, file_link = upload_supporting_file()
|
|
344
|
+
if existing_data:
|
|
345
|
+
if filepath != "":
|
|
346
|
+
response = caltechdata_write(
|
|
347
|
+
existing_data, token, filepath, production=False, publish=False
|
|
348
|
+
)
|
|
349
|
+
elif file_link != "":
|
|
350
|
+
response = caltechdata_write(
|
|
351
|
+
existing_data,
|
|
352
|
+
token,
|
|
353
|
+
file_links=[file_link],
|
|
354
|
+
s3_link=file_link,
|
|
355
|
+
production=False,
|
|
356
|
+
publish=False,
|
|
357
|
+
)
|
|
358
|
+
else:
|
|
359
|
+
response = caltechdata_write(
|
|
360
|
+
existing_data, token, production=False, publish=False
|
|
361
|
+
)
|
|
362
|
+
rec_id = response
|
|
363
|
+
print(
|
|
364
|
+
f"You can view and publish this record at https://data.caltechlibrary.dev/uploads/{rec_id}"
|
|
365
|
+
)
|
|
366
|
+
break
|
|
367
|
+
else:
|
|
368
|
+
print("Going back to the main menu.")
|
|
369
|
+
elif choice == "create":
|
|
370
|
+
args = parse_arguments()
|
|
371
|
+
family_name, given_name = get_names(args["orcid"])
|
|
372
|
+
metadata = {
|
|
373
|
+
"titles": [{"title": args["title"]}],
|
|
374
|
+
"descriptions": [
|
|
375
|
+
{"description": args["description"], "descriptionType": "Abstract"}
|
|
376
|
+
],
|
|
377
|
+
"creators": [
|
|
378
|
+
{
|
|
379
|
+
"affiliation": [
|
|
380
|
+
{
|
|
381
|
+
"affiliationIdentifier": affiliation_identifier,
|
|
382
|
+
"affiliationIdentifierScheme": affiliationIdentifierScheme,
|
|
383
|
+
"name": name,
|
|
384
|
+
}
|
|
385
|
+
],
|
|
386
|
+
"familyName": family_name,
|
|
387
|
+
"givenName": given_name,
|
|
388
|
+
"name": f"{family_name}, {given_name}",
|
|
389
|
+
"nameIdentifiers": [
|
|
390
|
+
{
|
|
391
|
+
"nameIdentifier": args["orcid"],
|
|
392
|
+
"nameIdentifierScheme": "ORCID",
|
|
393
|
+
}
|
|
394
|
+
],
|
|
395
|
+
"nameType": "Personal",
|
|
396
|
+
}
|
|
397
|
+
],
|
|
398
|
+
"types": {"resourceType": "", "resourceTypeGeneral": "Dataset"},
|
|
399
|
+
"rightsList": [
|
|
400
|
+
{
|
|
401
|
+
"rightsIdentifier": args["license"],
|
|
402
|
+
}
|
|
403
|
+
],
|
|
404
|
+
"fundingReferences": args["fundingReferences"],
|
|
405
|
+
"schemaVersion": "http://datacite.org/schema/kernel-4",
|
|
406
|
+
}
|
|
407
|
+
filepath, file_link = upload_supporting_file()
|
|
408
|
+
if confirm_upload():
|
|
409
|
+
if filepath != "":
|
|
410
|
+
response = caltechdata_write(
|
|
411
|
+
metadata, token, filepath, production=False, publish=False
|
|
412
|
+
)
|
|
413
|
+
elif file_link != "":
|
|
414
|
+
response = caltechdata_write(
|
|
415
|
+
metadata,
|
|
416
|
+
token,
|
|
417
|
+
file_links=[file_link],
|
|
418
|
+
production=False,
|
|
419
|
+
publish=False,
|
|
420
|
+
)
|
|
421
|
+
else:
|
|
422
|
+
response = caltechdata_write(
|
|
423
|
+
metadata, token, production=False, publish=False
|
|
424
|
+
)
|
|
425
|
+
rec_id = response
|
|
426
|
+
print(
|
|
427
|
+
f"You can view and publish this record at https://data.caltechlibrary.dev/uploads/{rec_id}"
|
|
428
|
+
)
|
|
429
|
+
with open(response + ".json", "w") as file:
|
|
430
|
+
json.dump(metadata, file, indent=2)
|
|
431
|
+
break
|
|
432
|
+
else:
|
|
433
|
+
break
|
|
434
|
+
else:
|
|
435
|
+
print("Invalid choice. Please enter 'existing' or 'create'.")
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
def edit_record():
|
|
439
|
+
record_id = input("Enter the CaltechDATA record ID: ")
|
|
440
|
+
token = get_or_set_token()
|
|
441
|
+
file_name = download_file_by_id(record_id, token)
|
|
442
|
+
if file_name:
|
|
443
|
+
try:
|
|
444
|
+
# Read the edited metadata file
|
|
445
|
+
with open(file_name, "r") as file:
|
|
446
|
+
metadata = json.load(file)
|
|
447
|
+
response = caltechdata_edit(
|
|
448
|
+
record_id, metadata, token, production=False, publish=False
|
|
449
|
+
)
|
|
450
|
+
if response:
|
|
451
|
+
print("Metadata edited successfully.")
|
|
452
|
+
else:
|
|
453
|
+
print("Failed to edit metadata.")
|
|
454
|
+
except Exception as e:
|
|
455
|
+
print(f"An error occurred during metadata editing: {e}")
|
|
456
|
+
else:
|
|
457
|
+
print("No metadata file found.")
|
|
458
|
+
choice = get_user_input("Do you want to add files? (y/n): ").lower()
|
|
459
|
+
if choice == "y":
|
|
460
|
+
filepath, file_link = upload_supporting_file(record_id)
|
|
461
|
+
print(file_link)
|
|
462
|
+
if filepath != "":
|
|
463
|
+
response = caltechdata_edit(
|
|
464
|
+
record_id, token=token, files=filepath, production=False, publish=False
|
|
465
|
+
)
|
|
466
|
+
elif file_link != "":
|
|
467
|
+
response = caltechdata_edit(
|
|
468
|
+
record_id,
|
|
469
|
+
metadata,
|
|
470
|
+
token=token,
|
|
471
|
+
file_links=file_link,
|
|
472
|
+
production=False,
|
|
473
|
+
publish=False,
|
|
474
|
+
)
|
|
475
|
+
rec_id = response
|
|
476
|
+
print(
|
|
477
|
+
f"You can view and publish this record at https://data.caltechlibrary.dev/uploads/{rec_id}"
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
def download_file_by_id(record_id, token=None):
|
|
482
|
+
url = f"https://data.caltechlibrary.dev/api/records/{record_id}"
|
|
483
|
+
|
|
484
|
+
headers = {
|
|
485
|
+
"accept": "application/vnd.datacite.datacite+json",
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
if token:
|
|
489
|
+
headers["Authorization"] = "Bearer %s" % token
|
|
490
|
+
|
|
491
|
+
try:
|
|
492
|
+
response = requests.get(url, headers=headers)
|
|
493
|
+
if response.status_code != 200:
|
|
494
|
+
# Might have a draft
|
|
495
|
+
response = requests.get(
|
|
496
|
+
url + "/draft",
|
|
497
|
+
headers=headers,
|
|
498
|
+
)
|
|
499
|
+
if response.status_code != 200:
|
|
500
|
+
raise Exception(f"Record {record_id} does not exist, cannot edit")
|
|
501
|
+
file_content = response.content
|
|
502
|
+
file_name = f"downloaded_data_{record_id}.json"
|
|
503
|
+
with open(file_name, "wb") as file:
|
|
504
|
+
file.write(file_content)
|
|
505
|
+
print(f"Metadata downloaded successfully: {file_name}")
|
|
506
|
+
with open(file_name, "r") as file:
|
|
507
|
+
metadata = json.load(file)
|
|
508
|
+
while True:
|
|
509
|
+
print("Fields:")
|
|
510
|
+
for i, field in enumerate(metadata.keys()):
|
|
511
|
+
print(f"{i + 1}. {field}")
|
|
512
|
+
|
|
513
|
+
field_choice = int(
|
|
514
|
+
input(
|
|
515
|
+
"Enter the number of the field you want to edit (or 0 to skip, 'exit' to exit): "
|
|
516
|
+
)
|
|
517
|
+
)
|
|
518
|
+
|
|
519
|
+
if field_choice == 0:
|
|
520
|
+
break
|
|
521
|
+
|
|
522
|
+
selected_field = list(metadata.keys())[field_choice - 1]
|
|
523
|
+
|
|
524
|
+
if isinstance(metadata[selected_field], list):
|
|
525
|
+
while True:
|
|
526
|
+
print(f"Items in {selected_field}:")
|
|
527
|
+
for i, item in enumerate(metadata[selected_field]):
|
|
528
|
+
print(f"{i + 1}. {item}")
|
|
529
|
+
|
|
530
|
+
item_choice = int(
|
|
531
|
+
input(
|
|
532
|
+
"Enter the number of the item you want to edit (or 0 to go back): "
|
|
533
|
+
)
|
|
534
|
+
)
|
|
535
|
+
|
|
536
|
+
if item_choice == 0:
|
|
537
|
+
break
|
|
538
|
+
|
|
539
|
+
selected_item = metadata[selected_field][item_choice - 1]
|
|
540
|
+
|
|
541
|
+
while True:
|
|
542
|
+
print(f"Subfields for {selected_field}:")
|
|
543
|
+
for i, subfield in enumerate(selected_item.keys()):
|
|
544
|
+
print(f"{i + 1}. {subfield}")
|
|
545
|
+
|
|
546
|
+
subfield_choice = int(
|
|
547
|
+
input(
|
|
548
|
+
"Enter the number of the subfield you want to edit (or 0 to go back): "
|
|
549
|
+
)
|
|
550
|
+
)
|
|
551
|
+
|
|
552
|
+
if subfield_choice == 0:
|
|
553
|
+
break
|
|
554
|
+
|
|
555
|
+
selected_subfield = list(selected_item.keys())[
|
|
556
|
+
subfield_choice - 1
|
|
557
|
+
]
|
|
558
|
+
|
|
559
|
+
new_value = input(
|
|
560
|
+
f"Enter the new value for {selected_subfield}: "
|
|
561
|
+
)
|
|
562
|
+
|
|
563
|
+
metadata[selected_field][item_choice - 1][
|
|
564
|
+
selected_subfield
|
|
565
|
+
] = new_value
|
|
566
|
+
|
|
567
|
+
with open(file_name, "w") as file:
|
|
568
|
+
json.dump(metadata, file, indent=2)
|
|
569
|
+
|
|
570
|
+
print(f"File updated successfully.")
|
|
571
|
+
|
|
572
|
+
else:
|
|
573
|
+
while True:
|
|
574
|
+
print(f"Subfields for {selected_field}:")
|
|
575
|
+
for i, subfield in enumerate(metadata[selected_field].keys()):
|
|
576
|
+
print(f"{i + 1}. {subfield}")
|
|
577
|
+
|
|
578
|
+
subfield_choice = int(
|
|
579
|
+
input(
|
|
580
|
+
"Enter the number of the subfield you want to edit (or 0 to go back): "
|
|
581
|
+
)
|
|
582
|
+
)
|
|
583
|
+
|
|
584
|
+
if subfield_choice == 0:
|
|
585
|
+
break
|
|
586
|
+
|
|
587
|
+
selected_subfield = list(metadata[selected_field].keys())[
|
|
588
|
+
subfield_choice - 1
|
|
589
|
+
]
|
|
590
|
+
|
|
591
|
+
new_value = input(
|
|
592
|
+
f"Enter the new value for {selected_subfield}: "
|
|
593
|
+
)
|
|
594
|
+
|
|
595
|
+
metadata[selected_field][selected_subfield] = new_value
|
|
596
|
+
|
|
597
|
+
with open(file_name, "w") as file:
|
|
598
|
+
json.dump(metadata, file, indent=2)
|
|
599
|
+
|
|
600
|
+
print(f"File updated successfully.")
|
|
601
|
+
|
|
602
|
+
except Exception as e:
|
|
603
|
+
print(f"An error occurred: {e}")
|
|
604
|
+
return file_name
|
|
605
|
+
|
|
606
|
+
|
|
607
|
+
if __name__ == "__main__":
|
|
608
|
+
main()
|
|
@@ -57,7 +57,6 @@ def get_vocabularies():
|
|
|
57
57
|
|
|
58
58
|
|
|
59
59
|
def customize_schema(json_record, schema="43"):
|
|
60
|
-
|
|
61
60
|
if schema == "43":
|
|
62
61
|
return customize_schema_rdm(json_record)
|
|
63
62
|
else:
|
|
@@ -134,7 +133,6 @@ def rdm_creators_contributors(person_list, peopleroles):
|
|
|
134
133
|
|
|
135
134
|
|
|
136
135
|
def customize_schema_rdm(json_record):
|
|
137
|
-
|
|
138
136
|
# Get vocabularies used in InvenioRDM
|
|
139
137
|
vocabularies = get_vocabularies()
|
|
140
138
|
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import json
|
|
3
|
+
import requests
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ReadmeFormatException(Exception):
|
|
7
|
+
"""Custom exception for errors in the README format."""
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def camel_case(s):
|
|
11
|
+
"""Converts a string to camelCase."""
|
|
12
|
+
s = re.sub(r"(\s|_|-)+", " ", s).title().replace(" ", "")
|
|
13
|
+
return s[0].lower() + s[1:] if s else ""
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def expand_special_keys(key, value):
|
|
17
|
+
"""Expand special keys into their structured format (affiliation, nameIdentifiers)."""
|
|
18
|
+
if key == "affiliation":
|
|
19
|
+
if "ror.org" not in value:
|
|
20
|
+
raise ValueError("Affiliation Identifier is not a ROR")
|
|
21
|
+
ror = value.split("ror.org/")[1].split("]")[0]
|
|
22
|
+
response = requests.get(f"https://api.ror.org/organizations/{ror}").json()
|
|
23
|
+
return [
|
|
24
|
+
{
|
|
25
|
+
"affiliationIdentifier": ror,
|
|
26
|
+
"affiliationIdentifierScheme": "ROR",
|
|
27
|
+
"name": response["name"],
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
elif key == "nameIdentifiers":
|
|
31
|
+
orcid = value.split("orcid.org/")[1].split("]")[0]
|
|
32
|
+
return [
|
|
33
|
+
{
|
|
34
|
+
"nameIdentifier": orcid,
|
|
35
|
+
"nameIdentifierScheme": "ORCID",
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
return value
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def parse_readme_to_json(readme_path):
|
|
42
|
+
try:
|
|
43
|
+
with open(readme_path, "r") as file:
|
|
44
|
+
lines = file.read().split("\n")
|
|
45
|
+
except IOError as e:
|
|
46
|
+
raise ReadmeFormatException(f"Failed to open or read the file: {e}")
|
|
47
|
+
|
|
48
|
+
json_data = {}
|
|
49
|
+
current_section = None
|
|
50
|
+
current_object = {}
|
|
51
|
+
|
|
52
|
+
title_line = lines.pop(0)
|
|
53
|
+
if title_line.startswith("#") == False:
|
|
54
|
+
raise ValueError('README.md needs to start with "# Title"')
|
|
55
|
+
else:
|
|
56
|
+
json_data["titles"] = [{"title": title_line.replace("# ", "")}]
|
|
57
|
+
|
|
58
|
+
section_pattern = re.compile(r"^##\s+(.*)$")
|
|
59
|
+
key_value_pattern = re.compile(r"^-\s+(.*?):\s+(.*)$")
|
|
60
|
+
link_pattern = re.compile(r"\[.*?\]\((.*?)\)")
|
|
61
|
+
|
|
62
|
+
for line_number, line in enumerate(lines, 1):
|
|
63
|
+
if not line.strip():
|
|
64
|
+
if current_object and current_section:
|
|
65
|
+
if current_section == "types":
|
|
66
|
+
json_data[current_section] = current_object
|
|
67
|
+
elif len(current_object) == 1:
|
|
68
|
+
key, value = next(iter(current_object.items()))
|
|
69
|
+
if key in ["language", "publicationYear", "publisher", "version"]:
|
|
70
|
+
json_data[current_section] = value
|
|
71
|
+
else:
|
|
72
|
+
json_data[current_section].append(current_object)
|
|
73
|
+
else:
|
|
74
|
+
json_data[current_section].append(current_object)
|
|
75
|
+
current_object = {}
|
|
76
|
+
continue
|
|
77
|
+
|
|
78
|
+
section_match = section_pattern.match(line)
|
|
79
|
+
if section_match:
|
|
80
|
+
if current_section and current_object:
|
|
81
|
+
if current_section == "types":
|
|
82
|
+
json_data[current_section] = current_object
|
|
83
|
+
elif len(current_object) == 1:
|
|
84
|
+
key, value = next(iter(current_object.items()))
|
|
85
|
+
if key in ["language", "publicationYear", "publisher", "version"]:
|
|
86
|
+
json_data[current_section].append(value)
|
|
87
|
+
else:
|
|
88
|
+
json_data[current_section].append(current_object)
|
|
89
|
+
else:
|
|
90
|
+
json_data[current_section].append(current_object)
|
|
91
|
+
current_object = {}
|
|
92
|
+
current_section = camel_case(section_match.group(1))
|
|
93
|
+
json_data[current_section] = [] if current_section != "types" else {}
|
|
94
|
+
continue
|
|
95
|
+
|
|
96
|
+
key_value_match = key_value_pattern.match(line)
|
|
97
|
+
if key_value_match and current_section:
|
|
98
|
+
key, value = key_value_match.groups()
|
|
99
|
+
key = camel_case(key)
|
|
100
|
+
|
|
101
|
+
if key in ["affiliation", "nameIdentifiers"]:
|
|
102
|
+
value = expand_special_keys(key, value)
|
|
103
|
+
else:
|
|
104
|
+
link_match = link_pattern.search(value)
|
|
105
|
+
if link_match:
|
|
106
|
+
value = link_match.group(1)
|
|
107
|
+
|
|
108
|
+
current_object[key] = value
|
|
109
|
+
|
|
110
|
+
elif line.strip() and not section_match:
|
|
111
|
+
raise ReadmeFormatException(
|
|
112
|
+
f"Incorrect format detected at line {line_number}: {line}"
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
if current_section and current_object:
|
|
116
|
+
if current_section == "types":
|
|
117
|
+
json_data[current_section] = current_object
|
|
118
|
+
elif len(current_object) == 1:
|
|
119
|
+
key, value = next(iter(current_object.items()))
|
|
120
|
+
if key in ["language", "publicationYear", "publisher", "version"]:
|
|
121
|
+
json_data[current_section].append(value)
|
|
122
|
+
else:
|
|
123
|
+
json_data[current_section].append(current_object)
|
|
124
|
+
else:
|
|
125
|
+
json_data[current_section].append(current_object)
|
|
126
|
+
|
|
127
|
+
return json_data
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
if __name__ == "__main__":
|
|
131
|
+
readme_path = "exampleREADME.md"
|
|
132
|
+
try:
|
|
133
|
+
json_data = parse_readme_to_json(readme_path)
|
|
134
|
+
output_json_path = "output1.json"
|
|
135
|
+
with open(output_json_path, "w") as json_file:
|
|
136
|
+
json.dump(json_data, json_file, indent=4)
|
|
137
|
+
print(f"Converted JSON saved to {output_json_path}")
|
|
138
|
+
except ReadmeFormatException as e:
|
|
139
|
+
print(f"Error parsing README file: {e}")
|
|
@@ -54,7 +54,6 @@ def humanbytes(num: Union[int, float], metric: bool = True, precision: int = 1)
|
|
|
54
54
|
|
|
55
55
|
|
|
56
56
|
if __name__ == "__main__":
|
|
57
|
-
|
|
58
57
|
print(humanbytes(2251799813685247)) # 2 pebibytes
|
|
59
58
|
print(humanbytes(2000000000000000, True)) # 2 petabytes
|
|
60
59
|
print(humanbytes(1099511627776)) # 1 tebibyte
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: caltechdata-api
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.6.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
|
|
@@ -18,38 +18,56 @@ Description-Content-Type: text/markdown
|
|
|
18
18
|
License-File: LICENSE
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
#
|
|
21
|
+
# CaltechDATA API Python Library
|
|
22
22
|
|
|
23
|
-
Python library for
|
|
23
|
+
The `caltechdata_api` Python library provides a convenient interface for interacting with the CaltechDATA API. It allows users to write files, create DataCite 4 standard JSON records, edit existing records, and retrieve metadata from the CaltechDATA repository.
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
- caltechdata_edit edits records in CaltechDATA
|
|
27
|
-
- get_metadata gets metadata from CaltechDATA records
|
|
25
|
+
## Features
|
|
28
26
|
|
|
29
|
-
|
|
27
|
+
### Writing and Editing Records
|
|
28
|
+
- `caltechdata_write`: Writes files and a DataCite 4 standard JSON record to the CaltechDATA repository.
|
|
29
|
+
- `caltechdata_edit`: Edits existing records in CaltechDATA.
|
|
30
|
+
|
|
31
|
+
### Metadata Operations
|
|
32
|
+
- `get_metadata`: Retrieves metadata from CaltechDATA records.
|
|
33
|
+
|
|
34
|
+
## Requirements
|
|
35
|
+
|
|
36
|
+
- Python 3 (Anaconda is recommended)
|
|
37
|
+
- `requests` library
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
Install the library via pip:
|
|
42
|
+
|
|
43
|
+
```shell
|
|
44
|
+
pip install caltechdata_api
|
|
45
|
+
```
|
|
30
46
|
|
|
31
47
|
## Examples
|
|
32
48
|
|
|
33
49
|
There are some example python scripts in the GitHub repository.
|
|
34
50
|
|
|
35
|
-
Create a record:
|
|
51
|
+
###Create a record:
|
|
36
52
|
|
|
37
53
|
```shell
|
|
38
54
|
python write.py example.json -fnames logo.gif
|
|
39
|
-
pbkn6-m9y63
|
|
55
|
+
# Output: pbkn6-m9y63 (unique identifier)
|
|
40
56
|
```
|
|
41
|
-
The response will be the unique identifier for the record. You can put this at
|
|
57
|
+
> The response will be the unique identifier for the record. You can put this at
|
|
42
58
|
the end of a url to visit the record (e.g.
|
|
43
59
|
https://data.caltechlibrary.dev/records/pbkn6-m9y63)
|
|
44
60
|
|
|
45
|
-
Edit a record
|
|
61
|
+
###Edit a record
|
|
62
|
+
Make changes to the example.json file to see a change)
|
|
46
63
|
```
|
|
47
64
|
python edit.py example.json -id pbkn6-m9y63
|
|
48
65
|
10.33569/pbkn6-m9y63
|
|
49
66
|
```
|
|
50
|
-
The response is the DOI for the record, which includes the unique identifier
|
|
67
|
+
> The response is the DOI for the record, which includes the unique identifier
|
|
51
68
|
for the record in the default configuration.
|
|
52
69
|
|
|
70
|
+
## Using Custom DOIs
|
|
53
71
|
Some groups have worked with the library to create custom DOIs. These can be
|
|
54
72
|
passed in the metadata like:
|
|
55
73
|
|
|
@@ -66,18 +84,16 @@ python edit.py example_custom.json -id m6zxz-p4j22
|
|
|
66
84
|
|
|
67
85
|
This returns the custom DOI of the record if it is successful.
|
|
68
86
|
|
|
69
|
-
## Setup
|
|
70
87
|
|
|
71
|
-
|
|
88
|
+
## Setup and Authentication
|
|
72
89
|
|
|
73
|
-
|
|
90
|
+
1. Acquire a personal access token from your CaltechDATA account (found under "Applications" at the top right of your screen).
|
|
91
|
+
2. Copy the token to a file named token.bash.
|
|
92
|
+
3. Load the token in the command line using source token.bash.
|
|
74
93
|
|
|
75
|
-
|
|
76
|
-
(find it at the top right of your screen under "Applications").
|
|
77
|
-
Then copy the token to token.bash. Type `source token.bash` in
|
|
78
|
-
the command line to load the token.
|
|
94
|
+
## Note on Testing
|
|
79
95
|
|
|
80
|
-
Only test your application on the test repository (data.caltechlibrary.dev). Testing the API on the public
|
|
96
|
+
Only test your application on the test repository (`data.caltechlibrary.dev`). Testing the API on the public
|
|
81
97
|
repository will generate junk records that are annoying to delete.
|
|
82
98
|
|
|
83
99
|
|
|
@@ -4,13 +4,16 @@ setup.py
|
|
|
4
4
|
caltechdata_api/__init__.py
|
|
5
5
|
caltechdata_api/caltechdata_edit.py
|
|
6
6
|
caltechdata_api/caltechdata_write.py
|
|
7
|
+
caltechdata_api/cli.py
|
|
7
8
|
caltechdata_api/customize_schema.py
|
|
8
9
|
caltechdata_api/download_file.py
|
|
9
10
|
caltechdata_api/get_files.py
|
|
10
11
|
caltechdata_api/get_metadata.py
|
|
12
|
+
caltechdata_api/md_to_json.py
|
|
11
13
|
caltechdata_api/utils.py
|
|
12
14
|
caltechdata_api.egg-info/PKG-INFO
|
|
13
15
|
caltechdata_api.egg-info/SOURCES.txt
|
|
14
16
|
caltechdata_api.egg-info/dependency_links.txt
|
|
17
|
+
caltechdata_api.egg-info/entry_points.txt
|
|
15
18
|
caltechdata_api.egg-info/requires.txt
|
|
16
19
|
caltechdata_api.egg-info/top_level.txt
|
|
@@ -60,7 +60,15 @@ name = meta["name"]
|
|
|
60
60
|
REQUIRES_PYTHON = ">=3.6.0"
|
|
61
61
|
|
|
62
62
|
# What packages are required for this module to be executed?
|
|
63
|
-
REQUIRED = [
|
|
63
|
+
REQUIRED = [
|
|
64
|
+
"requests",
|
|
65
|
+
"datacite>1.1.0",
|
|
66
|
+
"tqdm>=4.62.3",
|
|
67
|
+
"pyyaml",
|
|
68
|
+
"s3fs",
|
|
69
|
+
"configparser",
|
|
70
|
+
"awscli",
|
|
71
|
+
]
|
|
64
72
|
|
|
65
73
|
# What packages are optional?
|
|
66
74
|
EXTRAS = {
|
|
@@ -163,4 +171,9 @@ setup(
|
|
|
163
171
|
cmdclass={
|
|
164
172
|
"upload": UploadCommand,
|
|
165
173
|
},
|
|
174
|
+
entry_points={
|
|
175
|
+
"console_scripts": [
|
|
176
|
+
"caltechdata_api=caltechdata_api.cli:main",
|
|
177
|
+
],
|
|
178
|
+
},
|
|
166
179
|
)
|
caltechdata_api-1.5.0/README.md
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# caltechdata_api
|
|
2
|
-
|
|
3
|
-
Python library for using the CaltechDATA API
|
|
4
|
-
|
|
5
|
-
- caltechdata_write write files and a DataCite 4 standard json record to CaltechDATA repository
|
|
6
|
-
- caltechdata_edit edits records in CaltechDATA
|
|
7
|
-
- get_metadata gets metadata from CaltechDATA records
|
|
8
|
-
|
|
9
|
-
Requires Python 3 (Recommended via Anaconda https://www.anaconda.com/download) with reqests library.
|
|
10
|
-
|
|
11
|
-
## Examples
|
|
12
|
-
|
|
13
|
-
There are some example python scripts in the GitHub repository.
|
|
14
|
-
|
|
15
|
-
Create a record:
|
|
16
|
-
|
|
17
|
-
```shell
|
|
18
|
-
python write.py example.json -fnames logo.gif
|
|
19
|
-
pbkn6-m9y63
|
|
20
|
-
```
|
|
21
|
-
The response will be the unique identifier for the record. You can put this at
|
|
22
|
-
the end of a url to visit the record (e.g.
|
|
23
|
-
https://data.caltechlibrary.dev/records/pbkn6-m9y63)
|
|
24
|
-
|
|
25
|
-
Edit a record (make changes to the example.json file to see a change)
|
|
26
|
-
```
|
|
27
|
-
python edit.py example.json -id pbkn6-m9y63
|
|
28
|
-
10.33569/pbkn6-m9y63
|
|
29
|
-
```
|
|
30
|
-
The response is the DOI for the record, which includes the unique identifier
|
|
31
|
-
for the record in the default configuration.
|
|
32
|
-
|
|
33
|
-
Some groups have worked with the library to create custom DOIs. These can be
|
|
34
|
-
passed in the metadata like:
|
|
35
|
-
|
|
36
|
-
```shell
|
|
37
|
-
python write.py example_custom.json -fnames logo.gif
|
|
38
|
-
m6zxz-p4j22
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
And then you can edit with
|
|
42
|
-
```
|
|
43
|
-
python edit.py example_custom.json -id m6zxz-p4j22
|
|
44
|
-
10.5281/inveniordm.1234
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
This returns the custom DOI of the record if it is successful.
|
|
48
|
-
|
|
49
|
-
## Setup
|
|
50
|
-
|
|
51
|
-
Install by typing 'pip install caltechdata_api'
|
|
52
|
-
|
|
53
|
-
## Usage
|
|
54
|
-
|
|
55
|
-
You need to acquire a personal access token from your CaltechDATA account
|
|
56
|
-
(find it at the top right of your screen under "Applications").
|
|
57
|
-
Then copy the token to token.bash. Type `source token.bash` in
|
|
58
|
-
the command line to load the token.
|
|
59
|
-
|
|
60
|
-
Only test your application on the test repository (data.caltechlibrary.dev). Testing the API on the public
|
|
61
|
-
repository will generate junk records that are annoying to delete.
|
|
62
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{caltechdata_api-1.5.0 → caltechdata_api-1.6.0}/caltechdata_api.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|