Skip to content

Commit e907f97

Browse files
committed
start adding different conversion strategies
1 parent 7a92471 commit e907f97

18 files changed

Lines changed: 4726 additions & 305 deletions

schema-conversion-orchestrator/ConvertersLinkMl.py

Lines changed: 5 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from linkml.utils.generator import Generator
77

88
from converter import ConverterInternal
9-
from schema_types import SchemaFeature, SchemaLanguage
9+
from schema_types import SchemaLanguage
1010
from utils import simple_cname_convert
1111

1212
from linkml_runtime.linkml_model import SchemaDefinition
@@ -31,15 +31,7 @@ def __init__(self):
3131
service_name="FlaskApp",
3232
source_format=SchemaLanguage.LinkMl,
3333
target_format=SchemaLanguage.JsonSchema,
34-
supported_features=[
35-
SchemaFeature.Comments,
36-
SchemaFeature.Hierarchy,
37-
SchemaFeature.References,
38-
SchemaFeature.Constraints,
39-
SchemaFeature.Properties,
40-
SchemaFeature.Attributes,
41-
SchemaFeature.Composition
42-
]
34+
supported_features=None
4335
)
4436

4537
def converter_logic(self, schema: str) -> str:
@@ -65,15 +57,7 @@ def __init__(self, target_format: SchemaLanguage):
6557
service_name="FlaskApp",
6658
source_format=SchemaLanguage.LinkMl,
6759
target_format=target_format,
68-
supported_features=[
69-
SchemaFeature.Comments,
70-
SchemaFeature.Hierarchy,
71-
SchemaFeature.References,
72-
SchemaFeature.Constraints,
73-
SchemaFeature.Properties,
74-
SchemaFeature.Attributes,
75-
SchemaFeature.Composition
76-
]
60+
supported_features=None
7761
)
7862

7963
def converter_logic(self, schema: str) -> str:
@@ -126,15 +110,7 @@ def __init__(self):
126110
service_name="FlaskApp",
127111
source_format=SchemaLanguage.JsonSchema,
128112
target_format=SchemaLanguage.LinkMl,
129-
supported_features=[
130-
SchemaFeature.Comments,
131-
SchemaFeature.Hierarchy,
132-
SchemaFeature.References,
133-
SchemaFeature.Constraints,
134-
SchemaFeature.Properties,
135-
SchemaFeature.Attributes,
136-
SchemaFeature.Composition
137-
]
113+
supported_features=None
138114
)
139115

140116
def converter_logic(self, schema: str) -> str:
@@ -174,15 +150,7 @@ def __init__(self):
174150
service_name="FlaskApp",
175151
source_format=SchemaLanguage.Owl,
176152
target_format=SchemaLanguage.LinkMl,
177-
supported_features=[
178-
SchemaFeature.Comments,
179-
SchemaFeature.Hierarchy,
180-
SchemaFeature.References,
181-
SchemaFeature.Constraints,
182-
SchemaFeature.Properties,
183-
SchemaFeature.Attributes,
184-
SchemaFeature.Composition
185-
]
153+
supported_features=None
186154
)
187155

188156
def converter_logic(self, schema: str) -> str:

schema-conversion-orchestrator/ConvertersMdModels.py

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import json
22

33
from converter import ConverterInternal
4-
from schema_types import SchemaLanguage, SchemaFeature
4+
from schema_types import SchemaLanguage
55

66
from mdmodels_core import DataModel, Templates
77

88

9-
109
class ConverterFromMdModels(ConverterInternal):
1110
def __init__(self, target_format: SchemaLanguage):
1211
super().__init__(
@@ -15,10 +14,7 @@ def __init__(self, target_format: SchemaLanguage):
1514
service_name="FlaskApp",
1615
source_format=SchemaLanguage.MdModels,
1716
target_format=target_format,
18-
supported_features=[
19-
SchemaFeature.Comments,
20-
SchemaFeature.Hierarchy,
21-
]
17+
supported_features=None
2218
)
2319

2420
def converter_logic(self, schema: str) -> str:
@@ -68,15 +64,7 @@ def __init__(self):
6864
service_name="FlaskApp",
6965
source_format=SchemaLanguage.JsonSchema,
7066
target_format=SchemaLanguage.MdModels,
71-
supported_features=[
72-
SchemaFeature.Comments,
73-
SchemaFeature.Hierarchy,
74-
SchemaFeature.References,
75-
SchemaFeature.Constraints,
76-
SchemaFeature.Properties,
77-
SchemaFeature.Attributes,
78-
SchemaFeature.Composition
79-
]
67+
supported_features=None
8068
)
8169

8270
def converter_logic(self, schema: str) -> str:
Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
21
from converter import ConverterInternal
3-
from schema_types import SchemaLanguage, SchemaFeature
2+
from schema_types import SchemaLanguage
43

54
import xmlschema
65
import json
76

87

9-
108
class ConverterXsdToJsonSchema(ConverterInternal):
119
def __init__(self):
1210
super().__init__(
@@ -15,15 +13,7 @@ def __init__(self):
1513
service_name="FlaskApp",
1614
source_format=SchemaLanguage.Xsd,
1715
target_format=SchemaLanguage.JsonSchema,
18-
supported_features=[
19-
SchemaFeature.Comments,
20-
SchemaFeature.Hierarchy,
21-
SchemaFeature.References,
22-
SchemaFeature.Constraints,
23-
SchemaFeature.Properties,
24-
SchemaFeature.Attributes,
25-
SchemaFeature.Composition
26-
]
16+
supported_features=None
2717
)
2818

2919
def converter_logic(self, schema: str) -> str:
@@ -38,4 +28,4 @@ def validate_input(self, schema: str) -> bool:
3828

3929
def validate_output(self, schema: str) -> bool:
4030
# Implement validation logic for JSON Schema
41-
return True
31+
return True
Lines changed: 30 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
1-
import traceback
2-
3-
from converter import Converter, ConverterExternal
4-
from schema_types import schema_language_from_string
5-
from logic import build_conversion_graph, identify_schema_features, find_paths, rank_paths
1+
from conversion_strategies import convert_with_strategy_most_features_preserved, ConversionStrategy, \
2+
convert_with_strategy_least_character_loss
3+
from converter import (Converter, ConverterExternal)
4+
from schema_types import schema_language_from_string, SchemaLanguagesFeatures
5+
from logic import build_conversion_graph, find_paths
66
from register_converters import register_converters
77
from flask import Flask, request
88
from typing import List, Dict
9+
from schema_languages_loader import load_schema_language_features
910

1011
app = Flask(__name__)
1112

1213
DETAILED_ERROR_OUTPUT = False
14+
CONVERSION_STRATEGY = ConversionStrategy.LeastCharacterLoss
1315

1416
converters: List[Converter] = register_converters()
1517
conversion_graph: Dict[str, List[Converter]] = build_conversion_graph(converters)
18+
schema_languages_features: SchemaLanguagesFeatures = load_schema_language_features()
19+
1620
print("Started Schema Conversion Orchestrator with the following converters:")
1721
for conv in converters:
1822
print(f"- {conv.name}: {conv.source_format} -> {conv.target_format} at {conv.service_address}")
@@ -22,6 +26,7 @@
2226
def health():
2327
return {"status": "ok"}, 200
2428

29+
2530
@app.route("/registerConversion", methods=["POST"])
2631
def register_conversion():
2732
data = request.json
@@ -35,7 +40,8 @@ def register_conversion():
3540
converters.append(conv)
3641
global conversion_graph
3742
conversion_graph = build_conversion_graph(converters)
38-
print(f"Registered new converter: {conv.name} from {conv.source_format} to {conv.target_format} at {conv.service_address}.")
43+
print(
44+
f"Registered new converter: {conv.name} from {conv.source_format} to {conv.target_format} at {conv.service_address}.")
3945
return {"status": "registered"}, 200
4046

4147

@@ -58,52 +64,24 @@ def convert():
5864
if not all_paths:
5965
return {"error": "No path found for conversion from source " + source + " to target " + target + "."}, 400
6066

61-
doc_features = set(identify_schema_features(schema, source, conversion_graph))
62-
ranked_paths = rank_paths(all_paths, doc_features)
63-
attempt_errors = []
64-
result_schema = None
65-
66-
# attempt conversion via best path and if it fails, try remaining paths and print error message only to console
67-
# if no path is left, return the error messages of all attempts consolidated
68-
# create only one loop and try and catch and do not treat the first path specially
69-
while result_schema is None and len(ranked_paths) > 0:
70-
best_path, unsupported_features = ranked_paths[0]
71-
try:
72-
result_schema = attempt_conversion_path(source, target, best_path, schema)
73-
except Exception as e:
74-
ranked_paths = ranked_paths[1:]
75-
if DETAILED_ERROR_OUTPUT:
76-
full_traceback = traceback.format_exc()
77-
attempt_errors.append(f"Error: {e}\nTraceback:\n{full_traceback}")
78-
else:
79-
attempt_errors.append(str(e))
80-
81-
if result_schema is None:
67+
if CONVERSION_STRATEGY == ConversionStrategy.MostFeaturesPreserved:
68+
attempts = convert_with_strategy_most_features_preserved(
69+
source, target, schema, all_paths)
70+
elif CONVERSION_STRATEGY == ConversionStrategy.LeastCharacterLoss:
71+
attempts = convert_with_strategy_least_character_loss(
72+
source, target, schema, all_paths)
73+
else:
74+
return {"error": "Unknown conversion strategy: " + CONVERSION_STRATEGY}, 500
75+
76+
best_attempt = attempts[0]
77+
success, schema, conversion_path = best_attempt
78+
79+
if not success:
8280
# return error message of all attempts together with the attempt number (1 to n)
83-
return {"error": "All conversion paths failed. Details: " + " | ".join([f"Attempt {i+1}: {msg}" for i, msg in enumerate(attempt_errors)])}, 500
84-
85-
return {"schema": result_schema}, 200
86-
87-
88-
def attempt_conversion_path(source: str, target: str, path: List[Converter], schema: str) -> str:
89-
print_conversion_path(source, target, path)
90-
current_schema = schema
91-
current_converter = None
92-
try:
93-
for conv in path:
94-
current_converter = conv
95-
current_schema = conv.convert(current_schema)
96-
print("Intermediate schema of format " + conv.target_format + " after conversion via " + conv.service_name + ": " + current_schema)
97-
return current_schema
98-
except Exception as e:
99-
print("Conversion failed at step from " + current_converter.source_format + " to " + current_converter.target_format + " via " + current_converter.service_name + " because of error: " + str(e) + ".")
100-
print("With intermediate schema: " + current_schema)
101-
raise Exception(f"Conversion failed at step from {current_converter.source_format} to {current_converter.target_format} via {current_converter.service_name} because of error: {str(e)}.")
102-
103-
def print_conversion_path(source: str, target: str, path: List[Converter]) -> None:
104-
print("Given the source format " + source + " and target format " + target + ", the best available path is:")
105-
for conv in path:
106-
print(f"{conv.source_format} -> {conv.target_format} via {conv.name} ({conv.service_address})")
81+
return {"error": "All conversion paths failed.", attempts: attempts}, 500
82+
83+
return {"schema": schema}, 200
84+
10785

10886
def call_internal_converter(source: str, target: str, schema: str) -> str:
10987
if source == "JsonSchema" and target == "LinkMl":
@@ -113,5 +91,6 @@ def call_internal_converter(source: str, target: str, schema: str) -> str:
11391
else:
11492
raise Exception("Unsupported internal conversion")
11593

94+
11695
if __name__ == "__main__":
11796
app.run(host="0.0.0.0", port=5002)

0 commit comments

Comments
 (0)