flamapy 2.6.0.dev2__tar.gz → 2.6.0.dev4__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 (21) hide show
  1. {flamapy-2.6.0.dev2 → flamapy-2.6.0.dev4}/PKG-INFO +6 -6
  2. {flamapy-2.6.0.dev2 → flamapy-2.6.0.dev4}/flamapy/interfaces/python/flamapy_feature_model.py +51 -32
  3. {flamapy-2.6.0.dev2 → flamapy-2.6.0.dev4}/flamapy.egg-info/PKG-INFO +6 -6
  4. flamapy-2.6.0.dev4/flamapy.egg-info/requires.txt +12 -0
  5. {flamapy-2.6.0.dev2 → flamapy-2.6.0.dev4}/pyproject.toml +6 -6
  6. {flamapy-2.6.0.dev2 → flamapy-2.6.0.dev4}/tests/test_basic_units.py +17 -0
  7. flamapy-2.6.0.dev2/flamapy.egg-info/requires.txt +0 -12
  8. {flamapy-2.6.0.dev2 → flamapy-2.6.0.dev4}/LICENSE +0 -0
  9. {flamapy-2.6.0.dev2 → flamapy-2.6.0.dev4}/README.md +0 -0
  10. {flamapy-2.6.0.dev2 → flamapy-2.6.0.dev4}/flamapy/commands/__init__.py +0 -0
  11. {flamapy-2.6.0.dev2 → flamapy-2.6.0.dev4}/flamapy/interfaces/python/__init__.py +0 -0
  12. {flamapy-2.6.0.dev2 → flamapy-2.6.0.dev4}/flamapy.egg-info/SOURCES.txt +0 -0
  13. {flamapy-2.6.0.dev2 → flamapy-2.6.0.dev4}/flamapy.egg-info/dependency_links.txt +0 -0
  14. {flamapy-2.6.0.dev2 → flamapy-2.6.0.dev4}/flamapy.egg-info/entry_points.txt +0 -0
  15. {flamapy-2.6.0.dev2 → flamapy-2.6.0.dev4}/flamapy.egg-info/top_level.txt +0 -0
  16. {flamapy-2.6.0.dev2 → flamapy-2.6.0.dev4}/setup.cfg +0 -0
  17. {flamapy-2.6.0.dev2 → flamapy-2.6.0.dev4}/setup.py +0 -0
  18. {flamapy-2.6.0.dev2 → flamapy-2.6.0.dev4}/tests/test_cli_basic_units.py +0 -0
  19. {flamapy-2.6.0.dev2 → flamapy-2.6.0.dev4}/tests/test_documentation_examples.py +0 -0
  20. {flamapy-2.6.0.dev2 → flamapy-2.6.0.dev4}/tests/test_fama_suite_bdd.py +0 -0
  21. {flamapy-2.6.0.dev2 → flamapy-2.6.0.dev4}/tests/test_fama_suite_sat.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flamapy
3
- Version: 2.6.0.dev2
3
+ Version: 2.6.0.dev4
4
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
5
  Author-email: Flamapy <flamapy@us.es>
6
6
  License-Expression: GPL-3.0-or-later
@@ -8,11 +8,11 @@ Project-URL: Homepage, https://github.com/flamapy/flamapy-feature-model
8
8
  Requires-Python: >=3.11
9
9
  Description-Content-Type: text/markdown
10
10
  License-File: LICENSE
11
- Requires-Dist: flamapy-fw~=2.6.0.dev2
12
- Requires-Dist: flamapy-fm~=2.6.0.dev2
13
- Requires-Dist: flamapy-sat~=2.6.0.dev2
14
- Requires-Dist: flamapy-bdd~=2.6.0.dev2
15
- Requires-Dist: flamapy-z3~=2.6.0.dev2
11
+ Requires-Dist: flamapy-fw~=2.6.0.dev4
12
+ Requires-Dist: flamapy-fm~=2.6.0.dev4
13
+ Requires-Dist: flamapy-sat~=2.6.0.dev4
14
+ Requires-Dist: flamapy-bdd~=2.6.0.dev4
15
+ Requires-Dist: flamapy-z3~=2.6.0.dev4
16
16
  Provides-Extra: dev
17
17
  Requires-Dist: pytest; extra == "dev"
18
18
  Requires-Dist: pytest-mock; extra == "dev"
@@ -90,6 +90,24 @@ class FLAMAFeatureModel:
90
90
  self.fm_model, "pysat_diagnosis"
91
91
  )
92
92
 
93
+ def _as_configuration(
94
+ self, configuration: Union[str, Dict[str, Any], Configuration]
95
+ ) -> Configuration:
96
+ """Resolve a configuration argument into a Configuration model.
97
+
98
+ Accepts a path to a configuration file (read via the configuration
99
+ transformation), a ``{feature: value}`` mapping, or an already-built
100
+ Configuration. This lets callers that already hold a configuration in
101
+ memory (e.g. an interactive UI) pass it directly without writing a file.
102
+ """
103
+ if isinstance(configuration, Configuration):
104
+ return configuration
105
+ if isinstance(configuration, dict):
106
+ return Configuration(configuration)
107
+ return self.discover_metamodel.use_transformation_t2m(
108
+ configuration, "configuration"
109
+ )
110
+
93
111
  def atomic_sets(self) -> Union[None, List[List[Any]]]:
94
112
  """
95
113
  This operation is used to find the atomic sets in a model:
@@ -297,12 +315,13 @@ class FLAMAFeatureModel:
297
315
  This operation selects a subset of the products of a product line based on certain
298
316
  criteria. For example, you might filter the products to only include those that
299
317
  contain a certain feature.
318
+
319
+ ``configuration_path`` accepts a configuration file path, a ``{feature: value}``
320
+ mapping, or a Configuration object.
300
321
  """
301
322
  try:
302
323
  self._transform_to_sat()
303
- configuration = self.discover_metamodel.use_transformation_t2m(
304
- configuration_path, "configuration"
305
- )
324
+ configuration = self._as_configuration(configuration_path)
306
325
  operation = self.discover_metamodel.get_operation(self.sat_model, "PySATFilter")
307
326
  operation.set_configuration(configuration)
308
327
  operation.execute(self.sat_model)
@@ -350,12 +369,13 @@ class FLAMAFeatureModel:
350
369
  This is a measure of how often a feature appears in the products of a
351
370
  product line. It's usually expressed as a percentage. A feature with
352
371
  100 per cent commonality is a core feature, as it appears in all products.
372
+
373
+ ``configuration_path`` accepts a configuration file path, a ``{feature: value}``
374
+ mapping, or a Configuration object.
353
375
  """
354
376
  try:
355
377
  self._transform_to_sat()
356
- configuration = self.discover_metamodel.use_transformation_t2m(
357
- configuration_path, "configuration"
358
- )
378
+ configuration = self._as_configuration(configuration_path)
359
379
 
360
380
  operation = self.discover_metamodel.get_operation(self.sat_model, "PySATCommonality")
361
381
  operation.set_configuration(configuration)
@@ -375,13 +395,13 @@ class FLAMAFeatureModel:
375
395
  This is a product that is produced from a valid configuration of features. A valid
376
396
  product satisfies all the constraints and dependencies in the feature model.
377
397
 
398
+ ``configuration_path`` accepts a configuration file path, a ``{feature: value}``
399
+ mapping, or a Configuration object.
378
400
  ``backend`` selects the analysis plugin ("sat", "bdd" or "z3"); defaults to sat.
379
401
  """
380
402
  try:
381
403
  model = self._select_backend(backend, Backend.SAT)
382
- configuration = self.discover_metamodel.use_transformation_t2m(
383
- configuration_path, "configuration"
384
- )
404
+ configuration = self._as_configuration(configuration_path)
385
405
  operation = self.discover_metamodel.get_operation(
386
406
  model, "SatisfiableConfiguration"
387
407
  )
@@ -635,27 +655,27 @@ class FLAMAFeatureModel:
635
655
  def diagnosis(
636
656
  self,
637
657
  configuration_path: str,
638
- test_case_path: str,
658
+ test_case_path: Optional[str] = None,
639
659
  max_diagnoses: Optional[int] = None,
640
660
  ) -> Union[None, List[str]]:
641
661
  """
642
- Returns a list of diagnoses explaining why a given configuration does not satisfy
643
- the test case constraints. Each diagnosis is a minimal set of constraints whose
644
- removal would resolve the inconsistency. Requires the pysat_diagnosis plugin.
662
+ Returns a list of diagnoses explaining why a configuration is not valid against the
663
+ feature model: each diagnosis is a minimal set of constraints whose removal would
664
+ resolve the inconsistency. Requires the pysat_diagnosis plugin.
665
+
666
+ ``configuration_path`` accepts a configuration file path, a ``{feature: value}``
667
+ mapping, or a Configuration object. ``test_case_path`` is optional and, when given,
668
+ diagnoses against that expected outcome instead; it accepts the same input types.
645
669
  """
646
670
  try:
647
671
  self._transform_to_diagnosis()
648
- configuration = self.discover_metamodel.use_transformation_t2m(
649
- configuration_path, "configuration"
650
- )
651
- test_case = self.discover_metamodel.use_transformation_t2m(
652
- test_case_path, "configuration"
653
- )
654
672
  operation = self.discover_metamodel.get_operation(
655
673
  self.diagnosis_model, "PySATDiagnosis"
656
674
  )
657
- operation.set_configuration(configuration)
658
- operation.set_test_case(test_case)
675
+ if configuration_path is not None:
676
+ operation.set_configuration(self._as_configuration(configuration_path))
677
+ if test_case_path is not None:
678
+ operation.set_test_case(self._as_configuration(test_case_path))
659
679
  if max_diagnoses is not None:
660
680
  operation.set_max_diagnoses(max_diagnoses)
661
681
  operation.execute(self.diagnosis_model)
@@ -667,27 +687,26 @@ class FLAMAFeatureModel:
667
687
  def conflict(
668
688
  self,
669
689
  configuration_path: str,
670
- test_case_path: str,
690
+ test_case_path: Optional[str] = None,
671
691
  max_conflicts: Optional[int] = None,
672
692
  ) -> Union[None, List[str]]:
673
693
  """
674
694
  Returns a list of conflict sets: minimal subsets of the model constraints that are
675
- inconsistent with the given configuration and test case. Requires the pysat_diagnosis
676
- plugin.
695
+ inconsistent with the given configuration. Requires the pysat_diagnosis plugin.
696
+
697
+ ``configuration_path`` accepts a configuration file path, a ``{feature: value}``
698
+ mapping, or a Configuration object. ``test_case_path`` is optional and, when given,
699
+ looks for conflicts against that expected outcome instead; same input types.
677
700
  """
678
701
  try:
679
702
  self._transform_to_diagnosis()
680
- configuration = self.discover_metamodel.use_transformation_t2m(
681
- configuration_path, "configuration"
682
- )
683
- test_case = self.discover_metamodel.use_transformation_t2m(
684
- test_case_path, "configuration"
685
- )
686
703
  operation = self.discover_metamodel.get_operation(
687
704
  self.diagnosis_model, "PySATConflict"
688
705
  )
689
- operation.set_configuration(configuration)
690
- operation.set_test_case(test_case)
706
+ if configuration_path is not None:
707
+ operation.set_configuration(self._as_configuration(configuration_path))
708
+ if test_case_path is not None:
709
+ operation.set_test_case(self._as_configuration(test_case_path))
691
710
  if max_conflicts is not None:
692
711
  operation.set_max_conflicts(max_conflicts)
693
712
  operation.execute(self.diagnosis_model)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flamapy
3
- Version: 2.6.0.dev2
3
+ Version: 2.6.0.dev4
4
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
5
  Author-email: Flamapy <flamapy@us.es>
6
6
  License-Expression: GPL-3.0-or-later
@@ -8,11 +8,11 @@ Project-URL: Homepage, https://github.com/flamapy/flamapy-feature-model
8
8
  Requires-Python: >=3.11
9
9
  Description-Content-Type: text/markdown
10
10
  License-File: LICENSE
11
- Requires-Dist: flamapy-fw~=2.6.0.dev2
12
- Requires-Dist: flamapy-fm~=2.6.0.dev2
13
- Requires-Dist: flamapy-sat~=2.6.0.dev2
14
- Requires-Dist: flamapy-bdd~=2.6.0.dev2
15
- Requires-Dist: flamapy-z3~=2.6.0.dev2
11
+ Requires-Dist: flamapy-fw~=2.6.0.dev4
12
+ Requires-Dist: flamapy-fm~=2.6.0.dev4
13
+ Requires-Dist: flamapy-sat~=2.6.0.dev4
14
+ Requires-Dist: flamapy-bdd~=2.6.0.dev4
15
+ Requires-Dist: flamapy-z3~=2.6.0.dev4
16
16
  Provides-Extra: dev
17
17
  Requires-Dist: pytest; extra == "dev"
18
18
  Requires-Dist: pytest-mock; extra == "dev"
@@ -0,0 +1,12 @@
1
+ flamapy-fw~=2.6.0.dev4
2
+ flamapy-fm~=2.6.0.dev4
3
+ flamapy-sat~=2.6.0.dev4
4
+ flamapy-bdd~=2.6.0.dev4
5
+ flamapy-z3~=2.6.0.dev4
6
+
7
+ [dev]
8
+ pytest
9
+ pytest-mock
10
+ prospector
11
+ mypy
12
+ coverage
@@ -4,18 +4,18 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "flamapy"
7
- version = "2.6.0.dev2"
7
+ version = "2.6.0.dev4"
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.11"
13
13
  dependencies = [
14
- "flamapy-fw~=2.6.0.dev2",
15
- "flamapy-fm~=2.6.0.dev2",
16
- "flamapy-sat~=2.6.0.dev2",
17
- "flamapy-bdd~=2.6.0.dev2",
18
- "flamapy-z3~=2.6.0.dev2",
14
+ "flamapy-fw~=2.6.0.dev4",
15
+ "flamapy-fm~=2.6.0.dev4",
16
+ "flamapy-sat~=2.6.0.dev4",
17
+ "flamapy-bdd~=2.6.0.dev4",
18
+ "flamapy-z3~=2.6.0.dev4",
19
19
  ]
20
20
 
21
21
  [project.optional-dependencies]
@@ -7,6 +7,14 @@ VALID_MODEL = "./resources/models/simple/valid_model.uvl"
7
7
  NON_VALID_MODEL = "./resources/models/simple/invalid_model.uvl"
8
8
 
9
9
  VALID_CONFIG = "./resources/configurations/valid_configuration.csvconf"
10
+ # Same configuration as VALID_CONFIG, expressed as an in-memory mapping. Config
11
+ # operations accept a path, a {feature: value} mapping, or a Configuration object.
12
+ VALID_CONFIG_DICT = {
13
+ "eCommerce": True, "Server": True, "PHP": True, "v74": True, "Storage": True,
14
+ "LOW": True, "Web": True, "Catalog": True, "Search": True, "BASIC": True,
15
+ "Shopping": True, "Cart": True, "Payment": True, "PayPal": True,
16
+ "Security": True, "HIGH": True,
17
+ }
10
18
 
11
19
 
12
20
  def test_atomic_sets():
@@ -239,6 +247,15 @@ def test_valid_configuration():
239
247
  assert result == True
240
248
 
241
249
 
250
+ def test_config_operations_accept_mapping():
251
+ # Config operations accept an in-memory {feature: value} mapping and must
252
+ # produce the same result as reading the equivalent configuration file.
253
+ flamafm = FLAMAFeatureModel(VALID_MODEL)
254
+
255
+ assert flamafm.filter(VALID_CONFIG_DICT) == flamafm.filter(VALID_CONFIG)
256
+ assert flamafm.satisfiable_configuration(VALID_CONFIG_DICT, False) is True
257
+
258
+
242
259
  def test_valid_product():
243
260
  # Prepare
244
261
  flamafm = FLAMAFeatureModel(VALID_MODEL)
@@ -1,12 +0,0 @@
1
- flamapy-fw~=2.6.0.dev2
2
- flamapy-fm~=2.6.0.dev2
3
- flamapy-sat~=2.6.0.dev2
4
- flamapy-bdd~=2.6.0.dev2
5
- flamapy-z3~=2.6.0.dev2
6
-
7
- [dev]
8
- pytest
9
- pytest-mock
10
- prospector
11
- mypy
12
- coverage
File without changes
File without changes
File without changes
File without changes