flamapy 2.5.0__tar.gz → 2.6.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.
Files changed (24) hide show
  1. flamapy-2.6.0.dev0/PKG-INFO +36 -0
  2. flamapy-2.6.0.dev0/README.md +13 -0
  3. {flamapy-2.5.0 → flamapy-2.6.0.dev0}/flamapy/interfaces/python/flamapy_feature_model.py +296 -10
  4. flamapy-2.6.0.dev0/flamapy.egg-info/PKG-INFO +36 -0
  5. {flamapy-2.5.0 → flamapy-2.6.0.dev0}/flamapy.egg-info/SOURCES.txt +1 -0
  6. flamapy-2.6.0.dev0/flamapy.egg-info/requires.txt +12 -0
  7. {flamapy-2.5.0 → flamapy-2.6.0.dev0}/pyproject.toml +6 -5
  8. flamapy-2.6.0.dev0/tests/test_documentation_examples.py +356 -0
  9. flamapy-2.5.0/PKG-INFO +0 -104
  10. flamapy-2.5.0/README.md +0 -82
  11. flamapy-2.5.0/flamapy.egg-info/PKG-INFO +0 -104
  12. flamapy-2.5.0/flamapy.egg-info/requires.txt +0 -11
  13. {flamapy-2.5.0 → flamapy-2.6.0.dev0}/LICENSE +0 -0
  14. {flamapy-2.5.0 → flamapy-2.6.0.dev0}/flamapy/commands/__init__.py +0 -0
  15. {flamapy-2.5.0 → flamapy-2.6.0.dev0}/flamapy/interfaces/python/__init__.py +0 -0
  16. {flamapy-2.5.0 → flamapy-2.6.0.dev0}/flamapy.egg-info/dependency_links.txt +0 -0
  17. {flamapy-2.5.0 → flamapy-2.6.0.dev0}/flamapy.egg-info/entry_points.txt +0 -0
  18. {flamapy-2.5.0 → flamapy-2.6.0.dev0}/flamapy.egg-info/top_level.txt +0 -0
  19. {flamapy-2.5.0 → flamapy-2.6.0.dev0}/setup.cfg +0 -0
  20. {flamapy-2.5.0 → flamapy-2.6.0.dev0}/setup.py +0 -0
  21. {flamapy-2.5.0 → flamapy-2.6.0.dev0}/tests/test_basic_units.py +0 -0
  22. {flamapy-2.5.0 → flamapy-2.6.0.dev0}/tests/test_cli_basic_units.py +0 -0
  23. {flamapy-2.5.0 → flamapy-2.6.0.dev0}/tests/test_fama_suite_bdd.py +0 -0
  24. {flamapy-2.5.0 → flamapy-2.6.0.dev0}/tests/test_fama_suite_sat.py +0 -0
@@ -0,0 +1,36 @@
1
+ Metadata-Version: 2.4
2
+ Name: flamapy
3
+ Version: 2.6.0.dev0
4
+ Summary: Flamapy feature model is a distribution of the flama framework containing all plugins required to analyze feature models. It also offers a richer API and a complete command line interface and documentation.
5
+ Author-email: Flamapy <flamapy@us.es>
6
+ License-Expression: GPL-3.0-or-later
7
+ Project-URL: Homepage, https://github.com/flamapy/flamapy-feature-model
8
+ Requires-Python: >=3.9
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: flamapy-fw~=2.6.0.dev0
12
+ Requires-Dist: flamapy-fm~=2.6.0.dev0
13
+ Requires-Dist: flamapy-sat~=2.6.0.dev0
14
+ Requires-Dist: flamapy-bdd~=2.6.0.dev0
15
+ Requires-Dist: flamapy-z3~=2.6.0.dev0
16
+ Provides-Extra: dev
17
+ Requires-Dist: pytest; extra == "dev"
18
+ Requires-Dist: pytest-mock; extra == "dev"
19
+ Requires-Dist: prospector; extra == "dev"
20
+ Requires-Dist: mypy; extra == "dev"
21
+ Requires-Dist: coverage; extra == "dev"
22
+ Dynamic: license-file
23
+
24
+ # flamapy
25
+
26
+ The flamapy feature-model distribution: a meta-package that installs the
27
+ framework and the feature-model analysis plugins, and provides the command-line
28
+ interface and the easy-to-use Python facade (`FLAMAFeatureModel`).
29
+
30
+ **Documentation:** https://docs.flamapy.org
31
+
32
+ ## Installation
33
+
34
+ ```bash
35
+ pip install flamapy
36
+ ```
@@ -0,0 +1,13 @@
1
+ # flamapy
2
+
3
+ The flamapy feature-model distribution: a meta-package that installs the
4
+ framework and the feature-model analysis plugins, and provides the command-line
5
+ interface and the easy-to-use Python facade (`FLAMAFeatureModel`).
6
+
7
+ **Documentation:** https://docs.flamapy.org
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ pip install flamapy
13
+ ```
@@ -1,5 +1,5 @@
1
1
  import logging
2
- from typing import List, Any, Union
2
+ from typing import Any, Dict, Generator, List, Optional, Tuple, Union
3
3
  from flamapy.core.discover import DiscoverMetamodels
4
4
  from flamapy.metamodels.fm_metamodel.models import FeatureModel
5
5
  from flamapy.core.exceptions import FlamaException
@@ -15,19 +15,12 @@ class FLAMAFeatureModel:
15
15
  Any model in UVL, FaMaXML or FeatureIDE format are accepted
16
16
  """
17
17
  self.model_path = model_path
18
- """
19
- Creating the interface witht he flama framework
20
- """
21
18
  self.discover_metamodel = DiscoverMetamodels()
22
- """
23
- We save the model for later ussage
24
- """
25
19
  self.fm_model = self._read(model_path)
26
- """
27
- We create a empty sat model and a bdd model to avoid double transformations
28
- """
29
20
  self.sat_model = None
30
21
  self.bdd_model = None
22
+ self.z3_model = None
23
+ self.diagnosis_model = None
31
24
 
32
25
  def _read(self, model_path: str) -> FeatureModel:
33
26
  return self.discover_metamodel.use_transformation_t2m(model_path, "fm")
@@ -40,6 +33,16 @@ class FLAMAFeatureModel:
40
33
  if self.bdd_model is None:
41
34
  self.bdd_model = self.discover_metamodel.use_transformation_m2m(self.fm_model, "bdd")
42
35
 
36
+ def _transform_to_z3(self) -> None:
37
+ if self.z3_model is None:
38
+ self.z3_model = self.discover_metamodel.use_transformation_m2m(self.fm_model, "z3")
39
+
40
+ def _transform_to_diagnosis(self) -> None:
41
+ if self.diagnosis_model is None:
42
+ self.diagnosis_model = self.discover_metamodel.use_transformation_m2m(
43
+ self.fm_model, "pysat_diagnosis"
44
+ )
45
+
43
46
  def atomic_sets(self) -> Union[None, List[List[Any]]]:
44
47
  """
45
48
  This operation is used to find the atomic sets in a model:
@@ -379,3 +382,286 @@ class FLAMAFeatureModel:
379
382
  except FlamaException as exception:
380
383
  logger.error("Error: %s", exception)
381
384
  return None
385
+
386
+ # FM-based operations
387
+
388
+ def metrics(self) -> Union[None, List[Dict[str, Any]]]:
389
+ """
390
+ Returns a collection of structural metrics for the feature model, such as number of
391
+ features, constraints, relations, and complexity indicators.
392
+ """
393
+ try:
394
+ return self.discover_metamodel.use_operation(
395
+ self.fm_model, "FMMetrics"
396
+ ).get_result()
397
+ except FlamaException as exception:
398
+ logger.error("Error: %s", exception)
399
+ return None
400
+
401
+ def variation_points(self) -> Union[None, Dict[str, List[str]]]:
402
+ """
403
+ Returns the variation points of the feature model. A variation point is a feature that
404
+ has at least one non-mandatory child, representing a decision point in the model.
405
+ The result maps each variation point name to the list of its variant feature names.
406
+ """
407
+ try:
408
+ raw = self.discover_metamodel.use_operation(
409
+ self.fm_model, "FMVariationPoints"
410
+ ).get_result()
411
+ return {vp.name: [v.name for v in variants] for vp, variants in raw.items()}
412
+ except FlamaException as exception:
413
+ logger.error("Error: %s", exception)
414
+ return None
415
+
416
+ # SAT-based operations
417
+
418
+ def backbone(self) -> Union[None, Dict[str, List[Any]]]:
419
+ """
420
+ Returns the backbone of the feature model: the set of features that must always be
421
+ selected (core) and those that must never be selected (dead) across all valid
422
+ configurations, grouped under 'core' and 'dead' keys.
423
+ """
424
+ try:
425
+ self._transform_to_sat()
426
+ return self.discover_metamodel.use_operation(
427
+ self.sat_model, "PySATBackbone"
428
+ ).get_result()
429
+ except FlamaException as exception:
430
+ logger.error("Error: %s", exception)
431
+ return None
432
+
433
+ # BDD-based operations
434
+
435
+ def homogeneity(self) -> Union[None, float]:
436
+ """
437
+ Measures how similar the products of the feature model are to each other. It is
438
+ computed as the average commonality factor across all features. A value of 1.0 means
439
+ all products are identical; lower values indicate more diversity.
440
+ """
441
+ try:
442
+ self._transform_to_bdd()
443
+ return self.discover_metamodel.use_operation(
444
+ self.bdd_model, "BDDHomogeneity"
445
+ ).get_result()
446
+ except FlamaException as exception:
447
+ logger.error("Error: %s", exception)
448
+ return None
449
+
450
+ def product_distribution(self) -> Union[None, List[int]]:
451
+ """
452
+ Returns the distribution of products by number of activated features. The value at
453
+ index i is the count of valid configurations that have exactly i features selected.
454
+ """
455
+ try:
456
+ self._transform_to_bdd()
457
+ return self.discover_metamodel.use_operation(
458
+ self.bdd_model, "BDDProductDistribution"
459
+ ).get_result()
460
+ except FlamaException as exception:
461
+ logger.error("Error: %s", exception)
462
+ return None
463
+
464
+ def variability(self) -> Union[None, Tuple[float, float]]:
465
+ """
466
+ Returns a tuple of (total_variability, partial_variability). Total variability is the
467
+ ratio of valid configurations to the theoretical maximum; partial variability is the
468
+ ratio relative to only the variant features.
469
+ """
470
+ try:
471
+ self._transform_to_bdd()
472
+ return self.discover_metamodel.use_operation(
473
+ self.bdd_model, "BDDVariability"
474
+ ).get_result()
475
+ except FlamaException as exception:
476
+ logger.error("Error: %s", exception)
477
+ return None
478
+
479
+ def variant_features(self) -> Union[None, List[str]]:
480
+ """
481
+ Returns the features that are neither core nor dead — they appear in some but not all
482
+ valid configurations. These are the features that actually vary across products.
483
+ """
484
+ try:
485
+ self._transform_to_bdd()
486
+ return self.discover_metamodel.use_operation(
487
+ self.bdd_model, "BDDVariantFeatures"
488
+ ).get_result()
489
+ except FlamaException as exception:
490
+ logger.error("Error: %s", exception)
491
+ return None
492
+
493
+ def unique_features(self) -> Union[None, List[str]]:
494
+ """
495
+ Returns features that appear in exactly one valid configuration. These features
496
+ uniquely identify a single product in the product line.
497
+ """
498
+ try:
499
+ self._transform_to_bdd()
500
+ return self.discover_metamodel.use_operation(
501
+ self.bdd_model, "BDDUniqueFeatures"
502
+ ).get_result()
503
+ except FlamaException as exception:
504
+ logger.error("Error: %s", exception)
505
+ return None
506
+
507
+ def pure_optional_features(self) -> Union[None, List[str]]:
508
+ """
509
+ Returns features with a feature inclusion probability of exactly 0.5, meaning they
510
+ are selected in exactly half of the valid configurations. These are the most
511
+ unconstrained optional features.
512
+ """
513
+ try:
514
+ self._transform_to_bdd()
515
+ return self.discover_metamodel.use_operation(
516
+ self.bdd_model, "BDDPureOptionalFeatures"
517
+ ).get_result()
518
+ except FlamaException as exception:
519
+ logger.error("Error: %s", exception)
520
+ return None
521
+
522
+ def feature_inclusion_probability(self) -> Union[None, Dict[str, float]]:
523
+ """
524
+ Returns a mapping from each feature name to its inclusion probability: the fraction
525
+ of valid configurations in which that feature is selected. Core features have
526
+ probability 1.0 and dead features have probability 0.0.
527
+ """
528
+ try:
529
+ self._transform_to_bdd()
530
+ return self.discover_metamodel.use_operation(
531
+ self.bdd_model, "BDDFeatureInclusionProbability"
532
+ ).get_result()
533
+ except FlamaException as exception:
534
+ logger.error("Error: %s", exception)
535
+ return None
536
+
537
+ def configurations_with_n_features(self, n: int) -> Union[None, List[Configuration]]:
538
+ """
539
+ Returns all valid configurations that have exactly n features selected.
540
+ """
541
+ try:
542
+ self._transform_to_bdd()
543
+ operation = self.discover_metamodel.get_operation(
544
+ self.bdd_model, "BDDConfigurationsWithNFeatures"
545
+ )
546
+ operation.set_n_features(n)
547
+ operation.execute(self.bdd_model)
548
+ return list(operation.get_result())
549
+ except FlamaException as exception:
550
+ logger.error("Error: %s", exception)
551
+ return None
552
+
553
+ def sampling(
554
+ self, size: int, with_replacement: bool = False
555
+ ) -> Union[None, List[Configuration]]:
556
+ """
557
+ Returns a random sample of valid configurations of the given size. When
558
+ with_replacement is True, the same configuration may appear more than once.
559
+ """
560
+ try:
561
+ self._transform_to_bdd()
562
+ operation = self.discover_metamodel.get_operation(self.bdd_model, "BDDSampling")
563
+ operation.set_sample_size(size)
564
+ operation.set_with_replacement(with_replacement)
565
+ operation.execute(self.bdd_model)
566
+ return operation.get_result()
567
+ except FlamaException as exception:
568
+ logger.error("Error: %s", exception)
569
+ return None
570
+
571
+ # Z3-based operations
572
+
573
+ def all_feature_bounds(self) -> Union[None, Dict[str, Dict[str, Any]]]:
574
+ """
575
+ Returns the value bounds for all typed (Integer, Real, String) attribute features in
576
+ the model. Each entry maps a feature name to a dict with 'min', 'max', and 'bounded'
577
+ keys. Requires the z3 metamodel plugin.
578
+ """
579
+ try:
580
+ self._transform_to_z3()
581
+ return self.discover_metamodel.use_operation(
582
+ self.z3_model, "Z3AllFeatureBounds"
583
+ ).get_result()
584
+ except FlamaException as exception:
585
+ logger.error("Error: %s", exception)
586
+ return None
587
+
588
+ def feature_bounds(self, variable_name: str) -> Union[None, Dict[str, Any]]:
589
+ """
590
+ Returns the value bounds for a specific typed attribute feature. The result dict
591
+ contains 'min', 'max', and 'bounded' keys. Requires the z3 metamodel plugin.
592
+ """
593
+ try:
594
+ self._transform_to_z3()
595
+ operation = self.discover_metamodel.get_operation(self.z3_model, "Z3FeatureBounds")
596
+ operation.set_variable_name(variable_name)
597
+ operation.execute(self.z3_model)
598
+ return operation.get_result()
599
+ except FlamaException as exception:
600
+ logger.error("Error: %s", exception)
601
+ return None
602
+
603
+ # Diagnosis-based operations
604
+
605
+ def diagnosis(
606
+ self,
607
+ configuration_path: str,
608
+ test_case_path: str,
609
+ max_diagnoses: Optional[int] = None,
610
+ ) -> Union[None, List[str]]:
611
+ """
612
+ Returns a list of diagnoses explaining why a given configuration does not satisfy
613
+ the test case constraints. Each diagnosis is a minimal set of constraints whose
614
+ removal would resolve the inconsistency. Requires the pysat_diagnosis plugin.
615
+ """
616
+ try:
617
+ self._transform_to_diagnosis()
618
+ configuration = self.discover_metamodel.use_transformation_t2m(
619
+ configuration_path, "configuration"
620
+ )
621
+ test_case = self.discover_metamodel.use_transformation_t2m(
622
+ test_case_path, "configuration"
623
+ )
624
+ operation = self.discover_metamodel.get_operation(
625
+ self.diagnosis_model, "PySATDiagnosis"
626
+ )
627
+ operation.set_configuration(configuration)
628
+ operation.set_test_case(test_case)
629
+ if max_diagnoses is not None:
630
+ operation.set_max_diagnoses(max_diagnoses)
631
+ operation.execute(self.diagnosis_model)
632
+ return operation.get_result()
633
+ except FlamaException as exception:
634
+ logger.error("Error: %s", exception)
635
+ return None
636
+
637
+ def conflict(
638
+ self,
639
+ configuration_path: str,
640
+ test_case_path: str,
641
+ max_conflicts: Optional[int] = None,
642
+ ) -> Union[None, List[str]]:
643
+ """
644
+ Returns a list of conflict sets: minimal subsets of the model constraints that are
645
+ inconsistent with the given configuration and test case. Requires the pysat_diagnosis
646
+ plugin.
647
+ """
648
+ try:
649
+ self._transform_to_diagnosis()
650
+ configuration = self.discover_metamodel.use_transformation_t2m(
651
+ configuration_path, "configuration"
652
+ )
653
+ test_case = self.discover_metamodel.use_transformation_t2m(
654
+ test_case_path, "configuration"
655
+ )
656
+ operation = self.discover_metamodel.get_operation(
657
+ self.diagnosis_model, "PySATConflict"
658
+ )
659
+ operation.set_configuration(configuration)
660
+ operation.set_test_case(test_case)
661
+ if max_conflicts is not None:
662
+ operation.set_max_conflicts(max_conflicts)
663
+ operation.execute(self.diagnosis_model)
664
+ return operation.get_result()
665
+ except FlamaException as exception:
666
+ logger.error("Error: %s", exception)
667
+ return None
@@ -0,0 +1,36 @@
1
+ Metadata-Version: 2.4
2
+ Name: flamapy
3
+ Version: 2.6.0.dev0
4
+ Summary: Flamapy feature model is a distribution of the flama framework containing all plugins required to analyze feature models. It also offers a richer API and a complete command line interface and documentation.
5
+ Author-email: Flamapy <flamapy@us.es>
6
+ License-Expression: GPL-3.0-or-later
7
+ Project-URL: Homepage, https://github.com/flamapy/flamapy-feature-model
8
+ Requires-Python: >=3.9
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: flamapy-fw~=2.6.0.dev0
12
+ Requires-Dist: flamapy-fm~=2.6.0.dev0
13
+ Requires-Dist: flamapy-sat~=2.6.0.dev0
14
+ Requires-Dist: flamapy-bdd~=2.6.0.dev0
15
+ Requires-Dist: flamapy-z3~=2.6.0.dev0
16
+ Provides-Extra: dev
17
+ Requires-Dist: pytest; extra == "dev"
18
+ Requires-Dist: pytest-mock; extra == "dev"
19
+ Requires-Dist: prospector; extra == "dev"
20
+ Requires-Dist: mypy; extra == "dev"
21
+ Requires-Dist: coverage; extra == "dev"
22
+ Dynamic: license-file
23
+
24
+ # flamapy
25
+
26
+ The flamapy feature-model distribution: a meta-package that installs the
27
+ framework and the feature-model analysis plugins, and provides the command-line
28
+ interface and the easy-to-use Python facade (`FLAMAFeatureModel`).
29
+
30
+ **Documentation:** https://docs.flamapy.org
31
+
32
+ ## Installation
33
+
34
+ ```bash
35
+ pip install flamapy
36
+ ```
@@ -13,5 +13,6 @@ flamapy/interfaces/python/__init__.py
13
13
  flamapy/interfaces/python/flamapy_feature_model.py
14
14
  tests/test_basic_units.py
15
15
  tests/test_cli_basic_units.py
16
+ tests/test_documentation_examples.py
16
17
  tests/test_fama_suite_bdd.py
17
18
  tests/test_fama_suite_sat.py
@@ -0,0 +1,12 @@
1
+ flamapy-fw~=2.6.0.dev0
2
+ flamapy-fm~=2.6.0.dev0
3
+ flamapy-sat~=2.6.0.dev0
4
+ flamapy-bdd~=2.6.0.dev0
5
+ flamapy-z3~=2.6.0.dev0
6
+
7
+ [dev]
8
+ pytest
9
+ pytest-mock
10
+ prospector
11
+ mypy
12
+ coverage
@@ -4,17 +4,18 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "flamapy"
7
- version = "2.5.0"
7
+ version = "2.6.0.dev0"
8
8
  description = "Flamapy feature model is a distribution of the flama framework containing all plugins required to analyze feature models. It also offers a richer API and a complete command line interface and documentation."
9
9
  readme = "README.md"
10
10
  license = "GPL-3.0-or-later"
11
11
  authors = [{ name = "Flamapy", email = "flamapy@us.es" }]
12
12
  requires-python = ">=3.9"
13
13
  dependencies = [
14
- "flamapy-fw~=2.5.0",
15
- "flamapy-fm~=2.5.0",
16
- "flamapy-sat~=2.5.0",
17
- "flamapy-bdd~=2.5.0",
14
+ "flamapy-fw~=2.6.0.dev0",
15
+ "flamapy-fm~=2.6.0.dev0",
16
+ "flamapy-sat~=2.6.0.dev0",
17
+ "flamapy-bdd~=2.6.0.dev0",
18
+ "flamapy-z3~=2.6.0.dev0",
18
19
  ]
19
20
 
20
21
  [project.optional-dependencies]
@@ -0,0 +1,356 @@
1
+ """Executable versions of every code example in the documentation.
2
+
3
+ Each operation page under ``flamapy_docs/_operations`` ships up to three runnable
4
+ snippets: the easy-to-use Python facade, the ``DiscoverMetamodels`` framework call
5
+ and the advanced (manual transformation) flow. The tests below mirror those
6
+ snippets so the documentation stays runnable and any regression in a documented
7
+ operation is caught here.
8
+
9
+ The Z3 operations run against a model with typed attributes; ``flamapy-z3`` is a
10
+ dependency of the ``flamapy`` distribution, so they are always exercised.
11
+ """
12
+ import pytest
13
+
14
+ from flamapy.core.discover import DiscoverMetamodels
15
+ from flamapy.interfaces.python.flamapy_feature_model import FLAMAFeatureModel
16
+
17
+ VALID_MODEL = "./resources/models/simple/valid_model.uvl"
18
+ VALID_CONFIG = "./resources/configurations/valid_configuration.csvconf"
19
+ # Feature model carrying typed attributes (Integer feature + Real attributes),
20
+ # required by the Z3 examples.
21
+ TYPED_MODEL = "./resources/models/simple/typed_attributes.uvl"
22
+
23
+
24
+ # ---------------------------------------------------------------------------
25
+ # Python facade examples (flamapy_docs/_operations/*.md, "facade usage")
26
+ # ---------------------------------------------------------------------------
27
+
28
+ def test_facade_atomic_sets():
29
+ fm = FLAMAFeatureModel(VALID_MODEL)
30
+ assert len(fm.atomic_sets()) == 17
31
+
32
+
33
+ def test_facade_average_branching_factor():
34
+ fm = FLAMAFeatureModel(VALID_MODEL)
35
+ assert fm.average_branching_factor() == 2.45
36
+
37
+
38
+ def test_facade_count_leafs():
39
+ fm = FLAMAFeatureModel(VALID_MODEL)
40
+ assert fm.count_leafs() == 17
41
+
42
+
43
+ def test_facade_estimated_number_of_configurations():
44
+ fm = FLAMAFeatureModel(VALID_MODEL)
45
+ assert fm.estimated_number_of_configurations() == 1904
46
+
47
+
48
+ def test_facade_feature_ancestors():
49
+ fm = FLAMAFeatureModel(VALID_MODEL)
50
+ assert fm.feature_ancestors("v74") == ["PHP", "Server", "eCommerce"]
51
+
52
+
53
+ def test_facade_leaf_features():
54
+ fm = FLAMAFeatureModel(VALID_MODEL)
55
+ assert len(fm.leaf_features()) == 17
56
+
57
+
58
+ def test_facade_max_depth():
59
+ fm = FLAMAFeatureModel(VALID_MODEL)
60
+ assert fm.max_depth() == 4
61
+
62
+
63
+ def test_facade_core_features():
64
+ fm = FLAMAFeatureModel(VALID_MODEL)
65
+ assert len(fm.core_features()) == 12
66
+
67
+
68
+ def test_facade_dead_features():
69
+ fm = FLAMAFeatureModel(VALID_MODEL)
70
+ assert fm.dead_features() == []
71
+
72
+
73
+ def test_facade_false_optional_features():
74
+ fm = FLAMAFeatureModel(VALID_MODEL)
75
+ assert fm.false_optional_features() == []
76
+
77
+
78
+ def test_facade_filter():
79
+ fm = FLAMAFeatureModel(VALID_MODEL)
80
+ assert len(fm.filter(VALID_CONFIG)) == 68
81
+
82
+
83
+ def test_facade_configurations_number():
84
+ fm = FLAMAFeatureModel(VALID_MODEL)
85
+ assert fm.configurations_number() == 816
86
+
87
+
88
+ def test_facade_configurations():
89
+ fm = FLAMAFeatureModel(VALID_MODEL)
90
+ assert len(fm.configurations()) == 816
91
+
92
+
93
+ def test_facade_commonality():
94
+ fm = FLAMAFeatureModel(VALID_MODEL)
95
+ assert isinstance(fm.commonality(VALID_CONFIG), float)
96
+
97
+
98
+ def test_facade_satisfiable_configuration():
99
+ fm = FLAMAFeatureModel(VALID_MODEL)
100
+ assert fm.satisfiable_configuration(VALID_CONFIG, False) is True
101
+
102
+
103
+ def test_facade_satisfiable():
104
+ fm = FLAMAFeatureModel(VALID_MODEL)
105
+ assert fm.satisfiable() is True
106
+
107
+
108
+ def test_facade_metrics():
109
+ fm = FLAMAFeatureModel(VALID_MODEL)
110
+ result = fm.metrics()
111
+ assert isinstance(result, list) and len(result) == 61
112
+ assert all("name" in entry and "result" in entry for entry in result)
113
+
114
+
115
+ def test_facade_variation_points():
116
+ fm = FLAMAFeatureModel(VALID_MODEL)
117
+ result = fm.variation_points()
118
+ assert isinstance(result, dict) and len(result) == 7
119
+ # Keys and values are feature-name strings.
120
+ assert all(isinstance(k, str) for k in result)
121
+ assert all(isinstance(v, str) for variants in result.values() for v in variants)
122
+
123
+
124
+ def test_facade_backbone():
125
+ fm = FLAMAFeatureModel(VALID_MODEL)
126
+ result = fm.backbone()
127
+ assert isinstance(result, dict)
128
+ assert set(result.keys()) == {"core", "dead"}
129
+
130
+
131
+ def test_facade_homogeneity():
132
+ fm = FLAMAFeatureModel(VALID_MODEL)
133
+ result = fm.homogeneity()
134
+ assert isinstance(result, float) and 0.0 <= result <= 1.0
135
+
136
+
137
+ def test_facade_product_distribution():
138
+ fm = FLAMAFeatureModel(VALID_MODEL)
139
+ result = fm.product_distribution()
140
+ assert isinstance(result, list)
141
+ # The distribution sums to the total number of configurations.
142
+ assert sum(result) == 816
143
+
144
+
145
+ def test_facade_variability():
146
+ fm = FLAMAFeatureModel(VALID_MODEL)
147
+ result = fm.variability()
148
+ assert isinstance(result, tuple) and len(result) == 2
149
+
150
+
151
+ def test_facade_variant_features():
152
+ fm = FLAMAFeatureModel(VALID_MODEL)
153
+ assert len(fm.variant_features()) == 16
154
+
155
+
156
+ def test_facade_unique_features():
157
+ fm = FLAMAFeatureModel(VALID_MODEL)
158
+ assert fm.unique_features() == []
159
+
160
+
161
+ def test_facade_pure_optional_features():
162
+ fm = FLAMAFeatureModel(VALID_MODEL)
163
+ assert sorted(fm.pure_optional_features()) == ["ADVANCED", "BASIC", "CreditCard", "Mobile"]
164
+
165
+
166
+ def test_facade_feature_inclusion_probability():
167
+ fm = FLAMAFeatureModel(VALID_MODEL)
168
+ result = fm.feature_inclusion_probability()
169
+ assert isinstance(result, dict)
170
+ assert all(0.0 <= p <= 1.0 for p in result.values())
171
+
172
+
173
+ def test_facade_configurations_with_n_features():
174
+ fm = FLAMAFeatureModel(VALID_MODEL)
175
+ assert isinstance(fm.configurations_with_n_features(5), list)
176
+
177
+
178
+ def test_facade_sampling():
179
+ fm = FLAMAFeatureModel(VALID_MODEL)
180
+ assert len(fm.sampling(5)) == 5
181
+
182
+
183
+ def test_facade_diagnosis():
184
+ fm = FLAMAFeatureModel(VALID_MODEL)
185
+ assert isinstance(fm.diagnosis(VALID_CONFIG, VALID_CONFIG), list)
186
+
187
+
188
+ def test_facade_conflict():
189
+ fm = FLAMAFeatureModel(VALID_MODEL)
190
+ assert isinstance(fm.conflict(VALID_CONFIG, VALID_CONFIG), list)
191
+
192
+
193
+ # ---------------------------------------------------------------------------
194
+ # Framework examples (flamapy_docs/_operations/*.md, "framework usage")
195
+ # `dm.use_operation_from_file(...)` for operations that need no configuration.
196
+ # ---------------------------------------------------------------------------
197
+
198
+ FRAMEWORK_OPERATIONS = [
199
+ "AtomicSets", # base-class name resolves to FMAtomicSets
200
+ "FMAverageBranchingFactor",
201
+ "FMCountLeafs",
202
+ "FMEstimatedConfigurationsNumber",
203
+ "FMLeafFeatures",
204
+ "FMMaxDepthTree",
205
+ "FMMetrics",
206
+ "FMVariationPoints",
207
+ "PySATBackbone",
208
+ "PySATConfigurations",
209
+ "PySATConfigurationsNumber",
210
+ "PySATCoreFeatures",
211
+ "PySATDeadFeatures",
212
+ "PySATFalseOptionalFeatures",
213
+ "PySATSatisfiable",
214
+ "BDDFeatureInclusionProbability",
215
+ "BDDHomogeneity",
216
+ "BDDProductDistribution",
217
+ "BDDPureOptionalFeatures",
218
+ "BDDUniqueFeatures",
219
+ "BDDVariability",
220
+ "BDDVariantFeatures",
221
+ "Sampling", # base-class name resolves to a Sampling op
222
+ ]
223
+
224
+
225
+ @pytest.mark.parametrize("operation_name", FRAMEWORK_OPERATIONS)
226
+ def test_framework_use_operation_from_file(operation_name):
227
+ dm = DiscoverMetamodels()
228
+ result = dm.use_operation_from_file(operation_name, VALID_MODEL)
229
+ assert result is not None
230
+
231
+
232
+ def test_framework_diagnosis_requires_configuration():
233
+ # Diagnosis/conflict are OperationWithConfiguration: they need configuration_file.
234
+ dm = DiscoverMetamodels()
235
+ result = dm.use_operation_from_file(
236
+ "PySATDiagnosis", VALID_MODEL, configuration_file=VALID_CONFIG
237
+ )
238
+ assert isinstance(result, list)
239
+
240
+
241
+ def test_framework_conflict_requires_configuration():
242
+ dm = DiscoverMetamodels()
243
+ result = dm.use_operation_from_file(
244
+ "PySATConflict", VALID_MODEL, configuration_file=VALID_CONFIG
245
+ )
246
+ assert isinstance(result, list)
247
+
248
+
249
+ # ---------------------------------------------------------------------------
250
+ # Advanced framework examples (manual transformation + get_operation)
251
+ # ---------------------------------------------------------------------------
252
+
253
+ def test_advanced_dead_features():
254
+ dm = DiscoverMetamodels()
255
+ feature_model = dm.use_transformation_t2m(VALID_MODEL, "fm")
256
+ sat_model = dm.use_transformation_m2m(feature_model, "pysat")
257
+ operation = dm.get_operation(sat_model, "PySATDeadFeatures")
258
+ operation.execute(sat_model)
259
+ assert operation.get_result() == []
260
+
261
+
262
+ def test_advanced_homogeneity():
263
+ dm = DiscoverMetamodels()
264
+ feature_model = dm.use_transformation_t2m(VALID_MODEL, "fm")
265
+ bdd_model = dm.use_transformation_m2m(feature_model, "bdd")
266
+ operation = dm.get_operation(bdd_model, "BDDHomogeneity")
267
+ operation.execute(bdd_model)
268
+ assert isinstance(operation.get_result(), float)
269
+
270
+
271
+ def test_advanced_configurations_with_n_features():
272
+ dm = DiscoverMetamodels()
273
+ feature_model = dm.use_transformation_t2m(VALID_MODEL, "fm")
274
+ bdd_model = dm.use_transformation_m2m(feature_model, "bdd")
275
+ operation = dm.get_operation(bdd_model, "BDDConfigurationsWithNFeatures")
276
+ operation.set_n_features(5)
277
+ operation.execute(bdd_model)
278
+ assert isinstance(list(operation.get_result()), list)
279
+
280
+
281
+ def test_advanced_diagnosis_with_configuration_and_test_case():
282
+ dm = DiscoverMetamodels()
283
+ feature_model = dm.use_transformation_t2m(VALID_MODEL, "fm")
284
+ sat_model = dm.use_transformation_m2m(feature_model, "pysat_diagnosis")
285
+ configuration = dm.use_transformation_t2m(VALID_CONFIG, "configuration")
286
+ test_case = dm.use_transformation_t2m(VALID_CONFIG, "configuration")
287
+ operation = dm.get_operation(sat_model, "PySATDiagnosis")
288
+ operation.set_configuration(configuration)
289
+ operation.set_test_case(test_case)
290
+ operation.execute(sat_model)
291
+ assert isinstance(operation.get_result(), list)
292
+
293
+
294
+ def test_advanced_conflict_with_configuration_and_test_case():
295
+ dm = DiscoverMetamodels()
296
+ feature_model = dm.use_transformation_t2m(VALID_MODEL, "fm")
297
+ sat_model = dm.use_transformation_m2m(feature_model, "pysat_diagnosis")
298
+ configuration = dm.use_transformation_t2m(VALID_CONFIG, "configuration")
299
+ test_case = dm.use_transformation_t2m(VALID_CONFIG, "configuration")
300
+ operation = dm.get_operation(sat_model, "PySATConflict")
301
+ operation.set_configuration(configuration)
302
+ operation.set_test_case(test_case)
303
+ operation.execute(sat_model)
304
+ assert isinstance(operation.get_result(), list)
305
+
306
+
307
+ # ---------------------------------------------------------------------------
308
+ # Z3 examples (optional plugin; require a model with typed attributes)
309
+ # ---------------------------------------------------------------------------
310
+
311
+ def test_facade_all_feature_bounds():
312
+ fm = FLAMAFeatureModel(TYPED_MODEL)
313
+ result = fm.all_feature_bounds()
314
+ assert result["Scoops"]["min"] == 1
315
+ assert result["Scoops"]["max"] == 5
316
+ assert result["Scoops"]["bounded"] is True
317
+
318
+
319
+ def test_facade_feature_bounds():
320
+ fm = FLAMAFeatureModel(TYPED_MODEL)
321
+ result = fm.feature_bounds("Scoops")
322
+ assert result["min"] == 1
323
+ assert result["max"] == 5
324
+
325
+
326
+ def test_advanced_all_feature_bounds():
327
+ dm = DiscoverMetamodels()
328
+ feature_model = dm.use_transformation_t2m(TYPED_MODEL, "fm")
329
+ z3_model = dm.use_transformation_m2m(feature_model, "z3")
330
+ operation = dm.get_operation(z3_model, "Z3AllFeatureBounds")
331
+ operation.execute(z3_model)
332
+ assert "Scoops" in operation.get_result()
333
+
334
+
335
+ def test_advanced_variable_bounds():
336
+ dm = DiscoverMetamodels()
337
+ feature_model = dm.use_transformation_t2m(TYPED_MODEL, "fm")
338
+ z3_model = dm.use_transformation_m2m(feature_model, "z3")
339
+ operation = dm.get_operation(z3_model, "Z3VariableBounds")
340
+ operation.set_variable_name("Scoops")
341
+ operation.execute(z3_model)
342
+ result = operation.get_result()
343
+ assert result["min_bound"] == 1
344
+ assert result["max_bound"] == 5
345
+
346
+
347
+ def test_advanced_attribute_optimization():
348
+ from flamapy.metamodels.z3_metamodel.operations.interfaces import OptimizationGoal
349
+
350
+ dm = DiscoverMetamodels()
351
+ feature_model = dm.use_transformation_t2m(TYPED_MODEL, "fm")
352
+ z3_model = dm.use_transformation_m2m(feature_model, "z3")
353
+ operation = dm.get_operation(z3_model, "Z3AttributeOptimization")
354
+ operation.set_attributes({"Price": OptimizationGoal.MINIMIZE})
355
+ operation.execute(z3_model)
356
+ assert isinstance(operation.get_result(), list)
flamapy-2.5.0/PKG-INFO DELETED
@@ -1,104 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: flamapy
3
- Version: 2.5.0
4
- Summary: Flamapy feature model is a distribution of the flama framework containing all plugins required to analyze feature models. It also offers a richer API and a complete command line interface and documentation.
5
- Author-email: Flamapy <flamapy@us.es>
6
- License-Expression: GPL-3.0-or-later
7
- Project-URL: Homepage, https://github.com/flamapy/flamapy-feature-model
8
- Requires-Python: >=3.9
9
- Description-Content-Type: text/markdown
10
- License-File: LICENSE
11
- Requires-Dist: flamapy-fw~=2.5.0
12
- Requires-Dist: flamapy-fm~=2.5.0
13
- Requires-Dist: flamapy-sat~=2.5.0
14
- Requires-Dist: flamapy-bdd~=2.5.0
15
- Provides-Extra: dev
16
- Requires-Dist: pytest; extra == "dev"
17
- Requires-Dist: pytest-mock; extra == "dev"
18
- Requires-Dist: prospector; extra == "dev"
19
- Requires-Dist: mypy; extra == "dev"
20
- Requires-Dist: coverage; extra == "dev"
21
- Dynamic: license-file
22
-
23
- <div align="center">
24
-
25
- <a href="">[![Pytest Testing Suite](https://github.com/flamapy/flamapy/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/flamapy/flamapy/actions/workflows/tests.yml)</a>
26
- <a href="">[![Commits Syntax Checker](https://github.com/flamapy/flamapy/actions/workflows/commits.yml/badge.svg?branch=main)](https://github.com/flamapy/flamapy/actions/workflows/commits.yml)</a>
27
- <a href="">![PyPI](https://img.shields.io/pypi/v/flamapy?label=pypi%20package)
28
- <a href="">![PyPI - Downloads](https://img.shields.io/pypi/dm/flamapy)
29
- </div>
30
-
31
- #
32
-
33
- <div id="top"></div>
34
- <br />
35
- <div align="center">
36
-
37
- <h3 align="center">FLAMAPY</h3>
38
-
39
- <p align="center">
40
- A new and easy way to use FLAMA
41
- <br />
42
- <a href="https://github.com/flamapy/flamapy/issues">Report Bug</a>
43
- ·
44
- <a href="https://github.com/flamapy/flamapy/issues">Request Feature</a>
45
- </p>
46
- </div>
47
- <!-- ABOUT THE PROJECT -->
48
-
49
- # About The Project
50
- 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.
51
-
52
- 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.
53
-
54
- # Using the CMD
55
- ```bash
56
- flamapy --help #This will show the commands available
57
- flamapy satisfiable <path to file> to check if a model is valid
58
- ...
59
- ```
60
- # Using the Python interface
61
- 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:
62
-
63
- ```python
64
- from flamapy.interfaces.python.flama_feature_model import FLAMAFeatureModel
65
-
66
- fm = FLAMAFeatureModel("path/to/feature/model")
67
- print(fm.valid())
68
- ```
69
- # Operations available:
70
- 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.
71
-
72
- * 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.
73
-
74
- * 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.
75
-
76
- * 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.
77
-
78
- * 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.
79
-
80
- * 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.
81
-
82
- * 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.
83
-
84
- * 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.
85
- * 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.
86
-
87
- * 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
88
- features are independent, but in most cases, constraints and dependencies between features need to be taken into account.
89
-
90
- * 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.
91
-
92
- * 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.
93
-
94
- * 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.
95
-
96
- * 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.
97
-
98
- * 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.
99
-
100
- * satisfiable: In the context of feature models, this usually refers to whether the feature model itself satisfies all the
101
- constraints and dependencies. A a valid feature model is one that does encodes at least a single valid product.
102
-
103
- * 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.
104
-
flamapy-2.5.0/README.md DELETED
@@ -1,82 +0,0 @@
1
- <div align="center">
2
-
3
- <a href="">[![Pytest Testing Suite](https://github.com/flamapy/flamapy/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/flamapy/flamapy/actions/workflows/tests.yml)</a>
4
- <a href="">[![Commits Syntax Checker](https://github.com/flamapy/flamapy/actions/workflows/commits.yml/badge.svg?branch=main)](https://github.com/flamapy/flamapy/actions/workflows/commits.yml)</a>
5
- <a href="">![PyPI](https://img.shields.io/pypi/v/flamapy?label=pypi%20package)
6
- <a href="">![PyPI - Downloads](https://img.shields.io/pypi/dm/flamapy)
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
-
@@ -1,104 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: flamapy
3
- Version: 2.5.0
4
- Summary: Flamapy feature model is a distribution of the flama framework containing all plugins required to analyze feature models. It also offers a richer API and a complete command line interface and documentation.
5
- Author-email: Flamapy <flamapy@us.es>
6
- License-Expression: GPL-3.0-or-later
7
- Project-URL: Homepage, https://github.com/flamapy/flamapy-feature-model
8
- Requires-Python: >=3.9
9
- Description-Content-Type: text/markdown
10
- License-File: LICENSE
11
- Requires-Dist: flamapy-fw~=2.5.0
12
- Requires-Dist: flamapy-fm~=2.5.0
13
- Requires-Dist: flamapy-sat~=2.5.0
14
- Requires-Dist: flamapy-bdd~=2.5.0
15
- Provides-Extra: dev
16
- Requires-Dist: pytest; extra == "dev"
17
- Requires-Dist: pytest-mock; extra == "dev"
18
- Requires-Dist: prospector; extra == "dev"
19
- Requires-Dist: mypy; extra == "dev"
20
- Requires-Dist: coverage; extra == "dev"
21
- Dynamic: license-file
22
-
23
- <div align="center">
24
-
25
- <a href="">[![Pytest Testing Suite](https://github.com/flamapy/flamapy/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/flamapy/flamapy/actions/workflows/tests.yml)</a>
26
- <a href="">[![Commits Syntax Checker](https://github.com/flamapy/flamapy/actions/workflows/commits.yml/badge.svg?branch=main)](https://github.com/flamapy/flamapy/actions/workflows/commits.yml)</a>
27
- <a href="">![PyPI](https://img.shields.io/pypi/v/flamapy?label=pypi%20package)
28
- <a href="">![PyPI - Downloads](https://img.shields.io/pypi/dm/flamapy)
29
- </div>
30
-
31
- #
32
-
33
- <div id="top"></div>
34
- <br />
35
- <div align="center">
36
-
37
- <h3 align="center">FLAMAPY</h3>
38
-
39
- <p align="center">
40
- A new and easy way to use FLAMA
41
- <br />
42
- <a href="https://github.com/flamapy/flamapy/issues">Report Bug</a>
43
- ·
44
- <a href="https://github.com/flamapy/flamapy/issues">Request Feature</a>
45
- </p>
46
- </div>
47
- <!-- ABOUT THE PROJECT -->
48
-
49
- # About The Project
50
- 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.
51
-
52
- 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.
53
-
54
- # Using the CMD
55
- ```bash
56
- flamapy --help #This will show the commands available
57
- flamapy satisfiable <path to file> to check if a model is valid
58
- ...
59
- ```
60
- # Using the Python interface
61
- 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:
62
-
63
- ```python
64
- from flamapy.interfaces.python.flama_feature_model import FLAMAFeatureModel
65
-
66
- fm = FLAMAFeatureModel("path/to/feature/model")
67
- print(fm.valid())
68
- ```
69
- # Operations available:
70
- 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.
71
-
72
- * 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.
73
-
74
- * 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.
75
-
76
- * 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.
77
-
78
- * 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.
79
-
80
- * 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.
81
-
82
- * 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.
83
-
84
- * 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.
85
- * 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.
86
-
87
- * 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
88
- features are independent, but in most cases, constraints and dependencies between features need to be taken into account.
89
-
90
- * 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.
91
-
92
- * 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.
93
-
94
- * 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.
95
-
96
- * 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.
97
-
98
- * 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.
99
-
100
- * satisfiable: In the context of feature models, this usually refers to whether the feature model itself satisfies all the
101
- constraints and dependencies. A a valid feature model is one that does encodes at least a single valid product.
102
-
103
- * 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.
104
-
@@ -1,11 +0,0 @@
1
- flamapy-fw~=2.5.0
2
- flamapy-fm~=2.5.0
3
- flamapy-sat~=2.5.0
4
- flamapy-bdd~=2.5.0
5
-
6
- [dev]
7
- pytest
8
- pytest-mock
9
- prospector
10
- mypy
11
- coverage
File without changes
File without changes
File without changes