folio-migration-tools 1.9.0rc6__py3-none-any.whl → 1.9.0rc7__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.
@@ -5,12 +5,12 @@ import i18n
5
5
  from folio_migration_tools import StrCoercible
6
6
 
7
7
 
8
- class TransfomationError(Exception):
8
+ class TransformationError(Exception):
9
9
  pass
10
10
 
11
11
 
12
- class TransformationFieldMappingError(TransfomationError):
13
- """Raised when the a field mapping fails, but the error is not critical.
12
+ class TransformationFieldMappingError(TransformationError):
13
+ """Raised when the field mapping fails, but the error is not critical.
14
14
  The issue should be logged for the library to act upon it"""
15
15
 
16
16
  def __init__(self, index_or_id="", message="", data_value: Union[str, StrCoercible]=""):
@@ -35,8 +35,8 @@ class TransformationFieldMappingError(TransfomationError):
35
35
  )
36
36
 
37
37
 
38
- class TransformationRecordFailedError(TransfomationError):
39
- """Raised when the a field mapping fails, Error is critical and means tranformation fails"""
38
+ class TransformationRecordFailedError(TransformationError):
39
+ """Raised when the field mapping fails, Error is critical and means transformation fails"""
40
40
 
41
41
  def __init__(self, index_or_id, message="", data_value=""):
42
42
  self.index_or_id = index_or_id
@@ -61,8 +61,8 @@ class TransformationRecordFailedError(TransfomationError):
61
61
  )
62
62
 
63
63
 
64
- class TransformationProcessError(TransfomationError):
65
- """Raised when the transformation fails due to incorrect configuraiton,
64
+ class TransformationProcessError(TransformationError):
65
+ """Raised when the transformation fails due to incorrect configuration,
66
66
  mapping or reference data. This error should take the process to a halt."""
67
67
 
68
68
  def __init__(
@@ -75,9 +75,7 @@ class ItemMapper(MappingFileMapperBase):
75
75
  self.folio_client,
76
76
  "/locations",
77
77
  "locations",
78
- self.validate_location_map(
79
- temporary_location_mapping, self.folio_client.locations
80
- ),
78
+ temporary_location_mapping,
81
79
  "code",
82
80
  "TemporaryLocationMapping",
83
81
  )
@@ -118,7 +116,7 @@ class ItemMapper(MappingFileMapperBase):
118
116
  self.folio_client,
119
117
  "/locations",
120
118
  "locations",
121
- self.validate_location_map(location_map, self.folio_client.locations),
119
+ location_map,
122
120
  "code",
123
121
  "LocationMapping",
124
122
  )
@@ -755,12 +755,8 @@ class MappingFileMapperBase(MapperBase):
755
755
  for k in data
756
756
  if k["folio_field"] == folio_prop_name
757
757
  and any(
758
- [
759
- is_set_or_bool_or_numeric(k.get("value", "")),
760
- is_set_or_bool_or_numeric(k.get("legacy_field", "")),
761
- is_set_or_bool_or_numeric(k.get("fallback_legacy_field", "")),
762
- is_set_or_bool_or_numeric(k.get("fallback_value", "")),
763
- ]
758
+ is_set_or_bool_or_numeric(k.get(key, ""))
759
+ for key in ("value", "legacy_field", "fallback_legacy_field", "fallback_value")
764
760
  )
765
761
  )
766
762
 
@@ -972,4 +968,4 @@ def in_deep(dictionary, keys):
972
968
 
973
969
 
974
970
  def is_set_or_bool_or_numeric(any_value):
975
- return any(isinstance(any_value, t) for t in [int, bool, float, complex]) or any_value.strip()
971
+ return (isinstance(any_value, str) and (any_value.strip() not in empty_vals)) or isinstance(any_value, (int, float, complex))
@@ -818,7 +818,7 @@ class Conditions:
818
818
  """
819
819
  This method handles the mapping of electronic access relationship IDs.
820
820
  If the record type being mapped is FOLIO holdings, it provides an (optional) alternative
821
- mapping baseed on a provided name parameter, bypassing the FOLIO MARC-to-Holdings mapping
821
+ mapping based on a provided name parameter, bypassing the FOLIO MARC-to-Holdings mapping
822
822
  engine behavior. This requires use of a supplemental mapping rules file in the
823
823
  HoldingsMarcTransformer task definition containing the name parameter.
824
824
  """
@@ -61,7 +61,10 @@ class RulesMapperHoldings(RulesMapperBase):
61
61
  self.boundwith_relationship_map = self.setup_boundwith_relationship_map(
62
62
  boundwith_relationship_map
63
63
  )
64
- self.location_map = location_map
64
+ self.location_map = self.validate_location_map(
65
+ location_map,
66
+ self.folio_client.locations,
67
+ )
65
68
  self.holdings_id_map: dict = {}
66
69
  self.ref_data_dicts: dict = {}
67
70
  self.fallback_holdings_type_id = self.task_configuration.fallback_holdings_type_id
@@ -3,9 +3,10 @@ from datetime import datetime
3
3
  from zoneinfo import ZoneInfo
4
4
 
5
5
  from dateutil import tz
6
- from dateutil.parser import parse
6
+ from dateutil.parser import parse, ParserError
7
7
 
8
8
  from folio_migration_tools.migration_report import MigrationReport
9
+ from folio_migration_tools.custom_exceptions import TransformationProcessError
9
10
 
10
11
  utc = ZoneInfo("UTC")
11
12
 
@@ -42,46 +43,47 @@ class LegacyLoan(object):
42
43
 
43
44
  self.tenant_timezone = tenant_timezone
44
45
  self.errors = []
46
+ self.row = row
45
47
  for prop in correct_headers:
46
48
  if prop not in legacy_loan_dict and prop not in optional_headers:
47
- self.errors.append(("Missing properties in legacy data", prop))
49
+ self.errors.append((f"Missing properties in legacy data {row=}", prop))
48
50
  if (
49
51
  prop != "next_item_status"
50
52
  and not legacy_loan_dict.get(prop, "").strip()
51
53
  and prop not in optional_headers
52
54
  ):
53
- self.errors.append(("Empty properties in legacy data", prop))
55
+ self.errors.append((f"Empty properties in legacy data {row=}", prop))
54
56
  try:
55
57
  temp_date_due: datetime = parse(legacy_loan_dict["due_date"])
56
58
  if temp_date_due.tzinfo != tz.UTC:
57
59
  temp_date_due = temp_date_due.replace(tzinfo=self.tenant_timezone)
58
60
  self.report(
59
- f"Provided due_date is not UTC, "
60
- f"setting tzinfo to tenant timezone ({self.tenant_timezone})"
61
+ f"Provided due_date is not UTC in {row=}, "
62
+ f"setting tz-info to tenant timezone ({self.tenant_timezone})"
61
63
  )
62
64
  if temp_date_due.hour == 0 and temp_date_due.minute == 0:
63
65
  temp_date_due = temp_date_due.replace(hour=23, minute=59)
64
66
  self.report(
65
- "Hour and minute not specified for due date. "
67
+ f"Hour and minute not specified for due date in {row=}. "
66
68
  "Assuming end of local calendar day (23:59)..."
67
69
  )
68
- except Exception as ee:
70
+ except (ParserError, OverflowError) as ee:
69
71
  logging.error(ee)
70
- self.errors.append(("Parse date failure. Setting UTC NOW", "due_date"))
72
+ self.errors.append((f"Parse date failure in {row=}. Setting UTC NOW", "due_date"))
71
73
  temp_date_due = datetime.now(ZoneInfo("UTC"))
72
74
  try:
73
75
  temp_date_out: datetime = parse(legacy_loan_dict["out_date"])
74
76
  if temp_date_out.tzinfo != tz.UTC:
75
77
  temp_date_out = temp_date_out.replace(tzinfo=self.tenant_timezone)
76
78
  self.report(
77
- f"Provided out_date is not UTC, "
78
- f"setting tzinfo to tenant timezone ({self.tenant_timezone})"
79
+ f"Provided out_date is not UTC in {row=}, "
80
+ f"setting tz-info to tenant timezone ({self.tenant_timezone})"
79
81
  )
80
- except Exception:
82
+ except (ParserError, OverflowError):
81
83
  temp_date_out = datetime.now(
82
84
  ZoneInfo("UTC")
83
85
  ) # TODO: Consider moving this assignment block above the temp_date_due
84
- self.errors.append(("Parse date failure. Setting UTC NOW", "out_date"))
86
+ self.errors.append((f"Parse date failure in {row=}. Setting UTC NOW", "out_date"))
85
87
 
86
88
  # good to go, set properties
87
89
  self.item_barcode: str = legacy_loan_dict["item_barcode"].strip()
@@ -94,7 +96,7 @@ class LegacyLoan(object):
94
96
  self.renewal_count = self.set_renewal_count(legacy_loan_dict)
95
97
  self.next_item_status = legacy_loan_dict.get("next_item_status", "").strip()
96
98
  if self.next_item_status not in legal_statuses:
97
- self.errors.append(("Not an allowed status", self.next_item_status))
99
+ self.errors.append((f"Not an allowed status {row=}", self.next_item_status))
98
100
  self.service_point_id = (
99
101
  legacy_loan_dict["service_point_id"]
100
102
  if legacy_loan_dict.get("service_point_id", "")
@@ -107,23 +109,19 @@ class LegacyLoan(object):
107
109
  try:
108
110
  return int(renewal_count)
109
111
  except ValueError:
110
- self.report(
111
- f"Unresolvable {renewal_count=} was replaced with 0.")
112
+ self.report(f"Unresolvable {renewal_count=} was replaced with 0.")
112
113
  else:
113
114
  self.report(f"Missing renewal count was replaced with 0.")
114
115
  return 0
115
116
 
116
117
  def correct_for_1_day_loans(self):
117
- try:
118
- if self.due_date.date() <= self.out_date.date():
119
- if self.due_date.hour == 0:
120
- self.due_date = self.due_date.replace(hour=23, minute=59)
121
- if self.out_date.hour == 0:
122
- self.out_date = self.out_date.replace(hour=0, minute=1)
123
- if self.due_date <= self.out_date:
124
- raise ValueError("Due date is before out date")
125
- except Exception:
126
- self.errors.append(("Time alignment issues", "both dates"))
118
+ if self.due_date.date() <= self.out_date.date():
119
+ if self.due_date.hour == 0:
120
+ self.due_date = self.due_date.replace(hour=23, minute=59)
121
+ if self.out_date.hour == 0:
122
+ self.out_date = self.out_date.replace(hour=0, minute=1)
123
+ if self.due_date <= self.out_date:
124
+ raise TransformationProcessError(self.row, "Due date is before out date")
127
125
 
128
126
  def to_dict(self):
129
127
  return {
@@ -140,8 +138,8 @@ class LegacyLoan(object):
140
138
  if self.tenant_timezone != ZoneInfo("UTC"):
141
139
  self.due_date = self.due_date.astimezone(ZoneInfo("UTC"))
142
140
  self.out_date = self.out_date.astimezone(ZoneInfo("UTC"))
143
- except Exception:
144
- self.errors.append(("UTC correction issues", "both dates"))
141
+ except TypeError:
142
+ self.errors.append((f"UTC correction issues {self.row}", "both dates"))
145
143
 
146
144
  def report(self, what_to_report: str):
147
145
  self.migration_report.add("Details", what_to_report)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: folio_migration_tools
3
- Version: 1.9.0rc6
3
+ Version: 1.9.0rc7
4
4
  Summary: A tool allowing you to migrate data from legacy ILS:s (Library systems) into FOLIO LSP
5
5
  License: MIT
6
6
  Keywords: FOLIO,ILS,LSP,Library Systems,MARC21,Library data
@@ -4,7 +4,7 @@ folio_migration_tools/circulation_helper.py,sha256=2kAkLM6caPiep0ZtBkMICbRDh53Kd
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
6
6
  folio_migration_tools/custom_dict.py,sha256=-FUnhKp90Dg8EHlY6twx-PYQxBUWEO7FgxL2b7pf-xk,678
7
- folio_migration_tools/custom_exceptions.py,sha256=fRdMt5AwH_XddZ-bts5ByslN5gYthkLdh7o22JroQeE,2686
7
+ folio_migration_tools/custom_exceptions.py,sha256=1zgOKy3NBUVGG6i9YxK6w2Hntlea8MHmm7mdnjBtzvQ,2687
8
8
  folio_migration_tools/extradata_writer.py,sha256=fuchNcMc6BYb9IyfAcvXg7X4J2TfX6YiROfT2hr0JMw,1678
9
9
  folio_migration_tools/folder_structure.py,sha256=yyVvbkM9PbczSHNI8vK0Ru7i0x4nbYGzrRriXrnIh38,6715
10
10
  folio_migration_tools/helper.py,sha256=KkOkNAGO_fuYqxdLrsbLzCJLQHUrFZG1NzD4RmpQ-KM,2804
@@ -15,16 +15,16 @@ folio_migration_tools/mapper_base.py,sha256=ftYQJ6UDsP96EvCr5t3yMJemsmSNXsSH5zCh
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=nJS-xx1LszvbYfw0qdTUHX9xXHlxS7wP5mYmixFMh8A,7221
18
- folio_migration_tools/mapping_file_transformation/item_mapper.py,sha256=CkpxQhwn-ZUpZu4nvybAyrQhdRVX2-wtCgT35-8JLh0,11005
18
+ folio_migration_tools/mapping_file_transformation/item_mapper.py,sha256=KiE-y6ZcKAV2XMqrgax3mx3KHB_oRxBfCBSanIBs95E,10853
19
19
  folio_migration_tools/mapping_file_transformation/manual_fee_fines_mapper.py,sha256=nCkqbxaDHKxMuqQHh_afxQp48YrVD-SeCZ0L1iGvnkk,13402
20
- folio_migration_tools/mapping_file_transformation/mapping_file_mapper_base.py,sha256=RacwSOP6r6i28EOywaepq5K5FimD8Ld5MlBo89FYO7c,37963
20
+ folio_migration_tools/mapping_file_transformation/mapping_file_mapper_base.py,sha256=vu-5dw20NbxpDTDNq2zIgbto8KkWMf6ImXj2U0XbHPg,37812
21
21
  folio_migration_tools/mapping_file_transformation/notes_mapper.py,sha256=auLQZqa4rSJo_MIV4Lc5-LG8RcBpp2bnKH243qNYq_0,3470
22
22
  folio_migration_tools/mapping_file_transformation/order_mapper.py,sha256=k-kIuf2ceXrPWe3oVnfhuQlE7eglcx6PDLVJtddkeiM,17680
23
23
  folio_migration_tools/mapping_file_transformation/organization_mapper.py,sha256=0zjw0-C-qTYH9GC6FDBElucWCZWdoOiTHOY7q9_4NQg,14571
24
24
  folio_migration_tools/mapping_file_transformation/ref_data_mapping.py,sha256=qFsn_LwKZeKFdOudfEQnNA3DEHOdNQVKzTPdZAlDPX0,8864
25
25
  folio_migration_tools/mapping_file_transformation/user_mapper.py,sha256=oWuIPRQL0anF_qTVFibHtc1oOaqyKCBH4O1hX5rQAZQ,7806
26
26
  folio_migration_tools/marc_rules_transformation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
- folio_migration_tools/marc_rules_transformation/conditions.py,sha256=am_VQ5P8vx-AFbVNBVeu0WkIbIh4cQJBLROxNTj_yUE,39143
27
+ folio_migration_tools/marc_rules_transformation/conditions.py,sha256=ttTZISieqveu3YpvpnawHh3In1_DNQMTziI5yasfmWU,39142
28
28
  folio_migration_tools/marc_rules_transformation/holdings_statementsparser.py,sha256=lTb5QWEAgwyFHy5vdSK6oDl1Q5v2GnzuV04xWV3p4rc,12401
29
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
@@ -33,7 +33,7 @@ folio_migration_tools/marc_rules_transformation/marc_reader_wrapper.py,sha256=9A
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=-vJDMNZe-7JbARgybVj6lLtZM79PgWU9V_k23330uLM,41195
35
35
  folio_migration_tools/marc_rules_transformation/rules_mapper_bibs.py,sha256=ckVeysbpW9s19pmHvogdRFOCouzz17Y6oKJD0_QfQAk,28924
36
- folio_migration_tools/marc_rules_transformation/rules_mapper_holdings.py,sha256=gPJaWcvt-CKIJxrEzheRzohnc3mFEnsznuZIXLPhyZM,18954
36
+ folio_migration_tools/marc_rules_transformation/rules_mapper_holdings.py,sha256=p_WIsn-6VphLNVCeDyvTEv-tdYFU5QuV4GhnM4gvwt8,19046
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
@@ -55,13 +55,13 @@ folio_migration_tools/task_configuration.py,sha256=C5-OQtZLH7b4lVeyj5v8OXsqKNN4t
55
55
  folio_migration_tools/test_infrastructure/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
56
56
  folio_migration_tools/test_infrastructure/mocked_classes.py,sha256=rNes6UlRqIWGwPurfiQK97IvgB5OPwnZTbv1T28jHzk,9150
57
57
  folio_migration_tools/transaction_migration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
- folio_migration_tools/transaction_migration/legacy_loan.py,sha256=M48ZU45yEL1h93Jbld5qKwF1DEKt6sGYPc-t_JgLYX0,5896
58
+ folio_migration_tools/transaction_migration/legacy_loan.py,sha256=3PDyC1wbJzF0CcNWelvZ0tC8hjl3p5hbLVJHrz78ORM,6006
59
59
  folio_migration_tools/transaction_migration/legacy_request.py,sha256=1ulyFzPQw_InOjyPzkWpGnNptgXdQ18nmri0J8Nlpkc,6124
60
60
  folio_migration_tools/transaction_migration/legacy_reserve.py,sha256=d0qbh2fWpwlVSYRL6wZyZG20__NAYNxh7sPSsB-LAes,1804
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.0rc6.dist-info/LICENSE,sha256=PhIEkitVi3ejgq56tt6sWoJIG_zmv82cjjd_aYPPGdI,1072
64
- folio_migration_tools-1.9.0rc6.dist-info/METADATA,sha256=EL9MObYfZSyJ1otUDkUQEL0T2P8yxU5E77qZ4HhKFrk,7415
65
- folio_migration_tools-1.9.0rc6.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
66
- folio_migration_tools-1.9.0rc6.dist-info/entry_points.txt,sha256=Hbe-HjqMcU8FwVshVIkeWyZd9XwgT1CCMNf06EpHQu8,77
67
- folio_migration_tools-1.9.0rc6.dist-info/RECORD,,
63
+ folio_migration_tools-1.9.0rc7.dist-info/LICENSE,sha256=PhIEkitVi3ejgq56tt6sWoJIG_zmv82cjjd_aYPPGdI,1072
64
+ folio_migration_tools-1.9.0rc7.dist-info/METADATA,sha256=ZBN-JMKfGXNzGGKEgecmOsbOS49pl09CF7KtyfVBhKs,7415
65
+ folio_migration_tools-1.9.0rc7.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
66
+ folio_migration_tools-1.9.0rc7.dist-info/entry_points.txt,sha256=Hbe-HjqMcU8FwVshVIkeWyZd9XwgT1CCMNf06EpHQu8,77
67
+ folio_migration_tools-1.9.0rc7.dist-info/RECORD,,