-
Notifications
You must be signed in to change notification settings - Fork 34
refactor(models): use cattrs to reduce boilerplate in model definitions #1893
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR refactors three model classes (Location, Partner, Connectivity) to use cattrs for automatic structuring from dictionaries, eliminating boilerplate __init__ methods. A new converters.py module is introduced with a pre-configured cattrs converter that ignores extra API keys.
Changes:
- Added cattrs dependency (≥24.1.0) to handle dict-to-model conversion
- Created
converters.pymodule with cattrs converter and enum structure hook infrastructure - Refactored Location, Partner, and Connectivity classes to use attrs-generated
__init__methods instead of custom implementations
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| uv.lock | Added cattrs 25.3.0 dependency and updated tox to 4.34.0 |
| pyproject.toml | Added cattrs>=24.1.0 to project dependencies |
| pyoverkiz/converters.py | New module providing a cattrs converter configured to ignore extra keys, with enum structure hooks for future model migrations |
| pyoverkiz/models.py | Refactored Location, Partner, and Connectivity to use attrs-generated init; updated Setup and Gateway to use converter.structure() for creating nested model instances; fixed type annotations for optional Location fields |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def configure_converter() -> None: | ||
| """Register structure hooks for all pyoverkiz enums. | ||
| This must be called after importing the enums module to ensure all enum | ||
| classes are available for registration. | ||
| """ | ||
| from pyoverkiz import enums | ||
|
|
||
| # Exclude base enum classes that are re-exported from the enums module | ||
| base_classes = (Enum, IntEnum, StrEnum) | ||
|
|
||
| for name in dir(enums): | ||
| obj = getattr(enums, name) | ||
| if isinstance(obj, type) and issubclass(obj, Enum) and obj not in base_classes: | ||
| converter.register_structure_hook(obj, _structure_enum) |
Copilot
AI
Jan 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The enum structure hooks registered in configure_converter are not currently used by the refactored models (Location, Partner, Connectivity don't have enum fields). While this is fine as preparation for future refactoring, the current implementation may not correctly handle optional enum fields (e.g., UpdateBoxStatus | None). Consider adding tests for enum structuring before migrating models with enum fields, or add a hook for Optional[Enum] types using cattrs.register_structure_hook for Union types.
I agree that
|
|
Agree, @tetienne! Lets see how we can improve the (especially v2) code to make it easier and more robust, but keeping the package lightweight. |
|
@iMicknl Do you want to merge this pr, and then let me continue the refactor? |
|
I will need to review the converters.py code first, I don't fully understand yet what is happening. This seems like quite a big change, perhaps we should see if we can add a few more tests to make sure we don't break existing behavior. My last (small) change broke a lot of installations 👀. Would you be willing to do this change on the v2 branch otherwise? |
Summary
__init__methodsWhy
The current models.py has significant boilerplate where fields are declared twice - once in the class body and again in custom
__init__methods. Using cattrs withforbid_extra_keys=Falseelegantly handles the**_pattern for ignoring unknown API fields, allowing attrs to generate the__init__automatically.This is a proof-of-concept that demonstrates the pattern before broader migration to remaining models.