flamapy-fw 2.0.0.dev0__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.
- flamapy-fw-2.0.0.dev0/PKG-INFO +41 -0
- flamapy-fw-2.0.0.dev0/README.md +23 -0
- flamapy-fw-2.0.0.dev0/flamapy/commands/__init__.py +88 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/__init__.py +0 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/config.py +3 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/discover.py +320 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/exceptions.py +30 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/models/__init__.py +4 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/models/ast.py +304 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/models/variability_model.py +15 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/operations/__init__.py +28 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/operations/abstract_operation.py +15 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/operations/atomic_sets.py +18 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/operations/average_branching_factor.py +14 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/operations/commonality.py +19 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/operations/configurations.py +15 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/operations/configurations_number.py +14 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/operations/core_features.py +15 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/operations/count_leafs.py +14 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/operations/dead_features.py +16 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/operations/error_detection.py +15 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/operations/error_diagnosis.py +15 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/operations/estimated_configurations_number.py +14 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/operations/false_optional_features.py +17 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/operations/filter.py +20 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/operations/metrics_operation.py +105 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/operations/sampling.py +30 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/operations/satisfiable.py +14 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/operations/satisfiable_configuration.py +19 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/operations/variability.py +14 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/plugins.py +194 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/transformations/__init__.py +6 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/transformations/abstract_transformation.py +10 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/transformations/model_to_model.py +21 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/transformations/model_to_text.py +20 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/transformations/text_to_model.py +20 -0
- flamapy-fw-2.0.0.dev0/flamapy/core/utils.py +9 -0
- flamapy-fw-2.0.0.dev0/flamapy/endpoint/diverso_lab.py +89 -0
- flamapy-fw-2.0.0.dev0/flamapy/metamodels/configuration_metamodel/__init__.py +0 -0
- flamapy-fw-2.0.0.dev0/flamapy/metamodels/configuration_metamodel/models/__init__.py +3 -0
- flamapy-fw-2.0.0.dev0/flamapy/metamodels/configuration_metamodel/models/configuration.py +32 -0
- flamapy-fw-2.0.0.dev0/flamapy/metamodels/configuration_metamodel/transformations/__init__.py +4 -0
- flamapy-fw-2.0.0.dev0/flamapy/metamodels/configuration_metamodel/transformations/configuration_basic_reader.py +34 -0
- flamapy-fw-2.0.0.dev0/flamapy_fw.egg-info/PKG-INFO +41 -0
- flamapy-fw-2.0.0.dev0/flamapy_fw.egg-info/SOURCES.txt +49 -0
- flamapy-fw-2.0.0.dev0/flamapy_fw.egg-info/dependency_links.txt +1 -0
- flamapy-fw-2.0.0.dev0/flamapy_fw.egg-info/entry_points.txt +3 -0
- flamapy-fw-2.0.0.dev0/flamapy_fw.egg-info/requires.txt +7 -0
- flamapy-fw-2.0.0.dev0/flamapy_fw.egg-info/top_level.txt +1 -0
- flamapy-fw-2.0.0.dev0/setup.cfg +4 -0
- flamapy-fw-2.0.0.dev0/setup.py +38 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: flamapy-fw
|
|
3
|
+
Version: 2.0.0.dev0
|
|
4
|
+
Summary: Flamapy is a Python-based AAFM framework that takes into consideration previous AAFM tool designs and enables multi-solver and multi-metamodel support for the integration of AAFM tooling on the Python ecosystem.
|
|
5
|
+
Home-page: https://github.com/flamapy/core
|
|
6
|
+
Author: Flamapy
|
|
7
|
+
Author-email: flamapy@us.es
|
|
8
|
+
License: UNKNOWN
|
|
9
|
+
Platform: UNKNOWN
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Requires-Python: >=3.9
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
Provides-Extra: dev
|
|
16
|
+
|
|
17
|
+
# Flamapy
|
|
18
|
+
Flamapy is a Python-based AAFM framework that takes into consideration previous AAFM tool designs and enables multi-solver and multi-metamodel support for the integration of AAFM tooling on the Python ecosystem.
|
|
19
|
+
|
|
20
|
+
The main features of the framework are:
|
|
21
|
+
* Easy to extend by enabling the creation of new plugins following a semi-automatic generator approach.
|
|
22
|
+
* Support multiple variability models. Currently, it provides support for cardinality-based feature models. However, it is easy to integrate others such as attributed feature models
|
|
23
|
+
* Support multiple solvers. Currently, it provides support for the PySAT metasolver, which enables more than ten different solvers.
|
|
24
|
+
* Support multiple operations. It is developed, having in mind multi-model operations such as those depicted by Familiar and single-model operations.
|
|
25
|
+
|
|
26
|
+
## Available plugins
|
|
27
|
+
[flamapy-fm](https://github.com/flamapy/fm_metamodel)
|
|
28
|
+
[flamapy-sat](https://github.com/flamapy/pysat_metamodel)
|
|
29
|
+
|
|
30
|
+
## Documentation
|
|
31
|
+
|
|
32
|
+
All the proyect related documentation can be found in wiki format at [the tool website](https://flamapy.github.io/)
|
|
33
|
+
|
|
34
|
+
## Changelog
|
|
35
|
+
Detailed changes for each release are documented in the [release notes](https://github.com/diverso-lab/core/releases)
|
|
36
|
+
|
|
37
|
+
## Contributing
|
|
38
|
+
|
|
39
|
+
See [CONTRIBUTING.md](https://github.com/diverso-lab/core/blob/master/CONTRIBUTING.md)
|
|
40
|
+
|
|
41
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Flamapy
|
|
2
|
+
Flamapy is a Python-based AAFM framework that takes into consideration previous AAFM tool designs and enables multi-solver and multi-metamodel support for the integration of AAFM tooling on the Python ecosystem.
|
|
3
|
+
|
|
4
|
+
The main features of the framework are:
|
|
5
|
+
* Easy to extend by enabling the creation of new plugins following a semi-automatic generator approach.
|
|
6
|
+
* Support multiple variability models. Currently, it provides support for cardinality-based feature models. However, it is easy to integrate others such as attributed feature models
|
|
7
|
+
* Support multiple solvers. Currently, it provides support for the PySAT metasolver, which enables more than ten different solvers.
|
|
8
|
+
* Support multiple operations. It is developed, having in mind multi-model operations such as those depicted by Familiar and single-model operations.
|
|
9
|
+
|
|
10
|
+
## Available plugins
|
|
11
|
+
[flamapy-fm](https://github.com/flamapy/fm_metamodel)
|
|
12
|
+
[flamapy-sat](https://github.com/flamapy/pysat_metamodel)
|
|
13
|
+
|
|
14
|
+
## Documentation
|
|
15
|
+
|
|
16
|
+
All the proyect related documentation can be found in wiki format at [the tool website](https://flamapy.github.io/)
|
|
17
|
+
|
|
18
|
+
## Changelog
|
|
19
|
+
Detailed changes for each release are documented in the [release notes](https://github.com/diverso-lab/core/releases)
|
|
20
|
+
|
|
21
|
+
## Contributing
|
|
22
|
+
|
|
23
|
+
See [CONTRIBUTING.md](https://github.com/diverso-lab/core/blob/master/CONTRIBUTING.md)
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#!/usr/bin/python
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from shutil import copytree
|
|
8
|
+
|
|
9
|
+
from hug import development_runner
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def parser() -> argparse.ArgumentParser:
|
|
13
|
+
main_parser = argparse.ArgumentParser()
|
|
14
|
+
subparser = main_parser.add_subparsers(title="commands", dest="command")
|
|
15
|
+
|
|
16
|
+
new_plugin = subparser.add_parser("new_plugin", help="new_plugin")
|
|
17
|
+
new_plugin.add_argument('name', type=str, help='A name for your plugin. Ex: flama')
|
|
18
|
+
new_plugin.add_argument('extension', type=str, help='A extension for your plugin. Ex: fm')
|
|
19
|
+
new_plugin.add_argument('--path', default='.', type=str, help='Plugin project path.')
|
|
20
|
+
|
|
21
|
+
subparser.add_parser("cli", help="cli", description='flamapy_admin.py api: command line api')
|
|
22
|
+
return main_parser
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def cmd_new_plugin(options: argparse.Namespace) -> None:
|
|
26
|
+
name = options.name
|
|
27
|
+
ext = options.extension
|
|
28
|
+
dst = options.path
|
|
29
|
+
src = 'skel_metamodel/'
|
|
30
|
+
|
|
31
|
+
# Check DST exist
|
|
32
|
+
if not os.path.isdir(dst):
|
|
33
|
+
print(f"Folder {dst} not exist")
|
|
34
|
+
sys.exit()
|
|
35
|
+
|
|
36
|
+
# Check DST is empty
|
|
37
|
+
if len(os.listdir(dst)) != 0:
|
|
38
|
+
print(f"Folder {dst} is not empty")
|
|
39
|
+
sys.exit()
|
|
40
|
+
|
|
41
|
+
# Check DST has permissions to WRITE
|
|
42
|
+
if not os.access(dst, os.W_OK):
|
|
43
|
+
print(f"Folder {dst} has not write permissions")
|
|
44
|
+
sys.exit()
|
|
45
|
+
|
|
46
|
+
# Generating structure
|
|
47
|
+
print("Generating structure ...")
|
|
48
|
+
|
|
49
|
+
copy_files = copytree(src, dst, dirs_exist_ok=True)
|
|
50
|
+
|
|
51
|
+
for copy_file in Path(copy_files).glob('**/*'):
|
|
52
|
+
if copy_file.is_dir():
|
|
53
|
+
continue
|
|
54
|
+
with open(copy_file, "r", encoding="utf-8") as file:
|
|
55
|
+
lines = file.readlines()
|
|
56
|
+
with open(copy_file, "w", encoding="utf-8") as filewrite:
|
|
57
|
+
for line in lines:
|
|
58
|
+
out_line = line.replace('__NAME__', name.capitalize()).replace('__EXT__', ext)
|
|
59
|
+
filewrite.write(out_line)
|
|
60
|
+
|
|
61
|
+
os.rename(os.path.join(dst, 'flamapy/metamodels/__NAME__'),
|
|
62
|
+
os.path.join(dst, f'flamapy/metamodels/{name}'))
|
|
63
|
+
print("Done!")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def cmd_cli() -> None:
|
|
67
|
+
subcommand = sys.argv[2:]
|
|
68
|
+
if not subcommand:
|
|
69
|
+
subcommand = ["help"]
|
|
70
|
+
sys.argv = [".", "-m", "flamapy.endpoint.diverso_lab", "cli", "-c"] + subcommand
|
|
71
|
+
development_runner.hug.interface.cli()
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def flamapy_admin() -> None:
|
|
75
|
+
main_parser = parser()
|
|
76
|
+
|
|
77
|
+
options, _ = main_parser.parse_known_args()
|
|
78
|
+
command = options.command
|
|
79
|
+
|
|
80
|
+
if command is None:
|
|
81
|
+
main_parser.print_help()
|
|
82
|
+
sys.exit()
|
|
83
|
+
|
|
84
|
+
if command == "new_plugin":
|
|
85
|
+
cmd_new_plugin(options)
|
|
86
|
+
|
|
87
|
+
if command == "cli":
|
|
88
|
+
cmd_cli()
|
|
File without changes
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
import logging
|
|
3
|
+
from importlib import import_module
|
|
4
|
+
from pkgutil import iter_modules
|
|
5
|
+
from types import ModuleType
|
|
6
|
+
from typing import Any, Optional, Protocol, Type, runtime_checkable, cast
|
|
7
|
+
|
|
8
|
+
from flamapy.core.config import PLUGIN_PATHS
|
|
9
|
+
from flamapy.core.exceptions import OperationNotFound
|
|
10
|
+
from flamapy.core.exceptions import TransformationNotFound
|
|
11
|
+
from flamapy.core.exceptions import ConfigurationNotFound
|
|
12
|
+
from flamapy.core.models import VariabilityModel
|
|
13
|
+
from flamapy.core.operations import Operation
|
|
14
|
+
from flamapy.core.plugins import (
|
|
15
|
+
Operations,
|
|
16
|
+
Plugin,
|
|
17
|
+
Plugins
|
|
18
|
+
)
|
|
19
|
+
from flamapy.core.transformations import Transformation
|
|
20
|
+
from flamapy.core.transformations.text_to_model import TextToModel
|
|
21
|
+
from flamapy.core.transformations.model_to_model import ModelToModel
|
|
22
|
+
from flamapy.metamodels.configuration_metamodel.models.configuration import Configuration
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
LOGGER = logging.getLogger('discover')
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@runtime_checkable
|
|
29
|
+
class OperationWithConfiguration(Protocol):
|
|
30
|
+
def set_configuration(self, configuration: Configuration) -> None:
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def filter_modules_from_plugin_paths() -> list[ModuleType]:
|
|
35
|
+
results: list[ModuleType] = []
|
|
36
|
+
for path in PLUGIN_PATHS:
|
|
37
|
+
try:
|
|
38
|
+
module: ModuleType = import_module(path)
|
|
39
|
+
results.append(module)
|
|
40
|
+
except ModuleNotFoundError:
|
|
41
|
+
LOGGER.exception('ModuleNotFoundError %s', path)
|
|
42
|
+
return results
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class DiscoverMetamodels:
|
|
46
|
+
def __init__(self) -> None:
|
|
47
|
+
self.module_paths = filter_modules_from_plugin_paths()
|
|
48
|
+
self.plugins: Plugins = self.discover()
|
|
49
|
+
|
|
50
|
+
def search_classes(self, module: ModuleType) -> list[Any]:
|
|
51
|
+
classes = []
|
|
52
|
+
for _, file_name, ispkg in iter_modules(
|
|
53
|
+
module.__path__, module.__name__ + '.'
|
|
54
|
+
):
|
|
55
|
+
if ispkg:
|
|
56
|
+
classes += self.search_classes(import_module(file_name))
|
|
57
|
+
else:
|
|
58
|
+
_file = import_module(file_name)
|
|
59
|
+
classes += inspect.getmembers(_file, inspect.isclass)
|
|
60
|
+
return classes
|
|
61
|
+
|
|
62
|
+
def discover(self) -> Plugins:
|
|
63
|
+
plugins = Plugins()
|
|
64
|
+
for pkg in self.module_paths:
|
|
65
|
+
for _, plugin_name, ispkg in iter_modules(
|
|
66
|
+
pkg.__path__, pkg.__name__ + '.'
|
|
67
|
+
):
|
|
68
|
+
if not ispkg:
|
|
69
|
+
continue
|
|
70
|
+
module = import_module(plugin_name)
|
|
71
|
+
plugin = Plugin(module=module)
|
|
72
|
+
|
|
73
|
+
classes = self.search_classes(module)
|
|
74
|
+
|
|
75
|
+
for _, _class in classes:
|
|
76
|
+
if not _class.__module__.startswith(module.__package__):
|
|
77
|
+
continue # Exclude modules not in current package
|
|
78
|
+
inherit = _class.mro()
|
|
79
|
+
|
|
80
|
+
if Operation in inherit:
|
|
81
|
+
plugin.append_operation(_class)
|
|
82
|
+
elif Transformation in inherit:
|
|
83
|
+
plugin.append_transformations(_class)
|
|
84
|
+
elif VariabilityModel in inherit:
|
|
85
|
+
plugin.variability_model = _class
|
|
86
|
+
plugins.append(plugin)
|
|
87
|
+
return plugins
|
|
88
|
+
|
|
89
|
+
def reload(self) -> None:
|
|
90
|
+
self.plugins = self.discover()
|
|
91
|
+
|
|
92
|
+
def get_operations(self) -> list[Type[Operation]]:
|
|
93
|
+
""" Get the operations for all modules """
|
|
94
|
+
operations: list[Type[Operation]] = []
|
|
95
|
+
for plugin in self.plugins:
|
|
96
|
+
operations += plugin.operations
|
|
97
|
+
return operations
|
|
98
|
+
|
|
99
|
+
def get_name_operations(self) -> list[str]:
|
|
100
|
+
operations = []
|
|
101
|
+
for operation in self.get_operations():
|
|
102
|
+
operations.append(operation.__name__)
|
|
103
|
+
base = operation.__base__.__name__
|
|
104
|
+
if base != 'ABC':
|
|
105
|
+
operations.append(base)
|
|
106
|
+
|
|
107
|
+
return operations
|
|
108
|
+
|
|
109
|
+
def get_transformations(self) -> list[Type[Transformation]]:
|
|
110
|
+
""" Get transformations for all modules """
|
|
111
|
+
transformations: list[Type[Transformation]] = []
|
|
112
|
+
for plugin in self.plugins:
|
|
113
|
+
transformations += plugin.transformations
|
|
114
|
+
return transformations
|
|
115
|
+
|
|
116
|
+
def get_transformations_t2m(self) -> list[Type[TextToModel]]:
|
|
117
|
+
""" Get t2m transformations for all modules """
|
|
118
|
+
|
|
119
|
+
transformations: list[Type[TextToModel]] = []
|
|
120
|
+
for plugin in self.plugins:
|
|
121
|
+
transformations += [
|
|
122
|
+
t for t in plugin.transformations if issubclass(t, TextToModel)
|
|
123
|
+
]
|
|
124
|
+
return transformations
|
|
125
|
+
|
|
126
|
+
def get_transformations_m2m(self) -> list[Type[ModelToModel]]:
|
|
127
|
+
""" Get m2m transformations for all modules """
|
|
128
|
+
|
|
129
|
+
transformations: list[Type[ModelToModel]] = []
|
|
130
|
+
for plugin in self.plugins:
|
|
131
|
+
transformations += [
|
|
132
|
+
t for t in plugin.transformations if issubclass(t, ModelToModel)
|
|
133
|
+
]
|
|
134
|
+
return transformations
|
|
135
|
+
|
|
136
|
+
def get_operations_by_plugin(self, plugin_name: str) -> Operations:
|
|
137
|
+
return self.plugins.get_operations_by_plugin_name(plugin_name)
|
|
138
|
+
|
|
139
|
+
def get_plugins_with_operation(self, operation_name: str) -> list[Plugin]:
|
|
140
|
+
return [
|
|
141
|
+
plugin for plugin in self.plugins
|
|
142
|
+
if operation_name in self.get_name_operations_by_plugin(plugin.name)
|
|
143
|
+
]
|
|
144
|
+
|
|
145
|
+
def get_name_operations_by_plugin(self, plugin_name: str) -> list[str]:
|
|
146
|
+
operations = []
|
|
147
|
+
for operation in self.get_operations_by_plugin(plugin_name):
|
|
148
|
+
operations.append(operation.__name__)
|
|
149
|
+
base = operation.__base__.__name__
|
|
150
|
+
if base != 'ABC':
|
|
151
|
+
operations.append(base)
|
|
152
|
+
|
|
153
|
+
return operations
|
|
154
|
+
|
|
155
|
+
def get_variability_models(self) -> list[VariabilityModel]:
|
|
156
|
+
return self.plugins.get_variability_models()
|
|
157
|
+
|
|
158
|
+
def get_plugins(self) -> list[str]:
|
|
159
|
+
return self.plugins.get_plugin_names()
|
|
160
|
+
|
|
161
|
+
def use_transformation_m2t(self, src: VariabilityModel, dst: str) -> str:
|
|
162
|
+
plugin = self.plugins.get_plugin_by_variability_model(src)
|
|
163
|
+
return plugin.use_transformation_m2t(src, dst)
|
|
164
|
+
|
|
165
|
+
def use_transformation_t2m(self, src: str, dst: str) -> VariabilityModel:
|
|
166
|
+
plugin = self.plugins.get_plugin_by_extension(dst)
|
|
167
|
+
return plugin.use_transformation_t2m(src)
|
|
168
|
+
|
|
169
|
+
def use_transformation_m2m(self, src: VariabilityModel, dst: str) -> VariabilityModel:
|
|
170
|
+
plugin = self.plugins.get_plugin_by_extension(dst)
|
|
171
|
+
return plugin.use_transformation_m2m(src, dst)
|
|
172
|
+
|
|
173
|
+
def get_operation(self, src: VariabilityModel, operation_name: str) -> Operation:
|
|
174
|
+
plugin = self.plugins.get_plugin_by_variability_model(src)
|
|
175
|
+
return plugin.get_operation(operation_name)
|
|
176
|
+
|
|
177
|
+
def use_operation(self, src: VariabilityModel, operation_name: str) -> Operation:
|
|
178
|
+
plugin = self.plugins.get_plugin_by_variability_model(src)
|
|
179
|
+
operation = plugin.get_operation(operation_name)
|
|
180
|
+
return plugin.use_operation(operation, src)
|
|
181
|
+
|
|
182
|
+
def use_operation_from_vm(
|
|
183
|
+
self,
|
|
184
|
+
operation_name: str,
|
|
185
|
+
vm_orig: VariabilityModel,
|
|
186
|
+
plugin_name: Optional[str] = None,
|
|
187
|
+
configuration_file: Optional[str] = None
|
|
188
|
+
) -> Any:
|
|
189
|
+
|
|
190
|
+
if operation_name not in self.get_name_operations():
|
|
191
|
+
raise OperationNotFound()
|
|
192
|
+
|
|
193
|
+
if plugin_name is not None:
|
|
194
|
+
plugin = self.plugins.get_plugin_by_name(plugin_name)
|
|
195
|
+
#vm_temp = plugin.use_transformation_t2m(file)
|
|
196
|
+
else:
|
|
197
|
+
#vm_temp = self.__transform_to_model_from_file(file)
|
|
198
|
+
plugin = self.plugins.get_plugin_by_extension(
|
|
199
|
+
vm_orig.get_extension())
|
|
200
|
+
|
|
201
|
+
if operation_name not in self.get_name_operations_by_plugin(plugin.name):
|
|
202
|
+
transformation_way = self.__search_transformation_way(
|
|
203
|
+
plugin, operation_name)
|
|
204
|
+
|
|
205
|
+
for (_, dst) in transformation_way:
|
|
206
|
+
_plugin = self.plugins.get_plugin_by_extension(dst)
|
|
207
|
+
vm_temp = _plugin.use_transformation_m2m(vm_temp, dst)
|
|
208
|
+
plugin = _plugin
|
|
209
|
+
|
|
210
|
+
operation = plugin.get_operation(operation_name)
|
|
211
|
+
if isinstance(operation, OperationWithConfiguration):
|
|
212
|
+
if configuration_file is None:
|
|
213
|
+
raise ConfigurationNotFound()
|
|
214
|
+
configuration = self.__transform_to_model_from_file(configuration_file)
|
|
215
|
+
operation.set_configuration(cast(Configuration, configuration))
|
|
216
|
+
|
|
217
|
+
operation = plugin.use_operation(operation, vm_temp)
|
|
218
|
+
|
|
219
|
+
return operation.get_result()
|
|
220
|
+
|
|
221
|
+
def use_operation_from_file(
|
|
222
|
+
self,
|
|
223
|
+
operation_name: str,
|
|
224
|
+
file: str,
|
|
225
|
+
plugin_name: Optional[str] = None,
|
|
226
|
+
configuration_file: Optional[str] = None
|
|
227
|
+
) -> Any:
|
|
228
|
+
|
|
229
|
+
if operation_name not in self.get_name_operations():
|
|
230
|
+
raise OperationNotFound()
|
|
231
|
+
|
|
232
|
+
if plugin_name is not None:
|
|
233
|
+
plugin = self.plugins.get_plugin_by_name(plugin_name)
|
|
234
|
+
vm_temp = plugin.use_transformation_t2m(file)
|
|
235
|
+
else:
|
|
236
|
+
vm_temp = self.__transform_to_model_from_file(file)
|
|
237
|
+
plugin = self.plugins.get_plugin_by_extension(
|
|
238
|
+
vm_temp.get_extension())
|
|
239
|
+
|
|
240
|
+
if operation_name not in self.get_name_operations_by_plugin(plugin.name):
|
|
241
|
+
transformation_way = self.__search_transformation_way(
|
|
242
|
+
plugin, operation_name)
|
|
243
|
+
|
|
244
|
+
for (_, dst) in transformation_way:
|
|
245
|
+
_plugin = self.plugins.get_plugin_by_extension(dst)
|
|
246
|
+
vm_temp = _plugin.use_transformation_m2m(vm_temp, dst)
|
|
247
|
+
plugin = _plugin
|
|
248
|
+
|
|
249
|
+
operation = plugin.get_operation(operation_name)
|
|
250
|
+
if isinstance(operation, OperationWithConfiguration):
|
|
251
|
+
if configuration_file is None:
|
|
252
|
+
raise ConfigurationNotFound()
|
|
253
|
+
configuration = self.__transform_to_model_from_file(configuration_file)
|
|
254
|
+
operation.set_configuration(cast(Configuration, configuration))
|
|
255
|
+
|
|
256
|
+
operation = plugin.use_operation(operation, vm_temp)
|
|
257
|
+
return operation.get_result()
|
|
258
|
+
|
|
259
|
+
def __transform_to_model_from_file(self, file: str) -> VariabilityModel:
|
|
260
|
+
t2m_transformations = self.get_transformations_t2m()
|
|
261
|
+
extension = file.split('.')[-1]
|
|
262
|
+
t2m_filters = filter(
|
|
263
|
+
lambda t2m: t2m.get_source_extension() == extension,
|
|
264
|
+
t2m_transformations
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
t2m = next(t2m_filters, None)
|
|
268
|
+
if t2m is None:
|
|
269
|
+
raise TransformationNotFound()
|
|
270
|
+
|
|
271
|
+
return t2m(file).transform()
|
|
272
|
+
|
|
273
|
+
def __search_transformation_way(
|
|
274
|
+
self,
|
|
275
|
+
plugin: Plugin,
|
|
276
|
+
operation_name: str
|
|
277
|
+
) -> list[tuple[str, str]]:
|
|
278
|
+
'''
|
|
279
|
+
Search way to reach plugin with operation_name using m2m transformations
|
|
280
|
+
'''
|
|
281
|
+
way: list[tuple[str, str]] = []
|
|
282
|
+
|
|
283
|
+
plugins_with_operation = self.get_plugins_with_operation(
|
|
284
|
+
operation_name)
|
|
285
|
+
m2m_transformations = self.get_transformations_m2m()
|
|
286
|
+
|
|
287
|
+
input_extension = plugin.get_extension()
|
|
288
|
+
|
|
289
|
+
def __search_recursive_way(
|
|
290
|
+
input_extension: str,
|
|
291
|
+
output_extension: str,
|
|
292
|
+
tmp_way: list[tuple[str, str]]
|
|
293
|
+
) -> list[tuple[str, str]]:
|
|
294
|
+
|
|
295
|
+
for m2m in m2m_transformations:
|
|
296
|
+
in_m2m = m2m.get_source_extension()
|
|
297
|
+
out_m2m = m2m.get_destination_extension()
|
|
298
|
+
|
|
299
|
+
if out_m2m == output_extension:
|
|
300
|
+
_next = (in_m2m, out_m2m)
|
|
301
|
+
|
|
302
|
+
if _next in tmp_way:
|
|
303
|
+
continue
|
|
304
|
+
|
|
305
|
+
tmp_way.insert(0, _next)
|
|
306
|
+
|
|
307
|
+
if input_extension == in_m2m:
|
|
308
|
+
return tmp_way
|
|
309
|
+
|
|
310
|
+
return __search_recursive_way(input_extension, in_m2m, tmp_way)
|
|
311
|
+
|
|
312
|
+
return tmp_way
|
|
313
|
+
|
|
314
|
+
for _plugin in plugins_with_operation:
|
|
315
|
+
output_extension = _plugin.get_extension()
|
|
316
|
+
way = __search_recursive_way(input_extension, output_extension, [])
|
|
317
|
+
if way and output_extension == way[-1][1]:
|
|
318
|
+
return way
|
|
319
|
+
|
|
320
|
+
raise NotImplementedError('Way to execute operation not found')
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
class FlamaException(Exception):
|
|
2
|
+
pass
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ParsingException(Exception):
|
|
6
|
+
pass
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class PluginNotFound(FlamaException):
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class OperationNotFound(FlamaException):
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class TransformationNotFound(FlamaException):
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ElementNotFound(FlamaException):
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class DuplicatedFeature(FlamaException):
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class ConfigurationNotFound(FlamaException):
|
|
30
|
+
pass
|