folio-migration-tools 1.2.1__py3-none-any.whl → 1.9.10__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.
Files changed (73) hide show
  1. folio_migration_tools/__init__.py +11 -0
  2. folio_migration_tools/__main__.py +169 -85
  3. folio_migration_tools/circulation_helper.py +96 -59
  4. folio_migration_tools/config_file_load.py +66 -0
  5. folio_migration_tools/custom_dict.py +6 -4
  6. folio_migration_tools/custom_exceptions.py +21 -19
  7. folio_migration_tools/extradata_writer.py +46 -0
  8. folio_migration_tools/folder_structure.py +63 -66
  9. folio_migration_tools/helper.py +29 -21
  10. folio_migration_tools/holdings_helper.py +57 -34
  11. folio_migration_tools/i18n_config.py +9 -0
  12. folio_migration_tools/library_configuration.py +173 -13
  13. folio_migration_tools/mapper_base.py +317 -106
  14. folio_migration_tools/mapping_file_transformation/courses_mapper.py +203 -0
  15. folio_migration_tools/mapping_file_transformation/holdings_mapper.py +83 -69
  16. folio_migration_tools/mapping_file_transformation/item_mapper.py +98 -94
  17. folio_migration_tools/mapping_file_transformation/manual_fee_fines_mapper.py +352 -0
  18. folio_migration_tools/mapping_file_transformation/mapping_file_mapper_base.py +702 -223
  19. folio_migration_tools/mapping_file_transformation/notes_mapper.py +90 -0
  20. folio_migration_tools/mapping_file_transformation/order_mapper.py +492 -0
  21. folio_migration_tools/mapping_file_transformation/organization_mapper.py +389 -0
  22. folio_migration_tools/mapping_file_transformation/ref_data_mapping.py +38 -27
  23. folio_migration_tools/mapping_file_transformation/user_mapper.py +149 -361
  24. folio_migration_tools/marc_rules_transformation/conditions.py +650 -246
  25. folio_migration_tools/marc_rules_transformation/holdings_statementsparser.py +292 -130
  26. folio_migration_tools/marc_rules_transformation/hrid_handler.py +244 -0
  27. folio_migration_tools/marc_rules_transformation/loc_language_codes.xml +20846 -0
  28. folio_migration_tools/marc_rules_transformation/marc_file_processor.py +300 -0
  29. folio_migration_tools/marc_rules_transformation/marc_reader_wrapper.py +136 -0
  30. folio_migration_tools/marc_rules_transformation/rules_mapper_authorities.py +241 -0
  31. folio_migration_tools/marc_rules_transformation/rules_mapper_base.py +681 -201
  32. folio_migration_tools/marc_rules_transformation/rules_mapper_bibs.py +395 -429
  33. folio_migration_tools/marc_rules_transformation/rules_mapper_holdings.py +531 -100
  34. folio_migration_tools/migration_report.py +85 -38
  35. folio_migration_tools/migration_tasks/__init__.py +1 -3
  36. folio_migration_tools/migration_tasks/authority_transformer.py +119 -0
  37. folio_migration_tools/migration_tasks/batch_poster.py +911 -198
  38. folio_migration_tools/migration_tasks/bibs_transformer.py +121 -116
  39. folio_migration_tools/migration_tasks/courses_migrator.py +192 -0
  40. folio_migration_tools/migration_tasks/holdings_csv_transformer.py +252 -247
  41. folio_migration_tools/migration_tasks/holdings_marc_transformer.py +321 -115
  42. folio_migration_tools/migration_tasks/items_transformer.py +264 -84
  43. folio_migration_tools/migration_tasks/loans_migrator.py +506 -195
  44. folio_migration_tools/migration_tasks/manual_fee_fines_transformer.py +187 -0
  45. folio_migration_tools/migration_tasks/migration_task_base.py +364 -74
  46. folio_migration_tools/migration_tasks/orders_transformer.py +373 -0
  47. folio_migration_tools/migration_tasks/organization_transformer.py +451 -0
  48. folio_migration_tools/migration_tasks/requests_migrator.py +130 -62
  49. folio_migration_tools/migration_tasks/reserves_migrator.py +253 -0
  50. folio_migration_tools/migration_tasks/user_transformer.py +180 -139
  51. folio_migration_tools/task_configuration.py +46 -0
  52. folio_migration_tools/test_infrastructure/__init__.py +0 -0
  53. folio_migration_tools/test_infrastructure/mocked_classes.py +406 -0
  54. folio_migration_tools/transaction_migration/legacy_loan.py +148 -34
  55. folio_migration_tools/transaction_migration/legacy_request.py +65 -25
  56. folio_migration_tools/transaction_migration/legacy_reserve.py +47 -0
  57. folio_migration_tools/transaction_migration/transaction_result.py +12 -1
  58. folio_migration_tools/translations/en.json +476 -0
  59. folio_migration_tools-1.9.10.dist-info/METADATA +169 -0
  60. folio_migration_tools-1.9.10.dist-info/RECORD +67 -0
  61. {folio_migration_tools-1.2.1.dist-info → folio_migration_tools-1.9.10.dist-info}/WHEEL +1 -2
  62. folio_migration_tools-1.9.10.dist-info/entry_points.txt +3 -0
  63. folio_migration_tools/generate_schemas.py +0 -46
  64. folio_migration_tools/mapping_file_transformation/mapping_file_mapping_base_impl.py +0 -44
  65. folio_migration_tools/mapping_file_transformation/user_mapper_base.py +0 -212
  66. folio_migration_tools/marc_rules_transformation/bibs_processor.py +0 -163
  67. folio_migration_tools/marc_rules_transformation/holdings_processor.py +0 -284
  68. folio_migration_tools/report_blurbs.py +0 -219
  69. folio_migration_tools/transaction_migration/legacy_fee_fine.py +0 -36
  70. folio_migration_tools-1.2.1.dist-info/METADATA +0 -134
  71. folio_migration_tools-1.2.1.dist-info/RECORD +0 -50
  72. folio_migration_tools-1.2.1.dist-info/top_level.txt +0 -1
  73. {folio_migration_tools-1.2.1.dist-info → folio_migration_tools-1.9.10.dist-info/licenses}/LICENSE +0 -0
@@ -1,48 +1,53 @@
1
1
  import calendar
2
+ import contextlib
2
3
  import logging
3
4
  import re
5
+ from typing import List
4
6
 
5
- from folio_migration_tools.custom_exceptions import TransformationFieldMappingError
7
+ import i18n
6
8
  from pymarc import Field, Record
7
9
 
10
+ from folio_migration_tools.custom_exceptions import TransformationFieldMappingError
8
11
 
9
- class HoldingsStatementsParser:
10
- @staticmethod
11
- def get_textual_statements(marc_record, field_textual, return_dict):
12
- for f in marc_record.get_fields(field_textual):
13
- return_dict["statements"].append(
14
- {"statement": (f["a"] or ""), "note": (f["z"] or ""), "staffNote": ""}
15
- )
16
- return_dict["migration_report"].append(
17
- ("Holdings statements", f"From {field_textual}")
18
- )
19
12
 
13
+ class HoldingsStatementsParser:
20
14
  @staticmethod
21
15
  def get_holdings_statements(
22
- marc_record: Record, pattern_tag, value_tag, field_textual, legacy_id: str
23
- ):
16
+ marc_record: Record,
17
+ pattern_tag: str,
18
+ value_tag: str,
19
+ field_textual: str,
20
+ legacy_ids: List[str],
21
+ dedupe_results: bool = True,
22
+ ) -> dict:
23
+ """_summary_
24
+
25
+ Args:
26
+ marc_record (Record): pymarc Record object
27
+ pattern_tag (str): MARC tag for the pattern field
28
+ value_tag (str): MARC tag for the value field
29
+ field_textual (str): MARC tag for the textual holdings field
30
+ legacy_ids (List[str]): List of legacy IDs associated with the record
31
+ dedupe_results (bool): Whether to deduplicate the results. Defaults to True.
32
+
33
+ Raises:
34
+ TransformationFieldMappingError: If there is an error in mapping the holdings statements.
35
+
36
+ Returns:
37
+ dict: A dictionary containing parsed holdings statements and related information.
38
+ """
39
+
24
40
  # Textual holdings statements
25
- return_dict = {"statements": [], "migration_report": [], "hlm_stmts": []}
41
+ return_dict: dict = {"statements": [], "migration_report": [], "hlm_stmts": []}
26
42
  HoldingsStatementsParser.get_textual_statements(
27
- marc_record,
28
- field_textual,
29
- return_dict,
43
+ marc_record, field_textual, return_dict, legacy_ids
30
44
  )
31
45
 
32
46
  value_fields = marc_record.get_fields(value_tag)
33
47
  for pattern_field in marc_record.get_fields(pattern_tag):
34
- if "8" not in pattern_field:
35
- raise TransformationFieldMappingError(
36
- legacy_id,
37
- f"{pattern_tag} subfield 8 not in field",
38
- pattern_field.format_field(),
39
- )
40
- linked_value_fields = [
41
- value_field
42
- for value_field in value_fields
43
- if "8" in value_field
44
- and value_field["8"].split(".")[0] == pattern_field["8"]
45
- ]
48
+ linked_value_fields = HoldingsStatementsParser.get_linked_value_fields(
49
+ pattern_tag, legacy_ids, value_fields, pattern_field
50
+ )
46
51
 
47
52
  if not any(linked_value_fields):
48
53
  return_dict["migration_report"].append(
@@ -53,130 +58,287 @@ class HoldingsStatementsParser:
53
58
  )
54
59
 
55
60
  else:
56
-
57
61
  for linked_value_field in linked_value_fields:
58
- parsed_dict = HoldingsStatementsParser.parse_linked_field(
59
- pattern_field, linked_value_field
60
- )
61
- if parsed_dict["hlm_stmt"]:
62
- return_dict["hlm_stmts"].append(parsed_dict["hlm_stmt"])
63
- if parsed_dict["statement"]:
64
- logging.info(
65
- f"HOLDINGS STATEMENT PATTERN\t{legacy_id}\t{pattern_field}"
66
- f"\t{linked_value_field}"
67
- f"\t{parsed_dict['statement']['statement']}"
68
- f"\t{parsed_dict['statement']['note']}"
69
- f"\t{parsed_dict['statement']['staffNote']}"
70
- )
71
- return_dict["migration_report"].append(
72
- (
73
- "Holdings statements",
74
- f"From {pattern_tag}",
75
- )
62
+ try:
63
+ parsed_dict = HoldingsStatementsParser.parse_linked_field(
64
+ pattern_field, linked_value_field
76
65
  )
77
- return_dict["statements"].append(parsed_dict["statement"])
66
+ except KeyError as e:
67
+ raise TransformationFieldMappingError(
68
+ legacy_ids,
69
+ i18n.t(
70
+ "subfield present in %{linked_value_tag} but not in %{pattern_field}",
71
+ pattern_field=pattern_field,
72
+ linked_value_tag=linked_value_field,
73
+ ),
74
+ pattern_field,
75
+ ) from e
76
+ HoldingsStatementsParser.prepare_return_dict(
77
+ pattern_tag, legacy_ids, return_dict, pattern_field, linked_value_field, parsed_dict
78
+ )
78
79
 
79
- return_dict["statements"] = dedupe_list_of_dict(return_dict["statements"])
80
+ if dedupe_results:
81
+ return_dict["statements"] = HoldingsStatementsParser.dedupe_list_of_dict(
82
+ return_dict["statements"]
83
+ )
80
84
  return return_dict
81
85
 
82
86
  @staticmethod
83
- def parse_linked_field(pattern_field: Field, linked_value_field: Field):
87
+ def prepare_return_dict(
88
+ pattern_tag, legacy_ids, return_dict, pattern_field, linked_value_field, parsed_dict
89
+ ):
90
+ if parsed_dict["hlm_stmt"]:
91
+ return_dict["hlm_stmts"].append(parsed_dict["hlm_stmt"])
92
+ if parsed_dict["statement"]:
93
+ logging.info(
94
+ f"HOLDINGS STATEMENT PATTERN\t{'-'.join(legacy_ids)}\t{pattern_field}"
95
+ f"\t{linked_value_field}"
96
+ f"\t{parsed_dict['statement']['statement']}"
97
+ f"\t{parsed_dict['statement']['note']}"
98
+ f"\t{parsed_dict['statement']['staffNote']}"
99
+ )
100
+ return_dict["migration_report"].append(
101
+ (
102
+ "Holdings statements",
103
+ f"From {pattern_tag}",
104
+ )
105
+ )
106
+ return_dict["statements"].append(parsed_dict["statement"])
107
+
108
+ @staticmethod
109
+ def get_linked_value_fields(pattern_tag, legacy_ids, value_fields, pattern_field):
110
+ if "8" not in pattern_field:
111
+ raise TransformationFieldMappingError(
112
+ legacy_ids,
113
+ i18n.t(
114
+ "%{tag} subfield %{subfield} not in field",
115
+ tag=pattern_tag,
116
+ subfield="8",
117
+ ),
118
+ pattern_field,
119
+ )
120
+ linked_value_fields = [
121
+ value_field
122
+ for value_field in value_fields
123
+ if "8" in value_field and value_field["8"].split(".")[0] == pattern_field["8"]
124
+ ]
125
+ return linked_value_fields
126
+
127
+ @staticmethod
128
+ def parse_linked_field(pattern_field: Field, linked_value_fields: Field):
129
+ break_ind = HoldingsStatementsParser.get_break_indicator(linked_value_fields)
130
+ _from, _to, is_span = HoldingsStatementsParser.get_from_to(
131
+ pattern_field, linked_value_fields
132
+ )
133
+ cron_from, cron_to, hlm_stmt, is_cron_span = HoldingsStatementsParser.get_cron_from_to(
134
+ pattern_field, linked_value_fields
135
+ )
84
136
  return_dict = {
85
- "hlm_stmt": "",
86
- "statement": {
87
- "statement": "",
88
- "note": "",
89
- "staffNote": "",
90
- },
137
+ "statement": {"statement": "", "note": "", "staffNote": ""},
138
+ "hlm_stmt": hlm_stmt,
91
139
  }
92
- _from, _to = get_from_to(pattern_field, linked_value_field)
93
- cron_from, cron_to, hlm_stmt = get_cron_from_to(
94
- pattern_field, linked_value_field
95
- )
96
- return_dict["hlm_stmt"] = hlm_stmt
97
- if cron_from:
140
+
141
+ _from, _to = HoldingsStatementsParser.format_from_to(_from, _to, cron_from, cron_to)
142
+ span = "-" if is_span or is_cron_span else ""
143
+ stmt = f"{_from}{span}{_to}{break_ind}" if _from else ""
144
+ stmt = stmt.strip()
145
+ if "z" in linked_value_fields:
146
+ return_dict["statement"]["note"] = linked_value_fields["z"]
147
+ if "x" in linked_value_fields:
148
+ return_dict["statement"]["staffNote"] = linked_value_fields["x"]
149
+ stmt = re.sub(" +", " ", stmt)
150
+ return_dict["statement"]["statement"] = stmt
151
+ return return_dict
152
+
153
+ @staticmethod
154
+ def format_from_to(_from, _to, cron_from, cron_to):
155
+ if _from and cron_from:
98
156
  _from = f"{_from} ({cron_from})"
157
+ if not _from and cron_from:
158
+ _from = cron_from
99
159
  if _to and cron_to:
100
160
  _to = f"{_to} ({cron_to})"
101
161
  if _to and cron_from and not cron_to:
102
162
  _to = f"{_to} ({cron_from})"
103
- stmt = f"{_from}-{_to}" if _from else ""
104
- stmt = stmt.strip("-")
105
- if "z" in linked_value_field:
106
- return_dict["statement"]["note"] = linked_value_field["z"]
107
- if "x" in linked_value_field:
108
- return_dict["statement"]["staffNote"] = linked_value_field["x"]
109
- stmt = re.sub(" +", " ", stmt)
110
- return_dict["statement"]["statement"] = stmt
111
- return return_dict
163
+ if not _to and cron_to:
164
+ _to = cron_to
165
+ if _to == cron_to and _to:
166
+ _to = f"({cron_to})"
167
+ if _from and _from == cron_from:
168
+ _from = f"({cron_from})"
169
+ return _from, _to
170
+
171
+ @staticmethod
172
+ def get_textual_statements(
173
+ marc_record: Record, field_textual: str, return_dict: dict, legacy_ids: List[str]
174
+ ):
175
+ """Returns the textual statements from the relevant marc fields
176
+
177
+ Args:
178
+ marc_record (Record): _description_
179
+ field_textual (str): _description_
180
+ return_dict (dict): _description_
181
+ legacy_ids (List[str]): List of legacy ids in record
182
+
183
+ Raises:
184
+ TransformationFieldMappingError: _description_
185
+ TransformationFieldMappingError: _description_
186
+ """
187
+ for f in marc_record.get_fields(field_textual):
188
+ if all(
189
+ [
190
+ len("".join(f.get_subfields("a")).strip()) == 0,
191
+ len("".join(f.get_subfields("z")).strip()) == 0,
192
+ len("".join(f.get_subfields("x")).strip()) == 0,
193
+ ]
194
+ ):
195
+ raise TransformationFieldMappingError(
196
+ legacy_ids,
197
+ i18n.t("%{field} a, x and z are missing or empty", field=field_textual),
198
+ f,
199
+ )
200
+ return_dict["statements"].append(
201
+ {
202
+ "statement": "".join(f.get_subfields("a")),
203
+ "note": "".join(f.get_subfields("z")),
204
+ "staffNote": "".join(f.get_subfields("x")),
205
+ }
206
+ )
207
+ return_dict["migration_report"].append(
208
+ ("Holdings statements", f"From {field_textual}")
209
+ )
112
210
 
211
+ @staticmethod
212
+ def get_break_indicator(field: Field):
213
+ if "w" not in field or field["w"] not in ["g", "n"]:
214
+ return ""
215
+ elif field["w"] == "g":
216
+ return ","
217
+ elif field["w"] == "n":
218
+ return ";"
219
+ else:
220
+ return ""
113
221
 
114
- def get_season(val):
115
- try:
116
- val = int(val)
117
- if val == 21:
222
+ @staticmethod
223
+ def g_s(val: str):
224
+ val_int = int(val)
225
+ if val_int == 21:
118
226
  return "Spring"
119
- elif val == 22:
227
+ elif val_int == 22:
120
228
  return "Summer"
121
- elif val == 23:
229
+ elif val_int == 23:
122
230
  return "Fall"
123
- elif val == 24:
231
+ elif val_int == 24:
124
232
  return "Winter"
125
233
  else:
126
234
  return val
127
- except Exception:
128
- return val
129
-
130
-
131
- def dedupe_list_of_dict(list_of_dict):
132
- return [dict(t) for t in {tuple(d.items()) for d in list_of_dict}]
133
-
134
-
135
- def get_cron_from_to(pattern_field: Field, linked_value_field: Field):
136
- cron_from = ""
137
- cron_to = ""
138
- hlm_stmt = ""
139
- year = False
140
-
141
- for chron_level in [cl for cl in "ijkl" if cl in linked_value_field]:
142
- desc = pattern_field[chron_level] or ""
143
- if linked_value_field[chron_level]:
144
- if chron_level == "i" and desc == "(year)":
145
- hlm_stmt = linked_value_field[chron_level]
146
- if desc == "(year)":
147
- year = True
148
- val, *val_rest = linked_value_field[chron_level].split("-")
149
- if desc == "(month)":
150
- try:
151
- val = f"{calendar.month_abbr[int(val)]}."
152
- except Exception:
153
- pass
154
- if "".join(val_rest):
155
- try:
156
- val_rest = calendar.month_abbr[int("".join(val_rest))]
157
- except Exception:
158
- pass
159
- if year:
160
- cron_from = f"{cron_from.strip()}:{val} "
161
- cron_to = f"{cron_to}:{''.join(val_rest)} "
162
- else:
163
- if "season" in desc:
164
- val = get_season(val)
165
- cron_from = f"{cron_from} {val} "
166
- cron_to = f"{cron_to} {''.join(val_rest)}"
167
- return (cron_from.strip(), cron_to.strip(), hlm_stmt)
168
-
169
-
170
- def get_from_to(pattern_field: Field, linked_value_field: Field):
171
- _from = ""
172
- _to = ""
173
- for enum_level in [el for el in "abcdef" if el in linked_value_field]:
174
- desc = pattern_field[enum_level] or ""
175
- desc = desc if "(" not in desc else ""
176
- if linked_value_field[enum_level]:
235
+
236
+ @staticmethod
237
+ def get_season(val: str):
238
+ try:
239
+ result = HoldingsStatementsParser.g_s(val)
240
+ if result == val:
241
+ result = HoldingsStatementsParser.g_m(int(val))
242
+ return result
243
+ except Exception:
244
+ return val
245
+
246
+ @staticmethod
247
+ def dedupe_list_of_dict(list_of_dict):
248
+ return [dict(t) for t in {tuple(d.items()): None for d in list_of_dict}]
249
+
250
+ @staticmethod
251
+ def g_m(m: int):
252
+ if m == 5:
253
+ return "May"
254
+ elif m == 6:
255
+ return "June"
256
+ elif m == 7:
257
+ return "July"
258
+ else:
259
+ return f"{calendar.month_abbr[m]}."
260
+
261
+ @staticmethod
262
+ def get_month(month_str: str):
263
+ month_str = month_str.strip()
264
+ if "/" in month_str:
265
+ return "/".join([HoldingsStatementsParser.g_m(int(m)) for m in month_str.split("/")])
266
+ else:
267
+ result = HoldingsStatementsParser.g_m(int(month_str))
268
+ if result == month_str:
269
+ result = HoldingsStatementsParser.g_s(month_str)
270
+ return result
271
+
272
+ @staticmethod
273
+ def get_cron_from_to(pattern_field: Field, linked_value_field: Field):
274
+ cron_from = ""
275
+ cron_to = ""
276
+ hlm_stmt = ""
277
+ year = False
278
+ is_span = False
279
+ for chron_level in [cl for cl in "ijkl" if cl in linked_value_field]:
280
+ desc = pattern_field.get(chron_level, "")
281
+ if linked_value_field.get(chron_level):
282
+ if chron_level == "i" and desc == "(year)":
283
+ hlm_stmt = linked_value_field[chron_level]
284
+ if desc == "(year)":
285
+ year = True
286
+ val, *val_rest = linked_value_field[chron_level].split("-")
287
+ is_span = "-" in linked_value_field[chron_level] or is_span
288
+ if desc == "(month)":
289
+ with contextlib.suppress(Exception):
290
+ val = HoldingsStatementsParser.get_month(val)
291
+ with contextlib.suppress(Exception):
292
+ val_rest = HoldingsStatementsParser.get_month(val_rest[0])
293
+ if "".join(val_rest):
294
+ with contextlib.suppress(Exception):
295
+ val_rest = HoldingsStatementsParser.get_month("".join(val_rest))
296
+ elif cron_to.strip() and val:
297
+ val_rest = val
298
+ if year:
299
+ cron_from, cron_to = HoldingsStatementsParser.format_year_cron_from_cron_to(
300
+ cron_from, cron_to, hlm_stmt, val, val_rest
301
+ )
302
+
303
+ else:
304
+ if "season" in desc:
305
+ val = HoldingsStatementsParser.get_season(val)
306
+ if "".join(val_rest):
307
+ val_rest = HoldingsStatementsParser.get_season("".join(val_rest))
308
+ cron_from = f"{cron_from} {val}".strip()
309
+ cron_to = f"{cron_to} {''.join(val_rest)}".strip()
310
+ return (f"{cron_from.strip()}", cron_to.strip(), hlm_stmt, is_span)
311
+
312
+ @staticmethod
313
+ def format_year_cron_from_cron_to(cron_from, cron_to, hlm_stmt, val, val_rest):
314
+ spill_year = f"{hlm_stmt}:" if "-" not in hlm_stmt else ""
315
+ cron_from = f"{cron_from.strip()}:{val}"
316
+ if cron_to and "".join(val_rest):
317
+ cron_to = f"{cron_to}:{''.join(val_rest)}"
318
+ elif not cron_to and "".join(val_rest):
319
+ cron_to = f"{spill_year}{''.join(val_rest)}"
320
+ return cron_from, cron_to
321
+
322
+ @staticmethod
323
+ def get_from_to(pattern_field: Field, linked_value_field: Field):
324
+ _from = ""
325
+ _to = ""
326
+ is_span = False
327
+ for enum_level in [el for el in "abcdef" if el in linked_value_field]:
328
+ desc = pattern_field.get(enum_level, "")
329
+ desc = desc.strip() if "(" not in desc else ""
330
+ _from, _to, is_span = HoldingsStatementsParser.format_enum_parts(
331
+ linked_value_field, _from, _to, is_span, enum_level, desc
332
+ )
333
+ return (f"{_from.strip()}", _to.strip(), is_span)
334
+
335
+ @staticmethod
336
+ def format_enum_parts(linked_value_field, _from, _to, is_span, enum_level, desc):
337
+ if linked_value_field.get(enum_level):
177
338
  val, *val_rest = linked_value_field[enum_level].split("-")
339
+ is_span = "-" in linked_value_field[enum_level] or is_span
178
340
  _from = f"{_from}{(':' if _from else '')}{desc}{val}"
179
341
  temp_to = "".join(val_rest)
180
342
  if temp_to.strip():
181
343
  _to = f"{_to}{(':' if _to else '')}{desc}{temp_to}"
182
- return (_from.strip(), _to.strip())
344
+ return _from, _to, is_span