-
Notifications
You must be signed in to change notification settings - Fork 36
refactor!: [V8] Split container classes into read/write versions (DM-3215) #2382
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
refactor!: [V8] Split container classes into read/write versions (DM-3215) #2382
Conversation
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. |
1c7537d to
1a7da07
Compare
|
/gemini review |
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.
Code Review
This pull request is a significant and well-executed refactoring of the container-related data classes. The introduction of dataclasses and the separation of read and write models (Container vs. ContainerApply) greatly improve code clarity, type safety, and maintainability, aligning well with the repository's style guide. The use of ...Core base classes to abstract common functionality is an excellent pattern.
However, I've identified a critical issue in the new implementation. The state field in the read versions of Constraint and Index classes has been changed from optional to required. This could lead to KeyError exceptions if the API omits this field in its responses, which the previous implementation handled gracefully. I've provided detailed comments and suggestions to address this potential regression.
- fix tests/tests_unit/test_api/test_assets.py - fix tests/tests_unit/test_api/test_data_modeling/test_containers.py - fix tests/tests_unit/test_api/test_data_sets.py - fix tests/tests_unit/test_api/test_datapoints.py - fix tests/tests_unit/test_api/test_documents.py - fix tests/tests_unit/test_api/test_entity_matching.py - fix tests/tests_unit/test_api/test_events.py - fix tests/tests_unit/test_api/test_extractionpipelines.py - fix tests/tests_unit/test_api/test_files.py (puh!) - fix tests/tests_unit/test_api/test_functions.py (mega puuh) - fix tests/tests_unit/test_api/test_iam.py - fix tests/tests_unit/test_api/test_labels.py - fix tests/tests_unit/test_api/test_raw.py - fix tests/tests_unit/test_api/test_relationships.py - fix tests/tests_unit/test_api/test_sequences.py (puh again) - fix tests/tests_unit/test_api/test_synthetic_time_series.py - fix tests/tests_unit/test_api/test_time_series.py - fix tests/tests_unit/test_api/test_vision_extract.py - fix tests/tests_unit/test_api_client.py ( 👀 ) - fix tests/tests_unit/test_cognite_client.py - fix tests/tests_unit/test_data_classes/test_capabilities.py - fix tests/tests_unit/test_http_client.py - fix tests/tests_unit/test_meta.py
e92c87f to
6a22e7e
Compare
3f22dcd to
016505a
Compare
also use dataclasses more
1a7da07 to
0b8f877
Compare
haakonvt
left a comment
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.
Thanks for having the patience to get all these classes split into proper read and write versions 😄 The removal of object.__setattr__ also brings joy to my heart!
A few questions:
| return self.as_id().as_property_ref(property) | ||
|
|
||
|
|
||
| @dataclass(frozen=True) |
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.
I'm unsure about frozen on write classes.
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.
I wanted to remove frozen, but you're not allowed to inherit frozen classes from non-frozen classes and vice versa. So they all need to be frozen or not.
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.
Huh, I see. That makes me a bit sad 🥲 Thoughts @erlendvollset ?
| property_loader=ContainerPropertyApply._load, | ||
| constraint_loader=ConstraintApply._load, | ||
| index_loader=IndexApply._load, |
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.
We seem to be always calling ._load on the passed callables - then I think I would prefer to pass the classes instead.
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 problem was with the Constraint and Index classes. If we switch the argument to constraint_class: type[ConstraintCore] and pass constraint_class=Constraint or constraint_class=ConstraintApply, mypy will complain with
cognite/client/data_classes/data_modeling/containers.py:127: error: Only concrete class can be given where "type[ConstraintCore]" is expected [type-abstract]
So I switched to using loader functions for these arguments.
We can still pass classes for the property. Should we?
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.
Oh how I love mypy 🙃 Does it work with a TypeVar using bound?
Anyway, feel free to just leave it as is 👍
| is_global: bool = False | ||
| last_updated_time: int = 0 | ||
| created_time: int = 0 | ||
| used_for: Literal["node", "edge", "all"] = "all" |
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.
Why do these have default values?
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.
Good point. They shouldn't.
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.
@haakonvt I removed all defaults from the read classes and made them kw_only. We don't care about these being convenient to construct.
The write classes can have defaults, but I wonder if we might want to make them kw_only too?
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.
Nice, agree on the read classes 👍
I think we shouldn't force the user into a specific way to instantiate the write classes.
| nullable=resource.get("nullable", True), | ||
| auto_increment=resource.get("autoIncrement", False), |
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.
Could you elaborate a bit on the change away from the previous behaviour? (Wrt # If nothing is specified, we will pass through null values)
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.
Maybe not a very conscious decision. I just found it cleaner to use sensible defaults where appropriate. But maybe we should keep them as optional and retain the None pass-through. What do you think?
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.
Having thought some more about it, I think your changes make sense.
Would like to know the reason for the previous behaviour choice though
and make them `kw_only`
c605eee to
1ba5b84
Compare
|
Merged into #2387 , closing |
The
Containerclass already had aContainerApplywrite version, but the member classes didn't. Since we added state fields, the read and write versions now differ, so split them.Also converted them to dataclasses.
@haakonvt feel free to ignore this PR until you've gotten the alpha version out :)