caltechdata-api 1.5.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.
Files changed (22) hide show
  1. {caltechdata_api-1.5.0 → caltechdata_api-1.6.1}/PKG-INFO +36 -20
  2. caltechdata_api-1.6.1/README.md +78 -0
  3. {caltechdata_api-1.5.0 → caltechdata_api-1.6.1}/caltechdata_api/caltechdata_edit.py +0 -1
  4. {caltechdata_api-1.5.0 → caltechdata_api-1.6.1}/caltechdata_api/caltechdata_write.py +2 -3
  5. caltechdata_api-1.6.1/caltechdata_api/cli.py +667 -0
  6. {caltechdata_api-1.5.0 → caltechdata_api-1.6.1}/caltechdata_api/customize_schema.py +0 -2
  7. caltechdata_api-1.6.1/caltechdata_api/md_to_json.py +195 -0
  8. {caltechdata_api-1.5.0 → caltechdata_api-1.6.1}/caltechdata_api/utils.py +0 -1
  9. {caltechdata_api-1.5.0 → caltechdata_api-1.6.1}/caltechdata_api.egg-info/PKG-INFO +36 -20
  10. {caltechdata_api-1.5.0 → caltechdata_api-1.6.1}/caltechdata_api.egg-info/SOURCES.txt +3 -0
  11. caltechdata_api-1.6.1/caltechdata_api.egg-info/entry_points.txt +3 -0
  12. {caltechdata_api-1.5.0 → caltechdata_api-1.6.1}/caltechdata_api.egg-info/requires.txt +2 -0
  13. {caltechdata_api-1.5.0 → caltechdata_api-1.6.1}/setup.py +14 -1
  14. caltechdata_api-1.5.0/README.md +0 -62
  15. {caltechdata_api-1.5.0 → caltechdata_api-1.6.1}/LICENSE +0 -0
  16. {caltechdata_api-1.5.0 → caltechdata_api-1.6.1}/caltechdata_api/__init__.py +0 -0
  17. {caltechdata_api-1.5.0 → caltechdata_api-1.6.1}/caltechdata_api/download_file.py +0 -0
  18. {caltechdata_api-1.5.0 → caltechdata_api-1.6.1}/caltechdata_api/get_files.py +0 -0
  19. {caltechdata_api-1.5.0 → caltechdata_api-1.6.1}/caltechdata_api/get_metadata.py +0 -0
  20. {caltechdata_api-1.5.0 → caltechdata_api-1.6.1}/caltechdata_api.egg-info/dependency_links.txt +0 -0
  21. {caltechdata_api-1.5.0 → caltechdata_api-1.6.1}/caltechdata_api.egg-info/top_level.txt +0 -0
  22. {caltechdata_api-1.5.0 → caltechdata_api-1.6.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: caltechdata_api
3
- Version: 1.5.0
3
+ Version: 1.6.1
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
- # caltechdata_api
21
+ # CaltechDATA API Python Library
22
22
 
23
- Python library for using the CaltechDATA API
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
- - caltechdata_write write files and a DataCite 4 standard json record to CaltechDATA repository
26
- - caltechdata_edit edits records in CaltechDATA
27
- - get_metadata gets metadata from CaltechDATA records
25
+ ## Features
28
26
 
29
- Requires Python 3 (Recommended via Anaconda https://www.anaconda.com/download) with reqests library.
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 (make changes to the example.json file to see a change)
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
- Install by typing 'pip install caltechdata_api'
88
+ ## Setup and Authentication
72
89
 
73
- ## Usage
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
- You need to acquire a personal access token from your CaltechDATA account
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
+
@@ -33,7 +33,6 @@ def caltechdata_accept(ids, token=None, production=False):
33
33
  }
34
34
 
35
35
  for idv in ids:
36
-
37
36
  result = requests.get(
38
37
  url + "/api/records/" + idv + "/draft/review", headers=headers
39
38
  )
@@ -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 OSN S3 links
70
+ # Currently configured for S3 links, assuming all are at same endpoint
71
71
  link_string = ""
72
- endpoint = "https://renc.osn.xsede.org/"
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,667 @@
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
+ from cryptography.fernet import Fernet
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
+ home_directory = os.path.expanduser("~")
25
+ caltechdata_directory = os.path.join(home_directory, ".caltechdata")
26
+
27
+
28
+ if not os.path.exists(caltechdata_directory):
29
+ os.makedirs(caltechdata_directory)
30
+
31
+
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()
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:
71
+ while True:
72
+ token = input("Enter your CaltechDATA token: ").strip()
73
+ confirm_token = input("Confirm your CaltechDATA token: ").strip()
74
+ if token == confirm_token:
75
+ encrypted_token = encrypt_token(token, key)
76
+ with open(token_file, "wb") as f:
77
+ f.write(encrypted_token)
78
+ return token
79
+ else:
80
+ print("Tokens do not match. Please try again.")
81
+
82
+
83
+ def welcome_message():
84
+ print("Welcome to CaltechDATA CLI")
85
+
86
+
87
+ def get_user_input(prompt, required=True):
88
+ while True:
89
+ user_input = input(prompt)
90
+ if required and not user_input:
91
+ print("This field is required. Please provide a value.")
92
+ else:
93
+ return user_input
94
+
95
+
96
+ def confirm_upload():
97
+ while True:
98
+ user_input = input("Do you want to send this record to CaltechDATA? (y/n): ")
99
+ if user_input.lower() == "y":
100
+ return True
101
+ elif user_input.lower() == "n":
102
+ print("Upload canceled.")
103
+ return False
104
+ else:
105
+ print("Invalid input. Please enter 'y' or 'n'.")
106
+
107
+
108
+ def check_award_number(award_number):
109
+ response = requests.get(
110
+ f"https://data.caltech.edu/api/awards?q=number:{award_number}"
111
+ )
112
+ data = response.json()
113
+ total_hits = data.get("hits", {}).get("total", 0)
114
+ return total_hits > 0
115
+
116
+
117
+ def get_funding_entries():
118
+ while True:
119
+ try:
120
+ num_entries = int(
121
+ input("How many funding entries do you want to provide? ")
122
+ )
123
+ if num_entries >= 0:
124
+ return num_entries
125
+ else:
126
+ print("Please enter a non-negative integer.")
127
+ except ValueError:
128
+ print("Please enter a valid integer.")
129
+
130
+
131
+ def validate_funder_identifier(funder_identifier):
132
+ response = requests.get(f"https://api.ror.org/organizations/{funder_identifier}")
133
+ if response.status_code == 200:
134
+ return True
135
+ else:
136
+ return False
137
+
138
+
139
+ def get_funding_details():
140
+ award_number = get_user_input("Enter the award number for funding: ")
141
+ award_exists = check_award_number(award_number)
142
+ if not award_exists:
143
+ print(
144
+ f"""Error: No award with number '{award_number}' found in
145
+ CaltechDATA. You will need to provide more details about the
146
+ funding."""
147
+ )
148
+ award_title = get_user_input("Enter the award title for funding: ")
149
+ while True:
150
+ funder_identifier = get_user_input("Enter the funder ROR (https://ror.org): ")
151
+ if validate_funder_identifier(funder_identifier):
152
+ break
153
+ else:
154
+ print(
155
+ """This funder identifier is not a ROR. Please enter a valid
156
+ ROR identifier (without the url). For example the ROR for the
157
+ NSF is 021nxhr62."""
158
+ )
159
+ print("-" * 10)
160
+ return {
161
+ "awardNumber": award_number,
162
+ "awardTitle": award_title,
163
+ "funderIdentifier": funder_identifier,
164
+ "funderIdentifierType": "ROR",
165
+ }
166
+
167
+
168
+ def parse_arguments():
169
+ welcome_message()
170
+ args = {}
171
+ args["title"] = get_user_input("Enter the title of the dataset: ")
172
+ args["description"] = get_user_input(
173
+ "Enter the abstract or description of the dataset: "
174
+ )
175
+ print("License options:")
176
+ print("1. Creative Commons Zero Waiver (cc-zero)")
177
+ print("2. Creative Commons Attribution (cc-by)")
178
+ print("3. Creative Commons Attribution Non Commercial (cc-by-nc)")
179
+
180
+ # Prompt user to select a license
181
+ while True:
182
+ license_number = input(
183
+ "Enter the number corresponding to the desired license: "
184
+ )
185
+ if license_number.isdigit() and 1 <= int(license_number) <= 8:
186
+ # Valid license number selected
187
+ args["license"] = {
188
+ "1": "cc0-1.0",
189
+ "2": "cc-by-4.0",
190
+ "3": "cc-by-nc-4.0",
191
+ }[license_number]
192
+ break
193
+ else:
194
+ print("Invalid input. Please enter a number between 1 and 8.")
195
+
196
+ while True:
197
+ orcid = get_user_input("Enter your ORCID identifier: ")
198
+ family_name, given_name = get_names(orcid)
199
+ if family_name is not None and given_name is not None:
200
+ args["orcid"] = orcid
201
+ break # Break out of the loop if names are successfully retrieved
202
+ retry = input("Do you want to try again? (y/n): ")
203
+ if retry.lower() != "y":
204
+ print("Exiting program.")
205
+ return
206
+ # Optional arguments
207
+ num_funding_entries = get_funding_entries()
208
+ funding_references = []
209
+ for _ in range(num_funding_entries):
210
+ funding_references.append(get_funding_details())
211
+ args["fundingReferences"] = funding_references
212
+ return args
213
+
214
+
215
+ def query_caltechdata_api(orcid):
216
+ response = requests.get(CALTECHDATA_API.format(orcid), headers=HEADERS)
217
+ return response.json()
218
+
219
+
220
+ def query_orcid_api(orcid):
221
+ response = requests.get(ORCID_API + orcid, headers=HEADERS)
222
+ return response.json()
223
+
224
+
225
+ def get_names(orcid):
226
+ caltechdata_response = query_caltechdata_api(orcid)
227
+ global affiliationIdentifierScheme, affiliation_identifier, name
228
+ if caltechdata_response.get("hits", {}).get("hits"):
229
+ hit = caltechdata_response["hits"]["hits"][0]
230
+ family_name = hit.get("family_name", "")
231
+ given_name = hit.get("given_name", "")
232
+ affiliation_identifier = "05dxps055"
233
+ affiliationIdentifierScheme = "ROR"
234
+ name = "California Institute of Technology"
235
+
236
+ else:
237
+ orcid_link = "https://orcid.org/"
238
+ headers = {"Accept": "application/json"}
239
+ orcid_response = requests.get(orcid_link + orcid, headers=headers)
240
+ try:
241
+ orcid_data = orcid_response.json()
242
+ name_info = orcid_data.get("person", {}).get("name", {})
243
+ family_name = name_info.get("family-name", {}).get("value", "")
244
+ given_name = name_info.get("given-names", {}).get("value", "")
245
+ except json.decoder.JSONDecodeError:
246
+ print(
247
+ f"Error: ORCID identifier not found or invalid. Please check the ORCID identifier and try again."
248
+ )
249
+ return None, None
250
+ return family_name, given_name
251
+
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
+
267
+ def upload_supporting_file(record_id=None):
268
+ filepath = ""
269
+ filepaths = []
270
+ file_links = []
271
+ while True:
272
+ choice = get_user_input(
273
+ "Do you want to upload or link data files? (upload/link/n): "
274
+ ).lower()
275
+ if choice == "link":
276
+ endpoint = "sdsc.osn.xsede.org"
277
+ path = "ini230004-bucket01/"
278
+ if not record_id:
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}/"
285
+ s3 = s3fs.S3FileSystem(anon=True, client_kwargs={"endpoint_url": endpoint})
286
+ # Find the files
287
+ files = s3.glob(path + record_id + "/*")
288
+
289
+ for link in files:
290
+ fname = link.split("/")[-1]
291
+ if "." not in fname:
292
+ # If there is a directory, get files
293
+ folder_files = s3.glob(link + "/*")
294
+ for file in folder_files:
295
+ name = file.split("/")[-1]
296
+ if "." not in name:
297
+ level_2_files = s3.glob(file + "/*")
298
+ for f in level_2_files:
299
+ name = f.split("/")[-1]
300
+ if "." not in name:
301
+ level_3_files = s3.glob(f + "/*")
302
+ for l3 in level_3_files:
303
+ file_links.append(endpoint + l3)
304
+ else:
305
+ file_links.append(endpoint + f)
306
+ else:
307
+ file_links.append(endpoint + file)
308
+ else:
309
+ file_links.append(endpoint + link)
310
+ return filepath, file_links
311
+ elif choice == "upload":
312
+ print("Current files in the directory:")
313
+ files = [
314
+ f for f in os.listdir() if not f.endswith(".json") and os.path.isfile(f)
315
+ ]
316
+ print("\n".join(files))
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
+ )
331
+ else:
332
+ filepath = os.path.abspath(filename)
333
+ filepaths.append(filepath)
334
+ else:
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
+
343
+ elif choice == "n":
344
+ break
345
+ else:
346
+ print("Invalid input. Please enter 'link' or 'upload' or 'n'.")
347
+
348
+ return filepaths, file_links
349
+
350
+
351
+ def upload_data_from_file():
352
+ while True:
353
+ print("Current JSON files in the directory:")
354
+ files = [f for f in os.listdir() if f.endswith(".json") and os.path.isfile(f)]
355
+ print("\n".join(files))
356
+
357
+ filename = get_user_input(
358
+ "Enter a README.md or JSON filename to upload to CaltechDATA (or type 'exit' to go back): "
359
+ )
360
+
361
+ if filename.lower() == "exit":
362
+ return None
363
+
364
+ if filename == "README.md":
365
+ data = parse_readme_to_json(filename)
366
+ return data
367
+ else:
368
+ try:
369
+ with open(filename, "r") as file:
370
+ data = json.load(file)
371
+ return data
372
+
373
+ except json.JSONDecodeError as e:
374
+ print(f"Error: Invalid JSON format in the file '{filename}'. {str(e)}")
375
+
376
+
377
+ def main():
378
+ choice = get_user_input(
379
+ "Do you want to create or edit a CaltechDATA record? (create/edit): "
380
+ ).lower()
381
+ if choice == "create":
382
+ create_record()
383
+ elif choice == "edit":
384
+ edit_record()
385
+ else:
386
+ print("Invalid choice. Please enter 'create' or 'edit'.")
387
+
388
+
389
+ def create_record():
390
+ token = get_or_set_token()
391
+ print("Using CaltechDATA token:", token)
392
+ while True:
393
+ choice = get_user_input(
394
+ "Do you want to use metadata from an existing file or create new metadata? (existing/create): "
395
+ ).lower()
396
+ if choice == "existing":
397
+ existing_data = upload_data_from_file()
398
+ filepath, file_link = upload_supporting_file()
399
+ if existing_data:
400
+ if filepath != "":
401
+ response = caltechdata_write(
402
+ existing_data, token, filepath, production=False, publish=False
403
+ )
404
+ elif file_link != "":
405
+ response = caltechdata_write(
406
+ existing_data,
407
+ token,
408
+ file_links=[file_link],
409
+ s3_link=file_link,
410
+ production=False,
411
+ publish=False,
412
+ )
413
+ else:
414
+ response = caltechdata_write(
415
+ existing_data, token, production=False, publish=False
416
+ )
417
+ rec_id = response
418
+ print(
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}/"""
422
+ )
423
+ break
424
+ else:
425
+ print("Going back to the main menu.")
426
+ elif choice == "create":
427
+ args = parse_arguments()
428
+ family_name, given_name = get_names(args["orcid"])
429
+ metadata = {
430
+ "titles": [{"title": args["title"]}],
431
+ "descriptions": [
432
+ {"description": args["description"], "descriptionType": "Abstract"}
433
+ ],
434
+ "creators": [
435
+ {
436
+ "affiliation": [
437
+ {
438
+ "affiliationIdentifier": affiliation_identifier,
439
+ "affiliationIdentifierScheme": affiliationIdentifierScheme,
440
+ "name": name,
441
+ }
442
+ ],
443
+ "familyName": family_name,
444
+ "givenName": given_name,
445
+ "name": f"{family_name}, {given_name}",
446
+ "nameIdentifiers": [
447
+ {
448
+ "nameIdentifier": args["orcid"],
449
+ "nameIdentifierScheme": "ORCID",
450
+ }
451
+ ],
452
+ "nameType": "Personal",
453
+ }
454
+ ],
455
+ "types": {"resourceType": "", "resourceTypeGeneral": "Dataset"},
456
+ "rightsList": [
457
+ {
458
+ "rightsIdentifier": args["license"],
459
+ }
460
+ ],
461
+ "fundingReferences": args["fundingReferences"],
462
+ "schemaVersion": "http://datacite.org/schema/kernel-4",
463
+ }
464
+ filepath, file_link = upload_supporting_file()
465
+ if confirm_upload():
466
+ if filepath != "":
467
+ response = caltechdata_write(
468
+ metadata, token, filepath, production=False, publish=False
469
+ )
470
+ elif file_link != "":
471
+ response = caltechdata_write(
472
+ metadata,
473
+ token,
474
+ file_links=[file_link],
475
+ production=False,
476
+ publish=False,
477
+ )
478
+ else:
479
+ response = caltechdata_write(
480
+ metadata, token, production=False, publish=False
481
+ )
482
+ rec_id = response
483
+ print(
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}/"""
487
+ )
488
+ with open(response + ".json", "w") as file:
489
+ json.dump(metadata, file, indent=2)
490
+ break
491
+ else:
492
+ break
493
+ else:
494
+ print("Invalid choice. Please enter 'existing' or 'create'.")
495
+
496
+
497
+ def edit_record():
498
+ record_id = input("Enter the CaltechDATA record ID: ")
499
+ token = get_or_set_token()
500
+ file_name = download_file_by_id(record_id, token)
501
+ if file_name:
502
+ try:
503
+ # Read the edited metadata file
504
+ with open(file_name, "r") as file:
505
+ metadata = json.load(file)
506
+ response = caltechdata_edit(
507
+ record_id, metadata, token, production=False, publish=False
508
+ )
509
+ if response:
510
+ print("Metadata edited successfully.")
511
+ else:
512
+ print("Failed to edit metadata.")
513
+ except Exception as e:
514
+ print(f"An error occurred during metadata editing: {e}")
515
+ else:
516
+ print("No metadata file found.")
517
+ choice = get_user_input("Do you want to add files? (y/n): ").lower()
518
+ if choice == "y":
519
+ filepath, file_link = upload_supporting_file(record_id)
520
+ print(file_link)
521
+ if filepath != "":
522
+ response = caltechdata_edit(
523
+ record_id, token=token, files=filepath, production=False, publish=False
524
+ )
525
+ elif file_link != "":
526
+ response = caltechdata_edit(
527
+ record_id,
528
+ metadata,
529
+ token=token,
530
+ file_links=file_link,
531
+ production=False,
532
+ publish=False,
533
+ )
534
+ rec_id = response
535
+ print(
536
+ f"You can view and publish this record at https://data.caltechlibrary.dev/uploads/{rec_id}\n"
537
+ )
538
+
539
+
540
+ def download_file_by_id(record_id, token=None):
541
+ url = f"https://data.caltechlibrary.dev/api/records/{record_id}"
542
+
543
+ headers = {
544
+ "accept": "application/vnd.datacite.datacite+json",
545
+ }
546
+
547
+ if token:
548
+ headers["Authorization"] = "Bearer %s" % token
549
+
550
+ try:
551
+ response = requests.get(url, headers=headers)
552
+ if response.status_code != 200:
553
+ # Might have a draft
554
+ response = requests.get(
555
+ url + "/draft",
556
+ headers=headers,
557
+ )
558
+ if response.status_code != 200:
559
+ raise Exception(f"Record {record_id} does not exist, cannot edit")
560
+ file_content = response.content
561
+ file_name = f"downloaded_data_{record_id}.json"
562
+ with open(file_name, "wb") as file:
563
+ file.write(file_content)
564
+ print(f"Metadata downloaded successfully: {file_name}")
565
+ with open(file_name, "r") as file:
566
+ metadata = json.load(file)
567
+ while True:
568
+ print("Fields:")
569
+ for i, field in enumerate(metadata.keys()):
570
+ print(f"{i + 1}. {field}")
571
+
572
+ field_choice = int(
573
+ input(
574
+ "Enter the number of the field you want to edit (or 0 to skip, 'exit' to exit): "
575
+ )
576
+ )
577
+
578
+ if field_choice == 0:
579
+ break
580
+
581
+ selected_field = list(metadata.keys())[field_choice - 1]
582
+
583
+ if isinstance(metadata[selected_field], list):
584
+ while True:
585
+ print(f"Items in {selected_field}:")
586
+ for i, item in enumerate(metadata[selected_field]):
587
+ print(f"{i + 1}. {item}")
588
+
589
+ item_choice = int(
590
+ input(
591
+ "Enter the number of the item you want to edit (or 0 to go back): "
592
+ )
593
+ )
594
+
595
+ if item_choice == 0:
596
+ break
597
+
598
+ selected_item = metadata[selected_field][item_choice - 1]
599
+
600
+ while True:
601
+ print(f"Subfields for {selected_field}:")
602
+ for i, subfield in enumerate(selected_item.keys()):
603
+ print(f"{i + 1}. {subfield}")
604
+
605
+ subfield_choice = int(
606
+ input(
607
+ "Enter the number of the subfield you want to edit (or 0 to go back): "
608
+ )
609
+ )
610
+
611
+ if subfield_choice == 0:
612
+ break
613
+
614
+ selected_subfield = list(selected_item.keys())[
615
+ subfield_choice - 1
616
+ ]
617
+
618
+ new_value = input(
619
+ f"Enter the new value for {selected_subfield}: "
620
+ )
621
+
622
+ metadata[selected_field][item_choice - 1][
623
+ selected_subfield
624
+ ] = new_value
625
+
626
+ with open(file_name, "w") as file:
627
+ json.dump(metadata, file, indent=2)
628
+
629
+ print(f"File updated successfully.")
630
+
631
+ else:
632
+ while True:
633
+ print(f"Subfields for {selected_field}:")
634
+ for i, subfield in enumerate(metadata[selected_field].keys()):
635
+ print(f"{i + 1}. {subfield}")
636
+
637
+ subfield_choice = int(
638
+ input(
639
+ "Enter the number of the subfield you want to edit (or 0 to go back): "
640
+ )
641
+ )
642
+
643
+ if subfield_choice == 0:
644
+ break
645
+
646
+ selected_subfield = list(metadata[selected_field].keys())[
647
+ subfield_choice - 1
648
+ ]
649
+
650
+ new_value = input(
651
+ f"Enter the new value for {selected_subfield}: "
652
+ )
653
+
654
+ metadata[selected_field][selected_subfield] = new_value
655
+
656
+ with open(file_name, "w") as file:
657
+ json.dump(metadata, file, indent=2)
658
+
659
+ print(f"File updated successfully.")
660
+
661
+ except Exception as e:
662
+ print(f"An error occurred: {e}")
663
+ return file_name
664
+
665
+
666
+ if __name__ == "__main__":
667
+ 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,195 @@
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
+ "schemeUri": f"https://orcid.org/{value}",
37
+ }
38
+ ]
39
+ return value
40
+
41
+
42
+ def parse_readme_to_json(readme_path):
43
+ try:
44
+ with open(readme_path, "r") as file:
45
+ lines = file.read().split("\n")
46
+ except IOError as e:
47
+ raise ReadmeFormatException(f"Failed to open or read the file: {e}")
48
+
49
+ json_data = {}
50
+ current_section = None
51
+ current_object = {}
52
+
53
+ title_line = lines.pop(0)
54
+ if title_line.startswith("#") == False:
55
+ raise ValueError('README.md needs to start with "# Title"')
56
+ else:
57
+ json_data["titles"] = [{"title": title_line.replace("# ", "")}]
58
+
59
+ contributors = []
60
+ identifiers = []
61
+ item_list = []
62
+
63
+ section_pattern = re.compile(r"^##\s+(.*)$")
64
+ key_value_pattern = re.compile(r"^-\s+(.*?):\s+(.*)$")
65
+ link_pattern = re.compile(r"\[.*?\]\((.*?)\)")
66
+
67
+ for line_number, line in enumerate(lines, 1):
68
+ if not line.strip():
69
+ if item_list and current_section:
70
+ json_data[current_section] = item_list
71
+ item_list = []
72
+ elif current_object and current_section:
73
+ if current_section == "types":
74
+ json_data[current_section] = current_object
75
+ elif len(current_object) == 1:
76
+ key, value = next(iter(current_object.items()))
77
+ if key in ["language", "publicationYear", "publisher", "version"]:
78
+ json_data[current_section] = value
79
+ else:
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 = {}
87
+ else:
88
+ json_data[current_section].append(current_object)
89
+ current_object = {}
90
+ continue
91
+
92
+ section_match = section_pattern.match(line)
93
+ if section_match:
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:
118
+ if current_section == "types":
119
+ json_data[current_section] = current_object
120
+ elif len(current_object) == 1:
121
+ key, value = next(iter(current_object.items()))
122
+ if key in ["language", "publicationYear", "publisher", "version"]:
123
+ json_data[current_section].append(value)
124
+ else:
125
+ json_data[current_section].append(current_object)
126
+ else:
127
+ json_data[current_section].append(current_object)
128
+ current_object = {}
129
+ current_section = camel_case(section_match.group(1))
130
+ json_data[current_section] = [] if current_section != "types" else {}
131
+ continue
132
+
133
+ key_value_match = key_value_pattern.match(line)
134
+ if key_value_match and current_section:
135
+ key, value = key_value_match.groups()
136
+ key = camel_case(key)
137
+
138
+ if key in ["affiliation", "nameIdentifiers"]:
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 = {}
156
+ else:
157
+ link_match = link_pattern.search(value)
158
+ if link_match:
159
+ value = link_match.group(1)
160
+ current_object[key] = value
161
+
162
+ elif line.strip() and not section_match:
163
+ raise ReadmeFormatException(
164
+ f"Incorrect format detected at line {line_number}: {line}"
165
+ )
166
+
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:
172
+ if current_section == "types":
173
+ json_data[current_section] = current_object
174
+ elif len(current_object) == 1:
175
+ key, value = next(iter(current_object.items()))
176
+ if key in ["language", "publicationYear", "publisher", "version"]:
177
+ json_data[current_section].append(value)
178
+ else:
179
+ json_data[current_section].append(current_object)
180
+ else:
181
+ json_data[current_section].append(current_object)
182
+
183
+ return json_data
184
+
185
+
186
+ if __name__ == "__main__":
187
+ readme_path = "/Users/elizabethwon/downloads/exampleREADME.md"
188
+ try:
189
+ json_data = parse_readme_to_json(readme_path)
190
+ output_json_path = "output1.json"
191
+ with open(output_json_path, "w") as json_file:
192
+ json.dump(json_data, json_file, indent=4)
193
+ print(f"Converted JSON saved to {output_json_path}")
194
+ except ReadmeFormatException as e:
195
+ 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.5.0
3
+ Version: 1.6.1
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
- # caltechdata_api
21
+ # CaltechDATA API Python Library
22
22
 
23
- Python library for using the CaltechDATA API
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
- - caltechdata_write write files and a DataCite 4 standard json record to CaltechDATA repository
26
- - caltechdata_edit edits records in CaltechDATA
27
- - get_metadata gets metadata from CaltechDATA records
25
+ ## Features
28
26
 
29
- Requires Python 3 (Recommended via Anaconda https://www.anaconda.com/download) with reqests library.
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 (make changes to the example.json file to see a change)
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
- Install by typing 'pip install caltechdata_api'
88
+ ## Setup and Authentication
72
89
 
73
- ## Usage
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
- You need to acquire a personal access token from your CaltechDATA account
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
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ caltechdata_api = caltechdata_api.cli:main
3
+
@@ -3,3 +3,5 @@ datacite>1.1.0
3
3
  tqdm>=4.62.3
4
4
  pyyaml
5
5
  s3fs
6
+ cryptography
7
+ s3cmd
@@ -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 = ["requests", "datacite>1.1.0", "tqdm>=4.62.3", "pyyaml", "s3fs"]
63
+ REQUIRED = [
64
+ "requests",
65
+ "datacite>1.1.0",
66
+ "tqdm>=4.62.3",
67
+ "pyyaml",
68
+ "s3fs",
69
+ "cryptography",
70
+ "s3cmd",
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
  )
@@ -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