Coverage for sparkle/types/__init__.py: 88%
40 statements
« prev ^ index » next coverage.py v7.6.4, created at 2024-11-05 14:48 +0000
« prev ^ index » next coverage.py v7.6.4, created at 2024-11-05 14:48 +0000
1"""This package provides types for Sparkle applications."""
2import importlib
3import inspect
4import re
5from typing import Callable
7from sparkle.types.sparkle_callable import SparkleCallable
8from sparkle.types.features import FeatureGroup, FeatureSubgroup, FeatureType
9from sparkle.types.status import SolverStatus
10from sparkle.types import objective
11from sparkle.types.objective import SparkleObjective, UseTime
14objective_string_regex = re.compile(r"(?P<name>[\w\-_]+)(:(?P<direction>min|max))?$")
15objective_variable_regex = re.compile(r"(-?\d+)$")
18def _check_class(candidate: Callable) -> bool:
19 """Verify whether a loaded class is a valid objective class."""
20 return inspect.isclass(candidate) and issubclass(candidate, SparkleObjective)
23def resolve_objective(objective_name: str) -> SparkleObjective:
24 """Try to resolve the objective class by (case-sensitive) name.
26 convention: objective_name(variable-k)?(:[min|max])?
28 Order of resolving:
29 class_name of user defined SparkleObjectives
30 class_name of sparkle defined SparkleObjectives
31 default SparkleObjective with minimization unless specified as max
33 Args:
34 name: The name of the objective class. Can include parameter value k.
36 Returns:
37 Instance of the Objective class or None if not found.
38 """
39 match = objective_string_regex.fullmatch(objective_name)
40 if match is None or objective_name == "" or not objective_name[0].isalpha():
41 return None
43 name = match.group("name")
44 minimise = not match.group("direction") == "max" # .group returns "" if no match
46 # Search for optional variable and record split point between name and variable
47 name_options = [(name, None), ] # Options of names to check for
48 if m := objective_variable_regex.search(name):
49 argument = int(m.group())
50 name_options = [(name[:m.start()], argument), ] + name_options # Prepend
52 # First try to resolve the user input classes
53 for rname, rarg in name_options:
54 try:
55 user_module = importlib.import_module("Settings.objective")
56 for o_name, o_class in inspect.getmembers(user_module,
57 predicate=_check_class):
58 if o_name == rname:
59 if rarg is not None:
60 return o_class(rarg)
61 return o_class()
62 except Exception:
63 pass
65 for rname, rarg in name_options:
66 # Try to match with specially defined classes
67 for o_name, o_class in inspect.getmembers(objective,
68 predicate=_check_class):
69 if o_name == rname:
70 if rarg is not None:
71 return o_class(rarg)
72 return o_class()
74 # No special objects found. Return objective with full name
75 return SparkleObjective(name=objective_name, minimise=minimise)