mps-cli 0.6.0__tar.gz → 0.6.1__tar.gz

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 (79) hide show
  1. {mps_cli-0.6.0 → mps_cli-0.6.1}/PKG-INFO +3 -1
  2. {mps_cli-0.6.0 → mps_cli-0.6.1}/pyproject.toml +6 -1
  3. {mps_cli-0.6.0 → mps_cli-0.6.1}/src/mpscli/demo.py +3 -0
  4. mps_cli-0.6.1/src/mpscli/model/SConcept.py +26 -0
  5. {mps_cli-0.6.0 → mps_cli-0.6.1}/src/mpscli/model/SLanguage.py +5 -5
  6. mps_cli-0.6.1/src/mpscli/model/builder/SLanguageBuilder.py +128 -0
  7. {mps_cli-0.6.0 → mps_cli-0.6.1}/src/mpscli/model/builder/SModelBuilderBase.py +18 -6
  8. {mps_cli-0.6.0 → mps_cli-0.6.1}/src/mpscli/model/builder/SModelBuilderBinaryPersistency.py +50 -0
  9. {mps_cli-0.6.0 → mps_cli-0.6.1}/src/mpscli/model/builder/SSolutionBuilder.py +14 -19
  10. mps_cli-0.6.1/src/mpscli/model/builder/SSolutionsRepositoryBuilder.py +311 -0
  11. mps_cli-0.6.1/src/mpscli/model/builder/utils/DiskModelLoader.py +377 -0
  12. mps_cli-0.6.1/src/mpscli/model/builder/utils/JarModelLoader.py +328 -0
  13. mps_cli-0.6.1/src/mpscli/model/builder/utils/JarScanner.py +167 -0
  14. {mps_cli-0.6.0 → mps_cli-0.6.1}/src/mpscli/model/builder/utils/ModelCache.py +12 -3
  15. mps_cli-0.6.1/src/mpscli/model/builder/utils/MpbBatchParser.py +207 -0
  16. mps_cli-0.6.1/src/mpscli/model/builder/utils/ParseCache.py +255 -0
  17. mps_cli-0.6.1/tests/binary/__init__.py +0 -0
  18. {mps_cli-0.6.0 → mps_cli-0.6.1}/tests/binary/test_binary_format_parity.py +2 -1
  19. {mps_cli-0.6.0 → mps_cli-0.6.1}/tests/binary/test_binary_language_from_mpl.py +2 -1
  20. {mps_cli-0.6.0 → mps_cli-0.6.1}/tests/binary/test_binary_library_top.py +2 -1
  21. {mps_cli-0.6.0 → mps_cli-0.6.1}/tests/binary/test_binary_references.py +2 -1
  22. mps_cli-0.6.1/tests/binary/test_binary_repository.py +93 -0
  23. {mps_cli-0.6.0 → mps_cli-0.6.1}/tests/binary/test_binary_repository_completeness.py +4 -3
  24. {mps_cli-0.6.0 → mps_cli-0.6.1}/tests/test_base.py +2 -2
  25. mps_cli-0.6.1/tests/test_disk_model_loader.py +249 -0
  26. mps_cli-0.6.1/tests/test_jar_model_loader.py +181 -0
  27. mps_cli-0.6.1/tests/test_jar_scanner.py +147 -0
  28. mps_cli-0.6.1/tests/test_model_cache.py +130 -0
  29. {mps_cli-0.6.0 → mps_cli-0.6.1}/tests/test_modules_and_models.py +12 -6
  30. mps_cli-0.6.1/tests/test_mpb_batch_parser.py +145 -0
  31. mps_cli-0.6.1/tests/test_parse_cache.py +291 -0
  32. mps_cli-0.6.1/tests/test_solutions_repository_builder.py +166 -0
  33. mps_cli-0.6.0/Readme.md +0 -42
  34. mps_cli-0.6.0/src/mpscli/model/SConcept.py +0 -21
  35. mps_cli-0.6.0/src/mpscli/model/builder/SLanguageBuilder.py +0 -105
  36. mps_cli-0.6.0/src/mpscli/model/builder/SSolutionsRepositoryBuilder.py +0 -126
  37. mps_cli-0.6.0/src/mpscli/model/builder/utils/MpbBatchParser.py +0 -124
  38. mps_cli-0.6.0/tests/binary/test_binary_repository.py +0 -52
  39. {mps_cli-0.6.0 → mps_cli-0.6.1}/.gitignore +0 -0
  40. {mps_cli-0.6.0 → mps_cli-0.6.1}/LICENSE +0 -0
  41. {mps_cli-0.6.0 → mps_cli-0.6.1}/README.md +0 -0
  42. {mps_cli-0.6.0 → mps_cli-0.6.1}/src/mpscli/__init__.py +0 -0
  43. {mps_cli-0.6.0 → mps_cli-0.6.1}/src/mpscli/demo_language_extraction.py +0 -0
  44. {mps_cli-0.6.0 → mps_cli-0.6.1}/src/mpscli/model/SModel.py +0 -0
  45. {mps_cli-0.6.0 → mps_cli-0.6.1}/src/mpscli/model/SNode.py +0 -0
  46. {mps_cli-0.6.0 → mps_cli-0.6.1}/src/mpscli/model/SNodeRef.py +0 -0
  47. {mps_cli-0.6.0 → mps_cli-0.6.1}/src/mpscli/model/SRepository.py +0 -0
  48. {mps_cli-0.6.0 → mps_cli-0.6.1}/src/mpscli/model/SSolution.py +0 -0
  49. {mps_cli-0.6.0 → mps_cli-0.6.1}/src/mpscli/model/__init__.py +0 -0
  50. {mps_cli-0.6.0 → mps_cli-0.6.1}/src/mpscli/model/builder/SModelBuilderDefaultPersistency.py +0 -0
  51. {mps_cli-0.6.0 → mps_cli-0.6.1}/src/mpscli/model/builder/SModelBuilderFilePerRootPersistency.py +0 -0
  52. {mps_cli-0.6.0 → mps_cli-0.6.1}/src/mpscli/model/builder/__init__.py +0 -0
  53. {mps_cli-0.6.0 → mps_cli-0.6.1}/src/mpscli/model/builder/binary/constants.py +0 -0
  54. {mps_cli-0.6.0 → mps_cli-0.6.1}/src/mpscli/model/builder/binary/imports.py +0 -0
  55. {mps_cli-0.6.0 → mps_cli-0.6.1}/src/mpscli/model/builder/binary/model_input_stream.py +0 -0
  56. {mps_cli-0.6.0 → mps_cli-0.6.1}/src/mpscli/model/builder/binary/module_refs.py +0 -0
  57. {mps_cli-0.6.0 → mps_cli-0.6.1}/src/mpscli/model/builder/binary/nodes.py +0 -0
  58. {mps_cli-0.6.0 → mps_cli-0.6.1}/src/mpscli/model/builder/binary/registry.py +0 -0
  59. {mps_cli-0.6.0 → mps_cli-0.6.1}/src/mpscli/model/builder/binary/used_languages.py +0 -0
  60. {mps_cli-0.6.0 → mps_cli-0.6.1}/src/mpscli/model/builder/binary/utils.py +0 -0
  61. {mps_cli-0.6.0 → mps_cli-0.6.1}/src/mpscli/model/builder/binary/uuid_utils.py +0 -0
  62. {mps_cli-0.6.0 → mps_cli-0.6.1}/src/mpscli/model/builder/utils/JarUtils.py +0 -0
  63. {mps_cli-0.6.0 → mps_cli-0.6.1}/src/mpscli/model/builder/utils/NodeIdEncodingUtils.py +0 -0
  64. {mps_cli-0.6.0 → mps_cli-0.6.1}/tests/__init__.py +0 -0
  65. {mps_cli-0.6.0 → mps_cli-0.6.1}/tests/binary/Readme.md +0 -0
  66. {mps_cli-0.6.0 → mps_cli-0.6.1}/tests/binary/test_binary_cross_module_ref.py +0 -0
  67. {mps_cli-0.6.0 → mps_cli-0.6.1}/tests/binary/test_binary_header.py +0 -0
  68. {mps_cli-0.6.0 → mps_cli-0.6.1}/tests/binary/test_binary_imports.py +0 -0
  69. {mps_cli-0.6.0 → mps_cli-0.6.1}/tests/binary/test_binary_model_imports.py +0 -0
  70. {mps_cli-0.6.0 → mps_cli-0.6.1}/tests/binary/test_binary_node_tree.py +0 -0
  71. {mps_cli-0.6.0 → mps_cli-0.6.1}/tests/binary/test_binary_performance.py +0 -0
  72. {mps_cli-0.6.0 → mps_cli-0.6.1}/tests/binary/test_binary_persistency_low_level_access.py +0 -0
  73. {mps_cli-0.6.0 → mps_cli-0.6.1}/tests/binary/test_binary_registry.py +0 -0
  74. {mps_cli-0.6.0 → mps_cli-0.6.1}/tests/context.py +0 -0
  75. {mps_cli-0.6.0 → mps_cli-0.6.1}/tests/test_language_extraction.py +0 -0
  76. {mps_cli-0.6.0 → mps_cli-0.6.1}/tests/test_model_attributes.py +0 -0
  77. {mps_cli-0.6.0 → mps_cli-0.6.1}/tests/test_model_imports.py +0 -0
  78. {mps_cli-0.6.0 → mps_cli-0.6.1}/tests/test_node_id_encoding_utils.py +0 -0
  79. {mps_cli-0.6.0 → mps_cli-0.6.1}/tests/test_nodes.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mps-cli
3
- Version: 0.6.0
3
+ Version: 0.6.1
4
4
  Summary: MPS Command Line Interface (MPS-CLI) is a library to parse MPS files and build the model as Python objects.
5
5
  Project-URL: Homepage, https://github.com/mbeddr/mps-cli
6
6
  Project-URL: Bug Tracker, https://github.com/mbeddr/mps-cli/issues
@@ -10,6 +10,8 @@ Classifier: License :: OSI Approved :: Eclipse Public License 2.0 (EPL-2.0)
10
10
  Classifier: Operating System :: OS Independent
11
11
  Classifier: Programming Language :: Python :: 3
12
12
  Requires-Python: >=3.7
13
+ Provides-Extra: dev
14
+ Requires-Dist: parameterized; extra == 'dev'
13
15
  Description-Content-Type: text/markdown
14
16
 
15
17
  ## MPS CLI Python Library
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "mps-cli"
7
- version = "0.6.0"
7
+ version = "0.6.1"
8
8
  authors = [
9
9
  { name="Daniel Ratiu", email="ratiud@googlemail.com" },
10
10
  { name="Prithvi Venkat", email="prithvi.rvce@gmail.com" },
@@ -19,6 +19,11 @@ classifiers = [
19
19
  "Operating System :: OS Independent",
20
20
  ]
21
21
 
22
+ [project.optional-dependencies]
23
+ dev = [
24
+ "parameterized",
25
+ ]
26
+
22
27
  [project.urls]
23
28
  "Homepage" = "https://github.com/mbeddr/mps-cli"
24
29
  "Bug Tracker" = "https://github.com/mbeddr/mps-cli/issues"
@@ -13,6 +13,7 @@ import sys
13
13
  import time
14
14
  from datetime import datetime
15
15
  from pathlib import Path
16
+ import logging
16
17
 
17
18
  sys.path.insert(1, "..")
18
19
 
@@ -283,6 +284,7 @@ def main() -> None:
283
284
  for c in lan.concepts:
284
285
  c.print_concept_details()
285
286
 
287
+
286
288
  if __name__ == "__main__":
287
289
  import multiprocessing
288
290
 
@@ -291,6 +293,7 @@ if __name__ == "__main__":
291
293
  # redirect stdout to a log file
292
294
  log_file = f"mps_debug_{datetime.now().strftime('%H%M%S')}.log"
293
295
  sys.stdout = open(log_file, "w", encoding="utf-8", buffering=1)
296
+ logging.basicConfig(level=logging.INFO, stream=sys.stderr, format="%(message)s")
294
297
  print(f"Logging to: {log_file}")
295
298
 
296
299
  main()
@@ -0,0 +1,26 @@
1
+ import logging
2
+
3
+ _log = logging.getLogger(__name__)
4
+
5
+
6
+ class SConcept:
7
+
8
+ def __init__(self, name, uuid):
9
+ self.name = name
10
+ self.uuid = uuid
11
+ self.properties = []
12
+ self.children = []
13
+ self.references = []
14
+
15
+ def print_concept_details(self):
16
+ _log.debug("concept: %s", self.name)
17
+ _log.debug("\tproperties: ")
18
+ for property in self.properties:
19
+ _log.debug("\t\t%s", property)
20
+ _log.debug("\tchildren: ")
21
+ for child in self.children:
22
+ _log.debug("\t\t%s", child)
23
+ _log.debug("\treferences: ")
24
+ for reference in self.references:
25
+ _log.debug("\t\t%s", reference)
26
+ _log.debug("<<<")
@@ -5,7 +5,10 @@ class SLanguage:
5
5
  self.uuid = uuid
6
6
  self.concepts = []
7
7
 
8
- # version number from the languageVersion attribute in the .mpl file..
8
+ # kept in sync with concepts list by SLanguageBuilder.get_concept()..
9
+ self._concepts_by_name = {}
10
+
11
+ # version number from the languageVersion attribute in the .mpl file.
9
12
  # stays 0 if this language was only seen via registry (never had its .mpl read)
10
13
  self.language_version = 0
11
14
 
@@ -15,10 +18,7 @@ class SLanguage:
15
18
  self.models = []
16
19
 
17
20
  def find_concept_by_name(self, name):
18
- for c in self.concepts:
19
- if c.name == name:
20
- return c
21
- return None
21
+ return self._concepts_by_name.get(name)
22
22
 
23
23
  def find_model_by_name(self, suffix):
24
24
  # find a specific aspect model by the last segment of its name.
@@ -0,0 +1,128 @@
1
+ import warnings
2
+ import xml.etree.ElementTree as ET
3
+ from pathlib import Path
4
+ from threading import Lock
5
+
6
+ from mpscli.model.SLanguage import SLanguage
7
+ from mpscli.model.SConcept import SConcept
8
+
9
+
10
+ class SLanguageBuilder:
11
+ languages = {}
12
+ # protectss languages dict, per-language _concepts_by_name dicts and per-concept properties/children/references
13
+ # lists also.. needed because all get_ methods are called from multiple threads during parallel
14
+ # parsing (phase3 ProcessPool workers and phase4 ProcessPool workerss)
15
+ _lock = Lock()
16
+
17
+ @classmethod
18
+ def get_language(cls, name, uuid):
19
+ lan = cls.languages.get(name)
20
+ if lan is not None:
21
+ return lan
22
+ with cls._lock:
23
+ lan = cls.languages.get(name)
24
+ if lan is None:
25
+ lan = SLanguage(name, uuid)
26
+ cls.languages[name] = lan
27
+ return lan
28
+
29
+ @classmethod
30
+ def get_concept(cls, language, concept_name, concept_uuid):
31
+ # always acquire lock since _concepts_by_name is mutated here and by other threads..
32
+ # SLanguage.__init__ always initialises _concepts_by_name so no hasattr check needed
33
+ with cls._lock:
34
+ concept = language._concepts_by_name.get(concept_name)
35
+ if concept is None:
36
+ concept = SConcept(concept_name, concept_uuid)
37
+ language.concepts.append(concept)
38
+ language._concepts_by_name[concept_name] = concept
39
+ return concept
40
+
41
+ @classmethod
42
+ def get_property(cls, concept, property_name):
43
+ # fast path cuz list iteration is GIL-atomic for reads in CPython
44
+ node_property = next(
45
+ (p for p in concept.properties if p == property_name), None
46
+ )
47
+ if node_property is not None:
48
+ return node_property
49
+ with cls._lock:
50
+ # double-check inside lock since another thread may have added it
51
+ node_property = next(
52
+ (p for p in concept.properties if p == property_name), None
53
+ )
54
+ if node_property is None:
55
+ concept.properties.append(property_name)
56
+ node_property = property_name
57
+ return node_property
58
+
59
+ @classmethod
60
+ def get_child(cls, concept, child_name):
61
+ child_role = next((c for c in concept.children if c == child_name), None)
62
+ if child_role is not None:
63
+ return child_role
64
+ with cls._lock:
65
+ child_role = next((c for c in concept.children if c == child_name), None)
66
+ if child_role is None:
67
+ concept.children.append(child_name)
68
+ child_role = child_name
69
+ return child_role
70
+
71
+ @classmethod
72
+ def get_reference(cls, concept, reference_name):
73
+ reference_role = next(
74
+ (r for r in concept.references if r == reference_name), None
75
+ )
76
+ if reference_role is not None:
77
+ return reference_role
78
+ with cls._lock:
79
+ reference_role = next(
80
+ (r for r in concept.references if r == reference_name), None
81
+ )
82
+ if reference_role is None:
83
+ concept.references.append(reference_name)
84
+ reference_role = reference_name
85
+ return reference_role
86
+
87
+ @classmethod
88
+ def load_from_mpl(cls, mpl_path: Path) -> SLanguage:
89
+ # reads a .mpl file and enriches the matching SLanguage with its version
90
+ # number and aspect models. if the language was already registered via
91
+ # a registry section in a .mpb file, get_language() returns the same object
92
+ # so no duplicate entries are created.
93
+ try:
94
+ return cls._read_and_enrich(mpl_path)
95
+ except Exception as exc:
96
+ warnings.warn(f"Failed to read language from {mpl_path.name}: {exc}")
97
+ return None
98
+
99
+ @classmethod
100
+ def _read_and_enrich(cls, mpl_path: Path) -> SLanguage:
101
+ root = ET.parse(mpl_path).getroot()
102
+ namespace = root.get("namespace", "")
103
+ uuid = root.get("uuid", "")
104
+ version = int(root.get("languageVersion", "0"))
105
+ lang = cls.get_language(namespace, uuid)
106
+ lang.language_version = version
107
+ lang.models = cls._load_aspect_models(mpl_path.parent / "models")
108
+ return lang
109
+
110
+ @classmethod
111
+ def _load_aspect_models(cls, models_dir: Path) -> list:
112
+ # parse every .mpb in the models directory next to the .mpl file
113
+ # these are the language aspects which is structure,, behavior, editor, constraints, typesystem, etc..
114
+ if not models_dir.exists():
115
+ return []
116
+ from mpscli.model.builder.SModelBuilderBinaryPersistency import (
117
+ SModelBuilderBinaryPersistency,
118
+ )
119
+
120
+ loaded = []
121
+ for mpb_file in sorted(models_dir.glob("*.mpb")):
122
+ try:
123
+ model = SModelBuilderBinaryPersistency().build(str(mpb_file))
124
+ if model is not None:
125
+ loaded.append(model)
126
+ except Exception as exc:
127
+ warnings.warn(f"Failed to parse aspect model {mpb_file.name}: {exc}")
128
+ return loaded
@@ -37,7 +37,11 @@ class SModelBuilderBase:
37
37
  else:
38
38
  ref_model_index = ref_to[0 : ref_to.find(":")]
39
39
  ref_node_uuid = ref_to[ref_to.find(":") + 1 : len(ref_to)]
40
- s_node_ref = SNodeRef(self.index_2_imported_model_uuid[ref_model_index], ref_node_uuid, resolve_info)
40
+ s_node_ref = SNodeRef(
41
+ self.index_2_imported_model_uuid[ref_model_index],
42
+ ref_node_uuid,
43
+ resolve_info,
44
+ )
41
45
  ref_name = self.index_2_reference_role[ref_role]
42
46
  s_node.references[ref_name] = s_node_ref
43
47
  for child_node_xml in node_xml.findall("node"):
@@ -45,10 +49,12 @@ class SModelBuilderBase:
45
49
  s_node.children.append(child_node)
46
50
 
47
51
  return s_node
52
+
48
53
  @staticmethod
49
54
  def is_model_generatable(model_xml_node):
50
55
  return any(
51
- attribute.get("name") == "doNotGenerate" and attribute.get("value") == "true"
56
+ attribute.get("name") == "doNotGenerate"
57
+ and attribute.get("value") == "true"
52
58
  for attribute in model_xml_node.findall("attribute")
53
59
  )
54
60
 
@@ -64,7 +70,7 @@ class SModelBuilderBase:
64
70
  imported_model_ref = import_xml_node.get("ref")
65
71
  imported_model_uuid = imported_model_ref[0 : imported_model_ref.find("(")]
66
72
  imported_models[import_index] = imported_model_uuid
67
- self.index_2_imported_model_uuid[import_index] = imported_model_uuid
73
+ self.index_2_imported_model_uuid[import_index] = imported_model_uuid
68
74
 
69
75
  return imported_models
70
76
 
@@ -74,7 +80,9 @@ class SModelBuilderBase:
74
80
  model_uuid = model_ref[0 : model_ref.find("(")]
75
81
  model_is_do_not_generate = self.is_model_generatable(model_xml_node)
76
82
  model_imported_models = self.extract_imported_models(self, model_xml_node)
77
- model = SModel(model_name, model_uuid, model_is_do_not_generate, model_imported_models)
83
+ model = SModel(
84
+ model_name, model_uuid, model_is_do_not_generate, model_imported_models
85
+ )
78
86
  return model
79
87
 
80
88
  def extract_registry(self, model_xml_node):
@@ -86,13 +94,17 @@ class SModelBuilderBase:
86
94
  for concept_xml_node in language_xml_node.findall("concept"):
87
95
  concept_id = concept_xml_node.get("id")
88
96
  concept_name = concept_xml_node.get("name")
89
- concept = SLanguageBuilder.get_concept(language, concept_name, concept_id)
97
+ concept = SLanguageBuilder.get_concept(
98
+ language, concept_name, concept_id
99
+ )
90
100
  concept_index = concept_xml_node.get("index")
91
101
  self.index_2_concept[concept_index] = concept
92
102
  for property_xml_node in concept_xml_node.findall("property"):
93
103
  property_name = property_xml_node.get("name")
94
104
  property_index = property_xml_node.get("index")
95
- node_property = SLanguageBuilder.get_property(concept, property_name)
105
+ node_property = SLanguageBuilder.get_property(
106
+ concept, property_name
107
+ )
96
108
  self.index_2_property[property_index] = node_property
97
109
  for child_xml_node in concept_xml_node.findall("child"):
98
110
  child_name = child_xml_node.get("name")
@@ -135,6 +135,56 @@ class SModelBuilderBinaryPersistency(SModelBuilderBase):
135
135
 
136
136
  return model
137
137
 
138
+ def build_from_bytes(self, data: bytes, path_hint: str = ""):
139
+ reader = ModelInputStream(data)
140
+
141
+ # 1. header: extracts stream version andd model UUID and model name
142
+ version, model_uuid, model_name = self._load_header(reader)
143
+ self.stream_version = version
144
+
145
+ uuid_str = model_uuid or "r:unknown"
146
+ name_str = model_name or "unknown.model"
147
+
148
+ # Import index 0 is always the current models own uuid..
149
+ # Java's SModel.importedModels() lists imports starting from index 1 and index 0 is implicitly
150
+ # the model itself used when resolving REF_THIS_MODEL
151
+ self.index_2_imported_model_uuid["0"] = uuid_str
152
+ model = SModel(name_str, uuid_str, False)
153
+
154
+ # 2. registry: builds concept/property/reference/child index maps
155
+ load_registry(reader, self)
156
+
157
+ # 3. model properties - used languages, devkits, imports
158
+ try:
159
+ self._load_model_properties(reader, version)
160
+ except _UnknownSubKind as e:
161
+ import warnings
162
+
163
+ warnings.warn(
164
+ f"[build_from_bytes] {path_hint}: {e} - skipped to MODEL_START"
165
+ )
166
+ advance_until_after(reader, MODEL_START)
167
+ return model
168
+
169
+ model.imported_models = {
170
+ index: imported_model_uuid
171
+ for index, imported_model_uuid in self.index_2_imported_model_uuid.items()
172
+ if index != "0"
173
+ }
174
+
175
+ # 4. model start..
176
+ token = reader.read_u32()
177
+ if token != MODEL_START:
178
+ raise RuntimeError(
179
+ f"Expected MODEL_START (0x{MODEL_START:08X}), "
180
+ f"got 0x{token:08X} at pos {reader.tell() - 4}"
181
+ )
182
+
183
+ # 5. Node tree: recursive read_children populates model.root_nodes..
184
+ read_children(reader, self, model, None)
185
+
186
+ return model
187
+
138
188
  def _load_header(self, reader: ModelInputStream):
139
189
  # Mirrors BinaryPersistence.loadHeader() in:
140
190
  # https://github.com/JetBrains/MPS/blob/6236c4073eac3cde78506add6b0fa90601d76009/core/persistence/source/jetbrains/mps/persistence/binary/BinaryPersistence.java
@@ -1,15 +1,13 @@
1
- import os
1
+ import logging
2
+ import warnings
2
3
  import xml.etree.ElementTree as ET
3
4
  from pathlib import Path
4
5
  from typing import List, Optional, Tuple
5
6
 
7
+ _log = logging.getLogger(__name__)
8
+
6
9
  from mpscli.model.SSolution import SSolution
7
- from mpscli.model.builder.SModelBuilderDefaultPersistency import (
8
- SModelBuilderDefaultPersistency,
9
- )
10
- from mpscli.model.builder.SModelBuilderFilePerRootPersistency import (
11
- SModelBuilderFilePerRootPersistency,
12
- )
10
+ from mpscli.model.builder.utils.DiskModelLoader import parse_fpr, parse_mps
13
11
  from mpscli.model.builder.utils.MpbBatchParser import MpbBatchParser
14
12
 
15
13
 
@@ -20,8 +18,9 @@ class SSolutionBuilder:
20
18
  def build_solution(self, path_to_msd_file: Path) -> Optional[SSolution]:
21
19
  models_dir = path_to_msd_file.parent / "models"
22
20
  if not models_dir.exists():
23
- print(
24
- f"ERROR: 'models' directory not found - no model is loaded from: {path_to_msd_file.parent}"
21
+ _log.warning(
22
+ "'models' directory not found - no model loaded from: %s",
23
+ path_to_msd_file.parent,
25
24
  )
26
25
  return None
27
26
  solutions = self.build_all([path_to_msd_file])
@@ -40,12 +39,10 @@ class SSolutionBuilder:
40
39
  for msd_path in msd_paths:
41
40
  solution = self._extract_solution_info(msd_path)
42
41
  solution.path_to_solution_file = msd_path
43
-
44
42
  models_dir = msd_path.parent / "models"
45
43
  if not models_dir.exists():
46
44
  solution_infos.append((solution, [], [], []))
47
45
  continue
48
-
49
46
  mpb, fpr, mps = self._collect_model_paths(models_dir)
50
47
  solution_infos.append((solution, mpb, fpr, mps))
51
48
  all_mpb_paths.extend(str(p) for p in mpb)
@@ -61,20 +58,18 @@ class SSolutionBuilder:
61
58
 
62
59
  for model_path in fpr_dirs:
63
60
  try:
64
- model = SModelBuilderFilePerRootPersistency().build(model_path)
65
- solution.models.append(model)
61
+ model = parse_fpr(model_path)
62
+ if model is not None:
63
+ solution.models.append(model)
66
64
  except Exception as exc:
67
- import warnings
68
-
69
65
  warnings.warn(f"Failed to parse {model_path}: {exc}")
70
66
 
71
67
  for model_path in mps_paths:
72
68
  try:
73
- model = SModelBuilderDefaultPersistency().build(model_path)
74
- solution.models.append(model)
69
+ model = parse_mps(model_path)
70
+ if model is not None:
71
+ solution.models.append(model)
75
72
  except Exception as exc:
76
- import warnings
77
-
78
73
  warnings.warn(f"Failed to parse {model_path}: {exc}")
79
74
 
80
75
  solutions.append(solution)