From 5eb8ba06cf6dc4191533582d135573ab998cb124 Mon Sep 17 00:00:00 2001 From: Hendra Anggrian Date: Thu, 3 Sep 2026 13:57:22 -0500 Subject: [PATCH] style: integrate yamllint, move ruff config to pyproject.toml, fix linter issues --- .github/workflows/ci.yml | 15 +++++-------- .github/workflows/video-build.yml | 1 - .yamllint.yml | 11 ++++++++++ codecov.yml | 4 ++-- ebuild/__main__.py | 2 +- ebuild/build/dispatch.py | 2 +- ebuild/build/ninja_backend.py | 1 - ebuild/cli/__init__.py | 2 +- ebuild/cli/integration.py | 8 +++---- ebuild/deliverable_packager.py | 4 +++- ebuild/deps/__init__.py | 3 ++- ebuild/eos_ai/__init__.py | 9 +++++--- ebuild/plugins/__init__.py | 4 +++- ebuild/system/doctor.py | 2 +- hardware/board/eradar360.yaml | 18 +++++++-------- pyproject.toml | 19 ++++++++++++++++ recipes/freertos.yaml | 22 +++++++++---------- tests/ebuild/test_dispatch.py | 2 -- tests/ebuild/test_eos_ai.py | 2 +- .../test_integration_initramfs_security.py | 1 - tests/unit/test_cad_pipeline.py | 2 -- tests/unit/test_doctor.py | 2 -- .../unit/test_empty_test_run_is_not_a_pass.py | 1 - tests/unit/test_package_efw.py | 1 - tools/cad_pipeline.py | 2 +- 25 files changed, 82 insertions(+), 58 deletions(-) create mode 100644 .yamllint.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 89bfb6c..94e5d0e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,23 +46,20 @@ jobs: # `pip install -r requirements.txt` referenced a file that does # not exist in this repository and failed the job outright. pip install -e . - pip install pytest pytest-cov pytest-benchmark mypy ruff + pip install pytest pytest-cov pytest-benchmark mypy ruff yamllint - name: Lint (ruff) - run: ruff check . --select=E,F,W --ignore=E501 - continue-on-error: true + run: ruff check . + + - name: Lint YAML (yamllint) + run: yamllint . # --exclude: layers/eosuite/ vendors its own tests/ package, so a bare # `mypy .` sees two modules named "tests" and bails with "Duplicate # module named 'tests'" before checking anything. continue-on-error hid # that the type check was doing no work at all. - name: Type check (mypy) - # --exclude: layers/eosuite/ vendors its own tests/ package, so a bare - # `mypy .` sees two modules named "tests" and bails with "Duplicate - # module named 'tests'" before checking anything. continue-on-error hid - # that the type check was doing no work at all. - run: mypy . --ignore-missing-imports --no-strict-optional --exclude '^layers/' - continue-on-error: true + run: mypy . --ignore-missing-imports --no-strict-optional --exclude '^(layers|core|promo)/' # Runs the whole tests/ tree. The previous steps ran only tests/unit/ # and tests/functional/ — 15 of the 98 collected tests — so diff --git a/.github/workflows/video-build.yml b/.github/workflows/video-build.yml index 1a1a63f..59869fa 100644 --- a/.github/workflows/video-build.yml +++ b/.github/workflows/video-build.yml @@ -92,4 +92,3 @@ jobs: fail_on_unmatched_files: false env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - diff --git a/.yamllint.yml b/.yamllint.yml new file mode 100644 index 0000000..520c1ac --- /dev/null +++ b/.yamllint.yml @@ -0,0 +1,11 @@ +extends: default + +ignore: | + .venv/ + core/ + +rules: + line-length: disable + truthy: + check-keys: false + document-start: disable diff --git a/codecov.yml b/codecov.yml index 25fa0fc..76d962b 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,5 +1,5 @@ codecov: - require_ci_to_pass: yes + require_ci_to_pass: true coverage: precision: 2 @@ -19,4 +19,4 @@ coverage: comment: layout: "reach, diff, flags, files" behavior: default - require_changes: no + require_changes: false diff --git a/ebuild/__main__.py b/ebuild/__main__.py index bc24ec0..2891767 100644 --- a/ebuild/__main__.py +++ b/ebuild/__main__.py @@ -8,4 +8,4 @@ from ebuild.cli.commands import cli if __name__ == "__main__": - cli() \ No newline at end of file + cli() diff --git a/ebuild/build/dispatch.py b/ebuild/build/dispatch.py index d27faa0..8498cd0 100644 --- a/ebuild/build/dispatch.py +++ b/ebuild/build/dispatch.py @@ -13,7 +13,7 @@ import subprocess import sys from pathlib import Path -from typing import Any, Dict, List, Optional, Set +from typing import Any, Dict, List, Optional logger = logging.getLogger(__name__) diff --git a/ebuild/build/ninja_backend.py b/ebuild/build/ninja_backend.py index 6557c5d..72e7b58 100644 --- a/ebuild/build/ninja_backend.py +++ b/ebuild/build/ninja_backend.py @@ -9,7 +9,6 @@ from __future__ import annotations import json -import re import sys from dataclasses import dataclass, field from pathlib import Path diff --git a/ebuild/cli/__init__.py b/ebuild/cli/__init__.py index aa04773..7efe452 100644 --- a/ebuild/cli/__init__.py +++ b/ebuild/cli/__init__.py @@ -9,4 +9,4 @@ __version__ = version("ebuild") except PackageNotFoundError: # Fallback if the package is run directly without being installed - __version__ = "unknown" \ No newline at end of file + __version__ = "unknown" diff --git a/ebuild/cli/integration.py b/ebuild/cli/integration.py index 9fd1eb1..77c9d91 100644 --- a/ebuild/cli/integration.py +++ b/ebuild/cli/integration.py @@ -18,7 +18,7 @@ import subprocess import sys from pathlib import Path -from typing import Dict, List, Optional +from typing import Any, Dict, List, Optional, Tuple import click @@ -36,7 +36,7 @@ "eipc": {"cmake_flag": "", "lang": "go", "sdk_subdir": "sdk/c"}, } -QEMU_ARCHS = { +QEMU_ARCHS: Dict[str, Dict[str, Any]] = { "x86_64": { "bin": "qemu-system-x86_64", "args": ["-machine", "q35", "-cpu", "qemu64", "-m", "512", @@ -138,7 +138,7 @@ def _cmake_build(repo_dir: Path, build_dir: Path, extra_flags: str, def _collect_libraries(build_dir: Path, repos: Dict[str, Path]) -> List[Path]: """Find all .a static libraries produced by the builds.""" - libs = [] + libs: List[Path] = [] for name in repos: repo_build = build_dir / name if repo_build.exists(): @@ -294,7 +294,7 @@ def _create_initramfs(rootfs: Path, build_dir: Path) -> Path: initramfs = build_dir / "initramfs.cpio.gz" entries = [rootfs, *sorted(rootfs.rglob("*"), key=lambda p: p.as_posix())] - hardlink_inodes = {} + hardlink_inodes: Dict[Optional[Tuple[int, int]], int] = {} hardlink_data_written = set() next_inode = 1 diff --git a/ebuild/deliverable_packager.py b/ebuild/deliverable_packager.py index bf4327d..d956484 100644 --- a/ebuild/deliverable_packager.py +++ b/ebuild/deliverable_packager.py @@ -26,7 +26,9 @@ from ebuild.sdk_generator import TARGET_ARCH, get_target_info except ImportError: sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) - from sdk_generator import TARGET_ARCH, get_target_info + # Imported from ebuild.sdk_generator in the try above as well; mypy + # cannot see that only one branch runs, so it flags this as a redefinition. + from sdk_generator import TARGET_ARCH, get_target_info # type: ignore[no-redef] SOURCE_REPOS = { "eos": {"dirs": ["core","hal","kernel","drivers","debug","services","systems", diff --git a/ebuild/deps/__init__.py b/ebuild/deps/__init__.py index 9da9525..a916c3d 100644 --- a/ebuild/deps/__init__.py +++ b/ebuild/deps/__init__.py @@ -10,6 +10,7 @@ from __future__ import annotations from pathlib import Path +from typing import Any, Dict # Default location for ebuild's persistent state EBUILD_HOME = Path.home() / ".ebuild" @@ -21,7 +22,7 @@ DEFAULT_EBOOT_REPO_URL = "https://github.com/embeddedos-org/eBoot.git" DEFAULT_EFIRMWARE_REPO_URL = "https://github.com/embeddedos-org/eFirmware.git" -DEFAULT_CONFIG = { +DEFAULT_CONFIG: Dict[str, Any] = { "repos": { # Both repos default to master; neither has a main. Cloning the # branch named here is what `ebuild setup` does first, so "main" diff --git a/ebuild/eos_ai/__init__.py b/ebuild/eos_ai/__init__.py index 61d463d..f38e793 100644 --- a/ebuild/eos_ai/__init__.py +++ b/ebuild/eos_ai/__init__.py @@ -26,9 +26,12 @@ from ebuild.eos_ai.eos_validator import EosConfigValidator from ebuild.eos_ai.eos_boot_integrator import EosBootIntegrator except ImportError: - EosConfigGenerator = None - EosConfigValidator = None - EosBootIntegrator = None + # When pyyaml is absent these stay None and callers test for truthiness. + # mypy cannot type a name that is a class when the import succeeds and + # None when it does not. + EosConfigGenerator = None # type: ignore[misc] + EosConfigValidator = None # type: ignore[misc] + EosBootIntegrator = None # type: ignore[misc] __all__ = [ "EosHardwareAnalyzer", diff --git a/ebuild/plugins/__init__.py b/ebuild/plugins/__init__.py index 7dfa7b3..3353ea5 100644 --- a/ebuild/plugins/__init__.py +++ b/ebuild/plugins/__init__.py @@ -41,7 +41,9 @@ def discover_plugins() -> List[PluginBase]: if hasattr(entry_points, "select"): eps = entry_points.select(group="ebuild.plugins") else: - eps = entry_points.get("ebuild.plugins", []) + # Before 3.10 entry_points() returned a dict; the current stubs + # only model EntryPoints, which has no .get, hence the ignore. + eps = entry_points.get("ebuild.plugins", []) # type: ignore[attr-defined] for ep in eps: try: diff --git a/ebuild/system/doctor.py b/ebuild/system/doctor.py index c405904..99a1826 100644 --- a/ebuild/system/doctor.py +++ b/ebuild/system/doctor.py @@ -25,7 +25,7 @@ import sys from dataclasses import dataclass from pathlib import Path -from typing import List, Optional +from typing import List OK, MISSING, WARN = "ok", "missing", "warn" diff --git a/hardware/board/eradar360.yaml b/hardware/board/eradar360.yaml index 3e6b9ef..2db54fa 100644 --- a/hardware/board/eradar360.yaml +++ b/hardware/board/eradar360.yaml @@ -43,16 +43,16 @@ peripherals: memory_map: flash_base: 0x00000000 - flash_size: 0x2000000 # 256MB NOR flash + flash_size: 0x2000000 # 256MB NOR flash ram_base: 0x00200000 - ram_size: 0x40000000 # 1GB DDR4 - spi0_base: 0xFE610000 # SPI0 controller (front radar) - spi1_base: 0xFE620000 # SPI1 controller (rear radar) - uart2_base: 0xFEB50000 # UART2 debug - uart3_base: 0xFEB60000 # UART3 V2X - i2c0_base: 0xFEA90000 # I2C0 bus - mipi_dsi_base: 0xFDE20000 # MIPI-DSI display controller - npu_base: 0xFDAB0000 # RKNPU (6 TOPS) + ram_size: 0x40000000 # 1GB DDR4 + spi0_base: 0xFE610000 # SPI0 controller (front radar) + spi1_base: 0xFE620000 # SPI1 controller (rear radar) + uart2_base: 0xFEB50000 # UART2 debug + uart3_base: 0xFEB60000 # UART3 V2X + i2c0_base: 0xFEA90000 # I2C0 bus + mipi_dsi_base: 0xFDE20000 # MIPI-DSI display controller + npu_base: 0xFDAB0000 # RKNPU (6 TOPS) boot: recovery_pin: GPIO0_A0 (active low, pull-up) diff --git a/pyproject.toml b/pyproject.toml index 303f2c6..3bafe3b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,3 +30,22 @@ ebuild = "ebuild.cli.commands:cli" [tool.setuptools.packages.find] include = ["ebuild*"] + +[tool.ruff] +exclude = [ + ".venv", + "core", + "layers/eosuite", +] + +[tool.ruff.lint] +select = ["E", "F", "W"] +ignore = [ + "E501", # line too long + "E731", # lambda assignment + "E741", # ambiguous variable name + "F403", # star import used (manim requires it in promo/) + "F405", # name may be undefined from a star import + "F541", # f-string without placeholders + "F841", # unused local variable +] diff --git a/recipes/freertos.yaml b/recipes/freertos.yaml index 2e9fa3a..2d2332c 100644 --- a/recipes/freertos.yaml +++ b/recipes/freertos.yaml @@ -1,11 +1,11 @@ -package: freertos -version: "11.1.0" -description: "Real-time operating system kernel for embedded devices" -license: MIT -url: https://github.com/FreeRTOS/FreeRTOS-Kernel/releases/download/V11.1.0/FreeRTOS-KernelV11.1.0.zip -checksum: sha256:eebd58aa71a623c9381f25f77b708c0ed14ef995a8913e2460fe9f286bb271eb -build: cmake -configure_args: - - -DFREERTOS_HEAP=4 - - -DFREERTOS_PORT=GCC_ARM_CM4F -dependencies: [] +package: freertos +version: "11.1.0" +description: "Real-time operating system kernel for embedded devices" +license: MIT +url: https://github.com/FreeRTOS/FreeRTOS-Kernel/releases/download/V11.1.0/FreeRTOS-KernelV11.1.0.zip +checksum: sha256:eebd58aa71a623c9381f25f77b708c0ed14ef995a8913e2460fe9f286bb271eb +build: cmake +configure_args: + - -DFREERTOS_HEAP=4 + - -DFREERTOS_PORT=GCC_ARM_CM4F +dependencies: [] diff --git a/tests/ebuild/test_dispatch.py b/tests/ebuild/test_dispatch.py index d4d75f7..1b681c6 100644 --- a/tests/ebuild/test_dispatch.py +++ b/tests/ebuild/test_dispatch.py @@ -4,13 +4,11 @@ """Tests for ebuild.build.dispatch — backend detection, dispatch, dry-run.""" import logging -from pathlib import Path from unittest.mock import patch import pytest from ebuild.build.dispatch import ( - ALL_BACKENDS, BackendDispatcher, BackendError, UnknownBackendError, diff --git a/tests/ebuild/test_eos_ai.py b/tests/ebuild/test_eos_ai.py index 45ee703..fe80ea9 100644 --- a/tests/ebuild/test_eos_ai.py +++ b/tests/ebuild/test_eos_ai.py @@ -260,4 +260,4 @@ def test_unknown_mcu_still_detects_peripherals(self): print(f"\n{'='*50}") print(f"Results: {passed}/{total} passed, {failed} failed") print(f"{'='*50}") - sys.exit(0 if failed == 0 else 1) \ No newline at end of file + sys.exit(0 if failed == 0 else 1) diff --git a/tests/ebuild/test_integration_initramfs_security.py b/tests/ebuild/test_integration_initramfs_security.py index 3dff3a7..a2cdcdf 100644 --- a/tests/ebuild/test_integration_initramfs_security.py +++ b/tests/ebuild/test_integration_initramfs_security.py @@ -24,7 +24,6 @@ import os import shutil import stat -import subprocess import pytest diff --git a/tests/unit/test_cad_pipeline.py b/tests/unit/test_cad_pipeline.py index 0886016..a03606f 100644 --- a/tests/unit/test_cad_pipeline.py +++ b/tests/unit/test_cad_pipeline.py @@ -19,8 +19,6 @@ import sys from pathlib import Path -import pytest - REPO = Path(__file__).resolve().parents[2] TOOL = REPO / "tools" / "cad_pipeline.py" SAMPLE = REPO / "samples" / "eos_reference_board.kicad_pcb" diff --git a/tests/unit/test_doctor.py b/tests/unit/test_doctor.py index 241071f..d3a5bc2 100644 --- a/tests/unit/test_doctor.py +++ b/tests/unit/test_doctor.py @@ -16,7 +16,6 @@ import json -import pytest from click.testing import CliRunner from ebuild.cli.commands import cli @@ -29,7 +28,6 @@ exit_code, format_report, host_checks, - run_all, toolchain_checks, ) diff --git a/tests/unit/test_empty_test_run_is_not_a_pass.py b/tests/unit/test_empty_test_run_is_not_a_pass.py index 6a59741..a0cd2c6 100644 --- a/tests/unit/test_empty_test_run_is_not_a_pass.py +++ b/tests/unit/test_empty_test_run_is_not_a_pass.py @@ -25,7 +25,6 @@ import sys -import pytest import yaml from click.testing import CliRunner diff --git a/tests/unit/test_package_efw.py b/tests/unit/test_package_efw.py index 91d2be2..97d3fdb 100644 --- a/tests/unit/test_package_efw.py +++ b/tests/unit/test_package_efw.py @@ -29,7 +29,6 @@ find_efwtool, missing_tool_message, pack, - verify, ) from ebuild.cli.commands import cli diff --git a/tools/cad_pipeline.py b/tools/cad_pipeline.py index d4b585c..e830d33 100644 --- a/tools/cad_pipeline.py +++ b/tools/cad_pipeline.py @@ -22,7 +22,7 @@ import os import json from dataclasses import dataclass, field -from typing import List, Optional +from typing import List # ── Data models ───────────────────────────────────────────────────────────────