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.
- folio_migration_tools/__init__.py +11 -0
- folio_migration_tools/__main__.py +169 -85
- folio_migration_tools/circulation_helper.py +96 -59
- folio_migration_tools/config_file_load.py +66 -0
- folio_migration_tools/custom_dict.py +6 -4
- folio_migration_tools/custom_exceptions.py +21 -19
- folio_migration_tools/extradata_writer.py +46 -0
- folio_migration_tools/folder_structure.py +63 -66
- folio_migration_tools/helper.py +29 -21
- folio_migration_tools/holdings_helper.py +57 -34
- folio_migration_tools/i18n_config.py +9 -0
- folio_migration_tools/library_configuration.py +173 -13
- folio_migration_tools/mapper_base.py +317 -106
- folio_migration_tools/mapping_file_transformation/courses_mapper.py +203 -0
- folio_migration_tools/mapping_file_transformation/holdings_mapper.py +83 -69
- folio_migration_tools/mapping_file_transformation/item_mapper.py +98 -94
- folio_migration_tools/mapping_file_transformation/manual_fee_fines_mapper.py +352 -0
- folio_migration_tools/mapping_file_transformation/mapping_file_mapper_base.py +702 -223
- folio_migration_tools/mapping_file_transformation/notes_mapper.py +90 -0
- folio_migration_tools/mapping_file_transformation/order_mapper.py +492 -0
- folio_migration_tools/mapping_file_transformation/organization_mapper.py +389 -0
- folio_migration_tools/mapping_file_transformation/ref_data_mapping.py +38 -27
- folio_migration_tools/mapping_file_transformation/user_mapper.py +149 -361
- folio_migration_tools/marc_rules_transformation/conditions.py +650 -246
- folio_migration_tools/marc_rules_transformation/holdings_statementsparser.py +292 -130
- folio_migration_tools/marc_rules_transformation/hrid_handler.py +244 -0
- folio_migration_tools/marc_rules_transformation/loc_language_codes.xml +20846 -0
- folio_migration_tools/marc_rules_transformation/marc_file_processor.py +300 -0
- folio_migration_tools/marc_rules_transformation/marc_reader_wrapper.py +136 -0
- folio_migration_tools/marc_rules_transformation/rules_mapper_authorities.py +241 -0
- folio_migration_tools/marc_rules_transformation/rules_mapper_base.py +681 -201
- folio_migration_tools/marc_rules_transformation/rules_mapper_bibs.py +395 -429
- folio_migration_tools/marc_rules_transformation/rules_mapper_holdings.py +531 -100
- folio_migration_tools/migration_report.py +85 -38
- folio_migration_tools/migration_tasks/__init__.py +1 -3
- folio_migration_tools/migration_tasks/authority_transformer.py +119 -0
- folio_migration_tools/migration_tasks/batch_poster.py +911 -198
- folio_migration_tools/migration_tasks/bibs_transformer.py +121 -116
- folio_migration_tools/migration_tasks/courses_migrator.py +192 -0
- folio_migration_tools/migration_tasks/holdings_csv_transformer.py +252 -247
- folio_migration_tools/migration_tasks/holdings_marc_transformer.py +321 -115
- folio_migration_tools/migration_tasks/items_transformer.py +264 -84
- folio_migration_tools/migration_tasks/loans_migrator.py +506 -195
- folio_migration_tools/migration_tasks/manual_fee_fines_transformer.py +187 -0
- folio_migration_tools/migration_tasks/migration_task_base.py +364 -74
- folio_migration_tools/migration_tasks/orders_transformer.py +373 -0
- folio_migration_tools/migration_tasks/organization_transformer.py +451 -0
- folio_migration_tools/migration_tasks/requests_migrator.py +130 -62
- folio_migration_tools/migration_tasks/reserves_migrator.py +253 -0
- folio_migration_tools/migration_tasks/user_transformer.py +180 -139
- folio_migration_tools/task_configuration.py +46 -0
- folio_migration_tools/test_infrastructure/__init__.py +0 -0
- folio_migration_tools/test_infrastructure/mocked_classes.py +406 -0
- folio_migration_tools/transaction_migration/legacy_loan.py +148 -34
- folio_migration_tools/transaction_migration/legacy_request.py +65 -25
- folio_migration_tools/transaction_migration/legacy_reserve.py +47 -0
- folio_migration_tools/transaction_migration/transaction_result.py +12 -1
- folio_migration_tools/translations/en.json +476 -0
- folio_migration_tools-1.9.10.dist-info/METADATA +169 -0
- folio_migration_tools-1.9.10.dist-info/RECORD +67 -0
- {folio_migration_tools-1.2.1.dist-info → folio_migration_tools-1.9.10.dist-info}/WHEEL +1 -2
- folio_migration_tools-1.9.10.dist-info/entry_points.txt +3 -0
- folio_migration_tools/generate_schemas.py +0 -46
- folio_migration_tools/mapping_file_transformation/mapping_file_mapping_base_impl.py +0 -44
- folio_migration_tools/mapping_file_transformation/user_mapper_base.py +0 -212
- folio_migration_tools/marc_rules_transformation/bibs_processor.py +0 -163
- folio_migration_tools/marc_rules_transformation/holdings_processor.py +0 -284
- folio_migration_tools/report_blurbs.py +0 -219
- folio_migration_tools/transaction_migration/legacy_fee_fine.py +0 -36
- folio_migration_tools-1.2.1.dist-info/METADATA +0 -134
- folio_migration_tools-1.2.1.dist-info/RECORD +0 -50
- folio_migration_tools-1.2.1.dist-info/top_level.txt +0 -1
- {folio_migration_tools-1.2.1.dist-info → folio_migration_tools-1.9.10.dist-info/licenses}/LICENSE +0 -0
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
|
|
2
|
+
import i18n
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from datetime import timezone
|
|
3
5
|
|
|
4
6
|
|
|
5
7
|
class MigrationReport:
|
|
@@ -9,58 +11,103 @@ class MigrationReport:
|
|
|
9
11
|
self.report = {}
|
|
10
12
|
self.stats = {}
|
|
11
13
|
|
|
12
|
-
def add(self,
|
|
13
|
-
"""Add section header and values to migration report.
|
|
14
|
+
def add(self, blurb_id, measure_to_add, number=1):
|
|
15
|
+
"""Add section header and values to migration report.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
blurb_id (string): ID of Blurb in translations file
|
|
19
|
+
measure_to_add (_type_): _description_
|
|
20
|
+
number (int, optional): _description_. Defaults to 1.
|
|
21
|
+
"""
|
|
14
22
|
try:
|
|
15
|
-
self.report[
|
|
23
|
+
self.report[blurb_id][measure_to_add] += number
|
|
16
24
|
except KeyError:
|
|
17
|
-
if
|
|
18
|
-
self.report[
|
|
19
|
-
if measure_to_add not in self.report[
|
|
20
|
-
self.report[
|
|
25
|
+
if blurb_id not in self.report:
|
|
26
|
+
self.report[blurb_id] = {"blurb_id": blurb_id}
|
|
27
|
+
if measure_to_add not in self.report[blurb_id]:
|
|
28
|
+
self.report[blurb_id][measure_to_add] = number
|
|
29
|
+
|
|
30
|
+
def set(self, blurb_id, measure_to_add: str, number: int):
|
|
31
|
+
"""Set a section value to a specific number
|
|
21
32
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
33
|
+
Args:
|
|
34
|
+
blurb (_type_): _description_
|
|
35
|
+
measure_to_add (str): _description_
|
|
36
|
+
number (int): _description_
|
|
37
|
+
"""
|
|
38
|
+
if blurb_id not in self.report:
|
|
39
|
+
self.report[blurb_id] = {}
|
|
40
|
+
self.report[blurb_id][measure_to_add] = number
|
|
27
41
|
|
|
28
42
|
def add_general_statistics(self, measure_to_add: str):
|
|
29
|
-
"""Shortcut for adding to the first breakdown
|
|
30
|
-
|
|
43
|
+
"""Shortcut for adding to the first breakdown
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
measure_to_add (str): _description_
|
|
47
|
+
"""
|
|
48
|
+
self.add("GeneralStatistics", measure_to_add)
|
|
31
49
|
|
|
32
|
-
def write_migration_report(
|
|
33
|
-
|
|
34
|
-
|
|
50
|
+
def write_migration_report(
|
|
51
|
+
self,
|
|
52
|
+
report_title,
|
|
53
|
+
report_file,
|
|
54
|
+
time_started: datetime,
|
|
55
|
+
):
|
|
56
|
+
"""Writes the migration report, including section headers, section blurbs, and values.
|
|
35
57
|
|
|
58
|
+
Args:
|
|
59
|
+
report_title (_type_):the header of the report.
|
|
60
|
+
report_file (_type_):path to file
|
|
61
|
+
time_started (datetime): The datetime stamp (in utc), of when the process started
|
|
62
|
+
"""
|
|
63
|
+
time_finished = datetime.now(timezone.utc)
|
|
64
|
+
report_file.write(
|
|
65
|
+
"\n".join(
|
|
66
|
+
[
|
|
67
|
+
"# " + report_title,
|
|
68
|
+
i18n.t("blurbs.Introduction.description"),
|
|
69
|
+
"## " + i18n.t("Timings"),
|
|
70
|
+
"",
|
|
71
|
+
i18n.t("Measure") + " | " + i18n.t("Value"),
|
|
72
|
+
"--- | ---:",
|
|
73
|
+
i18n.t("Time Started:") + " | " + datetime.isoformat(time_started),
|
|
74
|
+
i18n.t("Time Finished:") + " | " + datetime.isoformat(time_finished),
|
|
75
|
+
i18n.t("Elapsed time:") + " | " + str(time_finished - time_started),
|
|
76
|
+
]
|
|
77
|
+
)
|
|
78
|
+
)
|
|
79
|
+
logging.info(f"Elapsed time: {time_finished-time_started}")
|
|
36
80
|
for a in self.report:
|
|
37
|
-
|
|
38
|
-
report_file.write(" \n")
|
|
39
|
-
report_file.write(f"## {blurb[0]} \n")
|
|
40
|
-
report_file.write(f"{blurb[1]} \n")
|
|
81
|
+
blurb_id = self.report[a].get("blurb_id") or ""
|
|
41
82
|
report_file.write(
|
|
42
|
-
|
|
83
|
+
"\n".join(
|
|
84
|
+
[
|
|
85
|
+
"",
|
|
86
|
+
"## " + i18n.t(f"blurbs.{blurb_id}.title"),
|
|
87
|
+
i18n.t(f"blurbs.{blurb_id}.description"),
|
|
88
|
+
"<details><summary>"
|
|
89
|
+
+ i18n.t("Click to expand all %{count} things", count=len(self.report[a]))
|
|
90
|
+
+ "</summary>",
|
|
91
|
+
"",
|
|
92
|
+
i18n.t("Measure") + " | " + i18n.t("Count"),
|
|
93
|
+
"--- | ---:",
|
|
94
|
+
]
|
|
95
|
+
+ [
|
|
96
|
+
f"{k or 'EMPTY'} | {self.report[a][k]:,}"
|
|
97
|
+
for k in sorted(self.report[a], key=as_str)
|
|
98
|
+
if k != "blurb_id"
|
|
99
|
+
]
|
|
100
|
+
+ ["</details>", ""]
|
|
101
|
+
)
|
|
43
102
|
)
|
|
44
|
-
report_file.write(" \n")
|
|
45
|
-
report_file.write("Measure | Count \n")
|
|
46
|
-
report_file.write("--- | ---: \n")
|
|
47
|
-
b = self.report[a]
|
|
48
|
-
sortedlist = [
|
|
49
|
-
(k, b[k]) for k in sorted(b, key=as_str) if k != "blurb_tuple"
|
|
50
|
-
]
|
|
51
|
-
for b in sortedlist:
|
|
52
|
-
report_file.write(f"{b[0] or 'EMPTY'} | {b[1]:,} \n")
|
|
53
|
-
report_file.write("</details> \n")
|
|
54
103
|
|
|
55
104
|
def log_me(self):
|
|
56
105
|
for a in self.report:
|
|
57
|
-
|
|
58
|
-
logging.info(f"{
|
|
106
|
+
blurb_id = self.report[a].get("blurb_id") or ""
|
|
107
|
+
logging.info(f"{blurb_id} ")
|
|
59
108
|
logging.info("_______________")
|
|
60
109
|
b = self.report[a]
|
|
61
|
-
sortedlist = [
|
|
62
|
-
(k, b[k]) for k in sorted(b, key=as_str) if k != "blurb_tuple"
|
|
63
|
-
]
|
|
110
|
+
sortedlist = [(k, b[k]) for k in sorted(b, key=as_str) if k != "blurb_id"]
|
|
64
111
|
for b in sortedlist:
|
|
65
112
|
logging.info(f"{b[0] or 'EMPTY'} \t\t{b[1]:,} ")
|
|
66
113
|
|
|
@@ -2,6 +2,4 @@ from os.path import dirname, basename, isfile, join
|
|
|
2
2
|
import glob
|
|
3
3
|
|
|
4
4
|
modules = glob.glob(join(dirname(__file__), "*.py"))
|
|
5
|
-
__all__ = [
|
|
6
|
-
basename(f)[:-3] for f in modules if isfile(f) and not f.endswith("__init__.py")
|
|
7
|
-
]
|
|
5
|
+
__all__ = [basename(f)[:-3] for f in modules if isfile(f) and not f.endswith("__init__.py")]
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Annotated
|
|
3
|
+
from typing import List
|
|
4
|
+
import i18n
|
|
5
|
+
|
|
6
|
+
from folio_uuid.folio_namespaces import FOLIONamespaces
|
|
7
|
+
from pydantic import Field
|
|
8
|
+
|
|
9
|
+
from folio_migration_tools.helper import Helper
|
|
10
|
+
from folio_migration_tools.library_configuration import FileDefinition
|
|
11
|
+
from folio_migration_tools.library_configuration import IlsFlavour
|
|
12
|
+
from folio_migration_tools.library_configuration import LibraryConfiguration
|
|
13
|
+
from folio_migration_tools.marc_rules_transformation.marc_file_processor import (
|
|
14
|
+
MarcFileProcessor,
|
|
15
|
+
)
|
|
16
|
+
from folio_migration_tools.marc_rules_transformation.rules_mapper_authorities import (
|
|
17
|
+
AuthorityMapper,
|
|
18
|
+
)
|
|
19
|
+
from folio_migration_tools.migration_tasks.migration_task_base import MigrationTaskBase
|
|
20
|
+
from folio_migration_tools.task_configuration import AbstractTaskConfiguration
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class AuthorityTransformer(MigrationTaskBase):
|
|
24
|
+
class TaskConfiguration(AbstractTaskConfiguration):
|
|
25
|
+
name: Annotated[
|
|
26
|
+
str,
|
|
27
|
+
Field(
|
|
28
|
+
description=(
|
|
29
|
+
"Name of this migration task. The name is being used to call the specific "
|
|
30
|
+
"task, and to distinguish tasks of similar types"
|
|
31
|
+
)
|
|
32
|
+
),
|
|
33
|
+
]
|
|
34
|
+
migration_task_type: Annotated[
|
|
35
|
+
str,
|
|
36
|
+
Field(
|
|
37
|
+
title="Migration task type",
|
|
38
|
+
description=("The type of migration task you want to perform"),
|
|
39
|
+
),
|
|
40
|
+
]
|
|
41
|
+
files: Annotated[
|
|
42
|
+
List[FileDefinition],
|
|
43
|
+
Field(
|
|
44
|
+
title="Source files", description=("List of MARC21 files with authority records")
|
|
45
|
+
),
|
|
46
|
+
]
|
|
47
|
+
ils_flavour: Annotated[
|
|
48
|
+
IlsFlavour,
|
|
49
|
+
Field(
|
|
50
|
+
title="ILS flavour", description="The type of ILS you are migrating records from."
|
|
51
|
+
),
|
|
52
|
+
]
|
|
53
|
+
tags_to_delete: Annotated[
|
|
54
|
+
List[str],
|
|
55
|
+
Field(
|
|
56
|
+
title="Tags to delete from MARC record",
|
|
57
|
+
description=(
|
|
58
|
+
"Tags in the incoming MARC authority that the process should remove "
|
|
59
|
+
"before adding them into FOLIO. These tags will be used in the "
|
|
60
|
+
"transformation before getting removed."
|
|
61
|
+
),
|
|
62
|
+
),
|
|
63
|
+
] = []
|
|
64
|
+
create_source_records: Annotated[
|
|
65
|
+
bool,
|
|
66
|
+
Field(
|
|
67
|
+
title="Create source records",
|
|
68
|
+
description=(
|
|
69
|
+
"Controls wheter or not to retain the MARC records in "
|
|
70
|
+
"Source Record Storage."
|
|
71
|
+
),
|
|
72
|
+
),
|
|
73
|
+
] = True
|
|
74
|
+
|
|
75
|
+
@staticmethod
|
|
76
|
+
def get_object_type() -> FOLIONamespaces:
|
|
77
|
+
return FOLIONamespaces.authorities
|
|
78
|
+
|
|
79
|
+
def __init__(
|
|
80
|
+
self,
|
|
81
|
+
task_config: TaskConfiguration,
|
|
82
|
+
library_config: LibraryConfiguration,
|
|
83
|
+
use_logging: bool = True,
|
|
84
|
+
):
|
|
85
|
+
super().__init__(library_config, task_config, use_logging)
|
|
86
|
+
self.processor: MarcFileProcessor
|
|
87
|
+
self.check_source_files(
|
|
88
|
+
self.folder_structure.legacy_records_folder, self.task_configuration.files
|
|
89
|
+
)
|
|
90
|
+
self.mapper: AuthorityMapper = AuthorityMapper(
|
|
91
|
+
self.folio_client, library_config, task_config
|
|
92
|
+
)
|
|
93
|
+
self.auth_ids: set = set()
|
|
94
|
+
logging.info("Init done")
|
|
95
|
+
|
|
96
|
+
def do_work(self):
|
|
97
|
+
self.do_work_marc_transformer()
|
|
98
|
+
|
|
99
|
+
def wrap_up(self):
|
|
100
|
+
logging.info("Done. Transformer Wrapping up...")
|
|
101
|
+
self.extradata_writer.flush()
|
|
102
|
+
self.processor.wrap_up()
|
|
103
|
+
with open(self.folder_structure.migration_reports_file, "w+") as report_file:
|
|
104
|
+
self.mapper.migration_report.write_migration_report(
|
|
105
|
+
i18n.t("Authority records transformation report"),
|
|
106
|
+
report_file,
|
|
107
|
+
self.start_datetime,
|
|
108
|
+
)
|
|
109
|
+
Helper.print_mapping_report(
|
|
110
|
+
report_file,
|
|
111
|
+
self.mapper.parsed_records,
|
|
112
|
+
self.mapper.mapped_folio_fields,
|
|
113
|
+
self.mapper.mapped_legacy_fields,
|
|
114
|
+
)
|
|
115
|
+
logging.info(
|
|
116
|
+
"Done. Transformation report written to %s",
|
|
117
|
+
self.folder_structure.migration_reports_file.name,
|
|
118
|
+
)
|
|
119
|
+
self.clean_out_empty_logs()
|