Skip to content

Commit fbffebe

Browse files
authored
Merge branch 'main' into chore/update-plan-code-smells
2 parents 57f3b83 + 5c3744f commit fbffebe

4 files changed

Lines changed: 352 additions & 96 deletions

File tree

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Copyright © LFV
2+
3+
from typing import Callable, Dict, Optional, Set, Type, TypeVar
4+
5+
from reqstool.common.models.urn_id import UrnId
6+
from reqstool.common.utils import Utils
7+
from reqstool.filters.id_filters import IDFilters
8+
9+
F = TypeVar("F", bound=IDFilters)
10+
11+
12+
def parse_filters(
13+
data: dict,
14+
ids_key: str,
15+
filter_cls: Type[F],
16+
validate_fn: Callable[[dict], None],
17+
) -> Dict[str, F]:
18+
"""Parse filter entries from raw YAML data into a dict of filter objects.
19+
20+
This utility extracts the duplicated filter-parsing logic that was previously
21+
present in both RequirementsModelGenerator and SVCsModelGenerator.
22+
23+
Args:
24+
data: Raw YAML data dict loaded from requirements.yml or svcs.yml.
25+
ids_key: The key used for explicit ID filters, either ``"requirement_ids"``
26+
or ``"svc_ids"``.
27+
filter_cls: The filter dataclass to instantiate, either
28+
:class:`~reqstool.filters.requirements_filters.RequirementFilter` or
29+
:class:`~reqstool.filters.svcs_filters.SVCFilter`.
30+
validate_fn: A callable that performs semantic validation on ``data`` (e.g.
31+
checks that includes/excludes are mutually exclusive). Called once before
32+
any parsing begins.
33+
34+
Returns:
35+
A dict mapping URN strings to filter instances. Returns an empty dict when
36+
``data`` contains no ``"filters"`` section.
37+
"""
38+
r_filters: Dict[str, F] = {}
39+
40+
validate_fn(data)
41+
42+
if "filters" not in data:
43+
return r_filters
44+
45+
for urn in data["filters"].keys():
46+
urn_filter = data["filters"][urn]
47+
48+
urn_ids_imports: Optional[Set[UrnId]] = None
49+
urn_ids_excludes: Optional[Set[UrnId]] = None
50+
custom_includes = None
51+
custom_exclude = None
52+
53+
if ids_key in urn_filter:
54+
if "includes" in urn_filter[ids_key]:
55+
filtered_ids = Utils.check_ids_to_filter(current_urn=urn, ids=urn_filter[ids_key]["includes"])
56+
ids_includes = list(filtered_ids)
57+
urn_ids_imports = set(Utils.convert_ids_to_urn_id(urn=urn, ids=ids_includes))
58+
59+
if "excludes" in urn_filter[ids_key]:
60+
filtered_ids = Utils.check_ids_to_filter(current_urn=urn, ids=urn_filter[ids_key]["excludes"])
61+
ids_excludes = list(filtered_ids)
62+
urn_ids_excludes = set(Utils.convert_ids_to_urn_id(urn=urn, ids=ids_excludes))
63+
64+
if "custom" in urn_filter:
65+
if "includes" in urn_filter["custom"]:
66+
custom_includes = urn_filter["custom"]["includes"]
67+
68+
if "excludes" in urn_filter["custom"]:
69+
custom_exclude = urn_filter["custom"]["excludes"]
70+
71+
r_filters[urn] = filter_cls(
72+
urn_ids_imports=urn_ids_imports,
73+
urn_ids_excludes=urn_ids_excludes,
74+
custom_imports=custom_includes,
75+
custom_exclude=custom_exclude,
76+
)
77+
78+
return r_filters

src/reqstool/model_generators/requirements_model_generator.py

Lines changed: 9 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
import re
44
import sys
55
from enum import Enum, unique
6-
from typing import Dict, List, Optional, Set
6+
from typing import Dict, List
77

88
from reqstool_python_decorators.decorators.decorators import Requirements
99
from ruamel.yaml import YAML
1010

1111
from reqstool.commands.exit_codes import EXIT_CODE_SYNTAX_VALIDATION_ERROR
12+
from reqstool.common.filter_parser import parse_filters
1213
from reqstool.common.models.lifecycle import LifecycleData
1314
from reqstool.common.models.urn_id import UrnId
1415
from reqstool.common.utils import Utils
@@ -233,56 +234,13 @@ def __parse_location_git(self, locations_obj, instance_type, locations):
233234

234235
locations.append(git_location)
235236

236-
def __parse_requirement_filters(self, data) -> Dict[str, RequirementFilter]: # NOSONAR
237-
r_filters = {}
238-
239-
self.semantic_validator._validate_req_imports_filter_has_excludes_xor_includes(data)
240-
241-
if "filters" in data:
242-
for urn in data["filters"].keys():
243-
urn_filter = data["filters"][urn]
244-
245-
req_urn_ids_imports: Optional[Set[UrnId]] = None
246-
req_urn_ids_excludes: Optional[Set[UrnId]] = None
247-
custom_includes = None
248-
custom_exclude = None
249-
250-
if "requirement_ids" in urn_filter:
251-
if "includes" in urn_filter["requirement_ids"]:
252-
filtered_ids = Utils.check_ids_to_filter(
253-
current_urn=urn, ids=urn_filter["requirement_ids"]["includes"]
254-
)
255-
req_ids_includes = set(filtered_ids)
256-
req_urn_ids_imports: Set[UrnId] = set(
257-
Utils.convert_ids_to_urn_id(urn=urn, ids=req_ids_includes)
258-
)
259-
260-
if "excludes" in urn_filter["requirement_ids"]:
261-
filtered_ids = Utils.check_ids_to_filter(
262-
current_urn=urn, ids=urn_filter["requirement_ids"]["excludes"]
263-
)
264-
req_ids_excludes = set(filtered_ids)
265-
req_urn_ids_excludes: Set[UrnId] = set(
266-
Utils.convert_ids_to_urn_id(urn=urn, ids=req_ids_excludes)
267-
)
268-
269-
if "custom" in urn_filter:
270-
if "includes" in urn_filter["custom"]:
271-
custom_includes = urn_filter["custom"]["includes"]
272-
273-
if "excludes" in urn_filter["custom"]:
274-
custom_exclude = urn_filter["custom"]["excludes"]
275-
276-
req_filter = RequirementFilter(
277-
urn_ids_imports=req_urn_ids_imports,
278-
urn_ids_excludes=req_urn_ids_excludes,
279-
custom_imports=custom_includes,
280-
custom_exclude=custom_exclude,
281-
)
282-
283-
r_filters[urn] = req_filter
284-
285-
return r_filters
237+
def __parse_requirement_filters(self, data) -> Dict[str, RequirementFilter]:
238+
return parse_filters(
239+
data=data,
240+
ids_key="requirement_ids",
241+
filter_cls=RequirementFilter,
242+
validate_fn=self.semantic_validator._validate_req_imports_filter_has_excludes_xor_includes,
243+
)
286244

287245
@Requirements("REQ_004", "REQ_036")
288246
def __parse_requirements(self, model, data): # NOSONAR

src/reqstool/model_generators/svcs_model_generator.py

Lines changed: 9 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
# Copyright © LFV
22

33
import sys
4-
from typing import Dict, Optional, Set
4+
from typing import Dict
55

66
from ruamel.yaml import YAML
77

88
from reqstool.commands.exit_codes import EXIT_CODE_SYNTAX_VALIDATION_ERROR
9+
from reqstool.common.filter_parser import parse_filters
910
from reqstool.common.models.lifecycle import LifecycleData
1011
from reqstool.common.models.urn_id import UrnId
1112
from reqstool.common.utils import Utils
@@ -71,47 +72,10 @@ def __parse_svcs(self, validated: SVCsPydanticModel) -> dict[UrnId, SVCData]:
7172

7273
return r_result
7374

74-
def __parse_svc_filters(self, data) -> Dict[str, SVCFilter]: # NOSONAR
75-
r_filters = {}
76-
77-
self.semantic_validator._validate_svc_imports_filter_has_excludes_xor_includes(data)
78-
79-
if "filters" in data:
80-
for urn in data["filters"].keys():
81-
urn_filter = data["filters"][urn]
82-
83-
svc_urn_ids_includes: Optional[Set[UrnId]] = None
84-
svc_urn_ids_excludes: Optional[Set[UrnId]] = None
85-
custom_includes = None
86-
custom_exclude = None
87-
88-
if "svc_ids" in urn_filter:
89-
if "includes" in urn_filter["svc_ids"]:
90-
svc_ids_includes = set(
91-
Utils.check_ids_to_filter(current_urn=urn, ids=urn_filter["svc_ids"]["includes"])
92-
)
93-
svc_urn_ids_includes = set(Utils.convert_ids_to_urn_id(urn=urn, ids=svc_ids_includes))
94-
95-
if "excludes" in urn_filter["svc_ids"]:
96-
svc_ids_excludes = set(
97-
Utils.check_ids_to_filter(current_urn=urn, ids=urn_filter["svc_ids"]["excludes"])
98-
)
99-
svc_urn_ids_excludes = set(Utils.convert_ids_to_urn_id(urn=urn, ids=svc_ids_excludes))
100-
101-
if "custom" in urn_filter:
102-
if "includes" in urn_filter["custom"]:
103-
custom_includes = urn_filter["custom"]["includes"]
104-
105-
if "excludes" in urn_filter["custom"]:
106-
custom_exclude = urn_filter["custom"]["excludes"]
107-
108-
svc_filter = SVCFilter(
109-
urn_ids_imports=svc_urn_ids_includes,
110-
urn_ids_excludes=svc_urn_ids_excludes,
111-
custom_imports=custom_includes,
112-
custom_exclude=custom_exclude,
113-
)
114-
115-
r_filters[urn] = svc_filter
116-
117-
return r_filters
75+
def __parse_svc_filters(self, data) -> Dict[str, SVCFilter]:
76+
return parse_filters(
77+
data=data,
78+
ids_key="svc_ids",
79+
filter_cls=SVCFilter,
80+
validate_fn=self.semantic_validator._validate_svc_imports_filter_has_excludes_xor_includes,
81+
)

0 commit comments

Comments
 (0)