diff --git a/.github/workflows/code_quality_checks.yml b/.github/workflows/code_quality_checks.yml index 48d2d82..2721143 100644 --- a/.github/workflows/code_quality_checks.yml +++ b/.github/workflows/code_quality_checks.yml @@ -13,8 +13,12 @@ jobs: steps: - uses: actions/checkout@v3 - - uses: pre-commit/action@v3.0.1 - + - name: setup environment + run: | + ./dev-setup.sh + - name: run pre-commit hooks + run: | + pre-commit run --all-files --show-diff-on-failure --color=always - name: Print message on failure if: failure() run: | diff --git a/.mypy.ini b/.mypy.ini new file mode 100644 index 0000000..f9d68f1 --- /dev/null +++ b/.mypy.ini @@ -0,0 +1,122 @@ +[mypy] +# Global mypy configuration + +[mypy-nodescraper.base.regexanalyzer] +ignore_errors = True + +[mypy-nodescraper.cli.cli] +ignore_errors = True + +[mypy-nodescraper.cli.dynamicparserbuilder] +ignore_errors = True + +[mypy-nodescraper.cli.helper] +ignore_errors = True + +[mypy-nodescraper.cli.inputargtypes] +ignore_errors = True + +[mypy-nodescraper.configbuilder] +ignore_errors = True + +[mypy-nodescraper.configregistry] +ignore_errors = True + +[mypy-nodescraper.enums.eventpriority] +ignore_errors = True + +[mypy-nodescraper.enums.systeminteraction] +ignore_errors = True + +[mypy-nodescraper.interfaces.connectionmanager] +ignore_errors = True + +[mypy-nodescraper.interfaces.datacollectortask] +ignore_errors = True + +[mypy-nodescraper.interfaces.dataplugin] +ignore_errors = True + +[mypy-nodescraper.interfaces.task] +ignore_errors = True + +[mypy-nodescraper.models.analyzerargs] +ignore_errors = True + +[mypy-nodescraper.models.datamodel] +ignore_errors = True + +[mypy-nodescraper.pluginexecutor] +ignore_errors = True + +[mypy-nodescraper.plugins.inband.bios.analyzer_args] +ignore_errors = True + +[mypy-nodescraper.plugins.inband.cmdline.cmdline_analyzer] +ignore_errors = True + +[mypy-nodescraper.plugins.inband.dimm.dimm_collector] +ignore_errors = True + +[mypy-nodescraper.plugins.inband.dkms.analyzer_args] +ignore_errors = True + +[mypy-nodescraper.plugins.inband.dmesg.dmesg_analyzer] +ignore_errors = True + +[mypy-nodescraper.plugins.inband.dmesg.dmesgdata] +ignore_errors = True + +[mypy-nodescraper.plugins.inband.memory.memory_collector] +ignore_errors = True + +[mypy-nodescraper.plugins.inband.os.os_collector] +ignore_errors = True + +[mypy-nodescraper.plugins.inband.package.analyzer_args] +ignore_errors = True + +[mypy-nodescraper.plugins.inband.process.analyzer_args] +ignore_errors = True + +[mypy-nodescraper.plugins.inband.process.process_collector] +ignore_errors = True + +[mypy-nodescraper.plugins.inband.rocm.rocm_plugin] +ignore_errors = True + +[mypy-nodescraper.taskresulthooks.filesystemloghook] +ignore_errors = True + +[mypy-nodescraper.typeutils] +ignore_errors = True + +[mypy-nodescraper.utils] +ignore_errors = True + +[mypy-test.unit.conftest] +ignore_errors = True + +[mypy-test.unit.framework.common.shared_utils] +ignore_errors = True + +[mypy-test.unit.framework.test_cli_helper] +ignore_errors = True + +[mypy-test.unit.framework.test_dataplugin] +ignore_errors = True + +[mypy-test.unit.framework.test_plugin_executor] +ignore_errors = True + +[mypy-nodescraper.models.collectorargs] +ignore_errors = True + +[mypy-nodescraper.plugins.inband.kernel_module.*] +ignore_errors = True + +[mypy-nodescraper.plugins.inband.nvme.nvme_collector] +ignore_errors = True + +[mypy-test.unit.framework.test_cli] +ignore_errors = True diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 04e4a7b..03f9342 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,3 +15,9 @@ repos: rev: 25.1.0 hooks: - id: black + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.15.0 + hooks: + - id: mypy + args: [--install-types, --non-interactive, --explicit-package-bases, --allow-redefinition] + language: system diff --git a/nodescraper/interfaces/dataanalyzertask.py b/nodescraper/interfaces/dataanalyzertask.py index 116ae02..2dd49f6 100644 --- a/nodescraper/interfaces/dataanalyzertask.py +++ b/nodescraper/interfaces/dataanalyzertask.py @@ -119,19 +119,19 @@ def __init_subclass__(cls, **kwargs: dict[str, Any]) -> None: raise TypeError(f"No data model set for {cls.__name__}") if hasattr(cls, "analyze_data"): - cls.analyze_data = analyze_decorator(cls.analyze_data) + setattr(cls, "analyze_data", analyze_decorator(cls.analyze_data)) # noqa @abc.abstractmethod def analyze_data( self, data: TDataModel, - args: Optional[TAnalyzeArg | dict], + args: Optional[TAnalyzeArg], ) -> TaskResult: """Analyze the provided data and return a TaskResult Args: data (TDataModel): data to analyze - args (Optional[TAnalyzeArg | dict]): Optional arguments for analysis, can be a model or dict + args (Optional[TAnalyzeArg]): Optional arguments for analysis. Dicts will be handled in the decorator" Returns: TaskResult: Task result containing the analysis outcome diff --git a/nodescraper/interfaces/task.py b/nodescraper/interfaces/task.py index 82b2252..8722c27 100644 --- a/nodescraper/interfaces/task.py +++ b/nodescraper/interfaces/task.py @@ -83,7 +83,7 @@ def max_event_priority_level(self, input_value: str | EventPriority): elif isinstance(input_value, int): value = EventPriority(input_value) elif isinstance(input_value, EventPriority): - value: EventPriority = input_value + value: EventPriority = input_value # type:ignore else: raise ValueError(f"Invalid type for max_event_priority_level: {type(input_value)}") diff --git a/nodescraper/models/event.py b/nodescraper/models/event.py index 947be3d..9d169d9 100644 --- a/nodescraper/models/event.py +++ b/nodescraper/models/event.py @@ -73,7 +73,8 @@ def validate_timestamp(cls, timestamp: datetime.datetime) -> datetime.datetime: if timestamp.tzinfo is None or timestamp.tzinfo.utcoffset(timestamp) is None: raise ValueError("datetime must be timezone aware") - if timestamp.utcoffset() is not None and timestamp.utcoffset().total_seconds() != 0: + utc_offset = timestamp.utcoffset() + if utc_offset is not None and utc_offset.total_seconds() != 0: timestamp = timestamp.astimezone(datetime.timezone.utc) return timestamp @@ -90,7 +91,7 @@ def validate_category(cls, category: str | Enum) -> str: if isinstance(category, Enum): category = category.value - category = category.strip().upper() + category = str(category).strip().upper() category = re.sub(r"[\s-]", "_", category) return category diff --git a/nodescraper/resultcollators/tablesummary.py b/nodescraper/resultcollators/tablesummary.py index 4d1fdbe..04708d3 100644 --- a/nodescraper/resultcollators/tablesummary.py +++ b/nodescraper/resultcollators/tablesummary.py @@ -40,7 +40,7 @@ def collate_results( connection_results (list[TaskResult]): list of connection results to collate """ - def gen_str_table(headers: list[str], rows: list[str]): + def gen_str_table(headers: list[str], rows: list[list[str | None]]): column_widths = [len(header) for header in headers] for row in rows: for i, cell in enumerate(row): @@ -59,16 +59,24 @@ def gen_row(row): tables = "" if connection_results: rows = [] - for result in connection_results: - rows.append([result.task, result.status.name, result.message]) + for connection_result in connection_results: + rows.append( + [ + connection_result.task, + connection_result.status.name, + connection_result.message, + ] + ) table = gen_str_table(["Connection", "Status", "Message"], rows) tables += f"\n\n{table}" if plugin_results: rows = [] - for result in plugin_results: - rows.append([result.source, result.status.name, result.message]) + for plugin_result in plugin_results: + rows.append( + [plugin_result.source, plugin_result.status.name, plugin_result.message] + ) table = gen_str_table(["Plugin", "Status", "Message"], rows) tables += f"\n\n{table}" diff --git a/pyproject.toml b/pyproject.toml index 888b1e9..f533ed7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,7 +27,8 @@ dev = [ "ruff", "pre-commit", "pytest", - "pytest-cov" + "pytest-cov", + "mypy" ] [project.urls]