folio-data-import 0.2.3__py3-none-any.whl → 0.2.5__py3-none-any.whl
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.
Potentially problematic release.
This version of folio-data-import might be problematic. Click here for more details.
- folio_data_import/MARCDataImport.py +59 -9
- folio_data_import/UserImport.py +7 -5
- {folio_data_import-0.2.3.dist-info → folio_data_import-0.2.5.dist-info}/METADATA +2 -2
- folio_data_import-0.2.5.dist-info/RECORD +9 -0
- folio_data_import-0.2.3.dist-info/RECORD +0 -9
- {folio_data_import-0.2.3.dist-info → folio_data_import-0.2.5.dist-info}/LICENSE +0 -0
- {folio_data_import-0.2.3.dist-info → folio_data_import-0.2.5.dist-info}/WHEEL +0 -0
- {folio_data_import-0.2.3.dist-info → folio_data_import-0.2.5.dist-info}/entry_points.txt +0 -0
|
@@ -3,6 +3,7 @@ import asyncio
|
|
|
3
3
|
import glob
|
|
4
4
|
import io
|
|
5
5
|
import os
|
|
6
|
+
import sys
|
|
6
7
|
from typing import List
|
|
7
8
|
import uuid
|
|
8
9
|
from contextlib import ExitStack
|
|
@@ -30,6 +31,9 @@ except AttributeError:
|
|
|
30
31
|
# The order in which the report summary should be displayed
|
|
31
32
|
REPORT_SUMMARY_ORDERING = {"created": 0, "updated": 1, "discarded": 2, "error": 3}
|
|
32
33
|
|
|
34
|
+
# Set default timeout and backoff values for HTTP requests when retrying job status and final summary checks
|
|
35
|
+
RETRY_TIMEOUT_START = 1
|
|
36
|
+
RETRY_TIMEOUT_RETRY_FACTOR = 2
|
|
33
37
|
|
|
34
38
|
class MARCImportJob:
|
|
35
39
|
"""
|
|
@@ -79,6 +83,7 @@ class MARCImportJob:
|
|
|
79
83
|
self.import_profile_name = import_profile_name
|
|
80
84
|
self.batch_size = batch_size
|
|
81
85
|
self.batch_delay = batch_delay
|
|
86
|
+
self.current_retry_timeout = None
|
|
82
87
|
|
|
83
88
|
async def do_work(self) -> None:
|
|
84
89
|
"""
|
|
@@ -148,10 +153,23 @@ class MARCImportJob:
|
|
|
148
153
|
Raises:
|
|
149
154
|
IndexError: If the job execution with the specified ID is not found.
|
|
150
155
|
"""
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
156
|
+
try:
|
|
157
|
+
self.current_retry_timeout = (
|
|
158
|
+
self.current_retry_timeout * RETRY_TIMEOUT_RETRY_FACTOR
|
|
159
|
+
) if self.current_retry_timeout else RETRY_TIMEOUT_START
|
|
160
|
+
job_status = self.folio_client.folio_get(
|
|
161
|
+
"/metadata-provider/jobExecutions?statusNot=DISCARDED&uiStatusAny"
|
|
162
|
+
"=PREPARING_FOR_PREVIEW&uiStatusAny=READY_FOR_PREVIEW&uiStatusAny=RUNNING&limit=50"
|
|
163
|
+
)
|
|
164
|
+
self.current_retry_timeout = None
|
|
165
|
+
except httpx.ConnectTimeout:
|
|
166
|
+
sleep(.25)
|
|
167
|
+
with httpx.Client(
|
|
168
|
+
timeout=self.current_retry_timeout,
|
|
169
|
+
verify=self.folio_client.ssl_verify
|
|
170
|
+
) as temp_client:
|
|
171
|
+
self.folio_client.httpx_client = temp_client
|
|
172
|
+
return await self.get_job_status()
|
|
155
173
|
try:
|
|
156
174
|
status = [
|
|
157
175
|
job for job in job_status["jobExecutions"] if job["id"] == self.job_id
|
|
@@ -392,9 +410,7 @@ class MARCImportJob:
|
|
|
392
410
|
await self.get_job_status()
|
|
393
411
|
sleep(1)
|
|
394
412
|
if self.finished:
|
|
395
|
-
job_summary = self.
|
|
396
|
-
f"/metadata-provider/jobSummary/{self.job_id}"
|
|
397
|
-
)
|
|
413
|
+
job_summary = await self.get_job_summary()
|
|
398
414
|
job_summary.pop("jobExecutionId")
|
|
399
415
|
job_summary.pop("totalErrors")
|
|
400
416
|
columns = ["Summary"] + list(job_summary.keys())
|
|
@@ -425,6 +441,31 @@ class MARCImportJob:
|
|
|
425
441
|
self.last_current = 0
|
|
426
442
|
self.finished = False
|
|
427
443
|
|
|
444
|
+
async def get_job_summary(self) -> dict:
|
|
445
|
+
"""
|
|
446
|
+
Retrieves the job summary for the current job execution.
|
|
447
|
+
|
|
448
|
+
Returns:
|
|
449
|
+
dict: The job summary for the current job execution.
|
|
450
|
+
"""
|
|
451
|
+
try:
|
|
452
|
+
self.current_retry_timeout = (
|
|
453
|
+
self.current_retry_timeout * RETRY_TIMEOUT_RETRY_FACTOR
|
|
454
|
+
) if self.current_retry_timeout else RETRY_TIMEOUT_START
|
|
455
|
+
job_summary = self.folio_client.folio_get(
|
|
456
|
+
f"/metadata-provider/jobSummary/{self.job_id}"
|
|
457
|
+
)
|
|
458
|
+
self.current_retry_timeout = None
|
|
459
|
+
except httpx.ReadTimeout: #
|
|
460
|
+
sleep(.25)
|
|
461
|
+
with httpx.Client(
|
|
462
|
+
timeout=self.current_retry_timeout,
|
|
463
|
+
verify=self.folio_client.ssl_verify
|
|
464
|
+
) as temp_client:
|
|
465
|
+
self.folio_client.httpx_client = temp_client
|
|
466
|
+
return await self.get_job_summary()
|
|
467
|
+
return job_summary
|
|
468
|
+
|
|
428
469
|
|
|
429
470
|
async def main() -> None:
|
|
430
471
|
"""
|
|
@@ -491,6 +532,17 @@ async def main() -> None:
|
|
|
491
532
|
if args.member_tenant_id:
|
|
492
533
|
folio_client.okapi_headers["x-okapi-tenant"] = args.member_tenant_id
|
|
493
534
|
|
|
535
|
+
if os.path.isabs(args.marc_file_path):
|
|
536
|
+
marc_files = [Path(x) for x in glob.glob(args.marc_file_path)]
|
|
537
|
+
else:
|
|
538
|
+
marc_files = list(Path("./").glob(args.marc_file_path))
|
|
539
|
+
|
|
540
|
+
if len(marc_files) == 0:
|
|
541
|
+
print(f"No files found matching {args.marc_file_path}. Exiting.")
|
|
542
|
+
sys.exit(1)
|
|
543
|
+
else:
|
|
544
|
+
print(marc_files)
|
|
545
|
+
|
|
494
546
|
if not args.import_profile_name:
|
|
495
547
|
import_profiles = folio_client.folio_get(
|
|
496
548
|
"/data-import-profiles/jobProfiles",
|
|
@@ -511,8 +563,6 @@ async def main() -> None:
|
|
|
511
563
|
]
|
|
512
564
|
answers = inquirer.prompt(questions)
|
|
513
565
|
args.import_profile_name = answers["import_profile_name"]
|
|
514
|
-
marc_files = [Path(x) for x in glob.glob(args.marc_file_path, root_dir="./")]
|
|
515
|
-
print(marc_files)
|
|
516
566
|
try:
|
|
517
567
|
await MARCImportJob(
|
|
518
568
|
folio_client,
|
folio_data_import/UserImport.py
CHANGED
|
@@ -181,12 +181,15 @@ class UserImporter: # noqa: R0902
|
|
|
181
181
|
KeyError: If an address type name in the user object is not found in address_type_map.
|
|
182
182
|
|
|
183
183
|
"""
|
|
184
|
-
if "personal" in user_obj
|
|
185
|
-
|
|
184
|
+
if "personal" in user_obj:
|
|
185
|
+
addresses = user_obj["personal"].pop("addresses", [])
|
|
186
|
+
mapped_addresses = []
|
|
187
|
+
for address in addresses:
|
|
186
188
|
try:
|
|
187
189
|
address["addressTypeId"] = self.address_type_map[
|
|
188
190
|
address["addressTypeId"]
|
|
189
191
|
]
|
|
192
|
+
mapped_addresses.append(address)
|
|
190
193
|
except KeyError:
|
|
191
194
|
if address["addressTypeId"] not in self.address_type_map.values():
|
|
192
195
|
print(
|
|
@@ -197,9 +200,8 @@ class UserImporter: # noqa: R0902
|
|
|
197
200
|
f"Row {line_number}: Address type {address['addressTypeId']} not found"
|
|
198
201
|
f", removing address\n"
|
|
199
202
|
)
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
del user_obj["personal"]["addresses"]
|
|
203
|
+
if mapped_addresses:
|
|
204
|
+
user_obj["personal"]["addresses"] = mapped_addresses
|
|
203
205
|
|
|
204
206
|
async def map_patron_groups(self, user_obj, line_number) -> None:
|
|
205
207
|
"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: folio_data_import
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.5
|
|
4
4
|
Summary: A python module to interact with the data importing capabilities of the open-source FOLIO ILS
|
|
5
5
|
License: MIT
|
|
6
6
|
Author: Brooks Travis
|
|
@@ -19,7 +19,7 @@ Requires-Dist: flake8-bugbear (>=24.8.19,<25.0.0)
|
|
|
19
19
|
Requires-Dist: flake8-docstrings (>=1.7.0,<2.0.0)
|
|
20
20
|
Requires-Dist: flake8-isort (>=6.1.1,<7.0.0)
|
|
21
21
|
Requires-Dist: folioclient (>=0.60.5,<0.61.0)
|
|
22
|
-
Requires-Dist: httpx (>=0.
|
|
22
|
+
Requires-Dist: httpx (>=0.27.2,<0.28.0)
|
|
23
23
|
Requires-Dist: inquirer (>=3.4.0,<4.0.0)
|
|
24
24
|
Requires-Dist: pyhumps (>=3.8.0,<4.0.0)
|
|
25
25
|
Requires-Dist: pymarc (>=5.2.2,<6.0.0)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
folio_data_import/MARCDataImport.py,sha256=Agm3y-BTYK5YiD3SvihQykRhqfmsXzEGmY-AXMGMrmc,21409
|
|
2
|
+
folio_data_import/UserImport.py,sha256=9oDVSax-E6HXy6ViBgY97EprXRgtywguFizT3vfh2zE,27951
|
|
3
|
+
folio_data_import/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
folio_data_import/__main__.py,sha256=kav_uUsnrIjGjVxQkk3exLKrc1mah9t2x3G6bGS-5I0,3710
|
|
5
|
+
folio_data_import-0.2.5.dist-info/LICENSE,sha256=qJX7wxMC7ky9Kq4v3zij8MjGEiC5wsB7pYeOhLj5TDk,1083
|
|
6
|
+
folio_data_import-0.2.5.dist-info/METADATA,sha256=cOqxonYSLtuOAo68E_rz8zuojl9iiRnE-KMnePEhePI,2420
|
|
7
|
+
folio_data_import-0.2.5.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
8
|
+
folio_data_import-0.2.5.dist-info/entry_points.txt,sha256=498SxWVXeEMRNw3PUf-eoReZvKewmYwPBtZhIUPr_Jg,192
|
|
9
|
+
folio_data_import-0.2.5.dist-info/RECORD,,
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
folio_data_import/MARCDataImport.py,sha256=IStQ--WpPtnoPunQLK-LBiWApA1n9PHdKeNaFWk01a0,19478
|
|
2
|
-
folio_data_import/UserImport.py,sha256=L9GT6HjcsPSIILTb5LwXuWjyNBl3J6ft4PC4fgoqweI,27910
|
|
3
|
-
folio_data_import/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
folio_data_import/__main__.py,sha256=kav_uUsnrIjGjVxQkk3exLKrc1mah9t2x3G6bGS-5I0,3710
|
|
5
|
-
folio_data_import-0.2.3.dist-info/LICENSE,sha256=qJX7wxMC7ky9Kq4v3zij8MjGEiC5wsB7pYeOhLj5TDk,1083
|
|
6
|
-
folio_data_import-0.2.3.dist-info/METADATA,sha256=zhDrLl8I8ymgN2BD4RQpmfKhKXpWJ52t7BNCrQ0lm7U,2420
|
|
7
|
-
folio_data_import-0.2.3.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
8
|
-
folio_data_import-0.2.3.dist-info/entry_points.txt,sha256=498SxWVXeEMRNw3PUf-eoReZvKewmYwPBtZhIUPr_Jg,192
|
|
9
|
-
folio_data_import-0.2.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|