Skip to content

Commit 350728f

Browse files
committed
added validator for str values in AnalyzerArgs base model
1 parent 2356efa commit 350728f

File tree

11 files changed

+74
-15
lines changed

11 files changed

+74
-15
lines changed

nodescraper/models/analyzerargs.py

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,68 @@
2323
# SOFTWARE.
2424
#
2525
###############################################################################
26-
from pydantic import BaseModel
26+
from typing import Any
27+
28+
from pydantic import BaseModel, model_validator
2729

2830

2931
class AnalyzerArgs(BaseModel):
32+
"""Base class for all analyzer arguments.
33+
34+
This class provides automatic string stripping for all string values
35+
in analyzer args. All analyzer args classes should inherit from this
36+
instead of BaseModel directly.
37+
38+
The strip_string_values validator runs in mode="before", which means
39+
it executes before any field validators in child classes. This ensures
40+
all string inputs are cleaned of leading/trailing whitespace before
41+
any further processing.
42+
"""
43+
3044
model_config = {"extra": "forbid", "exclude_none": True}
3145

46+
@model_validator(mode="before")
47+
@classmethod
48+
def strip_string_values(cls, data: Any) -> Any:
49+
"""Strip whitespace from all string values in analyzer args.
50+
51+
This validator recursively processes:
52+
- String values: strips whitespace
53+
- Lists: strips strings in lists
54+
- Dicts: strips string values in dicts
55+
- Other types: left unchanged
56+
57+
Runs in mode="before" to ensure stripping happens before any
58+
field validators execute in child classes.
59+
60+
Args:
61+
data: The input data to validate
62+
63+
Returns:
64+
The data with all string values stripped
65+
"""
66+
if isinstance(data, dict):
67+
return {k: cls._strip_value(v) for k, v in data.items()}
68+
return data
69+
70+
@classmethod
71+
def _strip_value(cls, value: Any) -> Any:
72+
"""Recursively strip string values.
73+
74+
Args:
75+
value: The value to process
76+
77+
Returns:
78+
The processed value
79+
"""
80+
if isinstance(value, str):
81+
return value.strip()
82+
elif isinstance(value, list):
83+
return [cls._strip_value(item) for item in value]
84+
elif isinstance(value, dict):
85+
return {k: cls._strip_value(v) for k, v in value.items()}
86+
return value
87+
3288
@classmethod
3389
def build_from_model(cls, datamodel):
3490
"""Build analyzer args instance from data model object

nodescraper/plugins/inband/bios/bios_analyzer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def analyze_data(
7575
self.result.message = "Bios data matches expected"
7676
self.result.status = ExecutionStatus.OK
7777
return self.result
78-
elif data.bios_version == str(bios_version).strip():
78+
elif data.bios_version == bios_version:
7979
self.result.message = "Bios data matches expected"
8080
self.result.status = ExecutionStatus.OK
8181
return self.result

nodescraper/plugins/inband/dkms/dkms_analyzer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def analyze_data(
8383
)
8484
if regex_data.match(actual_value):
8585
break
86-
elif actual_value == str(accepted_value).strip():
86+
elif actual_value == accepted_value:
8787
break
8888
else:
8989
expected_values.append(accepted_values)

nodescraper/plugins/inband/kernel/kernel_analyzer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def analyze_data(
7272
self.result.message = "Kernel matches expected"
7373
self.result.status = ExecutionStatus.OK
7474
return self.result
75-
elif data.kernel_version == str(kernel).strip():
75+
elif data.kernel_version == kernel:
7676
self.result.message = "Kernel matches expected"
7777
self.result.status = ExecutionStatus.OK
7878
return self.result

nodescraper/plugins/inband/memory/analyzer_args.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@
2323
# SOFTWARE.
2424
#
2525
###############################################################################
26-
from pydantic import BaseModel
26+
from nodescraper.models.analyzerargs import AnalyzerArgs
2727

2828

29-
class MemoryAnalyzerArgs(BaseModel):
29+
class MemoryAnalyzerArgs(AnalyzerArgs):
3030
ratio: float = 0.66
3131
memory_threshold: str = "30Gi"

nodescraper/plugins/inband/os/os_analyzer.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ def analyze_data(self, data: OsDataModel, args: Optional[OsAnalyzerArgs] = None)
5454
return self.result
5555

5656
for os_name in args.exp_os:
57-
if (str(os_name).strip() == data.os_name and args.exact_match) or (
58-
str(os_name).strip() in data.os_name and not args.exact_match
57+
if (os_name == data.os_name and args.exact_match) or (
58+
os_name in data.os_name and not args.exact_match
5959
):
6060
self.result.message = "OS name matches expected"
6161
self.result.status = ExecutionStatus.OK

nodescraper/plugins/inband/package/package_analyzer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ def package_exact_match(
157157
elif exp_value is None:
158158
# allow any version when expected version is None
159159
continue
160-
elif version != str(exp_value).strip():
160+
elif version != exp_value:
161161
not_found_match.append((exp_key, version))
162162
self._log_event(
163163
EventCategory.APPLICATION,

nodescraper/plugins/inband/rocm/analyzer_args.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,13 @@
2525
###############################################################################
2626
from typing import Union
2727

28-
from pydantic import BaseModel, Field, field_validator
28+
from pydantic import Field, field_validator
2929

30+
from nodescraper.models.analyzerargs import AnalyzerArgs
3031
from nodescraper.plugins.inband.rocm.rocmdata import RocmDataModel
3132

3233

33-
class RocmAnalyzerArgs(BaseModel):
34+
class RocmAnalyzerArgs(AnalyzerArgs):
3435
exp_rocm: Union[str, list] = Field(default_factory=list)
3536

3637
@field_validator("exp_rocm", mode="before")

nodescraper/plugins/inband/rocm/rocm_analyzer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def analyze_data(
5858
return self.result
5959

6060
for rocm_version in args.exp_rocm:
61-
if data.rocm_version == str(rocm_version).strip():
61+
if data.rocm_version == rocm_version:
6262
self.result.message = "ROCm version matches expected"
6363
self.result.status = ExecutionStatus.OK
6464
return self.result

nodescraper/plugins/inband/storage/analyzer_args.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,12 @@
2525
###############################################################################
2626
from typing import Optional
2727

28-
from pydantic import BaseModel, Field
28+
from pydantic import Field
2929

30+
from nodescraper.models.analyzerargs import AnalyzerArgs
3031

31-
class StorageAnalyzerArgs(BaseModel):
32+
33+
class StorageAnalyzerArgs(AnalyzerArgs):
3234
min_required_free_space_abs: Optional[str] = None
3335
min_required_free_space_prct: Optional[int] = None
3436
ignore_devices: Optional[list[str]] = Field(default_factory=list)

0 commit comments

Comments
 (0)