Skip to content

Commit 45edef5

Browse files
committed
extract operation parameter normalization and change tracking rules
1 parent 1e2a3c6 commit 45edef5

File tree

4 files changed

+105
-9
lines changed

4 files changed

+105
-9
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from typing import Dict, Iterable, Tuple
2+
3+
4+
5+
def merge_operation_default_params(default_parameters: Dict, passed_parameters: Dict) -> Dict:
6+
return {
7+
**dict(default_parameters or {}),
8+
**dict(passed_parameters or {}),
9+
}
10+
11+
12+
13+
def collect_changed_keys(current_parameters: Dict, updated_parameters: Dict, existing_changed_keys: Iterable[str]) -> Tuple[str, ...]:
14+
changed_keys = list(existing_changed_keys)
15+
for key, value in updated_parameters.items():
16+
if key not in changed_keys and current_parameters.get(key) != value:
17+
changed_keys.append(key)
18+
return tuple(changed_keys)
19+
20+
21+
22+
def resolve_setdefault_value(current_parameters: Dict, key, value):
23+
if key in current_parameters:
24+
return current_parameters[key], False
25+
return value, True

fedot/core/operations/operation_parameters.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
from copy import deepcopy
22
from typing import Iterable
33

4+
from fedot.core.operations.operation_parameter_rules import (
5+
collect_changed_keys,
6+
merge_operation_default_params,
7+
resolve_setdefault_value,
8+
)
49
from fedot.core.repository.default_params_repository import DefaultOperationParamsRepository
510

611

@@ -28,23 +33,21 @@ def __bool__(self):
2833
@staticmethod
2934
def from_operation_type(operation_type: str, **parameters):
3035
default_parameters = get_default_params(operation_type)
31-
parameters = {**default_parameters, **parameters}
36+
parameters = merge_operation_default_params(default_parameters, parameters)
3237
return OperationParameters(**parameters)
3338

3439
def update(self, **params):
35-
for key, value in params.items():
36-
if key not in self._changed_keys:
37-
if self._parameters.get(key) != value:
38-
self._changed_keys.append(key)
39-
self._parameters.update({key: value})
40+
self._changed_keys = list(collect_changed_keys(self._parameters, params, self._changed_keys))
41+
self._parameters.update(params)
4042

4143
def get(self, key, default_value=None):
4244
return self._parameters.get(key, default_value)
4345

4446
def setdefault(self, key, value):
45-
if key not in self._parameters.keys():
46-
self.update(**{key: value})
47-
return self.get(key)
47+
resolved_value, should_update = resolve_setdefault_value(self._parameters, key, value)
48+
if should_update:
49+
self.update(**{key: resolved_value})
50+
return resolved_value
4851

4952
def to_dict(self) -> dict:
5053
return deepcopy(self._parameters)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from fedot.core.operations.operation_parameter_rules import (
2+
collect_changed_keys,
3+
merge_operation_default_params,
4+
resolve_setdefault_value,
5+
)
6+
7+
8+
9+
def test_operation_parameter_rules_merge_defaults_and_track_changes():
10+
merged = merge_operation_default_params({'a': 1, 'b': 2}, {'b': 3, 'c': 4})
11+
changed_keys = collect_changed_keys({'a': 1, 'b': 2}, {'a': 1, 'b': 3, 'd': 4}, ())
12+
13+
assert merged == {'a': 1, 'b': 3, 'c': 4}
14+
assert changed_keys == ('b', 'd')
15+
16+
17+
18+
def test_operation_parameter_rules_resolve_setdefault_value_explicitly():
19+
existing_value, should_update_existing = resolve_setdefault_value({'a': 1}, 'a', 2)
20+
missing_value, should_update_missing = resolve_setdefault_value({'a': 1}, 'b', 3)
21+
22+
assert existing_value == 1
23+
assert should_update_existing is False
24+
assert missing_value == 3
25+
assert should_update_missing is True
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from fedot.core.operations.operation_parameters import OperationParameters, get_default_params
2+
3+
4+
5+
def test_params_keeper_update():
6+
params = {'a': 1, 'b': 2, 'c': 3}
7+
keeper = OperationParameters(**params)
8+
new_params = {'a': 1, 'b': 3, 'd': 4}
9+
keeper.update(**new_params)
10+
expected_params = {'a': 1, 'b': 3, 'c': 3, 'd': 4}
11+
actual_params = keeper.to_dict()
12+
changed_params = keeper.changed_parameters.keys()
13+
assert actual_params == expected_params
14+
assert 'a' not in changed_params
15+
assert 'b' in changed_params
16+
assert 'd' in changed_params
17+
18+
19+
20+
def test_params_keeper_get():
21+
params = {'a': 1, 'b': 2, 'c': 3}
22+
keeper = OperationParameters(**params)
23+
a = keeper.get('a')
24+
b = keeper.get('b', -1)
25+
d = keeper.get('d', 5)
26+
assert a == 1
27+
assert b == 2
28+
assert d == 5
29+
30+
31+
32+
def test_params_keeper_setdefault_and_defaults_from_repository():
33+
keeper = OperationParameters(alpha=1.0)
34+
existing_value = keeper.setdefault('alpha', 2.0)
35+
missing_value = keeper.setdefault('beta', 3.0)
36+
default_params = get_default_params('ridge')
37+
merged_keeper = OperationParameters.from_operation_type('ridge', alpha=0.75)
38+
39+
assert existing_value == 1.0
40+
assert missing_value == 3.0
41+
assert keeper.get('beta') == 3.0
42+
assert merged_keeper.get('alpha') == 0.75
43+
assert set(default_params).issubset(set(merged_keeper.to_dict()))

0 commit comments

Comments
 (0)