Module soitool.serialize_export_import_soi
Includes functionality for serializing, exporting and importing SOI.
Expand source code
"""Includes functionality for serializing, exporting and importing SOI."""
import json
from datetime import datetime
from schema import Schema, And, Or
from soitool.soi import SOI
from soitool.compressor import compress, decompress
from soitool.modules.module_table import TableModule
from soitool.modules.module_authentication_board import (
AuthenticationBoardModule,
)
from soitool.modules.module_subtractorcodes import SubtractorcodesModule
from soitool.modules.module_freetext import FreeTextModule
from soitool.modules.module_frequency_table import FrequencyTableModule
from soitool.modules.module_phonebook import PhonebookModule
from soitool.modules.module_predefined_codes import PredefinedCodesModule
from soitool.modules.module_code_phrase import CodePhraseModule
# Valid schema for serialized SOI
SERIALIZED_SOI_SCHEMA = Schema(
{
"title": And(str, len),
"description": str,
"version": And(str, len),
"date": Or(str, None),
"valid": {"from_date": Or(str, None), "to_date": Or(str, None)},
"icon": Or(str, None),
"classification": And(
str,
len,
Or(
"UGRADERT",
"BEGRENSET",
"KONFIDENSIELT",
"HEMMELIG",
"STRENGT HEMMELIG",
),
),
"orientation": And(str, len, Or("portrait", "landscape")),
"placement_strategy": And(str, len, Or("manual", "auto")),
"algorithm_bin": And(str, len, Or("BFF", "BBF")),
"algorithm_pack": And(
str, len, Or("MaxRectsBl", "SkylineBl", "GuillotineBssfSas")
),
"algorithm_sort": And(str, len, Or("none", "area", "width", "height")),
"modules": [
{
"type": And(str, len),
"data": object,
"meta": {
"x": And(Or(int, float), lambda x: x >= 0),
"y": And(Or(int, float), lambda y: y >= 0),
"page": And(int, lambda page: page >= 0),
"name": And(str, len),
},
}
],
"attachments": [
{
"type": And(str, len),
"data": object,
"meta": {
"x": And(Or(int, float), lambda x: x >= 0),
"y": And(Or(int, float), lambda y: y >= 0),
"page": And(int, lambda page: page >= 0),
"name": And(str, len),
},
}
],
}
)
def serialize_soi(soi):
"""Serialize SOI to JSON-string.
Parameters
----------
soi : soitool.soi.SOI
SOI to serialize.
Returns
-------
String
JSON-string containing all SOI-information.
Raises
------
TypeError
Raises error if parameter 'soi' is not an SOI.
"""
# If parameter 'soi' is not an SOI
if not isinstance(soi, SOI):
raise TypeError(
"Invalid type for parameter 'soi': " + "'{}'.".format(soi)
)
# Create dict with relevant module-information
modules = []
for module in soi.modules:
modules.append(
{
"type": module["widget"].type,
"data": module["widget"].get_data(),
"meta": module["meta"],
}
)
# Create dict with relevant attachment-information
attachments = []
for attachment in soi.attachments:
attachments.append(
{
"type": attachment["widget"].type,
"data": attachment["widget"].get_data(),
"meta": attachment["meta"],
}
)
# Create dict with all relevant SOI-information
serialized = {
"title": soi.title,
"description": soi.description,
"version": soi.version,
"date": soi.date,
"valid": {"from_date": soi.valid_from, "to_date": soi.valid_to},
"icon": soi.icon,
"classification": soi.classification,
"orientation": soi.orientation,
"placement_strategy": soi.placement_strategy,
"algorithm_bin": soi.algorithm_bin,
"algorithm_pack": soi.algorithm_pack,
"algorithm_sort": soi.algorithm_sort,
"modules": modules,
"attachments": attachments,
}
return json.dumps(serialized)
def export_soi(soi, compressed=True):
"""Export SOI.
A .txt-file is created to contain compressed SOI.
A .json-file is created to contain uncompressed SOI.
Parameters
----------
soi: soitool.soi.SOI
SOI to export
compressed : bool, optional
Serialized SOI will be compressed if True (default).
"""
# Serialize SOI
serialized = serialize_soi(soi)
file_name = generate_soi_filename(soi)
if compressed:
serialized = compress(serialized)
file = open(file_name + ".txt", "w")
else:
file = open(file_name + ".json", "w")
file.write(str(serialized))
file.close()
def import_soi(file_path, database):
"""Import compressed or uncompressed serialized SOI.
Reads content of file and decompresses it for .txt-files.
Constructs an SOI-object based on the file content.
Parameters
----------
file_path : string
Full path to a file containing serialized SOI.
database : soitool.database.Database
Database-instance passed to specific modules.
Returns
-------
soitool.soi.SOI
SOI-instance.
Raises
------
ValueError
If file content is invalid against SERIALIZED_SOI_SCHEMA.
TypeError
If 'type' of module or attachment is not implemented.
"""
with open(file_path, "r") as file:
serialized = file.read()
if file_path.endswith(".txt"):
return construct_soi_from_serialized(
serialized, database, compressed=True
)
return construct_soi_from_serialized(serialized, database)
def construct_soi_from_serialized(serialized, database, compressed=False):
"""Construct an SOI-object from a serialized SOI.
Parameters
----------
serialized : string
Serialized SOI.
database : soitool.database.Database
Database-instance passed to specific modules.
compressed : bool, optional
True if serialized SOI is compressed, by default False.
Returns
-------
soitool.soi.SOI
SOI-instance.
Raises
------
ValueError
If 'serialized' is invalid against SERIALIZED_SOI_SCHEMA.
TypeError
If 'type' of module or attachment is not implemented.
"""
if compressed:
serialized = json.loads(decompress(serialized))
else:
serialized = json.loads(serialized)
# Raise error if file content is invalid
if not SERIALIZED_SOI_SCHEMA.is_valid(serialized):
raise ValueError("Serialized SOI does not have correct format.")
# Construct modules and attachments
modules = construct_modules_from_serialized(
serialized["modules"], database
)
attachments = construct_modules_from_serialized(
serialized["attachments"], database
)
# Create SOI
soi = SOI(
serialized["title"],
serialized["description"],
serialized["version"],
serialized["date"],
serialized["valid"]["from_date"],
serialized["valid"]["to_date"],
serialized["icon"],
serialized["classification"],
serialized["orientation"],
serialized["placement_strategy"],
serialized["algorithm_bin"],
serialized["algorithm_pack"],
serialized["algorithm_sort"],
modules,
attachments,
)
return soi
def construct_modules_from_serialized(serialized_modules, database):
"""Instantiate modules from serialized format.
Parameters
----------
serialized_modules : list
Containing dicts with serialized modules or attachment-modules.
database : soitool.database.Database
Database-instance passed to specific modules.
Returns
-------
list
Containing dicts with instantiated modules or attachment-modules.
Raises
------
TypeError
If type of module is not recognized.
"""
modules = []
for module in serialized_modules:
module_type = module["type"]
data = module["data"]
if module_type == "TableModule":
modules.append(
{"widget": TableModule(data), "meta": module["meta"]}
)
elif module_type == "AuthenticationBoardModule":
modules.append(
{
"widget": AuthenticationBoardModule(data),
"meta": module["meta"],
}
)
elif module_type == "SubtractorcodesModule":
modules.append(
{
"widget": SubtractorcodesModule(data),
"meta": module["meta"],
}
)
elif module_type == "FreeTextModule":
modules.append(
{"widget": FreeTextModule(data), "meta": module["meta"]}
)
elif module_type == "PhonebookModule":
modules.append(
{"widget": PhonebookModule(data), "meta": module["meta"]}
)
elif module_type == "FrequencyTableModule":
modules.append(
{"widget": FrequencyTableModule(data), "meta": module["meta"]}
)
elif module_type == "PredefinedCodesModule":
modules.append(
{
"widget": PredefinedCodesModule(database, data),
"meta": module["meta"],
}
)
elif module_type == "CodePhraseModule":
modules.append(
{
"widget": CodePhraseModule(database, data),
"meta": module["meta"],
}
)
else:
raise TypeError(
"Module-type '{}' is not recognized.".format(module_type)
)
return modules
def generate_soi_filename(soi):
"""Generate filename for SOI without extension.
Parameters
----------
soi : SOI
SOI to generate filename for.
Returns
-------
str
Filename for the SOI of the format 'SOI_title_YYYY_mm_dd'.
"""
title = soi.title
parsed_date = datetime.strptime(soi.date, "%Y-%m-%d")
date_string = parsed_date.strftime("%Y_%m_%d")
return f"SOI_{title}_{date_string}"
Functions
def construct_modules_from_serialized(serialized_modules, database)
-
Instantiate modules from serialized format.
Parameters
serialized_modules
:list
- Containing dicts with serialized modules or attachment-modules.
database
:Database
- Database-instance passed to specific modules.
Returns
list
- Containing dicts with instantiated modules or attachment-modules.
Raises
TypeError
- If type of module is not recognized.
Expand source code
def construct_modules_from_serialized(serialized_modules, database): """Instantiate modules from serialized format. Parameters ---------- serialized_modules : list Containing dicts with serialized modules or attachment-modules. database : soitool.database.Database Database-instance passed to specific modules. Returns ------- list Containing dicts with instantiated modules or attachment-modules. Raises ------ TypeError If type of module is not recognized. """ modules = [] for module in serialized_modules: module_type = module["type"] data = module["data"] if module_type == "TableModule": modules.append( {"widget": TableModule(data), "meta": module["meta"]} ) elif module_type == "AuthenticationBoardModule": modules.append( { "widget": AuthenticationBoardModule(data), "meta": module["meta"], } ) elif module_type == "SubtractorcodesModule": modules.append( { "widget": SubtractorcodesModule(data), "meta": module["meta"], } ) elif module_type == "FreeTextModule": modules.append( {"widget": FreeTextModule(data), "meta": module["meta"]} ) elif module_type == "PhonebookModule": modules.append( {"widget": PhonebookModule(data), "meta": module["meta"]} ) elif module_type == "FrequencyTableModule": modules.append( {"widget": FrequencyTableModule(data), "meta": module["meta"]} ) elif module_type == "PredefinedCodesModule": modules.append( { "widget": PredefinedCodesModule(database, data), "meta": module["meta"], } ) elif module_type == "CodePhraseModule": modules.append( { "widget": CodePhraseModule(database, data), "meta": module["meta"], } ) else: raise TypeError( "Module-type '{}' is not recognized.".format(module_type) ) return modules
def construct_soi_from_serialized(serialized, database, compressed=False)
-
Construct an SOI-object from a serialized SOI.
Parameters
serialized
:string
- Serialized SOI.
database
:Database
- Database-instance passed to specific modules.
compressed
:bool
, optional- True if serialized SOI is compressed, by default False.
Returns
SOI
- SOI-instance.
Raises
ValueError
- If 'serialized' is invalid against SERIALIZED_SOI_SCHEMA.
TypeError
- If 'type' of module or attachment is not implemented.
Expand source code
def construct_soi_from_serialized(serialized, database, compressed=False): """Construct an SOI-object from a serialized SOI. Parameters ---------- serialized : string Serialized SOI. database : soitool.database.Database Database-instance passed to specific modules. compressed : bool, optional True if serialized SOI is compressed, by default False. Returns ------- soitool.soi.SOI SOI-instance. Raises ------ ValueError If 'serialized' is invalid against SERIALIZED_SOI_SCHEMA. TypeError If 'type' of module or attachment is not implemented. """ if compressed: serialized = json.loads(decompress(serialized)) else: serialized = json.loads(serialized) # Raise error if file content is invalid if not SERIALIZED_SOI_SCHEMA.is_valid(serialized): raise ValueError("Serialized SOI does not have correct format.") # Construct modules and attachments modules = construct_modules_from_serialized( serialized["modules"], database ) attachments = construct_modules_from_serialized( serialized["attachments"], database ) # Create SOI soi = SOI( serialized["title"], serialized["description"], serialized["version"], serialized["date"], serialized["valid"]["from_date"], serialized["valid"]["to_date"], serialized["icon"], serialized["classification"], serialized["orientation"], serialized["placement_strategy"], serialized["algorithm_bin"], serialized["algorithm_pack"], serialized["algorithm_sort"], modules, attachments, ) return soi
def export_soi(soi, compressed=True)
-
Export SOI.
A .txt-file is created to contain compressed SOI. A .json-file is created to contain uncompressed SOI.
Parameters
soi
:SOI
- SOI to export
compressed
:bool
, optional- Serialized SOI will be compressed if True (default).
Expand source code
def export_soi(soi, compressed=True): """Export SOI. A .txt-file is created to contain compressed SOI. A .json-file is created to contain uncompressed SOI. Parameters ---------- soi: soitool.soi.SOI SOI to export compressed : bool, optional Serialized SOI will be compressed if True (default). """ # Serialize SOI serialized = serialize_soi(soi) file_name = generate_soi_filename(soi) if compressed: serialized = compress(serialized) file = open(file_name + ".txt", "w") else: file = open(file_name + ".json", "w") file.write(str(serialized)) file.close()
def generate_soi_filename(soi)
-
Generate filename for SOI without extension.
Parameters
soi
:SOI
- SOI to generate filename for.
Returns
str
- Filename for the SOI of the format 'SOI_title_YYYY_mm_dd'.
Expand source code
def generate_soi_filename(soi): """Generate filename for SOI without extension. Parameters ---------- soi : SOI SOI to generate filename for. Returns ------- str Filename for the SOI of the format 'SOI_title_YYYY_mm_dd'. """ title = soi.title parsed_date = datetime.strptime(soi.date, "%Y-%m-%d") date_string = parsed_date.strftime("%Y_%m_%d") return f"SOI_{title}_{date_string}"
def import_soi(file_path, database)
-
Import compressed or uncompressed serialized SOI.
Reads content of file and decompresses it for .txt-files. Constructs an SOI-object based on the file content.
Parameters
file_path
:string
- Full path to a file containing serialized SOI.
database
:Database
- Database-instance passed to specific modules.
Returns
SOI
- SOI-instance.
Raises
ValueError
- If file content is invalid against SERIALIZED_SOI_SCHEMA.
TypeError
- If 'type' of module or attachment is not implemented.
Expand source code
def import_soi(file_path, database): """Import compressed or uncompressed serialized SOI. Reads content of file and decompresses it for .txt-files. Constructs an SOI-object based on the file content. Parameters ---------- file_path : string Full path to a file containing serialized SOI. database : soitool.database.Database Database-instance passed to specific modules. Returns ------- soitool.soi.SOI SOI-instance. Raises ------ ValueError If file content is invalid against SERIALIZED_SOI_SCHEMA. TypeError If 'type' of module or attachment is not implemented. """ with open(file_path, "r") as file: serialized = file.read() if file_path.endswith(".txt"): return construct_soi_from_serialized( serialized, database, compressed=True ) return construct_soi_from_serialized(serialized, database)
def serialize_soi(soi)
-
Serialize SOI to JSON-string.
Parameters
soi
:SOI
- SOI to serialize.
Returns
String
- JSON-string containing all SOI-information.
Raises
TypeError
- Raises error if parameter 'soi' is not an SOI.
Expand source code
def serialize_soi(soi): """Serialize SOI to JSON-string. Parameters ---------- soi : soitool.soi.SOI SOI to serialize. Returns ------- String JSON-string containing all SOI-information. Raises ------ TypeError Raises error if parameter 'soi' is not an SOI. """ # If parameter 'soi' is not an SOI if not isinstance(soi, SOI): raise TypeError( "Invalid type for parameter 'soi': " + "'{}'.".format(soi) ) # Create dict with relevant module-information modules = [] for module in soi.modules: modules.append( { "type": module["widget"].type, "data": module["widget"].get_data(), "meta": module["meta"], } ) # Create dict with relevant attachment-information attachments = [] for attachment in soi.attachments: attachments.append( { "type": attachment["widget"].type, "data": attachment["widget"].get_data(), "meta": attachment["meta"], } ) # Create dict with all relevant SOI-information serialized = { "title": soi.title, "description": soi.description, "version": soi.version, "date": soi.date, "valid": {"from_date": soi.valid_from, "to_date": soi.valid_to}, "icon": soi.icon, "classification": soi.classification, "orientation": soi.orientation, "placement_strategy": soi.placement_strategy, "algorithm_bin": soi.algorithm_bin, "algorithm_pack": soi.algorithm_pack, "algorithm_sort": soi.algorithm_sort, "modules": modules, "attachments": attachments, } return json.dumps(serialized)