Skip to content

Conversation

@CoMPaTech
Copy link
Owner

@CoMPaTech CoMPaTech commented Aug 8, 2025

Summary by CodeRabbit

  • Refactor

    • Improved the fixture generation script for better maintainability and dynamic processing of JSON files.
    • Updated internal data structure inheritance for consistency.
  • Style

    • Expanded numeric fields in several data classes to accept integer and null values for improved flexibility.
  • Chores

    • Updated project version to 0.2.7.
    • Added a new debugging script to validate JSON userdata deserialization stepwise.

@coderabbitai
Copy link

coderabbitai bot commented Aug 8, 2025

Walkthrough

This update introduces a new base dataclass, AirOSDataClass, in airos/data.py, with all other dataclasses now inheriting from it. Several numeric fields have expanded type annotations to accept float, int, or None. The Remote dataclass's age field was adjusted for optionality. The script for generating fixtures was refactored for automation and logging, and the project version was incremented.

Changes

Cohort / File(s) Change Summary
Dataclass Base & Typing Updates
airos/data.py
Introduced AirOSDataClass as a new base for all dataclasses; updated inheritance; expanded numeric field types; made Remote.age optional.
Fixture Generation Refactor
script/generate_ha_fixture.py
Refactored script to dynamically process all relevant JSON files, added logging, error handling, and directory checks; replaced manual fixture creation with a single automated function.
New Debug Script
script/mashumaro-step-debug.py
Added a new standalone script to debug and validate JSON userdata deserialization stepwise with detailed logging.
Project Version Bump
pyproject.toml
Updated project version from 0.2.6 to 0.2.7.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Script
    participant FileSystem
    participant AirOS
    participant JSON

    User->>Script: Run script
    Script->>FileSystem: List JSON files in userdata/
    loop For each JSON file (excluding "mocked")
        Script->>FileSystem: Read JSON file
        Script->>JSON: Parse JSON
        Script->>AirOS: Call derived_data()
        AirOS-->>Script: Return derived data
        Script->>JSON: Convert to AirOSData
        Script->>FileSystem: Write fixture to fixtures/
        Script->>User: Log progress
    end
    Script->>User: Log completion
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • Bump json to mashumaro #23: Adds detailed AirOSData dataclass models and updates usage, directly relating to changes in dataclass structure and inheritance.
  • Classing #28: Focuses on renaming and relocating the AirOSData class in the same module, related by touching the same dataclass definitions.
  • Fix apmac and add determined mac address #35: Introduces a new Derived dataclass and integrates derived MAC address data, also modifying dataclasses in airos/data.py.

Poem

In fields of code where dataclasses grow,
A new base was planted, neat in its row.
Types now accept float, int, or none—
More flexible data for everyone!
Fixtures bloom with less manual care,
Debug scripts hop in with logging flair.
And version numbers hop in the air.
🐇✨

Note

🔌 MCP (Model Context Protocol) integration is now available in Early Access!

Pro users can now connect to remote MCP servers under the Integrations page to get reviews and chat conversations that understand additional development context.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch validate_fixture

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai or @coderabbitai title anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@codecov
Copy link

codecov bot commented Aug 8, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.71%. Comparing base (e82cb88) to head (b626c19).
⚠️ Report is 4 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main      #52   +/-   ##
=======================================
  Coverage   95.70%   95.71%           
=======================================
  Files           9        9           
  Lines        1281     1283    +2     
=======================================
+ Hits         1226     1228    +2     
  Misses         55       55           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🔭 Outside diff range comments (1)
airos/data.py (1)

185-190: Potential deserialization failure on unknown Host.netrole

pre_deserialize deletes an unknown netrole, but Host.netrole is non-optional. If a device returns a new/unknown value, mashumaro will error due to a missing required field. Recommend making it optional with a sane default to degrade gracefully.

 @dataclass
-class Host(AirOSDataClass):
+class Host(AirOSDataClass):
@@
-    netrole: NetRole
+    netrole: NetRole | None = None

Alternatively, adapt the sanitizer to set None instead of deleting the key when the target field is optional.

🧹 Nitpick comments (3)
pyproject.toml (1)

7-7: Pre-release version vs Production/Stable classifier

You bumped to a pre-release (0.2.7a0) while classifiers still say "Development Status :: 5 - Production/Stable". If this is an alpha, consider either using a stable version (e.g., 0.2.7) or downgrading the classifier to reflect pre-release status. This avoids confusing downstream consumers.

Also applies to: 13-18

script/generate_ha_fixture.py (2)

43-52: File encodings and context managers — minor hardening

Specify UTF-8 explicitly and prefer json.load. Same for writes.

-            try:
-                with open(base_fixture_path) as source:
-                    source_data = json.loads(source.read())
+            try:
+                with open(base_fixture_path, "r", encoding="utf-8") as source:
+                    source_data = json.load(source)
@@
-                with open(new_fixture_path, "w") as new:
-                    json.dump(new_data.to_dict(), new, indent=2, sort_keys=True)
+                with open(new_fixture_path, "w", encoding="utf-8") as new:
+                    json.dump(new_data.to_dict(), new, indent=2, sort_keys=True)

55-58: Include stack traces for easier debugging

Use _LOGGER.exception to include traceback on unexpected failures.

-            except json.JSONDecodeError:
-                _LOGGER.error("Skipping '%s': Not a valid JSON file.", filename)
-            except Exception as e:
-                _LOGGER.error("Error processing '%s': %s", filename, e)
+            except json.JSONDecodeError:
+                _LOGGER.error("Skipping '%s': Not a valid JSON file.", filename)
+            except Exception:
+                _LOGGER.exception("Error processing '%s'", filename)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e82cb88 and 897eaf4.

📒 Files selected for processing (3)
  • airos/data.py (19 hunks)
  • pyproject.toml (1 hunks)
  • script/generate_ha_fixture.py (2 hunks)
🔇 Additional comments (8)
airos/data.py (7)

95-99: Good foundation: shared base for mashumaro dataclasses

Introducing AirOSDataClass centralizes the mashumaro mixin and keeps leaf classes clean. No issues spotted.


158-166: Consistent inheritance migration to AirOSDataClass

All dataclasses now consistently inherit from AirOSDataClass. This unifies serialization behavior and reduces boilerplate. Looks good.

Also applies to: 193-205, 214-223, 230-244, 247-256, 259-266, 268-280, 283-293, 296-307, 310-315, 318-360, 369-381, 383-419, 421-471, 474-492, 495-503, 506-517, 520-526, 529-542, 545-561


169-185: Host: relax numeric types for load/cpu — LGTM

Changing loadavg and cpuload to float | int | None will deserialise more real-world values. No functional issues.

Also applies to: 178-183


299-306: GPSData numeric unions — LGTM

Allowing lat/lon/dop/alt to be float | int | None improves robustness against varying firmware outputs. No concerns.


523-525: GPSMain numeric unions — LGTM

lat/lon relaxed to float | int | None aligns with GPSData. Looks correct.


326-327: Remote.cpuload relaxed to float | int | None — LGTM

Matches Host behavior and real-world variability.


359-360: Remote.age optionality verified – safe to approve

  • airos/data.py:359 – age: int | None = None
  • No usages of Remote.age found elsewhere in the codebase

Marking age as optional aligns with NanoStation 8.7.11 and introduces no downstream impact.

script/generate_ha_fixture.py (1)

61-65: Main guard — LGTM

Logging config and entry point are fine. No changes needed.

@sonarqubecloud
Copy link

sonarqubecloud bot commented Aug 8, 2025

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (5)
script/mashumaro-step-debug.py (5)

1-1: Add a shebang to make the script directly executable.

Helps running via ./script/mashumaro-step-debug.py.

+#!/usr/bin/env python3
 """Debug userdata json to see where things don't add up."""

12-13: Remove duplicate sys.path manipulation and ensure import precedence.

The project_root_dir is added twice; also prefer insert(0) to ensure it precedes site-packages.

-    sys.path.append(project_root_dir)
+    sys.path.insert(0, project_root_dir)
-    current_script_dir = os.path.dirname(os.path.abspath(__file__))
-    project_root_dir = os.path.abspath(os.path.join(current_script_dir, os.pardir))
-
-    if project_root_dir not in sys.path:
-        sys.path.append(project_root_dir)
+    # (duplicate sys.path manipulation removed)

Also applies to: 27-32


41-45: Use the preprocessed Wireless data for subsequent steps.

Currently the result is computed but ignored; using it ensures consistent deserialization if pre-processing mutates values (e.g., enum normalization).

-        wireless_data_prepped = Wireless.__pre_deserialize__(wireless_data.copy())  # noqa: F841
+        wireless_data = Wireless.__pre_deserialize__(wireless_data.copy())

49-59: Avoid accumulating unused objects and suppressing F841; just construct to validate.

This reduces memory for large sta lists and removes the need for noqa pragmas.

-        station_obj_list = []
         for i, station_data in enumerate(station_list_data):
@@
-            remote_obj = Remote.from_dict(remote_data)  # noqa: F841
+            Remote.from_dict(remote_data)
@@
-            station_obj = Station.from_dict(station_data)
-            station_obj_list.append(station_obj)  # noqa: F841
+            Station.from_dict(station_data)

53-56: Downgrade verbose/PII-prone logging to DEBUG and avoid dumping full payloads at INFO.

Remote data may include identifiers (MAC/IP). Keep it for debugging but not at INFO.

-            _LOGGER.info("      -> Checking Remote object at index %s...", i)
-            _LOGGER.info("Remote data = %s", remote_data)
+            _LOGGER.info("      -> Checking Remote object at index %s...", i)
+            _LOGGER.debug("Remote data = %s", remote_data)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 897eaf4 and b626c19.

📒 Files selected for processing (2)
  • pyproject.toml (1 hunks)
  • script/mashumaro-step-debug.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • pyproject.toml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Process test coverage
🔇 Additional comments (1)
script/mashumaro-step-debug.py (1)

39-39: No concerns: project targets Python ≥ 3.13—builtin generics are supported
The pyproject.toml declares requires-python = ">=3.13", so using dict[str, Any] (added in 3.9) is fully supported. No changes needed here.

@CoMPaTech CoMPaTech merged commit 7710ec3 into main Aug 8, 2025
14 checks passed
@CoMPaTech CoMPaTech deleted the validate_fixture branch August 8, 2025 19:38
@coderabbitai coderabbitai bot mentioned this pull request Aug 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant