folio-migration-tools 1.9.0a5__py3-none-any.whl → 1.9.0a7__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.
@@ -3,6 +3,7 @@ import logging
3
3
  import sys
4
4
  from os import environ
5
5
  from pathlib import Path
6
+ from sqlite3 import connect
6
7
 
7
8
  import httpx
8
9
  import humps
@@ -124,7 +125,8 @@ def main():
124
125
  except TransformationProcessError as tpe:
125
126
  logging.critical(tpe.message)
126
127
  print(f"\n{tpe.message}: {tpe.data_value}")
127
- sys.exit("Transformation Failure")
128
+ print("Task failure. Halting.")
129
+ sys.exit(1)
128
130
  logging.info("Work done. Shutting down")
129
131
  sys.exit(0)
130
132
  except json.decoder.JSONDecodeError as json_error:
@@ -148,10 +150,17 @@ def main():
148
150
  print("Halting")
149
151
  sys.exit("JSON Not Matching Spec")
150
152
  except httpx.HTTPError as connection_error:
151
- print(
152
- f"\nConnection Error when connecting to {connection_error.request.url}. "
153
- "Are you connectet to the Internet/VPN? Do you need to update DNS settings?"
154
- )
153
+ if hasattr(connection_error, "response"):
154
+ print(
155
+ f"\nHTTP Error when connecting to {connection_error.request.url}. "
156
+ f"Status code: {connection_error.response.status_code}. "
157
+ f"\nResponse: {connection_error.response.text}"
158
+ )
159
+ else:
160
+ print(
161
+ f"\nConnection Error when connecting to {connection_error.request.url}. "
162
+ "Are you connected to the Internet/VPN? Do you need to update DNS settings?"
163
+ )
155
164
  sys.exit("HTTP Not Connecting")
156
165
  except FileNotFoundError as fnf_error:
157
166
  print(f"\n{fnf_error.strerror}: {fnf_error.filename}")
@@ -62,14 +62,9 @@ class IlsFlavour(str, Enum):
62
62
 
63
63
 
64
64
  class FolioRelease(str, Enum):
65
- lotus = "lotus"
66
- morning_glory = "morning-glory"
67
- nolana = "nolana"
68
- orchid = "orchid"
69
- poppy = "poppy"
70
- quesnelia = "quesnelia"
71
65
  ramsons = "ramsons"
72
66
  sunflower = "sunflower"
67
+ trillium = "trillium"
73
68
 
74
69
 
75
70
  class LibraryConfiguration(BaseModel):
@@ -444,7 +444,7 @@ class MapperBase:
444
444
  except IndexError:
445
445
  if call_numbers:
446
446
  bound_with_holding["callNumber"] = call_numbers[0]
447
- except SyntaxError:
447
+ except (SyntaxError, ValueError):
448
448
  bound_with_holding["callNumber"] = call_number
449
449
  else:
450
450
  bound_with_holding["callNumber"] = call_number
@@ -6,9 +6,7 @@ import httpx
6
6
  import i18n
7
7
  from folio_uuid import FOLIONamespaces
8
8
  from folioclient import FolioClient
9
- from pymarc import Field
10
- from pymarc import Record
11
- from pymarc import Subfield
9
+ from pymarc import Field, Record, Subfield
12
10
 
13
11
  from folio_migration_tools.custom_exceptions import TransformationProcessError
14
12
  from folio_migration_tools.helper import Helper
@@ -220,7 +218,7 @@ class HRIDHandler:
220
218
  ),
221
219
  )
222
220
  self.handle_035_generation(
223
- marc_record, legacy_ids, self.migration_report, self.deactivate035_from001
221
+ marc_record, legacy_ids, self.migration_report, self.deactivate035_from001, False
224
222
  )
225
223
  Helper.log_data_issue(
226
224
  legacy_ids,
@@ -24,6 +24,7 @@ from folio_migration_tools.custom_exceptions import (
24
24
  from folio_migration_tools.helper import Helper
25
25
  from folio_migration_tools.library_configuration import (
26
26
  FileDefinition,
27
+ HridHandling,
27
28
  IlsFlavour,
28
29
  LibraryConfiguration,
29
30
  )
@@ -62,6 +63,8 @@ class BibsRulesMapper(RulesMapperBase):
62
63
  [self.task_configuration.create_source_records, (not getattr(self.task_configuration, "data_import_marc", False))]
63
64
  )
64
65
  self.data_import_marc = self.task_configuration.data_import_marc
66
+ if self.data_import_marc:
67
+ self.hrid_handler.deactivate035_from001 = True
65
68
  self.start = time.time()
66
69
 
67
70
  def perform_initial_preparation(self, marc_record: pymarc.Record, legacy_ids):
@@ -73,7 +76,7 @@ class BibsRulesMapper(RulesMapperBase):
73
76
  str(legacy_ids[-1]),
74
77
  )
75
78
  )
76
- if self.create_source_records:
79
+ if self.create_source_records or self.hrid_handler.handling == HridHandling.preserve001:
77
80
  self.hrid_handler.handle_hrid(
78
81
  FOLIONamespaces.instances,
79
82
  folio_instance,
@@ -5,6 +5,7 @@ import sys
5
5
  import time
6
6
  import traceback
7
7
  from datetime import datetime
8
+ from math import log
8
9
  from typing import Annotated, List
9
10
  from uuid import uuid4
10
11
 
@@ -136,12 +137,12 @@ class BatchPoster(MigrationTaskBase):
136
137
  def do_work(self):
137
138
  with self.folio_client.get_folio_http_client() as httpx_client:
138
139
  self.http_client = httpx_client
139
- try:
140
- batch = []
141
- if self.task_configuration.object_type == "SRS":
142
- self.create_snapshot()
143
- with open(self.folder_structure.failed_recs_path, "w") as failed_recs_file:
144
- for file_def in self.task_configuration.files:
140
+ with open(self.folder_structure.failed_recs_path, "w", encoding='utf-8') as failed_recs_file:
141
+ try:
142
+ batch = []
143
+ if self.task_configuration.object_type == "SRS":
144
+ self.create_snapshot()
145
+ for idx, file_def in enumerate(self.task_configuration.files):
145
146
  path = self.folder_structure.results_folder / file_def.file_name
146
147
  with open(path) as rows:
147
148
  logging.info("Running %s", path)
@@ -172,9 +173,8 @@ class BatchPoster(MigrationTaskBase):
172
173
  self.processed,
173
174
  failed_recs_file,
174
175
  )
175
- logging.critical("Halting %s", tpe)
176
- print(f"\n\t{tpe.message}")
177
- sys.exit(1)
176
+ batch = []
177
+ raise
178
178
  except TransformationRecordFailedError as exception:
179
179
  self.handle_generic_exception(
180
180
  exception,
@@ -184,7 +184,21 @@ class BatchPoster(MigrationTaskBase):
184
184
  failed_recs_file,
185
185
  )
186
186
  batch = []
187
-
187
+ except (FileNotFoundError, PermissionError) as ose:
188
+ logging.error("Error reading file: %s", ose)
189
+
190
+ except Exception as ee:
191
+ if "idx" in locals() and self.task_configuration.files[idx:]:
192
+ for file in self.task_configuration.files[idx:]:
193
+ try:
194
+ with open(file, "r") as failed_file:
195
+ failed_file.seek(self.processed)
196
+ failed_recs_file.write(failed_file.read())
197
+ self.processed = 0
198
+ except (FileNotFoundError, PermissionError) as ose:
199
+ logging.error("Error reading file: %s", ose)
200
+ raise ee
201
+ finally:
188
202
  if self.task_configuration.object_type != "Extradata" and any(batch):
189
203
  try:
190
204
  self.post_batch(batch, failed_recs_file, self.processed)
@@ -193,10 +207,8 @@ class BatchPoster(MigrationTaskBase):
193
207
  exception, last_row, batch, self.processed, failed_recs_file
194
208
  )
195
209
  logging.info("Done posting %s records. ", (self.processed))
196
- except Exception as ee:
197
- if self.task_configuration.object_type == "SRS":
198
- self.commit_snapshot()
199
- raise ee
210
+ if self.task_configuration.object_type == "SRS":
211
+ self.commit_snapshot()
200
212
 
201
213
  def post_record_batch(self, batch, failed_recs_file, row):
202
214
  json_rec = json.loads(row.split("\t")[-1])
@@ -339,6 +351,10 @@ class BatchPoster(MigrationTaskBase):
339
351
 
340
352
  def post_batch(self, batch, failed_recs_file, num_records, recursion_depth=0):
341
353
  response = self.do_post(batch)
354
+ if response.status_code == 401:
355
+ logging.error("Authorization failed (%s). Fetching new auth token...", response.text)
356
+ self.folio_client.login()
357
+ response = self.do_post(batch)
342
358
  if response.status_code == 201:
343
359
  logging.info(
344
360
  (
@@ -8,11 +8,11 @@ import traceback
8
8
  from datetime import datetime, timedelta
9
9
  from typing import Optional
10
10
  from urllib.error import HTTPError
11
+ from zoneinfo import ZoneInfo
11
12
 
12
13
  import i18n
13
14
  from dateutil import parser as du_parser
14
15
  from folio_uuid.folio_namespaces import FOLIONamespaces
15
- from zoneinfo import ZoneInfo
16
16
 
17
17
  from folio_migration_tools.circulation_helper import CirculationHelper
18
18
  from folio_migration_tools.helper import Helper
@@ -131,34 +131,13 @@ class LoansMigrator(MigrationTaskBase):
131
131
  logging.info("Init completed")
132
132
 
133
133
  def check_smtp_config(self):
134
- if self.library_configuration.folio_release.lower() == FolioRelease.morning_glory:
135
- logging.warn("DEPRECATED: Morning Glory support will be removed in a future release!")
136
- okapi_config_base_path = "/configurations/entries"
137
- okapi_config_query = "(module=={}%20and%20configName=={}%20and%20code=={})"
138
- okapi_config_limit = 1000
139
- okapi_config_module = "SMTP_SERVER"
140
- okapi_config_name = "smtp"
141
- okapi_config_code = "EMAIL_SMTP_HOST_DISABLED"
142
- smtp_config_path = (
143
- okapi_config_base_path
144
- + "?"
145
- + str(okapi_config_limit)
146
- + "&query="
147
- + okapi_config_query.format(
148
- okapi_config_module, okapi_config_name, okapi_config_code
149
- )
150
- )
151
- smtp_config_disabled = self.folio_client.folio_get_single_object(smtp_config_path)[
152
- "configs"
153
- ]
154
- else:
155
- try:
156
- smtp_config = self.folio_client.folio_get_single_object("/smtp-configuration")[
157
- "smtpConfigurations"
158
- ][0]
159
- smtp_config_disabled = "disabled" in smtp_config["host"].lower()
160
- except IndexError:
161
- smtp_config_disabled = True
134
+ try:
135
+ smtp_config = self.folio_client.folio_get_single_object("/smtp-configuration")[
136
+ "smtpConfigurations"
137
+ ][0]
138
+ smtp_config_disabled = "disabled" in smtp_config["host"].lower()
139
+ except IndexError:
140
+ smtp_config_disabled = True
162
141
  print_smtp_warning()
163
142
  if not smtp_config_disabled:
164
143
  logging.warn("SMTP connection not disabled...")
@@ -1,8 +1,7 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: folio_migration_tools
3
- Version: 1.9.0a5
3
+ Version: 1.9.0a7
4
4
  Summary: A tool allowing you to migrate data from legacy ILS:s (Library systems) into FOLIO LSP
5
- Home-page: https://github.com/FOLIO-FSE/folio_migration_tools
6
5
  License: MIT
7
6
  Keywords: FOLIO,ILS,LSP,Library Systems,MARC21,Library data
8
7
  Author: Theodor Tolstoy
@@ -27,6 +26,7 @@ Requires-Dist: pyhumps (>=3.7.3,<4.0.0)
27
26
  Requires-Dist: pymarc (>=5.2.3,<6.0.0)
28
27
  Requires-Dist: python-dateutil (>=2.8.2,<3.0.0)
29
28
  Requires-Dist: python-i18n (>=0.3.9,<0.4.0)
29
+ Project-URL: Homepage, https://github.com/FOLIO-FSE/folio_migration_tools
30
30
  Project-URL: Repository, https://github.com/FOLIO-FSE/folio_migration_tools
31
31
  Description-Content-Type: text/markdown
32
32
 
@@ -1,5 +1,5 @@
1
1
  folio_migration_tools/__init__.py,sha256=yTPImroNb0CPuYmG4nm6aAcu5gpFJ7o1uM2dJS-47ec,93
2
- folio_migration_tools/__main__.py,sha256=ceAx_91SQS-Ab2g7umZpQtpMKWEHy3ivnWK4I3x2tuU,6926
2
+ folio_migration_tools/__main__.py,sha256=etBycP4P9KkbpLcI4sWqwHaVyP8_OQeg-uJOESt5adY,7310
3
3
  folio_migration_tools/circulation_helper.py,sha256=2kAkLM6caPiep0ZtBkMICbRDh53KdfdH21oEX1eMRDI,14193
4
4
  folio_migration_tools/colors.py,sha256=GP0wdI_GZ2WD5SjrbPN-S3u8vvN_u6rGQIBBcWv_0ZM,227
5
5
  folio_migration_tools/config_file_load.py,sha256=zHHa6NDkN6EJiQE4DgjrFQPVKsd70POsfbGkB8308jg,2822
@@ -10,8 +10,8 @@ folio_migration_tools/folder_structure.py,sha256=yyVvbkM9PbczSHNI8vK0Ru7i0x4nbYG
10
10
  folio_migration_tools/helper.py,sha256=KkOkNAGO_fuYqxdLrsbLzCJLQHUrFZG1NzD4RmpQ-KM,2804
11
11
  folio_migration_tools/holdings_helper.py,sha256=yJpz6aJrKRBiJ1MtT5bs2vXAc88uJuGh2_KDuCySOKc,7559
12
12
  folio_migration_tools/i18n_config.py,sha256=3AH_2b9zTsxE4XTe4isM_zYtPJSlK0ix6eBmV7kAYUM,228
13
- folio_migration_tools/library_configuration.py,sha256=60hgGtyvHhRUKXHvqz41-2V5EtUaySMV20JIKk279N0,3636
14
- folio_migration_tools/mapper_base.py,sha256=dmwsgeolBWjmzaztms5r1_7OG2PlTcp0D74TQCE6cgk,20303
13
+ folio_migration_tools/library_configuration.py,sha256=JE23VSUKDeCxzj_fOeQwkXF4fwd_y9s_hNy91YtEy7A,3514
14
+ folio_migration_tools/mapper_base.py,sha256=4rtZxmWp1qaAIG2awiJ3RElPM9IVA-n8-Qzzs0R31qc,20317
15
15
  folio_migration_tools/mapping_file_transformation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
16
  folio_migration_tools/mapping_file_transformation/courses_mapper.py,sha256=mJQxxeTn1bCYb2zwFYyXJ6EGZpJ0DsmwOY3nED7D_gQ,8091
17
17
  folio_migration_tools/mapping_file_transformation/holdings_mapper.py,sha256=GI9xnN74EsUMAshXKNJ6p9bGPdLtK0PCXqbB3nIxrC8,7207
@@ -26,24 +26,24 @@ folio_migration_tools/mapping_file_transformation/user_mapper.py,sha256=oWuIPRQL
26
26
  folio_migration_tools/marc_rules_transformation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
27
  folio_migration_tools/marc_rules_transformation/conditions.py,sha256=MnbMThiOZ6IenXirjMSNkqJ86RtFzbF4cp1T4YcfpyA,36349
28
28
  folio_migration_tools/marc_rules_transformation/holdings_statementsparser.py,sha256=lTb5QWEAgwyFHy5vdSK6oDl1Q5v2GnzuV04xWV3p4rc,12401
29
- folio_migration_tools/marc_rules_transformation/hrid_handler.py,sha256=lEvtJFWe5FoU372nHqTdnVF76qCKZjWgUJqIpiKUHY0,10026
29
+ folio_migration_tools/marc_rules_transformation/hrid_handler.py,sha256=Ihdv0_1q7gL_pZ3HWU3GcfV_jjpIfOLithWk9z_uH3Y,9997
30
30
  folio_migration_tools/marc_rules_transformation/loc_language_codes.xml,sha256=ztn2_yKws6qySL4oSsZh7sOjxq5bCC1PhAnXJdtgmJ0,382912
31
31
  folio_migration_tools/marc_rules_transformation/marc_file_processor.py,sha256=WkOQRDi7f4PZ5qmVH3Q-1_zdGEKYSvOGC6jixDwDp98,12349
32
32
  folio_migration_tools/marc_rules_transformation/marc_reader_wrapper.py,sha256=9ATjYMRAjy0QcXtmNZaHVhHLJ5hE1WUgOcF6KMJjbgo,5309
33
33
  folio_migration_tools/marc_rules_transformation/rules_mapper_authorities.py,sha256=GFw8j9UtCxnUdLShmPzJa1MpCK8a0NkQIN5C3jyouRs,9604
34
34
  folio_migration_tools/marc_rules_transformation/rules_mapper_base.py,sha256=WWSJgYvF9LeY8vh-BtQi7Fm3J-cowUJKWa0Wk2Ge7fc,39358
35
- folio_migration_tools/marc_rules_transformation/rules_mapper_bibs.py,sha256=5BHCEAoTmsJLzG9161Y49-DwA_-Jr44XUGX725-dNKE,28755
35
+ folio_migration_tools/marc_rules_transformation/rules_mapper_bibs.py,sha256=ckVeysbpW9s19pmHvogdRFOCouzz17Y6oKJD0_QfQAk,28924
36
36
  folio_migration_tools/marc_rules_transformation/rules_mapper_holdings.py,sha256=EBxf9Qh5Y0eDOmqYssWfaizxafiXSYDFzWmCuPtdG-8,18226
37
37
  folio_migration_tools/migration_report.py,sha256=BkRspM1hwTBnWeqsHamf7yVEofzLj560Q-9G--O00hw,4258
38
38
  folio_migration_tools/migration_tasks/__init__.py,sha256=ZkbY_yGyB84Ke8OMlYUzyyBj4cxxNrhMTwQlu_GbdDs,211
39
39
  folio_migration_tools/migration_tasks/authority_transformer.py,sha256=AoXg9s-GLO3yEEDCrQV7hc4YVXxwxsdxDdpj1zhHydE,4251
40
- folio_migration_tools/migration_tasks/batch_poster.py,sha256=iaWhvxdYli0kgsXLHGmFFBMeVXGpAv9eDg02BagyQ2U,29732
40
+ folio_migration_tools/migration_tasks/batch_poster.py,sha256=yQa72SA2sCDCcPgWrdP0jPixG2J6z5_Bhe9NzEDhzBA,30750
41
41
  folio_migration_tools/migration_tasks/bibs_transformer.py,sha256=XzlPo-0uuugJA4SM80xOlOj5nDK6OMDXFnAYg80hOBc,7791
42
42
  folio_migration_tools/migration_tasks/courses_migrator.py,sha256=dQerp97P3r7wmxK3Ovg6AriO6K_nTr6vA8RKj_XBEt4,5728
43
43
  folio_migration_tools/migration_tasks/holdings_csv_transformer.py,sha256=Hwr4YjgNIQpi2N-x8eq-mmRpXAyxYylQjpYubm03-ec,19668
44
44
  folio_migration_tools/migration_tasks/holdings_marc_transformer.py,sha256=yN0a8YVNx2P6NswxSylTca0MmNk1shze3PyKXv9JJIw,9547
45
45
  folio_migration_tools/migration_tasks/items_transformer.py,sha256=MOpnw1yvNKc6x4ZNjlB1nA2XiXMFdAso-8v2bET5tbE,15011
46
- folio_migration_tools/migration_tasks/loans_migrator.py,sha256=3OysTLy15lH0SRWoYgkFIlDXXMLn6OElmAk-YlG4z1M,34260
46
+ folio_migration_tools/migration_tasks/loans_migrator.py,sha256=PCjr_bC2ixhPPk_D54m7B871_bQObn5oP_Sow3ocg54,33238
47
47
  folio_migration_tools/migration_tasks/manual_fee_fines_transformer.py,sha256=CnmlTge7nChUJ10EiUkriQtJlVxWqglgfhjgneh2_yM,7247
48
48
  folio_migration_tools/migration_tasks/migration_task_base.py,sha256=5vVkBqUvCGuGPUyWlnKsLCFtgOQzq4jjBK_TBUHs7BE,13742
49
49
  folio_migration_tools/migration_tasks/orders_transformer.py,sha256=dGJlTZi5OHCsK8HS7bda8jcZcnWNc80DHgOOhuM1nhE,11474
@@ -60,7 +60,7 @@ folio_migration_tools/transaction_migration/legacy_request.py,sha256=1ulyFzPQw_I
60
60
  folio_migration_tools/transaction_migration/legacy_reserve.py,sha256=rZVtiMBYnt6aI0WxAwPN8fML_MKEUSUYsadCKPTeB4E,1839
61
61
  folio_migration_tools/transaction_migration/transaction_result.py,sha256=cTdCN0BnlI9_ZJB2Z3Fdkl9gpymIi-9mGZsRFlQcmDk,656
62
62
  folio_migration_tools/translations/en.json,sha256=HOVpkb_T-SN_x0NpDp8gyvV1hMLCui3SsG7ByyIv0OU,38669
63
- folio_migration_tools-1.9.0a5.dist-info/LICENSE,sha256=PhIEkitVi3ejgq56tt6sWoJIG_zmv82cjjd_aYPPGdI,1072
64
- folio_migration_tools-1.9.0a5.dist-info/METADATA,sha256=ohkzY98Ct_djuhK-ks9sFehWfuQCsEE42kOOQQeyDR4,7318
65
- folio_migration_tools-1.9.0a5.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
66
- folio_migration_tools-1.9.0a5.dist-info/RECORD,,
63
+ folio_migration_tools-1.9.0a7.dist-info/LICENSE,sha256=PhIEkitVi3ejgq56tt6sWoJIG_zmv82cjjd_aYPPGdI,1072
64
+ folio_migration_tools-1.9.0a7.dist-info/METADATA,sha256=vvVvLOBAoK-NY7na8o2wF7llFGWy74ExfyZBgbKpwYA,7330
65
+ folio_migration_tools-1.9.0a7.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
66
+ folio_migration_tools-1.9.0a7.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.9.1
2
+ Generator: poetry-core 2.0.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any