flamapy 2.0.0.dev2__tar.gz → 2.0.0.dev3__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-2.0.0.dev3/PKG-INFO +100 -0
- flamapy-2.0.0.dev3/README.md +82 -0
- flamapy-2.0.0.dev3/flamapy/commands/__init__.py +168 -0
- flamapy-2.0.0.dev3/flamapy/interfaces/python/__init__.py +5 -0
- flamapy-2.0.0.dev2/flamapy/interfaces/python/FLAMAFeatureModel.py → flamapy-2.0.0.dev3/flamapy/interfaces/python/flamapy_feature_model.py +133 -132
- flamapy-2.0.0.dev3/flamapy.egg-info/PKG-INFO +100 -0
- {flamapy-2.0.0.dev2 → flamapy-2.0.0.dev3}/flamapy.egg-info/SOURCES.txt +3 -3
- flamapy-2.0.0.dev3/flamapy.egg-info/entry_points.txt +3 -0
- flamapy-2.0.0.dev3/flamapy.egg-info/requires.txt +12 -0
- {flamapy-2.0.0.dev2 → flamapy-2.0.0.dev3}/setup.py +2 -2
- flamapy-2.0.0.dev2/PKG-INFO +0 -84
- flamapy-2.0.0.dev2/README.md +0 -66
- flamapy-2.0.0.dev2/flamapy/interfaces/__init__.py +0 -0
- flamapy-2.0.0.dev2/flamapy/interfaces/python/__init__.py +0 -0
- flamapy-2.0.0.dev2/flamapy.egg-info/PKG-INFO +0 -84
- flamapy-2.0.0.dev2/flamapy.egg-info/entry_points.txt +0 -3
- flamapy-2.0.0.dev2/flamapy.egg-info/requires.txt +0 -12
- {flamapy-2.0.0.dev2 → flamapy-2.0.0.dev3}/flamapy.egg-info/dependency_links.txt +0 -0
- {flamapy-2.0.0.dev2 → flamapy-2.0.0.dev3}/flamapy.egg-info/top_level.txt +0 -0
- {flamapy-2.0.0.dev2 → flamapy-2.0.0.dev3}/setup.cfg +0 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: flamapy
|
|
3
|
+
Version: 2.0.0.dev3
|
|
4
|
+
Summary: Flamapy feature model is a distribution of the flama framework containing all plugins required to analyze feature models. It also offers a richier API and a complete command line interface and documentation.
|
|
5
|
+
Home-page: https://github.com/flamapy/flamapy-feature-model
|
|
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
|
+
<div align="center">
|
|
18
|
+
|
|
19
|
+
<a href="">[](https://github.com/flamapy/flamapy/actions/workflows/tests.yml)</a>
|
|
20
|
+
<a href="">[](https://github.com/flamapy/flamapy/actions/workflows/commits.yml)</a>
|
|
21
|
+
<a href="">
|
|
22
|
+
<a href="">
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
#
|
|
26
|
+
|
|
27
|
+
<div id="top"></div>
|
|
28
|
+
<br />
|
|
29
|
+
<div align="center">
|
|
30
|
+
|
|
31
|
+
<h3 align="center">FLAMAPY</h3>
|
|
32
|
+
|
|
33
|
+
<p align="center">
|
|
34
|
+
A new and easy way to use FLAMA
|
|
35
|
+
<br />
|
|
36
|
+
<a href="https://github.com/flamapy/flamapy/issues">Report Bug</a>
|
|
37
|
+
·
|
|
38
|
+
<a href="https://github.com/flamapy/flamapy/issues">Request Feature</a>
|
|
39
|
+
</p>
|
|
40
|
+
</div>
|
|
41
|
+
<!-- ABOUT THE PROJECT -->
|
|
42
|
+
|
|
43
|
+
# About The Project
|
|
44
|
+
FLAMAPY Feature model distribution provides an easier way of using FLAMAPY when analysing feature models. It packs the most used plugins for analyis of feature models adding a layer of convenience to use the framework or integrate it. If some other operations are required please see in the [documentation](flamapy.github.io/docs) if its supported in the ecosystem though the Python interface.
|
|
45
|
+
|
|
46
|
+
Feature Model Analysis has a crucial role in software product line engineering, enabling us to understand, design, and validate the complex relationships among features in a software product line. These feature models can often be complex and challenging to analyze due to their variability, making it difficult to identify conflicts, dead features, and potential optimizations. This is where this distribution comes in.
|
|
47
|
+
|
|
48
|
+
# Using the CMD
|
|
49
|
+
```bash
|
|
50
|
+
flamapy --help #This will show the commands available
|
|
51
|
+
flamapy satisfiable <path to file> to check if a model is valid
|
|
52
|
+
...
|
|
53
|
+
```
|
|
54
|
+
# Using the Python interface
|
|
55
|
+
This is simple, Flama FM dist in hosted in pypi, therefore simply add the package flama-fm-dist to your requirements file and call the API as follows:
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from flamapy.interfaces.python.flama_feature_model import FLAMAFeatureModel
|
|
59
|
+
|
|
60
|
+
fm = FLAMAFeatureModel("path/to/feature/model")
|
|
61
|
+
print(fm.valid())
|
|
62
|
+
```
|
|
63
|
+
# Operations available:
|
|
64
|
+
Currently this distribution offers a subset of the operations available in the ecosystem, in the case of the feature mdoel distribution, we provide those operations that are well tested and used by the community. Nonetheless, If other more complex operations are required you can rely on the python interface of the framework to execute them all.
|
|
65
|
+
|
|
66
|
+
* atomic_sets: This operation is used to find the atomic sets in a model: It returns the atomic sets if they are found in the model. If the model does not follow the UVL specification, an exception is raised and the operation returns False.
|
|
67
|
+
|
|
68
|
+
* average_branching_factor:This refers to the average number of child features that a parent feature has in a feature model. It's calculated by dividing the total number of child features by the total number of parent features. A high average branching factor indicates a complex feature model with many options, while a low average branching factor indicates a simpler model.
|
|
69
|
+
|
|
70
|
+
* commonality: This is a measure of how often a feature appears in the products of a product line. It's usually expressed as a percentage. A feature with 100 per cent commonality is a core feature, as it appears in all products.
|
|
71
|
+
|
|
72
|
+
* configurations: These are the individual outcomes that can be produced from a feature model. Each product is a combination of features that satisfies all the constraints and dependencies in the feature model.
|
|
73
|
+
|
|
74
|
+
* configurations_number: This is the total number of different full configurations that can be produced from a feature model. It's calculated by considering all possible combinations of features, taking into account the constraints and dependencies between features.
|
|
75
|
+
|
|
76
|
+
* core_features: These are the features that are present in all products of a product line. In a feature model, they are the features that are mandatory and not optional. Core features define the commonality among all products in a product line. This call requires sat to be called, however, there is an implementation within flamapy that does not requires sat, please use the framework in case of needing it.
|
|
77
|
+
|
|
78
|
+
* count_leafs: This operation counts the number of leaf features in a feature model. Leaf features are those that do not have any child features. They represent the most specific options in a product line.
|
|
79
|
+
* dead_features: These are features that, due to the constraints and dependencies in the feature model, cannot be included in any valid product. Dead features are usually a sign of an error in the feature model.
|
|
80
|
+
|
|
81
|
+
* estimated_number_of_configurations: This is an estimate of the total number of different products that can be produced from a feature model. It's calculated by considering all possible combinations of features. This can be a simple multiplication if all
|
|
82
|
+
features are independent, but in most cases, constraints and dependencies between features need to be taken into account.
|
|
83
|
+
|
|
84
|
+
* false_optional_features: These are features that appear to be optional in the feature model, but due to the constraints and dependencies, must be included in every valid product. Like dead features, false optional features are usually a sign of an error in the feature model.
|
|
85
|
+
|
|
86
|
+
* feature_ancestors: These are the features that are directly or indirectly the parent of a given feature in a feature model. Ancestors of a feature are found by traversing up the feature hierarchy. This information can be useful to understand the context and dependencies of a feature.
|
|
87
|
+
|
|
88
|
+
* filter: This operation selects a subset of the products of a product line based on certain criteria. For example, youmight filter the products to only include those that contain a certain feature.
|
|
89
|
+
|
|
90
|
+
* leaf_features: This operation is used to find leaf features in a model: It returns the leaf features if they are found in themodel. If the model does not follow the UVL specification, an exception is raised and the operation returns False.
|
|
91
|
+
|
|
92
|
+
* max_depth: This operation is used to find the max depth of the tree in a model: It returns the max depth of the tree. If the model does not follow the UVL specification, an exception is raised and the operation returns False.
|
|
93
|
+
|
|
94
|
+
* satisfiable: In the context of feature models, this usually refers to whether the feature model itself satisfies all the
|
|
95
|
+
constraints and dependencies. A a valid feature model is one that does encodes at least a single valid product.
|
|
96
|
+
|
|
97
|
+
* satisfiable_configuration: This is a product that is produced from a valid configuration of features. A valid product satisfies all the constraints and dependencies in the feature model.
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<a href="">[](https://github.com/flamapy/flamapy/actions/workflows/tests.yml)</a>
|
|
4
|
+
<a href="">[](https://github.com/flamapy/flamapy/actions/workflows/commits.yml)</a>
|
|
5
|
+
<a href="">
|
|
6
|
+
<a href="">
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
<div id="top"></div>
|
|
12
|
+
<br />
|
|
13
|
+
<div align="center">
|
|
14
|
+
|
|
15
|
+
<h3 align="center">FLAMAPY</h3>
|
|
16
|
+
|
|
17
|
+
<p align="center">
|
|
18
|
+
A new and easy way to use FLAMA
|
|
19
|
+
<br />
|
|
20
|
+
<a href="https://github.com/flamapy/flamapy/issues">Report Bug</a>
|
|
21
|
+
·
|
|
22
|
+
<a href="https://github.com/flamapy/flamapy/issues">Request Feature</a>
|
|
23
|
+
</p>
|
|
24
|
+
</div>
|
|
25
|
+
<!-- ABOUT THE PROJECT -->
|
|
26
|
+
|
|
27
|
+
# About The Project
|
|
28
|
+
FLAMAPY Feature model distribution provides an easier way of using FLAMAPY when analysing feature models. It packs the most used plugins for analyis of feature models adding a layer of convenience to use the framework or integrate it. If some other operations are required please see in the [documentation](flamapy.github.io/docs) if its supported in the ecosystem though the Python interface.
|
|
29
|
+
|
|
30
|
+
Feature Model Analysis has a crucial role in software product line engineering, enabling us to understand, design, and validate the complex relationships among features in a software product line. These feature models can often be complex and challenging to analyze due to their variability, making it difficult to identify conflicts, dead features, and potential optimizations. This is where this distribution comes in.
|
|
31
|
+
|
|
32
|
+
# Using the CMD
|
|
33
|
+
```bash
|
|
34
|
+
flamapy --help #This will show the commands available
|
|
35
|
+
flamapy satisfiable <path to file> to check if a model is valid
|
|
36
|
+
...
|
|
37
|
+
```
|
|
38
|
+
# Using the Python interface
|
|
39
|
+
This is simple, Flama FM dist in hosted in pypi, therefore simply add the package flama-fm-dist to your requirements file and call the API as follows:
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
from flamapy.interfaces.python.flama_feature_model import FLAMAFeatureModel
|
|
43
|
+
|
|
44
|
+
fm = FLAMAFeatureModel("path/to/feature/model")
|
|
45
|
+
print(fm.valid())
|
|
46
|
+
```
|
|
47
|
+
# Operations available:
|
|
48
|
+
Currently this distribution offers a subset of the operations available in the ecosystem, in the case of the feature mdoel distribution, we provide those operations that are well tested and used by the community. Nonetheless, If other more complex operations are required you can rely on the python interface of the framework to execute them all.
|
|
49
|
+
|
|
50
|
+
* atomic_sets: This operation is used to find the atomic sets in a model: It returns the atomic sets if they are found in the model. If the model does not follow the UVL specification, an exception is raised and the operation returns False.
|
|
51
|
+
|
|
52
|
+
* average_branching_factor:This refers to the average number of child features that a parent feature has in a feature model. It's calculated by dividing the total number of child features by the total number of parent features. A high average branching factor indicates a complex feature model with many options, while a low average branching factor indicates a simpler model.
|
|
53
|
+
|
|
54
|
+
* commonality: This is a measure of how often a feature appears in the products of a product line. It's usually expressed as a percentage. A feature with 100 per cent commonality is a core feature, as it appears in all products.
|
|
55
|
+
|
|
56
|
+
* configurations: These are the individual outcomes that can be produced from a feature model. Each product is a combination of features that satisfies all the constraints and dependencies in the feature model.
|
|
57
|
+
|
|
58
|
+
* configurations_number: This is the total number of different full configurations that can be produced from a feature model. It's calculated by considering all possible combinations of features, taking into account the constraints and dependencies between features.
|
|
59
|
+
|
|
60
|
+
* core_features: These are the features that are present in all products of a product line. In a feature model, they are the features that are mandatory and not optional. Core features define the commonality among all products in a product line. This call requires sat to be called, however, there is an implementation within flamapy that does not requires sat, please use the framework in case of needing it.
|
|
61
|
+
|
|
62
|
+
* count_leafs: This operation counts the number of leaf features in a feature model. Leaf features are those that do not have any child features. They represent the most specific options in a product line.
|
|
63
|
+
* dead_features: These are features that, due to the constraints and dependencies in the feature model, cannot be included in any valid product. Dead features are usually a sign of an error in the feature model.
|
|
64
|
+
|
|
65
|
+
* estimated_number_of_configurations: This is an estimate of the total number of different products that can be produced from a feature model. It's calculated by considering all possible combinations of features. This can be a simple multiplication if all
|
|
66
|
+
features are independent, but in most cases, constraints and dependencies between features need to be taken into account.
|
|
67
|
+
|
|
68
|
+
* false_optional_features: These are features that appear to be optional in the feature model, but due to the constraints and dependencies, must be included in every valid product. Like dead features, false optional features are usually a sign of an error in the feature model.
|
|
69
|
+
|
|
70
|
+
* feature_ancestors: These are the features that are directly or indirectly the parent of a given feature in a feature model. Ancestors of a feature are found by traversing up the feature hierarchy. This information can be useful to understand the context and dependencies of a feature.
|
|
71
|
+
|
|
72
|
+
* filter: This operation selects a subset of the products of a product line based on certain criteria. For example, youmight filter the products to only include those that contain a certain feature.
|
|
73
|
+
|
|
74
|
+
* leaf_features: This operation is used to find leaf features in a model: It returns the leaf features if they are found in themodel. If the model does not follow the UVL specification, an exception is raised and the operation returns False.
|
|
75
|
+
|
|
76
|
+
* max_depth: This operation is used to find the max depth of the tree in a model: It returns the max depth of the tree. If the model does not follow the UVL specification, an exception is raised and the operation returns False.
|
|
77
|
+
|
|
78
|
+
* satisfiable: In the context of feature models, this usually refers to whether the feature model itself satisfies all the
|
|
79
|
+
constraints and dependencies. A a valid feature model is one that does encodes at least a single valid product.
|
|
80
|
+
|
|
81
|
+
* satisfiable_configuration: This is a product that is produced from a valid configuration of features. A valid product satisfies all the constraints and dependencies in the feature model.
|
|
82
|
+
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
from functools import wraps
|
|
5
|
+
import inspect
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from shutil import copytree
|
|
8
|
+
from typing import List, Tuple, Optional
|
|
9
|
+
from types import FunctionType
|
|
10
|
+
|
|
11
|
+
from flamapy.interfaces.python.flamapy_feature_model import FLAMAFeatureModel
|
|
12
|
+
# List to store registered commands and their arguments
|
|
13
|
+
MANUAL_COMMANDS = []
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def command(name, description, *args): # type: ignore
|
|
17
|
+
|
|
18
|
+
def decorator(func): # type: ignore
|
|
19
|
+
MANUAL_COMMANDS.append((name, description, func, args))
|
|
20
|
+
|
|
21
|
+
@wraps(func)
|
|
22
|
+
def wrapper(*func_args, **func_kwargs): # type: ignore
|
|
23
|
+
return func(*func_args, **func_kwargs)
|
|
24
|
+
return wrapper
|
|
25
|
+
return decorator
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def extract_commands(cls: type) -> List[Tuple[str, str, FunctionType, List[inspect.Parameter]]]:
|
|
29
|
+
commands = []
|
|
30
|
+
for name, method in inspect.getmembers(cls, predicate=inspect.isfunction):
|
|
31
|
+
if name.startswith("_"):
|
|
32
|
+
continue
|
|
33
|
+
docstring: Optional[str] = method.__doc__
|
|
34
|
+
signature = inspect.signature(method)
|
|
35
|
+
# Exclude 'self' from parameters
|
|
36
|
+
parameters = list(signature.parameters.values())[1:] # Skip 'self'
|
|
37
|
+
commands.append((name, docstring or "", method, parameters))
|
|
38
|
+
return commands
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@command('generate_plugin', """This command generates a new plugin to implement your
|
|
42
|
+
cusom operations. To execute it you should set yourself in the path of the
|
|
43
|
+
flamapy src directory""",
|
|
44
|
+
('name', str, 'The pluggins name'),
|
|
45
|
+
('extension', str, 'The extansion to be registered with the flamapy ecosystem'),
|
|
46
|
+
('path', str, 'The path to generate it'))
|
|
47
|
+
def generate_plugin(args): # type: ignore
|
|
48
|
+
name = args.name
|
|
49
|
+
ext = args.extension
|
|
50
|
+
dst = args.path
|
|
51
|
+
src = 'skel_metamodel/'
|
|
52
|
+
|
|
53
|
+
# Check DST exist
|
|
54
|
+
if not os.path.isdir(dst):
|
|
55
|
+
print(f"Folder {dst} not exist")
|
|
56
|
+
sys.exit()
|
|
57
|
+
|
|
58
|
+
# Check DST is empty
|
|
59
|
+
if len(os.listdir(dst)) != 0:
|
|
60
|
+
print(f"Folder {dst} is not empty")
|
|
61
|
+
sys.exit()
|
|
62
|
+
|
|
63
|
+
# Check DST has permissions to WRITE
|
|
64
|
+
if not os.access(dst, os.W_OK):
|
|
65
|
+
print(f"Folder {dst} has not write permissions")
|
|
66
|
+
sys.exit()
|
|
67
|
+
|
|
68
|
+
# Generating structure
|
|
69
|
+
print("Generating structure ...")
|
|
70
|
+
|
|
71
|
+
copy_files = copytree(src, dst, dirs_exist_ok=True)
|
|
72
|
+
|
|
73
|
+
for copy_file in Path(copy_files).glob('**/*'):
|
|
74
|
+
if copy_file.is_dir():
|
|
75
|
+
continue
|
|
76
|
+
with open(copy_file, "r", encoding="utf-8") as file:
|
|
77
|
+
lines = file.readlines()
|
|
78
|
+
with open(copy_file, "w", encoding="utf-8") as filewrite:
|
|
79
|
+
for line in lines:
|
|
80
|
+
out_line = line.replace('__NAME__', name.capitalize()).replace('__EXT__', ext)
|
|
81
|
+
filewrite.write(out_line)
|
|
82
|
+
|
|
83
|
+
os.rename(os.path.join(dst, 'flamapy/metamodels/__NAME__'),
|
|
84
|
+
os.path.join(dst, f'flamapy/metamodels/{name}'))
|
|
85
|
+
print("Plugin generated!")
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def setup_dynamic_commands(subparsers, dynamic_commands): # type: ignore
|
|
89
|
+
for name, docstring, method, parameters in dynamic_commands:
|
|
90
|
+
subparser = subparsers.add_parser(name, help=docstring)
|
|
91
|
+
subparser.add_argument('model_path', type=str, help='Path to the feature model file')
|
|
92
|
+
if 'configuration_path' in [param.name for param in parameters]:
|
|
93
|
+
subparser.add_argument('--configuration_path',
|
|
94
|
+
type=str,
|
|
95
|
+
help='Path to the configuration file',
|
|
96
|
+
required=False)
|
|
97
|
+
for param in parameters:
|
|
98
|
+
arg_name = param.name
|
|
99
|
+
if arg_name not in ['model_path']: # Avoid duplicates
|
|
100
|
+
if param.default == param.empty: # Positional argument
|
|
101
|
+
subparser.add_argument(arg_name,
|
|
102
|
+
type=param.annotation,
|
|
103
|
+
help=param.annotation.__name__)
|
|
104
|
+
else: # Optional argument
|
|
105
|
+
subparser.add_argument(f'--{arg_name}',
|
|
106
|
+
type=param.annotation,
|
|
107
|
+
default=param.default,
|
|
108
|
+
help=f'Optional {param.annotation.__name__}')
|
|
109
|
+
subparser.set_defaults(func=method, method_name=name, parameters=parameters)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def setup_manual_commands(subparsers, manual_commands): # type: ignore
|
|
113
|
+
for name, description, func, args in manual_commands:
|
|
114
|
+
subparser = subparsers.add_parser(name, help=description)
|
|
115
|
+
for arg in args:
|
|
116
|
+
arg_name, arg_type, arg_help = arg
|
|
117
|
+
subparser.add_argument(arg_name, type=arg_type, help=arg_help)
|
|
118
|
+
subparser.set_defaults(func=func)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def execute_command(args: argparse.Namespace) -> None:
|
|
122
|
+
try:
|
|
123
|
+
if hasattr(args, 'method_name'):
|
|
124
|
+
cls_instance = FLAMAFeatureModel(args.model_path)
|
|
125
|
+
method_parameters = [param.name for param in args.parameters]
|
|
126
|
+
command_args = {k: v for k, v in vars(args).items() if k in method_parameters}
|
|
127
|
+
method = getattr(cls_instance, args.method_name)
|
|
128
|
+
result = method(**command_args)
|
|
129
|
+
if result is not None:
|
|
130
|
+
print(result)
|
|
131
|
+
else:
|
|
132
|
+
func = args.func
|
|
133
|
+
command_args = {k: v for k, v in vars(args).items() if k != 'func'}
|
|
134
|
+
result = func(args)
|
|
135
|
+
if result is not None:
|
|
136
|
+
print(result)
|
|
137
|
+
except FileNotFoundError as fnf_error:
|
|
138
|
+
print(f"File not found error: {fnf_error}")
|
|
139
|
+
except TypeError as type_error:
|
|
140
|
+
print(f"Type error: {type_error}")
|
|
141
|
+
except ValueError as value_error:
|
|
142
|
+
print(f"Value error: {value_error}")
|
|
143
|
+
except KeyError as key_error:
|
|
144
|
+
print(f"Key error: {key_error}")
|
|
145
|
+
except AttributeError as attr_error:
|
|
146
|
+
print(f"Attribute error: {attr_error}")
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def flamapy_cli() -> None:
|
|
150
|
+
parser = argparse.ArgumentParser(description='FLAMA Feature Model CLI')
|
|
151
|
+
subparsers = parser.add_subparsers(dest='command')
|
|
152
|
+
|
|
153
|
+
dynamic_commands = extract_commands(FLAMAFeatureModel)
|
|
154
|
+
setup_dynamic_commands(subparsers, dynamic_commands)
|
|
155
|
+
setup_manual_commands(subparsers, MANUAL_COMMANDS)
|
|
156
|
+
|
|
157
|
+
args = parser.parse_args()
|
|
158
|
+
|
|
159
|
+
if args.command:
|
|
160
|
+
execute_command(args)
|
|
161
|
+
else:
|
|
162
|
+
print("Feature model operations:")
|
|
163
|
+
for name, docstring, _, _ in dynamic_commands:
|
|
164
|
+
print(f" {name}: {docstring}")
|
|
165
|
+
print("Framework developers operations:")
|
|
166
|
+
for name, description, _, _ in MANUAL_COMMANDS:
|
|
167
|
+
print(f" {name}: {description}")
|
|
168
|
+
print("Execute flamapy --help for more information")
|
|
@@ -1,47 +1,44 @@
|
|
|
1
|
+
from typing import List, Any, Union
|
|
1
2
|
from flamapy.core.discover import DiscoverMetamodels
|
|
2
3
|
from flamapy.metamodels.fm_metamodel.models import FeatureModel
|
|
3
|
-
from
|
|
4
|
+
from flamapy.core.exceptions import FlamaException
|
|
5
|
+
from flamapy.metamodels.configuration_metamodel.models import Configuration
|
|
4
6
|
|
|
5
|
-
class FLAMAFeatureModel():
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
class FLAMAFeatureModel:
|
|
9
|
+
|
|
10
|
+
def __init__(self, model_path: str):
|
|
8
11
|
"""
|
|
9
12
|
This is the path in the filesystem where the model is located.
|
|
10
13
|
Any model in UVL, FaMaXML or FeatureIDE format are accepted
|
|
11
14
|
"""
|
|
12
|
-
self.model_path=model_path
|
|
13
|
-
"""
|
|
14
|
-
This is the path in the filesystem where the configuration is located.
|
|
15
|
-
Only CSV format are accepted (see documentation for more information)
|
|
16
|
-
"""
|
|
17
|
-
self.configuration_path=configuration_path
|
|
15
|
+
self.model_path = model_path
|
|
18
16
|
"""
|
|
19
17
|
Creating the interface witht he flama framework
|
|
20
18
|
"""
|
|
21
|
-
self.
|
|
19
|
+
self.discover_metamodel = DiscoverMetamodels()
|
|
22
20
|
"""
|
|
23
21
|
We save the model for later ussage
|
|
24
22
|
"""
|
|
25
|
-
self.fm_model=self._read(model_path)
|
|
23
|
+
self.fm_model = self._read(model_path)
|
|
26
24
|
"""
|
|
27
25
|
We create a empty sat model and a bdd model to avoid double transformations
|
|
28
26
|
"""
|
|
29
|
-
self.sat_model=None
|
|
30
|
-
self.bdd_model=None
|
|
27
|
+
self.sat_model = None
|
|
28
|
+
self.bdd_model = None
|
|
31
29
|
|
|
30
|
+
def _read(self, model_path: str) -> FeatureModel:
|
|
31
|
+
return self.discover_metamodel.use_transformation_t2m(model_path, 'fm')
|
|
32
32
|
|
|
33
|
-
def
|
|
34
|
-
return self.dm.use_transformation_t2m(model_path,'fm')
|
|
35
|
-
|
|
36
|
-
def _transform_to_sat(self):
|
|
33
|
+
def _transform_to_sat(self) -> None:
|
|
37
34
|
if self.sat_model is None:
|
|
38
|
-
self.sat_model=self.
|
|
39
|
-
|
|
40
|
-
def _transform_to_bdd(self):
|
|
35
|
+
self.sat_model = self.discover_metamodel.use_transformation_m2m(self.fm_model, "pysat")
|
|
36
|
+
|
|
37
|
+
def _transform_to_bdd(self) -> None:
|
|
41
38
|
if self.bdd_model is None:
|
|
42
|
-
self.bdd_model=self.
|
|
39
|
+
self.bdd_model = self.discover_metamodel.use_transformation_m2m(self.fm_model, "bdd")
|
|
43
40
|
|
|
44
|
-
def atomic_sets(self):
|
|
41
|
+
def atomic_sets(self) -> Union[None, List[List[Any]]]:
|
|
45
42
|
"""
|
|
46
43
|
This operation is used to find the atomic sets in a model:
|
|
47
44
|
It returns the atomic sets if they are found in the model.
|
|
@@ -51,7 +48,8 @@ class FLAMAFeatureModel():
|
|
|
51
48
|
|
|
52
49
|
# Try to use the Find operation, which returns the atomic sets if they are found
|
|
53
50
|
try:
|
|
54
|
-
atomic_sets = self.
|
|
51
|
+
atomic_sets = self.discover_metamodel.use_operation(self.fm_model,
|
|
52
|
+
'FMAtomicSets').get_result()
|
|
55
53
|
result = []
|
|
56
54
|
for atomic_set in atomic_sets:
|
|
57
55
|
partial_set = []
|
|
@@ -59,12 +57,11 @@ class FLAMAFeatureModel():
|
|
|
59
57
|
partial_set.append(feature.name)
|
|
60
58
|
result.append(partial_set)
|
|
61
59
|
return result
|
|
62
|
-
except
|
|
63
|
-
print(f"Error: {
|
|
60
|
+
except FlamaException as exception:
|
|
61
|
+
print(f"Error: {exception}")
|
|
64
62
|
return None
|
|
65
63
|
|
|
66
|
-
|
|
67
|
-
def average_branching_factor(self):
|
|
64
|
+
def average_branching_factor(self) -> Union[None, float]:
|
|
68
65
|
"""
|
|
69
66
|
This refers to the average number of child features that a parent feature has in a
|
|
70
67
|
feature model. It's calculated by dividing the total number of child features by the
|
|
@@ -75,14 +72,14 @@ class FLAMAFeatureModel():
|
|
|
75
72
|
|
|
76
73
|
# Try to use the Find operation, which returns the atomic sets if they are found
|
|
77
74
|
try:
|
|
78
|
-
result = self.
|
|
75
|
+
result = self.discover_metamodel.use_operation(self.fm_model,
|
|
76
|
+
'FMAverageBranchingFactor').get_result()
|
|
79
77
|
return result
|
|
80
|
-
except
|
|
81
|
-
print(f"Error: {
|
|
78
|
+
except FlamaException as exception:
|
|
79
|
+
print(f"Error: {exception}")
|
|
82
80
|
return None
|
|
83
81
|
|
|
84
|
-
|
|
85
|
-
def count_leafs(self):
|
|
82
|
+
def count_leafs(self) -> Union[None, int]:
|
|
86
83
|
"""
|
|
87
84
|
This operation counts the number of leaf features in a feature model. Leaf features
|
|
88
85
|
are those that do not have any child features. They represent the most specific
|
|
@@ -91,14 +88,14 @@ class FLAMAFeatureModel():
|
|
|
91
88
|
|
|
92
89
|
# Try to use the Find operation, which returns the atomic sets if they are found
|
|
93
90
|
try:
|
|
94
|
-
result = self.
|
|
91
|
+
result = self.discover_metamodel.use_operation(self.fm_model,
|
|
92
|
+
'FMCountLeafs').get_result()
|
|
95
93
|
return result
|
|
96
|
-
except
|
|
97
|
-
print(f"Error: {
|
|
94
|
+
except FlamaException as exception:
|
|
95
|
+
print(f"Error: {exception}")
|
|
98
96
|
return None
|
|
99
97
|
|
|
100
|
-
|
|
101
|
-
def estimated_number_of_configurations(self):
|
|
98
|
+
def estimated_number_of_configurations(self) -> Union[None, int]:
|
|
102
99
|
"""
|
|
103
100
|
This is an estimate of the total number of different products that can be produced
|
|
104
101
|
from a feature model. It's calculated by considering all possible combinations of
|
|
@@ -109,14 +106,14 @@ class FLAMAFeatureModel():
|
|
|
109
106
|
|
|
110
107
|
# Try to use the Find operation, which returns the atomic sets if they are found
|
|
111
108
|
try:
|
|
112
|
-
result = self.
|
|
109
|
+
result = self.discover_metamodel.use_operation(
|
|
110
|
+
self.fm_model, 'FMEstimatedConfigurationsNumber').get_result()
|
|
113
111
|
return result
|
|
114
|
-
except
|
|
115
|
-
print(f"Error: {
|
|
112
|
+
except FlamaException as exception:
|
|
113
|
+
print(f"Error: {exception}")
|
|
116
114
|
return None
|
|
117
115
|
|
|
118
|
-
|
|
119
|
-
def feature_ancestors(self,feature_name:str):
|
|
116
|
+
def feature_ancestors(self, feature_name: str) -> Union[None, List[str]]:
|
|
120
117
|
'''
|
|
121
118
|
These are the features that are directly or indirectly the parent of a given feature in
|
|
122
119
|
a feature model. Ancestors of a feature are found by traversing up the feature hierarchy.
|
|
@@ -124,7 +121,7 @@ class FLAMAFeatureModel():
|
|
|
124
121
|
'''
|
|
125
122
|
# Try to use the Find operation, which returns the atomic sets if they are found
|
|
126
123
|
try:
|
|
127
|
-
operation = self.
|
|
124
|
+
operation = self.discover_metamodel.get_operation(self.fm_model, 'FMFeatureAncestors')
|
|
128
125
|
operation.set_feature(self.fm_model.get_feature_by_name(feature_name))
|
|
129
126
|
operation.execute(self.fm_model)
|
|
130
127
|
flama_result = operation.get_result()
|
|
@@ -132,38 +129,36 @@ class FLAMAFeatureModel():
|
|
|
132
129
|
for res in flama_result:
|
|
133
130
|
result.append(res.name)
|
|
134
131
|
return result
|
|
135
|
-
except
|
|
136
|
-
print(f"Error: {
|
|
132
|
+
except FlamaException as exception:
|
|
133
|
+
print(f"Error: {exception}")
|
|
137
134
|
return None
|
|
138
135
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
def leaf_features(self):
|
|
136
|
+
def leaf_features(self) -> Union[None, List[str]]:
|
|
142
137
|
"""
|
|
143
138
|
This operation is used to find leaf features in a model:
|
|
144
139
|
It returns the leaf features if they are found in the model.
|
|
145
140
|
If the model does not follow the UVL specification, an
|
|
146
141
|
exception is raised and the operation returns False.
|
|
147
|
-
|
|
142
|
+
|
|
148
143
|
Traditionally you would use the flama tool by
|
|
149
|
-
features =
|
|
144
|
+
features = discover_metamodel.use_operation_from_file('OperationString', model)
|
|
150
145
|
however, in this tool we know that this operation is from the fm metamodel,
|
|
151
146
|
so we avoid to execute the transformation if possible
|
|
152
147
|
"""
|
|
153
148
|
|
|
154
149
|
# Try to use the operation, which returns the leaf features if they are found
|
|
155
150
|
try:
|
|
156
|
-
features = self.
|
|
151
|
+
features = self.discover_metamodel.use_operation(self.fm_model,
|
|
152
|
+
'FMLeafFeatures').get_result()
|
|
157
153
|
leaf_features = []
|
|
158
154
|
for feature in features:
|
|
159
155
|
leaf_features.append(feature.name)
|
|
160
156
|
return leaf_features
|
|
161
|
-
except
|
|
162
|
-
print(f"Error: {
|
|
157
|
+
except FlamaException as exception:
|
|
158
|
+
print(f"Error: {exception}")
|
|
163
159
|
return None
|
|
164
160
|
|
|
165
|
-
|
|
166
|
-
def max_depth(self):
|
|
161
|
+
def max_depth(self) -> Union[None, int]:
|
|
167
162
|
"""
|
|
168
163
|
This operation is used to find the max depth of the tree in a model:
|
|
169
164
|
It returns the max depth of the tree.
|
|
@@ -173,32 +168,31 @@ class FLAMAFeatureModel():
|
|
|
173
168
|
|
|
174
169
|
# Try to use the Find operation, which returns the max depth of the tree
|
|
175
170
|
try:
|
|
176
|
-
return self.
|
|
177
|
-
|
|
178
|
-
|
|
171
|
+
return self.discover_metamodel.use_operation(self.fm_model,
|
|
172
|
+
'FMMaxDepthTree').get_result()
|
|
173
|
+
except FlamaException as exception:
|
|
174
|
+
print(f"Error: {exception}")
|
|
179
175
|
return None
|
|
180
176
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
"""
|
|
184
|
-
|
|
185
|
-
def core_features(self):
|
|
177
|
+
#The methods above rely on sat to be executed.
|
|
178
|
+
def core_features(self) -> Union[None, List[str]]:
|
|
186
179
|
"""
|
|
187
|
-
These are the features that are present in all products of a product line.
|
|
188
|
-
they are the features that are mandatory and not optional.
|
|
189
|
-
among all products in a product line.
|
|
190
|
-
|
|
180
|
+
These are the features that are present in all products of a product line.
|
|
181
|
+
In a feature model, they are the features that are mandatory and not optional.
|
|
182
|
+
Core features define the commonality among all products in a product line.
|
|
183
|
+
This call requires sat to be called, however, there is an implementation within
|
|
184
|
+
flamapy that does not requires sat. please use the framework in case of needing it.
|
|
191
185
|
"""
|
|
192
186
|
try:
|
|
193
187
|
self._transform_to_sat()
|
|
194
|
-
features = self.
|
|
188
|
+
features = self.discover_metamodel.use_operation(self.sat_model,
|
|
189
|
+
'PySATCoreFeatures').get_result()
|
|
195
190
|
return features
|
|
196
|
-
except
|
|
197
|
-
print(f"Error: {
|
|
191
|
+
except FlamaException as exception:
|
|
192
|
+
print(f"Error: {exception}")
|
|
198
193
|
return None
|
|
199
194
|
|
|
200
|
-
|
|
201
|
-
def dead_features(self):
|
|
195
|
+
def dead_features(self) -> Union[None, List[str]]:
|
|
202
196
|
"""
|
|
203
197
|
These are features that, due to the constraints and dependencies in the
|
|
204
198
|
feature model, cannot be included in any valid product. Dead features are usually
|
|
@@ -206,14 +200,14 @@ class FLAMAFeatureModel():
|
|
|
206
200
|
"""
|
|
207
201
|
try:
|
|
208
202
|
self._transform_to_sat()
|
|
209
|
-
features = self.
|
|
203
|
+
features = self.discover_metamodel.use_operation(self.sat_model,
|
|
204
|
+
'PySATDeadFeatures').get_result()
|
|
210
205
|
return features
|
|
211
|
-
except
|
|
212
|
-
print(f"Error: {
|
|
206
|
+
except FlamaException as exception:
|
|
207
|
+
print(f"Error: {exception}")
|
|
213
208
|
return None
|
|
214
209
|
|
|
215
|
-
|
|
216
|
-
def false_optional_features(self):
|
|
210
|
+
def false_optional_features(self) -> Union[None, List[str]]:
|
|
217
211
|
"""
|
|
218
212
|
These are features that appear to be optional in the feature model, but due to the
|
|
219
213
|
constraints and dependencies, must be included in every valid product. Like dead features,
|
|
@@ -221,120 +215,128 @@ class FLAMAFeatureModel():
|
|
|
221
215
|
"""
|
|
222
216
|
try:
|
|
223
217
|
self._transform_to_sat()
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
operation.feature_model=self.fm_model
|
|
218
|
+
operation = self.discover_metamodel.get_operation(self.sat_model,
|
|
219
|
+
'PySATFalseOptionalFeatures')
|
|
220
|
+
operation.feature_model = self.fm_model
|
|
227
221
|
operation.execute(self.sat_model)
|
|
228
222
|
features = operation.get_result()
|
|
229
223
|
return features
|
|
230
|
-
except
|
|
231
|
-
print(f"Error: {
|
|
224
|
+
except FlamaException as exception:
|
|
225
|
+
print(f"Error: {exception}")
|
|
232
226
|
return None
|
|
233
227
|
|
|
234
|
-
|
|
235
|
-
def filter(self, configurationPath:str):
|
|
228
|
+
def filter(self, configuration_path: str) -> Union[None, List[Configuration]]:
|
|
236
229
|
"""
|
|
237
|
-
This operation selects a subset of the products of a product line based on certain
|
|
238
|
-
For example, you might filter the products to only include those that
|
|
230
|
+
This operation selects a subset of the products of a product line based on certain
|
|
231
|
+
criteria. For example, you might filter the products to only include those that
|
|
232
|
+
contain a certain feature.
|
|
239
233
|
"""
|
|
240
234
|
try:
|
|
241
235
|
self._transform_to_sat()
|
|
242
|
-
configuration = self.
|
|
243
|
-
|
|
244
|
-
operation = self.
|
|
236
|
+
configuration = self.discover_metamodel.use_transformation_t2m(configuration_path,
|
|
237
|
+
'configuration')
|
|
238
|
+
operation = self.discover_metamodel.get_operation(self.sat_model, 'PySATFilter')
|
|
245
239
|
operation.set_configuration(configuration)
|
|
246
240
|
operation.execute(self.sat_model)
|
|
247
241
|
result = operation.get_result()
|
|
248
242
|
return result
|
|
249
|
-
except
|
|
250
|
-
print(f"Error: {
|
|
243
|
+
except FlamaException as exception:
|
|
244
|
+
print(f"Error: {exception}")
|
|
251
245
|
return None
|
|
252
246
|
|
|
253
|
-
|
|
254
|
-
def configurations_number(self, with_sat:bool=False):
|
|
247
|
+
def configurations_number(self, with_sat: bool = False) -> Union[None, int]:
|
|
255
248
|
"""
|
|
256
|
-
This is the total number of different full configurations that can be
|
|
257
|
-
It's calculated by considering all possible
|
|
258
|
-
the constraints and
|
|
249
|
+
This is the total number of different full configurations that can be
|
|
250
|
+
produced from a feature model. It's calculated by considering all possible
|
|
251
|
+
combinations of features, taking into account the constraints and
|
|
252
|
+
dependencies between features.
|
|
259
253
|
"""
|
|
260
254
|
try:
|
|
261
|
-
nop=0
|
|
255
|
+
nop = 0
|
|
262
256
|
if with_sat:
|
|
263
257
|
self._transform_to_sat()
|
|
264
|
-
nop = self.
|
|
265
|
-
|
|
258
|
+
nop = self.discover_metamodel.use_operation(
|
|
259
|
+
self.sat_model, 'PySATConfigurationsNumber'
|
|
260
|
+
).get_result()
|
|
266
261
|
else:
|
|
267
262
|
self._transform_to_bdd()
|
|
268
|
-
nop = self.
|
|
263
|
+
nop = self.discover_metamodel.use_operation(
|
|
264
|
+
self.bdd_model, 'BDDConfigurationsNumber'
|
|
265
|
+
).get_result()
|
|
269
266
|
return nop
|
|
270
|
-
except
|
|
271
|
-
print(f"Error: {
|
|
267
|
+
except FlamaException as exception:
|
|
268
|
+
print(f"Error: {exception}")
|
|
272
269
|
return None
|
|
273
270
|
|
|
274
|
-
|
|
275
|
-
def configurations(self, with_sat:bool=False):
|
|
271
|
+
def configurations(self, with_sat: bool = False) -> Union[None, List[Configuration]]:
|
|
276
272
|
"""
|
|
277
273
|
These are the individual outcomes that can be produced from a feature model. Each product
|
|
278
274
|
is a combination of features that satisfies all the constraints and dependencies in the
|
|
279
275
|
feature model.
|
|
280
276
|
"""
|
|
281
277
|
try:
|
|
282
|
-
products=[]
|
|
278
|
+
products = []
|
|
283
279
|
if with_sat:
|
|
284
280
|
self._transform_to_sat()
|
|
285
|
-
products = self.
|
|
281
|
+
products = self.discover_metamodel.use_operation(self.sat_model,
|
|
282
|
+
'PySATConfigurations'
|
|
283
|
+
).get_result()
|
|
286
284
|
else:
|
|
287
285
|
self._transform_to_bdd()
|
|
288
|
-
products = self.
|
|
286
|
+
products = self.discover_metamodel.use_operation(self.bdd_model,
|
|
287
|
+
'BDDConfigurations'
|
|
288
|
+
).get_result()
|
|
289
289
|
return products
|
|
290
|
-
except
|
|
291
|
-
print(f"Error: {
|
|
290
|
+
except FlamaException as exception:
|
|
291
|
+
print(f"Error: {exception}")
|
|
292
292
|
return None
|
|
293
293
|
|
|
294
|
-
|
|
295
|
-
def commonality(self, configurationPath:str):
|
|
294
|
+
def commonality(self, configuration_path: str) -> Union[None, float]:
|
|
296
295
|
"""
|
|
297
296
|
This is a measure of how often a feature appears in the products of a
|
|
298
297
|
product line. It's usually expressed as a percentage. A feature with
|
|
299
|
-
100
|
|
298
|
+
100 per cent commonality is a core feature, as it appears in all products.
|
|
300
299
|
"""
|
|
301
300
|
try:
|
|
302
301
|
self._transform_to_sat()
|
|
303
|
-
configuration = self.
|
|
302
|
+
configuration = self.discover_metamodel.use_transformation_t2m(configuration_path,
|
|
303
|
+
'configuration')
|
|
304
304
|
|
|
305
|
-
operation = self.
|
|
305
|
+
operation = self.discover_metamodel.get_operation(self.sat_model, 'PySATCommonality')
|
|
306
306
|
operation.set_configuration(configuration)
|
|
307
307
|
operation.execute(self.sat_model)
|
|
308
308
|
return operation.get_result()
|
|
309
|
-
except
|
|
310
|
-
print(f"Error: {
|
|
309
|
+
except FlamaException as exception:
|
|
310
|
+
print(f"Error: {exception}")
|
|
311
311
|
return None
|
|
312
312
|
|
|
313
|
-
|
|
314
|
-
|
|
313
|
+
def satisfiable_configuration(self,
|
|
314
|
+
configuration_path: str,
|
|
315
|
+
full_configuration: bool = False) -> Union[None, bool]:
|
|
315
316
|
"""
|
|
316
317
|
This is a product that is produced from a valid configuration of features. A valid
|
|
317
318
|
product satisfies all the constraints and dependencies in the feature model.
|
|
318
319
|
"""
|
|
319
320
|
try:
|
|
320
321
|
self._transform_to_sat()
|
|
321
|
-
configuration = self.
|
|
322
|
-
|
|
323
|
-
|
|
322
|
+
configuration = self.discover_metamodel.use_transformation_t2m(configuration_path,
|
|
323
|
+
'configuration')
|
|
324
|
+
operation = self.discover_metamodel.get_operation(self.sat_model,
|
|
325
|
+
'PySATSatisfiableConfiguration')
|
|
326
|
+
|
|
324
327
|
if full_configuration:
|
|
325
328
|
operation.set_configuration(configuration, is_full=True)
|
|
326
329
|
else:
|
|
327
330
|
operation.set_configuration(configuration, is_full=False)
|
|
328
|
-
|
|
331
|
+
|
|
329
332
|
operation.execute(self.sat_model)
|
|
330
333
|
result = operation.get_result()
|
|
331
334
|
return result
|
|
332
|
-
except
|
|
333
|
-
print(f"Error: {
|
|
335
|
+
except FlamaException as exception:
|
|
336
|
+
print(f"Error: {exception}")
|
|
334
337
|
return None
|
|
335
338
|
|
|
336
|
-
|
|
337
|
-
def satisfiable(self):
|
|
339
|
+
def satisfiable(self) -> Union[None, bool]:
|
|
338
340
|
"""
|
|
339
341
|
In the context of feature models, this usually refers to whether the feature model itself
|
|
340
342
|
satisfies all the constraints and dependencies. A a valid feature model is one that
|
|
@@ -342,10 +344,9 @@ class FLAMAFeatureModel():
|
|
|
342
344
|
"""
|
|
343
345
|
try:
|
|
344
346
|
self._transform_to_sat()
|
|
345
|
-
result = self.
|
|
347
|
+
result = self.discover_metamodel.use_operation(self.sat_model,
|
|
348
|
+
'PySATSatisfiable').get_result()
|
|
346
349
|
return result
|
|
347
|
-
except
|
|
348
|
-
print(f"Error: {
|
|
349
|
-
return None
|
|
350
|
-
|
|
351
|
-
|
|
350
|
+
except FlamaException as exception:
|
|
351
|
+
print(f"Error: {exception}")
|
|
352
|
+
return None
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: flamapy
|
|
3
|
+
Version: 2.0.0.dev3
|
|
4
|
+
Summary: Flamapy feature model is a distribution of the flama framework containing all plugins required to analyze feature models. It also offers a richier API and a complete command line interface and documentation.
|
|
5
|
+
Home-page: https://github.com/flamapy/flamapy-feature-model
|
|
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
|
+
<div align="center">
|
|
18
|
+
|
|
19
|
+
<a href="">[](https://github.com/flamapy/flamapy/actions/workflows/tests.yml)</a>
|
|
20
|
+
<a href="">[](https://github.com/flamapy/flamapy/actions/workflows/commits.yml)</a>
|
|
21
|
+
<a href="">
|
|
22
|
+
<a href="">
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
#
|
|
26
|
+
|
|
27
|
+
<div id="top"></div>
|
|
28
|
+
<br />
|
|
29
|
+
<div align="center">
|
|
30
|
+
|
|
31
|
+
<h3 align="center">FLAMAPY</h3>
|
|
32
|
+
|
|
33
|
+
<p align="center">
|
|
34
|
+
A new and easy way to use FLAMA
|
|
35
|
+
<br />
|
|
36
|
+
<a href="https://github.com/flamapy/flamapy/issues">Report Bug</a>
|
|
37
|
+
·
|
|
38
|
+
<a href="https://github.com/flamapy/flamapy/issues">Request Feature</a>
|
|
39
|
+
</p>
|
|
40
|
+
</div>
|
|
41
|
+
<!-- ABOUT THE PROJECT -->
|
|
42
|
+
|
|
43
|
+
# About The Project
|
|
44
|
+
FLAMAPY Feature model distribution provides an easier way of using FLAMAPY when analysing feature models. It packs the most used plugins for analyis of feature models adding a layer of convenience to use the framework or integrate it. If some other operations are required please see in the [documentation](flamapy.github.io/docs) if its supported in the ecosystem though the Python interface.
|
|
45
|
+
|
|
46
|
+
Feature Model Analysis has a crucial role in software product line engineering, enabling us to understand, design, and validate the complex relationships among features in a software product line. These feature models can often be complex and challenging to analyze due to their variability, making it difficult to identify conflicts, dead features, and potential optimizations. This is where this distribution comes in.
|
|
47
|
+
|
|
48
|
+
# Using the CMD
|
|
49
|
+
```bash
|
|
50
|
+
flamapy --help #This will show the commands available
|
|
51
|
+
flamapy satisfiable <path to file> to check if a model is valid
|
|
52
|
+
...
|
|
53
|
+
```
|
|
54
|
+
# Using the Python interface
|
|
55
|
+
This is simple, Flama FM dist in hosted in pypi, therefore simply add the package flama-fm-dist to your requirements file and call the API as follows:
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from flamapy.interfaces.python.flama_feature_model import FLAMAFeatureModel
|
|
59
|
+
|
|
60
|
+
fm = FLAMAFeatureModel("path/to/feature/model")
|
|
61
|
+
print(fm.valid())
|
|
62
|
+
```
|
|
63
|
+
# Operations available:
|
|
64
|
+
Currently this distribution offers a subset of the operations available in the ecosystem, in the case of the feature mdoel distribution, we provide those operations that are well tested and used by the community. Nonetheless, If other more complex operations are required you can rely on the python interface of the framework to execute them all.
|
|
65
|
+
|
|
66
|
+
* atomic_sets: This operation is used to find the atomic sets in a model: It returns the atomic sets if they are found in the model. If the model does not follow the UVL specification, an exception is raised and the operation returns False.
|
|
67
|
+
|
|
68
|
+
* average_branching_factor:This refers to the average number of child features that a parent feature has in a feature model. It's calculated by dividing the total number of child features by the total number of parent features. A high average branching factor indicates a complex feature model with many options, while a low average branching factor indicates a simpler model.
|
|
69
|
+
|
|
70
|
+
* commonality: This is a measure of how often a feature appears in the products of a product line. It's usually expressed as a percentage. A feature with 100 per cent commonality is a core feature, as it appears in all products.
|
|
71
|
+
|
|
72
|
+
* configurations: These are the individual outcomes that can be produced from a feature model. Each product is a combination of features that satisfies all the constraints and dependencies in the feature model.
|
|
73
|
+
|
|
74
|
+
* configurations_number: This is the total number of different full configurations that can be produced from a feature model. It's calculated by considering all possible combinations of features, taking into account the constraints and dependencies between features.
|
|
75
|
+
|
|
76
|
+
* core_features: These are the features that are present in all products of a product line. In a feature model, they are the features that are mandatory and not optional. Core features define the commonality among all products in a product line. This call requires sat to be called, however, there is an implementation within flamapy that does not requires sat, please use the framework in case of needing it.
|
|
77
|
+
|
|
78
|
+
* count_leafs: This operation counts the number of leaf features in a feature model. Leaf features are those that do not have any child features. They represent the most specific options in a product line.
|
|
79
|
+
* dead_features: These are features that, due to the constraints and dependencies in the feature model, cannot be included in any valid product. Dead features are usually a sign of an error in the feature model.
|
|
80
|
+
|
|
81
|
+
* estimated_number_of_configurations: This is an estimate of the total number of different products that can be produced from a feature model. It's calculated by considering all possible combinations of features. This can be a simple multiplication if all
|
|
82
|
+
features are independent, but in most cases, constraints and dependencies between features need to be taken into account.
|
|
83
|
+
|
|
84
|
+
* false_optional_features: These are features that appear to be optional in the feature model, but due to the constraints and dependencies, must be included in every valid product. Like dead features, false optional features are usually a sign of an error in the feature model.
|
|
85
|
+
|
|
86
|
+
* feature_ancestors: These are the features that are directly or indirectly the parent of a given feature in a feature model. Ancestors of a feature are found by traversing up the feature hierarchy. This information can be useful to understand the context and dependencies of a feature.
|
|
87
|
+
|
|
88
|
+
* filter: This operation selects a subset of the products of a product line based on certain criteria. For example, youmight filter the products to only include those that contain a certain feature.
|
|
89
|
+
|
|
90
|
+
* leaf_features: This operation is used to find leaf features in a model: It returns the leaf features if they are found in themodel. If the model does not follow the UVL specification, an exception is raised and the operation returns False.
|
|
91
|
+
|
|
92
|
+
* max_depth: This operation is used to find the max depth of the tree in a model: It returns the max depth of the tree. If the model does not follow the UVL specification, an exception is raised and the operation returns False.
|
|
93
|
+
|
|
94
|
+
* satisfiable: In the context of feature models, this usually refers to whether the feature model itself satisfies all the
|
|
95
|
+
constraints and dependencies. A a valid feature model is one that does encodes at least a single valid product.
|
|
96
|
+
|
|
97
|
+
* satisfiable_configuration: This is a product that is produced from a valid configuration of features. A valid product satisfies all the constraints and dependencies in the feature model.
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
|
|
@@ -6,6 +6,6 @@ flamapy.egg-info/dependency_links.txt
|
|
|
6
6
|
flamapy.egg-info/entry_points.txt
|
|
7
7
|
flamapy.egg-info/requires.txt
|
|
8
8
|
flamapy.egg-info/top_level.txt
|
|
9
|
-
flamapy/
|
|
10
|
-
flamapy/interfaces/python/
|
|
11
|
-
flamapy/interfaces/python/
|
|
9
|
+
flamapy/commands/__init__.py
|
|
10
|
+
flamapy/interfaces/python/__init__.py
|
|
11
|
+
flamapy/interfaces/python/flamapy_feature_model.py
|
|
@@ -16,7 +16,7 @@ dev_requirements = read_requirements("requirements-dev.txt")
|
|
|
16
16
|
|
|
17
17
|
setuptools.setup(
|
|
18
18
|
name="flamapy",
|
|
19
|
-
version="2.0.0.
|
|
19
|
+
version="2.0.0.dev3",
|
|
20
20
|
author="Flamapy",
|
|
21
21
|
author_email="flamapy@us.es",
|
|
22
22
|
description="Flamapy feature model is a distribution of the flama framework containing all plugins required to analyze feature models. It also offers a richier API and a complete command line interface and documentation.",
|
|
@@ -36,7 +36,7 @@ setuptools.setup(
|
|
|
36
36
|
},
|
|
37
37
|
entry_points={
|
|
38
38
|
'console_scripts': [
|
|
39
|
-
'flamapy
|
|
39
|
+
'flamapy = flamapy.commands:flamapy_cli',
|
|
40
40
|
],
|
|
41
41
|
},
|
|
42
42
|
)
|
flamapy-2.0.0.dev2/PKG-INFO
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: flamapy
|
|
3
|
-
Version: 2.0.0.dev2
|
|
4
|
-
Summary: Flamapy feature model is a distribution of the flama framework containing all plugins required to analyze feature models. It also offers a richier API and a complete command line interface and documentation.
|
|
5
|
-
Home-page: https://github.com/flamapy/flamapy-feature-model
|
|
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
|
-
<div align="center">
|
|
18
|
-
|
|
19
|
-
<a href="">[](https://github.com/flamapy/flamapy/actions/workflows/tests.yml)</a>
|
|
20
|
-
<a href="">[](https://github.com/flamapy/flamapy/actions/workflows/commits.yml)</a>
|
|
21
|
-
<a href="">
|
|
22
|
-
<a href="">
|
|
23
|
-
</div>
|
|
24
|
-
|
|
25
|
-
#
|
|
26
|
-
|
|
27
|
-
<div id="top"></div>
|
|
28
|
-
<br />
|
|
29
|
-
<div align="center">
|
|
30
|
-
|
|
31
|
-
<h3 align="center">FLAMAPY</h3>
|
|
32
|
-
|
|
33
|
-
<p align="center">
|
|
34
|
-
A new and easy way to use FLAMA
|
|
35
|
-
<br />
|
|
36
|
-
<a href="https://github.com/flamapy/flamapy/issues">Report Bug</a>
|
|
37
|
-
·
|
|
38
|
-
<a href="https://github.com/flamapy/flamapy/issues">Request Feature</a>
|
|
39
|
-
</p>
|
|
40
|
-
</div>
|
|
41
|
-
<!-- ABOUT THE PROJECT -->
|
|
42
|
-
|
|
43
|
-
## About The Project
|
|
44
|
-
|
|
45
|
-
FLAMAPY Feature model distribution provides an easier way of using FLAMA when analysing feature models. It packs the most used plugins for analyis of feature models adding a layer of convenience to use the framework or integrate it.
|
|
46
|
-
|
|
47
|
-
Feature Model Analysis has a crucial role in software product line engineering, enabling us to understand, design, and validate the complex relationships among features in a software product line. These feature models can often be complex and challenging to analyze due to their variability, making it difficult to identify conflicts, dead features, and potential optimizations. This is where this distribution comes in.
|
|
48
|
-
|
|
49
|
-
# Soon comming, easy to use CMD
|
|
50
|
-
## TODO
|
|
51
|
-
|
|
52
|
-
# Using the Python interface
|
|
53
|
-
This is simple, Flama FM dist in hosted in pypi, therefore simply add the package flama-fm-dist to your requirements file and call the API as follows:
|
|
54
|
-
|
|
55
|
-
```python
|
|
56
|
-
from flamapy.interfaces.python.FLAMAFeatureModel import FLAMAFeatureModel
|
|
57
|
-
|
|
58
|
-
fm = FLAMAFeatureModel("path/to/feature/model")
|
|
59
|
-
print(fm.valid())
|
|
60
|
-
```
|
|
61
|
-
Currently the operations provided by this distribution are:
|
|
62
|
-
* atomic_sets: This operation is used to find the atomic sets in a model. It returns the atomic sets if they are found in the model. If the model does not follow the UVL specification, an exception is raised and the operation returns False.
|
|
63
|
-
* average_branching_factor: This refers to the average number of child features that a parent feature has in a feature model. It's calculated by dividing the total number of child features by the total number of parent features. A high average branching factor indicates a complex feature model with many options, while a low average branching factor indicates a simpler model.
|
|
64
|
-
* count_leafs: This operation counts the number of leaf features in a feature model. Leaf features are those that do not have any child features. They represent the most specific options in a product line.
|
|
65
|
-
* estimated_number_of_products: This is an estimate of the total number of different products that can be produced from a feature model. It's calculated by considering all possible combinations of features. This can be a simple multiplication if all features are independent, but in most cases, constraints and dependencies between features need to be taken into account.
|
|
66
|
-
* feature_ancestors: These are the features that are directly or indirectly the parent of a given feature in a feature model. Ancestors of a feature are found by traversing up the feature hierarchy. This information can be useful to understand the context and dependencies of a feature.
|
|
67
|
-
* leaf_features: This operation is used to find leaf features in a model. It returns the leaf features if they are found in the model. If the model does not follow the UVL specification, an
|
|
68
|
-
exception is raised and the operation returns False.
|
|
69
|
-
* max_dept: This operation is used to find the max depth of the tree in a model.It returns the max depth of the tree.
|
|
70
|
-
* commonality: This is a measure of how often a feature appears in the products of a product line. It's usually expressed as a percentage. A feature with 100% commonality is a core feature, as it appears in all products.
|
|
71
|
-
* core_features: These are the features that are present in all products of a product line. In a feature model, they are the features that are mandatory and not optional. Core features define the commonality among all products in a product line. This call requires sat to be called, however, there is an implementation within flama that does not requires sat. please use the framework in case of needing it.
|
|
72
|
-
* dead_features: These are features that, due to the constraints and dependencies in the feature model, cannot be included in any valid product. Dead features are usually a sign of an error in the feature model.
|
|
73
|
-
* error_detection: This refers to the process of identifying and locating errors in a feature model. Errors can include things like dead features, false optional features, or contradictions in the constraints.
|
|
74
|
-
* false_optional_features: These are features that appear to be optional in the feature model, but due to the constraints and dependencies, must be included in every valid product. Like dead features, false optional features are usually a sign of an error in the feature model.
|
|
75
|
-
* filter: This operation selects a subset of the products of a product line based on certain criteria. For example, you might filter the products to only include those that contain a certain feature.
|
|
76
|
-
* products number: This is the total number of different products that can be produced from a feature model.It's calculated by considering all possible combinations of features, taking into account the constraints and dependencies between features.
|
|
77
|
-
* products: This operation returns all the products of a product line. A product is a valid combination of features that can be produced from a feature model. The products are returned as a list of lists, where each inner list represents a product and contains the features that are included in that product.
|
|
78
|
-
* valid_configuration: This operation checks if a given configuration is valid in a feature model. A configuration is a list of features that are included in a product. The operation returns True if the configuration is valid, and False if it's not.
|
|
79
|
-
* valid_product: This operation checks if a given product (full configuration) is valid in a feature model. A product is a list of features that are included in a product. The operation returns True if the product is valid, and False if it's not.
|
|
80
|
-
* valid: This operation checks if a feature model is valid. A feature model is valid if it follows the UVL specification. The operation returns True if the feature model is valid, and False if it's not.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
flamapy-2.0.0.dev2/README.md
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
<div align="center">
|
|
2
|
-
|
|
3
|
-
<a href="">[](https://github.com/flamapy/flamapy/actions/workflows/tests.yml)</a>
|
|
4
|
-
<a href="">[](https://github.com/flamapy/flamapy/actions/workflows/commits.yml)</a>
|
|
5
|
-
<a href="">
|
|
6
|
-
<a href="">
|
|
7
|
-
</div>
|
|
8
|
-
|
|
9
|
-
#
|
|
10
|
-
|
|
11
|
-
<div id="top"></div>
|
|
12
|
-
<br />
|
|
13
|
-
<div align="center">
|
|
14
|
-
|
|
15
|
-
<h3 align="center">FLAMAPY</h3>
|
|
16
|
-
|
|
17
|
-
<p align="center">
|
|
18
|
-
A new and easy way to use FLAMA
|
|
19
|
-
<br />
|
|
20
|
-
<a href="https://github.com/flamapy/flamapy/issues">Report Bug</a>
|
|
21
|
-
·
|
|
22
|
-
<a href="https://github.com/flamapy/flamapy/issues">Request Feature</a>
|
|
23
|
-
</p>
|
|
24
|
-
</div>
|
|
25
|
-
<!-- ABOUT THE PROJECT -->
|
|
26
|
-
|
|
27
|
-
## About The Project
|
|
28
|
-
|
|
29
|
-
FLAMAPY Feature model distribution provides an easier way of using FLAMA when analysing feature models. It packs the most used plugins for analyis of feature models adding a layer of convenience to use the framework or integrate it.
|
|
30
|
-
|
|
31
|
-
Feature Model Analysis has a crucial role in software product line engineering, enabling us to understand, design, and validate the complex relationships among features in a software product line. These feature models can often be complex and challenging to analyze due to their variability, making it difficult to identify conflicts, dead features, and potential optimizations. This is where this distribution comes in.
|
|
32
|
-
|
|
33
|
-
# Soon comming, easy to use CMD
|
|
34
|
-
## TODO
|
|
35
|
-
|
|
36
|
-
# Using the Python interface
|
|
37
|
-
This is simple, Flama FM dist in hosted in pypi, therefore simply add the package flama-fm-dist to your requirements file and call the API as follows:
|
|
38
|
-
|
|
39
|
-
```python
|
|
40
|
-
from flamapy.interfaces.python.FLAMAFeatureModel import FLAMAFeatureModel
|
|
41
|
-
|
|
42
|
-
fm = FLAMAFeatureModel("path/to/feature/model")
|
|
43
|
-
print(fm.valid())
|
|
44
|
-
```
|
|
45
|
-
Currently the operations provided by this distribution are:
|
|
46
|
-
* atomic_sets: This operation is used to find the atomic sets in a model. It returns the atomic sets if they are found in the model. If the model does not follow the UVL specification, an exception is raised and the operation returns False.
|
|
47
|
-
* average_branching_factor: This refers to the average number of child features that a parent feature has in a feature model. It's calculated by dividing the total number of child features by the total number of parent features. A high average branching factor indicates a complex feature model with many options, while a low average branching factor indicates a simpler model.
|
|
48
|
-
* count_leafs: This operation counts the number of leaf features in a feature model. Leaf features are those that do not have any child features. They represent the most specific options in a product line.
|
|
49
|
-
* estimated_number_of_products: This is an estimate of the total number of different products that can be produced from a feature model. It's calculated by considering all possible combinations of features. This can be a simple multiplication if all features are independent, but in most cases, constraints and dependencies between features need to be taken into account.
|
|
50
|
-
* feature_ancestors: These are the features that are directly or indirectly the parent of a given feature in a feature model. Ancestors of a feature are found by traversing up the feature hierarchy. This information can be useful to understand the context and dependencies of a feature.
|
|
51
|
-
* leaf_features: This operation is used to find leaf features in a model. It returns the leaf features if they are found in the model. If the model does not follow the UVL specification, an
|
|
52
|
-
exception is raised and the operation returns False.
|
|
53
|
-
* max_dept: This operation is used to find the max depth of the tree in a model.It returns the max depth of the tree.
|
|
54
|
-
* commonality: This is a measure of how often a feature appears in the products of a product line. It's usually expressed as a percentage. A feature with 100% commonality is a core feature, as it appears in all products.
|
|
55
|
-
* core_features: These are the features that are present in all products of a product line. In a feature model, they are the features that are mandatory and not optional. Core features define the commonality among all products in a product line. This call requires sat to be called, however, there is an implementation within flama that does not requires sat. please use the framework in case of needing it.
|
|
56
|
-
* dead_features: These are features that, due to the constraints and dependencies in the feature model, cannot be included in any valid product. Dead features are usually a sign of an error in the feature model.
|
|
57
|
-
* error_detection: This refers to the process of identifying and locating errors in a feature model. Errors can include things like dead features, false optional features, or contradictions in the constraints.
|
|
58
|
-
* false_optional_features: These are features that appear to be optional in the feature model, but due to the constraints and dependencies, must be included in every valid product. Like dead features, false optional features are usually a sign of an error in the feature model.
|
|
59
|
-
* filter: This operation selects a subset of the products of a product line based on certain criteria. For example, you might filter the products to only include those that contain a certain feature.
|
|
60
|
-
* products number: This is the total number of different products that can be produced from a feature model.It's calculated by considering all possible combinations of features, taking into account the constraints and dependencies between features.
|
|
61
|
-
* products: This operation returns all the products of a product line. A product is a valid combination of features that can be produced from a feature model. The products are returned as a list of lists, where each inner list represents a product and contains the features that are included in that product.
|
|
62
|
-
* valid_configuration: This operation checks if a given configuration is valid in a feature model. A configuration is a list of features that are included in a product. The operation returns True if the configuration is valid, and False if it's not.
|
|
63
|
-
* valid_product: This operation checks if a given product (full configuration) is valid in a feature model. A product is a list of features that are included in a product. The operation returns True if the product is valid, and False if it's not.
|
|
64
|
-
* valid: This operation checks if a feature model is valid. A feature model is valid if it follows the UVL specification. The operation returns True if the feature model is valid, and False if it's not.
|
|
65
|
-
|
|
66
|
-
|
|
File without changes
|
|
File without changes
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: flamapy
|
|
3
|
-
Version: 2.0.0.dev2
|
|
4
|
-
Summary: Flamapy feature model is a distribution of the flama framework containing all plugins required to analyze feature models. It also offers a richier API and a complete command line interface and documentation.
|
|
5
|
-
Home-page: https://github.com/flamapy/flamapy-feature-model
|
|
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
|
-
<div align="center">
|
|
18
|
-
|
|
19
|
-
<a href="">[](https://github.com/flamapy/flamapy/actions/workflows/tests.yml)</a>
|
|
20
|
-
<a href="">[](https://github.com/flamapy/flamapy/actions/workflows/commits.yml)</a>
|
|
21
|
-
<a href="">
|
|
22
|
-
<a href="">
|
|
23
|
-
</div>
|
|
24
|
-
|
|
25
|
-
#
|
|
26
|
-
|
|
27
|
-
<div id="top"></div>
|
|
28
|
-
<br />
|
|
29
|
-
<div align="center">
|
|
30
|
-
|
|
31
|
-
<h3 align="center">FLAMAPY</h3>
|
|
32
|
-
|
|
33
|
-
<p align="center">
|
|
34
|
-
A new and easy way to use FLAMA
|
|
35
|
-
<br />
|
|
36
|
-
<a href="https://github.com/flamapy/flamapy/issues">Report Bug</a>
|
|
37
|
-
·
|
|
38
|
-
<a href="https://github.com/flamapy/flamapy/issues">Request Feature</a>
|
|
39
|
-
</p>
|
|
40
|
-
</div>
|
|
41
|
-
<!-- ABOUT THE PROJECT -->
|
|
42
|
-
|
|
43
|
-
## About The Project
|
|
44
|
-
|
|
45
|
-
FLAMAPY Feature model distribution provides an easier way of using FLAMA when analysing feature models. It packs the most used plugins for analyis of feature models adding a layer of convenience to use the framework or integrate it.
|
|
46
|
-
|
|
47
|
-
Feature Model Analysis has a crucial role in software product line engineering, enabling us to understand, design, and validate the complex relationships among features in a software product line. These feature models can often be complex and challenging to analyze due to their variability, making it difficult to identify conflicts, dead features, and potential optimizations. This is where this distribution comes in.
|
|
48
|
-
|
|
49
|
-
# Soon comming, easy to use CMD
|
|
50
|
-
## TODO
|
|
51
|
-
|
|
52
|
-
# Using the Python interface
|
|
53
|
-
This is simple, Flama FM dist in hosted in pypi, therefore simply add the package flama-fm-dist to your requirements file and call the API as follows:
|
|
54
|
-
|
|
55
|
-
```python
|
|
56
|
-
from flamapy.interfaces.python.FLAMAFeatureModel import FLAMAFeatureModel
|
|
57
|
-
|
|
58
|
-
fm = FLAMAFeatureModel("path/to/feature/model")
|
|
59
|
-
print(fm.valid())
|
|
60
|
-
```
|
|
61
|
-
Currently the operations provided by this distribution are:
|
|
62
|
-
* atomic_sets: This operation is used to find the atomic sets in a model. It returns the atomic sets if they are found in the model. If the model does not follow the UVL specification, an exception is raised and the operation returns False.
|
|
63
|
-
* average_branching_factor: This refers to the average number of child features that a parent feature has in a feature model. It's calculated by dividing the total number of child features by the total number of parent features. A high average branching factor indicates a complex feature model with many options, while a low average branching factor indicates a simpler model.
|
|
64
|
-
* count_leafs: This operation counts the number of leaf features in a feature model. Leaf features are those that do not have any child features. They represent the most specific options in a product line.
|
|
65
|
-
* estimated_number_of_products: This is an estimate of the total number of different products that can be produced from a feature model. It's calculated by considering all possible combinations of features. This can be a simple multiplication if all features are independent, but in most cases, constraints and dependencies between features need to be taken into account.
|
|
66
|
-
* feature_ancestors: These are the features that are directly or indirectly the parent of a given feature in a feature model. Ancestors of a feature are found by traversing up the feature hierarchy. This information can be useful to understand the context and dependencies of a feature.
|
|
67
|
-
* leaf_features: This operation is used to find leaf features in a model. It returns the leaf features if they are found in the model. If the model does not follow the UVL specification, an
|
|
68
|
-
exception is raised and the operation returns False.
|
|
69
|
-
* max_dept: This operation is used to find the max depth of the tree in a model.It returns the max depth of the tree.
|
|
70
|
-
* commonality: This is a measure of how often a feature appears in the products of a product line. It's usually expressed as a percentage. A feature with 100% commonality is a core feature, as it appears in all products.
|
|
71
|
-
* core_features: These are the features that are present in all products of a product line. In a feature model, they are the features that are mandatory and not optional. Core features define the commonality among all products in a product line. This call requires sat to be called, however, there is an implementation within flama that does not requires sat. please use the framework in case of needing it.
|
|
72
|
-
* dead_features: These are features that, due to the constraints and dependencies in the feature model, cannot be included in any valid product. Dead features are usually a sign of an error in the feature model.
|
|
73
|
-
* error_detection: This refers to the process of identifying and locating errors in a feature model. Errors can include things like dead features, false optional features, or contradictions in the constraints.
|
|
74
|
-
* false_optional_features: These are features that appear to be optional in the feature model, but due to the constraints and dependencies, must be included in every valid product. Like dead features, false optional features are usually a sign of an error in the feature model.
|
|
75
|
-
* filter: This operation selects a subset of the products of a product line based on certain criteria. For example, you might filter the products to only include those that contain a certain feature.
|
|
76
|
-
* products number: This is the total number of different products that can be produced from a feature model.It's calculated by considering all possible combinations of features, taking into account the constraints and dependencies between features.
|
|
77
|
-
* products: This operation returns all the products of a product line. A product is a valid combination of features that can be produced from a feature model. The products are returned as a list of lists, where each inner list represents a product and contains the features that are included in that product.
|
|
78
|
-
* valid_configuration: This operation checks if a given configuration is valid in a feature model. A configuration is a list of features that are included in a product. The operation returns True if the configuration is valid, and False if it's not.
|
|
79
|
-
* valid_product: This operation checks if a given product (full configuration) is valid in a feature model. A product is a list of features that are included in a product. The operation returns True if the product is valid, and False if it's not.
|
|
80
|
-
* valid: This operation checks if a feature model is valid. A feature model is valid if it follows the UVL specification. The operation returns True if the feature model is valid, and False if it's not.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|