22from typing import List
33from strenum import StrEnum
44
5- from converter import (ConversionResult , ConversionResults , ConversionPaths , Converter )
5+ from converter import (ConversionResult , ConversionResults , ConversionPaths , Converter , conversion_path_to_string , ConversionsCache )
66from schema_types import SchemaLanguage
77from logic import identify_schema_features , rank_paths
8- from app import DETAILED_ERROR_OUTPUT , schema_languages_features
8+ from app import DETAILED_ERROR_OUTPUT
99
1010
1111class ConversionStrategy (StrEnum ):
@@ -20,8 +20,9 @@ def convert_with_strategy_most_features_preserved(source: SchemaLanguage, target
2020 doc_features = set (identify_schema_features (schema , source ))
2121 if not doc_features :
2222 print ("Warning: No schema feature identification available for the given schema format '" + source + "'." )
23- ranked_paths = rank_paths (paths , doc_features , schema_languages_features )
23+ ranked_paths = rank_paths (paths , doc_features )
2424 all_attempts : List [ConversionResult ] = []
25+ conversions_cache = {} # cache for all conversion sub-paths
2526 result_schema = None
2627
2728 # attempt conversion via best path and if it fails, try remaining paths and print error message only to console
@@ -30,7 +31,9 @@ def convert_with_strategy_most_features_preserved(source: SchemaLanguage, target
3031 while result_schema is None and len (ranked_paths ) > 0 :
3132 best_path , unsupported_features = ranked_paths [0 ]
3233 try :
33- result_schema = attempt_conversion_path (source , target , best_path , schema )
34+ result_schema , conversions_cache_update = attempt_conversion_path (source , target , best_path , schema ,
35+ conversions_cache )
36+ conversions_cache = conversions_cache_update
3437
3538 if not result_schema :
3639 all_attempts .append ((False , "Conversion resulted in 'None' schema." , best_path ))
@@ -56,10 +59,13 @@ def convert_with_strategy_least_character_loss(source: SchemaLanguage, target: S
5659 Does not stop at success but explores all paths. Trivial feature loss strategy which is character based.
5760 Much less effort than a proper feature loss analysis and still effective."""
5861 all_attempts : List [ConversionResult ] = []
62+ conversions_cache = {} # cache for all conversion sub-paths
5963 for path in paths :
6064 result_schema = None
6165 try :
62- result_schema = attempt_conversion_path (source , target , path , schema )
66+ result_schema , conversions_cache_update = attempt_conversion_path (source , target , path , schema ,
67+ conversions_cache )
68+ conversions_cache = conversions_cache_update
6369
6470 if not result_schema :
6571 all_attempts .append ((False , "Conversion resulted in 'None' schema." , path ))
@@ -78,17 +84,41 @@ def convert_with_strategy_least_character_loss(source: SchemaLanguage, target: S
7884 return all_attempts
7985
8086
81- def attempt_conversion_path (source : str , target : str , path : List [Converter ], schema : str ) -> str :
87+ # the conversions cache contains the results of all previously attempted conversion sub-paths
88+ def attempt_conversion_path (source : str , target : str , path : List [Converter ], schema : str ,
89+ conversions_cache : ConversionsCache ) -> tuple [str , ConversionsCache ]:
8290 print_conversion_path (source , target , path )
8391 current_schema = schema
8492 current_converter = None
93+ conversion_sub_path = []
8594 try :
8695 for conv in path :
8796 current_converter = conv
88- current_schema = conv .convert (current_schema )
89- print (
90- "Intermediate schema of format " + conv .target_format + " after conversion via " + conv .service_name + ": " + current_schema )
91- return current_schema
97+ conversion_sub_path .append (conv )
98+
99+ # check cache
100+ conversion_sub_path_hash = conversion_path_to_string (conversion_sub_path )
101+ if conversion_sub_path_hash in conversions_cache :
102+ # cache hit
103+ cached_result = conversions_cache [conversion_sub_path_hash ]
104+ if cached_result is None :
105+ # previously failed conversion for this sub-path
106+ raise Exception ("Previously failed conversion for this sub-path." )
107+ else :
108+ # use cached result in case of cache hit and good previous conversion
109+ current_schema = cached_result
110+ print (
111+ "Using cached intermediate schema of format " + conv .target_format + " after conversion via " + conv .service_name + ": " + current_schema )
112+ continue
113+ else :
114+ # cache miss - perform conversion
115+ current_schema = conv .convert (current_schema )
116+ print (
117+ "Intermediate schema of format " + conv .target_format + " after conversion via " + conv .service_name + ": " + current_schema )
118+ # store in cache
119+ conversions_cache [conversion_sub_path_hash ] = current_schema
120+
121+ return current_schema , conversions_cache
92122 except Exception as e :
93123 print (
94124 "Conversion failed at step from " + current_converter .source_format + " to " + current_converter .target_format + " via " + current_converter .service_name + " because of error: " + str (
0 commit comments