caltechdata-api 1.6.0__tar.gz → 1.6.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.6.0 → caltechdata_api-1.6.1}/PKG-INFO +1 -1
- {caltechdata_api-1.6.0 → caltechdata_api-1.6.1}/caltechdata_api/cli.py +103 -44
- {caltechdata_api-1.6.0 → caltechdata_api-1.6.1}/caltechdata_api/md_to_json.py +62 -6
- {caltechdata_api-1.6.0 → caltechdata_api-1.6.1}/caltechdata_api.egg-info/PKG-INFO +1 -1
- {caltechdata_api-1.6.0 → caltechdata_api-1.6.1}/caltechdata_api.egg-info/requires.txt +2 -2
- {caltechdata_api-1.6.0 → caltechdata_api-1.6.1}/setup.py +2 -2
- {caltechdata_api-1.6.0 → caltechdata_api-1.6.1}/LICENSE +0 -0
- {caltechdata_api-1.6.0 → caltechdata_api-1.6.1}/README.md +0 -0
- {caltechdata_api-1.6.0 → caltechdata_api-1.6.1}/caltechdata_api/__init__.py +0 -0
- {caltechdata_api-1.6.0 → caltechdata_api-1.6.1}/caltechdata_api/caltechdata_edit.py +0 -0
- {caltechdata_api-1.6.0 → caltechdata_api-1.6.1}/caltechdata_api/caltechdata_write.py +0 -0
- {caltechdata_api-1.6.0 → caltechdata_api-1.6.1}/caltechdata_api/customize_schema.py +0 -0
- {caltechdata_api-1.6.0 → caltechdata_api-1.6.1}/caltechdata_api/download_file.py +0 -0
- {caltechdata_api-1.6.0 → caltechdata_api-1.6.1}/caltechdata_api/get_files.py +0 -0
- {caltechdata_api-1.6.0 → caltechdata_api-1.6.1}/caltechdata_api/get_metadata.py +0 -0
- {caltechdata_api-1.6.0 → caltechdata_api-1.6.1}/caltechdata_api/utils.py +0 -0
- {caltechdata_api-1.6.0 → caltechdata_api-1.6.1}/caltechdata_api.egg-info/SOURCES.txt +0 -0
- {caltechdata_api-1.6.0 → caltechdata_api-1.6.1}/caltechdata_api.egg-info/dependency_links.txt +0 -0
- {caltechdata_api-1.6.0 → caltechdata_api-1.6.1}/caltechdata_api.egg-info/entry_points.txt +0 -0
- {caltechdata_api-1.6.0 → caltechdata_api-1.6.1}/caltechdata_api.egg-info/top_level.txt +0 -0
- {caltechdata_api-1.6.0 → caltechdata_api-1.6.1}/setup.cfg +0 -0
|
@@ -5,7 +5,7 @@ from caltechdata_api import caltechdata_write, caltechdata_edit
|
|
|
5
5
|
from .md_to_json import parse_readme_to_json
|
|
6
6
|
import json
|
|
7
7
|
import os
|
|
8
|
-
import
|
|
8
|
+
from cryptography.fernet import Fernet
|
|
9
9
|
|
|
10
10
|
CALTECHDATA_API = "https://data.caltech.edu/api/names?q=identifiers.identifier:{}"
|
|
11
11
|
ORCID_API = "https://orcid.org/"
|
|
@@ -21,26 +21,60 @@ funderIdentifier = ""
|
|
|
21
21
|
funderIdentifierType = ""
|
|
22
22
|
funderName = ""
|
|
23
23
|
|
|
24
|
+
home_directory = os.path.expanduser("~")
|
|
25
|
+
caltechdata_directory = os.path.join(home_directory, ".caltechdata")
|
|
24
26
|
|
|
25
|
-
CONFIG_FILE = "caltechdata_config.ini"
|
|
26
27
|
|
|
28
|
+
if not os.path.exists(caltechdata_directory):
|
|
29
|
+
os.makedirs(caltechdata_directory)
|
|
27
30
|
|
|
28
|
-
def get_or_set_token():
|
|
29
|
-
config = configparser.ConfigParser()
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
def generate_key():
|
|
33
|
+
return Fernet.generate_key()
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# Load the key from a file or generate a new one if not present
|
|
37
|
+
def load_or_generate_key():
|
|
38
|
+
key_file = os.path.join(caltechdata_directory, "key.key")
|
|
39
|
+
if os.path.exists(key_file):
|
|
40
|
+
with open(key_file, "rb") as f:
|
|
41
|
+
return f.read()
|
|
35
42
|
else:
|
|
43
|
+
key = generate_key()
|
|
44
|
+
with open(key_file, "wb") as f:
|
|
45
|
+
f.write(key)
|
|
46
|
+
return key
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# Encrypt the token
|
|
50
|
+
def encrypt_token(token, key):
|
|
51
|
+
f = Fernet(key)
|
|
52
|
+
return f.encrypt(token.encode())
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
# Decrypt the token
|
|
56
|
+
def decrypt_token(encrypted_token, key):
|
|
57
|
+
f = Fernet(key)
|
|
58
|
+
return f.decrypt(encrypted_token).decode()
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# Function to get or set token
|
|
62
|
+
def get_or_set_token():
|
|
63
|
+
key = load_or_generate_key()
|
|
64
|
+
token_file = os.path.join(caltechdata_directory, "token.txt")
|
|
65
|
+
try:
|
|
66
|
+
with open(token_file, "rb") as f:
|
|
67
|
+
encrypted_token = f.read()
|
|
68
|
+
token = decrypt_token(encrypted_token, key)
|
|
69
|
+
return token
|
|
70
|
+
except FileNotFoundError:
|
|
36
71
|
while True:
|
|
37
|
-
token =
|
|
38
|
-
confirm_token =
|
|
72
|
+
token = input("Enter your CaltechDATA token: ").strip()
|
|
73
|
+
confirm_token = input("Confirm your CaltechDATA token: ").strip()
|
|
39
74
|
if token == confirm_token:
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
config.write(configfile)
|
|
75
|
+
encrypted_token = encrypt_token(token, key)
|
|
76
|
+
with open(token_file, "wb") as f:
|
|
77
|
+
f.write(encrypted_token)
|
|
44
78
|
return token
|
|
45
79
|
else:
|
|
46
80
|
print("Tokens do not match. Please try again.")
|
|
@@ -216,26 +250,42 @@ def get_names(orcid):
|
|
|
216
250
|
return family_name, given_name
|
|
217
251
|
|
|
218
252
|
|
|
253
|
+
def write_s3cmd_config(access_key, secret_key, endpoint):
|
|
254
|
+
configf = os.path.join(home_directory, ".s3cfg")
|
|
255
|
+
if not os.path.exists(key_file):
|
|
256
|
+
with open(configf, "w") as file:
|
|
257
|
+
file.write(
|
|
258
|
+
f"""[default]
|
|
259
|
+
access_key = {access_key}
|
|
260
|
+
host_base = {endpoint}
|
|
261
|
+
host_bucket = %(bucket).{endpoint}
|
|
262
|
+
secret_key = {secret_key}
|
|
263
|
+
"""
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
|
|
219
267
|
def upload_supporting_file(record_id=None):
|
|
220
268
|
filepath = ""
|
|
221
|
-
|
|
269
|
+
filepaths = []
|
|
270
|
+
file_links = []
|
|
222
271
|
while True:
|
|
223
272
|
choice = get_user_input(
|
|
224
273
|
"Do you want to upload or link data files? (upload/link/n): "
|
|
225
274
|
).lower()
|
|
226
275
|
if choice == "link":
|
|
227
|
-
endpoint = "
|
|
276
|
+
endpoint = "sdsc.osn.xsede.org"
|
|
228
277
|
path = "ini230004-bucket01/"
|
|
229
|
-
|
|
230
278
|
if not record_id:
|
|
231
|
-
|
|
232
|
-
|
|
279
|
+
access_key = get_user_input("Enter the access key: ")
|
|
280
|
+
secret_key = get_user_input("Enter the secret key: ")
|
|
281
|
+
write_s3cmd_config(access_key, secret_key, endpoint)
|
|
282
|
+
print("""S3 connection configured.""")
|
|
283
|
+
break
|
|
284
|
+
endpoint = f"https://{endpoint}/"
|
|
233
285
|
s3 = s3fs.S3FileSystem(anon=True, client_kwargs={"endpoint_url": endpoint})
|
|
234
286
|
# Find the files
|
|
235
287
|
files = s3.glob(path + record_id + "/*")
|
|
236
288
|
|
|
237
|
-
file_links = []
|
|
238
|
-
|
|
239
289
|
for link in files:
|
|
240
290
|
fname = link.split("/")[-1]
|
|
241
291
|
if "." not in fname:
|
|
@@ -264,33 +314,38 @@ def upload_supporting_file(record_id=None):
|
|
|
264
314
|
f for f in os.listdir() if not f.endswith(".json") and os.path.isfile(f)
|
|
265
315
|
]
|
|
266
316
|
print("\n".join(files))
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
317
|
+
while True:
|
|
318
|
+
filename = get_user_input(
|
|
319
|
+
"Enter the filename to upload as a supporting file (or 'n' to finish): "
|
|
320
|
+
)
|
|
321
|
+
if filename == "n":
|
|
322
|
+
break
|
|
323
|
+
if filename in files:
|
|
324
|
+
file_size = os.path.getsize(filename)
|
|
325
|
+
if file_size > 1024 * 1024 * 1024:
|
|
326
|
+
print(
|
|
327
|
+
"""The file is greater than 1 GB. Please upload the
|
|
328
|
+
metadata to CaltechDATA, and you'll be provided
|
|
329
|
+
instructions to upload the files to S3 directly."""
|
|
330
|
+
)
|
|
278
331
|
else:
|
|
279
|
-
|
|
280
|
-
|
|
332
|
+
filepath = os.path.abspath(filename)
|
|
333
|
+
filepaths.append(filepath)
|
|
281
334
|
else:
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
335
|
+
print(
|
|
336
|
+
f"Error: File '{filename}' not found. Please enter a valid filename."
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
add_more = get_user_input("Do you want to add more files? (y/n): ").lower()
|
|
340
|
+
if add_more != "y":
|
|
341
|
+
break
|
|
342
|
+
|
|
288
343
|
elif choice == "n":
|
|
289
344
|
break
|
|
290
345
|
else:
|
|
291
346
|
print("Invalid input. Please enter 'link' or 'upload' or 'n'.")
|
|
292
347
|
|
|
293
|
-
return
|
|
348
|
+
return filepaths, file_links
|
|
294
349
|
|
|
295
350
|
|
|
296
351
|
def upload_data_from_file():
|
|
@@ -361,7 +416,9 @@ def create_record():
|
|
|
361
416
|
)
|
|
362
417
|
rec_id = response
|
|
363
418
|
print(
|
|
364
|
-
f"You can view and publish this record at https://data.caltechlibrary.dev/uploads/{rec_id}
|
|
419
|
+
f"""You can view and publish this record at https://data.caltechlibrary.dev/uploads/{rec_id}
|
|
420
|
+
If you need to upload large files to S3, you can type
|
|
421
|
+
`s3cmd put DATA_FILE s3://ini230004-bucket01/{rec_id}/"""
|
|
365
422
|
)
|
|
366
423
|
break
|
|
367
424
|
else:
|
|
@@ -424,7 +481,9 @@ def create_record():
|
|
|
424
481
|
)
|
|
425
482
|
rec_id = response
|
|
426
483
|
print(
|
|
427
|
-
f"You can view and publish this record at https://data.caltechlibrary.dev/uploads/{rec_id}
|
|
484
|
+
f"""You can view and publish this record at https://data.caltechlibrary.dev/uploads/{rec_id}
|
|
485
|
+
If you need to upload large files to S3, you can type
|
|
486
|
+
`s3cmd put DATA_FILE s3://ini230004-bucket01/{rec_id}/"""
|
|
428
487
|
)
|
|
429
488
|
with open(response + ".json", "w") as file:
|
|
430
489
|
json.dump(metadata, file, indent=2)
|
|
@@ -474,7 +533,7 @@ def edit_record():
|
|
|
474
533
|
)
|
|
475
534
|
rec_id = response
|
|
476
535
|
print(
|
|
477
|
-
f"You can view and publish this record at https://data.caltechlibrary.dev/uploads/{rec_id}"
|
|
536
|
+
f"You can view and publish this record at https://data.caltechlibrary.dev/uploads/{rec_id}\n"
|
|
478
537
|
)
|
|
479
538
|
|
|
480
539
|
|
|
@@ -33,6 +33,7 @@ def expand_special_keys(key, value):
|
|
|
33
33
|
{
|
|
34
34
|
"nameIdentifier": orcid,
|
|
35
35
|
"nameIdentifierScheme": "ORCID",
|
|
36
|
+
"schemeUri": f"https://orcid.org/{value}",
|
|
36
37
|
}
|
|
37
38
|
]
|
|
38
39
|
return value
|
|
@@ -55,13 +56,20 @@ def parse_readme_to_json(readme_path):
|
|
|
55
56
|
else:
|
|
56
57
|
json_data["titles"] = [{"title": title_line.replace("# ", "")}]
|
|
57
58
|
|
|
59
|
+
contributors = []
|
|
60
|
+
identifiers = []
|
|
61
|
+
item_list = []
|
|
62
|
+
|
|
58
63
|
section_pattern = re.compile(r"^##\s+(.*)$")
|
|
59
64
|
key_value_pattern = re.compile(r"^-\s+(.*?):\s+(.*)$")
|
|
60
65
|
link_pattern = re.compile(r"\[.*?\]\((.*?)\)")
|
|
61
66
|
|
|
62
67
|
for line_number, line in enumerate(lines, 1):
|
|
63
68
|
if not line.strip():
|
|
64
|
-
if
|
|
69
|
+
if item_list and current_section:
|
|
70
|
+
json_data[current_section] = item_list
|
|
71
|
+
item_list = []
|
|
72
|
+
elif current_object and current_section:
|
|
65
73
|
if current_section == "types":
|
|
66
74
|
json_data[current_section] = current_object
|
|
67
75
|
elif len(current_object) == 1:
|
|
@@ -70,6 +78,12 @@ def parse_readme_to_json(readme_path):
|
|
|
70
78
|
json_data[current_section] = value
|
|
71
79
|
else:
|
|
72
80
|
json_data[current_section].append(current_object)
|
|
81
|
+
elif current_section in ["creators", "contributors"]:
|
|
82
|
+
contributors.append(current_object)
|
|
83
|
+
current_object = {}
|
|
84
|
+
elif current_section == "identifiers":
|
|
85
|
+
identifiers.append(current_object)
|
|
86
|
+
current_object = {}
|
|
73
87
|
else:
|
|
74
88
|
json_data[current_section].append(current_object)
|
|
75
89
|
current_object = {}
|
|
@@ -77,7 +91,30 @@ def parse_readme_to_json(readme_path):
|
|
|
77
91
|
|
|
78
92
|
section_match = section_pattern.match(line)
|
|
79
93
|
if section_match:
|
|
80
|
-
if
|
|
94
|
+
if item_list:
|
|
95
|
+
json_data[current_section] = item_list
|
|
96
|
+
elif current_object:
|
|
97
|
+
if current_section in json_data:
|
|
98
|
+
if isinstance(json_data[current_section], list):
|
|
99
|
+
json_data[current_section].append(current_object)
|
|
100
|
+
elif isinstance(json_data[current_section], dict):
|
|
101
|
+
json_data[current_section].update(current_object)
|
|
102
|
+
else:
|
|
103
|
+
json_data[current_section] = (
|
|
104
|
+
[current_object]
|
|
105
|
+
if current_section != "types"
|
|
106
|
+
else current_object
|
|
107
|
+
)
|
|
108
|
+
current_object = {}
|
|
109
|
+
|
|
110
|
+
elif contributors and current_section in ["creators", "contributors"]:
|
|
111
|
+
json_data[current_section] = contributors
|
|
112
|
+
contributors = []
|
|
113
|
+
elif identifiers and current_section == "identifiers":
|
|
114
|
+
json_data[current_section] = identifiers
|
|
115
|
+
identifiers = []
|
|
116
|
+
|
|
117
|
+
elif current_section and current_object:
|
|
81
118
|
if current_section == "types":
|
|
82
119
|
json_data[current_section] = current_object
|
|
83
120
|
elif len(current_object) == 1:
|
|
@@ -100,19 +137,38 @@ def parse_readme_to_json(readme_path):
|
|
|
100
137
|
|
|
101
138
|
if key in ["affiliation", "nameIdentifiers"]:
|
|
102
139
|
value = expand_special_keys(key, value)
|
|
140
|
+
elif (
|
|
141
|
+
key == "nameType"
|
|
142
|
+
and current_object
|
|
143
|
+
and current_section in ["creators", "contributors"]
|
|
144
|
+
):
|
|
145
|
+
contributors.append(current_object)
|
|
146
|
+
current_object = {}
|
|
147
|
+
elif current_section in ["subjects"]:
|
|
148
|
+
item_list.append({key: value})
|
|
149
|
+
elif current_section == "dates":
|
|
150
|
+
if key == "date":
|
|
151
|
+
current_object["date"] = value
|
|
152
|
+
elif key == "dateType":
|
|
153
|
+
current_object["dateType"] = value
|
|
154
|
+
item_list.append(current_object)
|
|
155
|
+
current_object = {}
|
|
103
156
|
else:
|
|
104
157
|
link_match = link_pattern.search(value)
|
|
105
158
|
if link_match:
|
|
106
159
|
value = link_match.group(1)
|
|
107
|
-
|
|
108
|
-
current_object[key] = value
|
|
160
|
+
current_object[key] = value
|
|
109
161
|
|
|
110
162
|
elif line.strip() and not section_match:
|
|
111
163
|
raise ReadmeFormatException(
|
|
112
164
|
f"Incorrect format detected at line {line_number}: {line}"
|
|
113
165
|
)
|
|
114
166
|
|
|
115
|
-
if
|
|
167
|
+
if contributors and current_section in ["creators", "contributors"]:
|
|
168
|
+
json_data[current_section] = contributors
|
|
169
|
+
elif identifiers and current_section == "identifiers":
|
|
170
|
+
json_data[current_section] = identifiers
|
|
171
|
+
elif current_section and current_object:
|
|
116
172
|
if current_section == "types":
|
|
117
173
|
json_data[current_section] = current_object
|
|
118
174
|
elif len(current_object) == 1:
|
|
@@ -128,7 +184,7 @@ def parse_readme_to_json(readme_path):
|
|
|
128
184
|
|
|
129
185
|
|
|
130
186
|
if __name__ == "__main__":
|
|
131
|
-
readme_path = "exampleREADME.md"
|
|
187
|
+
readme_path = "/Users/elizabethwon/downloads/exampleREADME.md"
|
|
132
188
|
try:
|
|
133
189
|
json_data = parse_readme_to_json(readme_path)
|
|
134
190
|
output_json_path = "output1.json"
|
|
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
|
|
File without changes
|
{caltechdata_api-1.6.0 → caltechdata_api-1.6.1}/caltechdata_api.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|