Fix QbField issues - #7463
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThe query field system adds typed boolean filters and sequence-based array dispatch. Numeric metadata is modeled explicitly, QueryBuilder accepts boolean fields, ORM tests cover boolean filtering, and field schemas use more specific boolean, UUID, numeric, and array declarations. ChangesTyped query fields and ORM schemas
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related issues
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
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. Comment |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #7463 +/- ##
==========================================
+ Coverage 80.65% 80.67% +0.02%
==========================================
Files 581 581
Lines 46987 47014 +27
==========================================
+ Hits 37893 37923 +30
+ Misses 9094 9091 -3 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/aiida/orm/fields.py (1)
159-173: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueAdd type annotations to
QbBoolFieldmethods.As per coding guidelines, types should be written in annotations. Adding type hints to these methods improves developer ergonomics and aligns with the rest of the file (e.g.,
QbFieldFilters).♻️ Proposed refactor
- def as_filter(self): + def as_filter(self) -> QbFieldFilters: """Return a filter for only values that are True.""" return QbFieldFilters(((self, '==', True),)) - def __and__(self, other): + def __and__(self, other: QbFieldFilters | QbBoolField) -> QbFieldFilters: """Return a filter for only values that are True and satisfy the other filter.""" return self.as_filter() & other - def __or__(self, other): + def __or__(self, other: QbFieldFilters | QbBoolField) -> QbFieldFilters: """Return a filter for only values that are True or satisfy the other filter.""" return self.as_filter() | other - def __invert__(self): + def __invert__(self) -> QbFieldFilters: """Return a filter for only values that are False.""" return QbFieldFilters(((self, '==', False),))🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/aiida/orm/fields.py` around lines 159 - 173, Update the QbBoolField methods as_filter, __and__, __or__, and __invert__ with appropriate parameter and return type annotations, including the other argument for the binary operators. Match the existing annotation conventions used by QbFieldFilters and preserve the current filter behavior.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/aiida/orm/fields.py`:
- Around line 159-173: Update the QbBoolField methods as_filter, __and__,
__or__, and __invert__ with appropriate parameter and return type annotations,
including the other argument for the binary operators. Match the existing
annotation conventions used by QbFieldFilters and preserve the current filter
behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 256b4f66-5d5a-426e-a4dc-3bc71c514f31
📒 Files selected for processing (48)
src/aiida/orm/fields.pysrc/aiida/orm/nodes/data/numeric.pysrc/aiida/orm/querybuilder.pytests/orm/test_fields/fields_AuthInfo.ymltests/orm/test_fields/fields_Comment.ymltests/orm/test_fields/fields_Computer.ymltests/orm/test_fields/fields_Group.ymltests/orm/test_fields/fields_Log.ymltests/orm/test_fields/fields_aiida.data.core.array.ArrayData.ymltests/orm/test_fields/fields_aiida.data.core.array.bands.BandsData.ymltests/orm/test_fields/fields_aiida.data.core.array.kpoints.KpointsData.ymltests/orm/test_fields/fields_aiida.data.core.array.projection.ProjectionData.ymltests/orm/test_fields/fields_aiida.data.core.array.trajectory.TrajectoryData.ymltests/orm/test_fields/fields_aiida.data.core.array.xy.XyData.ymltests/orm/test_fields/fields_aiida.data.core.base.BaseType.ymltests/orm/test_fields/fields_aiida.data.core.bool.Bool.ymltests/orm/test_fields/fields_aiida.data.core.cif.CifData.ymltests/orm/test_fields/fields_aiida.data.core.code.Code.ymltests/orm/test_fields/fields_aiida.data.core.code.abstract.AbstractCode.ymltests/orm/test_fields/fields_aiida.data.core.code.containerized.ContainerizedCode.ymltests/orm/test_fields/fields_aiida.data.core.code.installed.InstalledCode.ymltests/orm/test_fields/fields_aiida.data.core.code.portable.PortableCode.ymltests/orm/test_fields/fields_aiida.data.core.dict.Dict.ymltests/orm/test_fields/fields_aiida.data.core.enum.EnumData.ymltests/orm/test_fields/fields_aiida.data.core.float.Float.ymltests/orm/test_fields/fields_aiida.data.core.folder.FolderData.ymltests/orm/test_fields/fields_aiida.data.core.int.Int.ymltests/orm/test_fields/fields_aiida.data.core.jsonable.JsonableData.ymltests/orm/test_fields/fields_aiida.data.core.list.List.ymltests/orm/test_fields/fields_aiida.data.core.numeric.NumericType.ymltests/orm/test_fields/fields_aiida.data.core.orbital.OrbitalData.ymltests/orm/test_fields/fields_aiida.data.core.remote.RemoteData.ymltests/orm/test_fields/fields_aiida.data.core.remote.stash.RemoteStashData.ymltests/orm/test_fields/fields_aiida.data.core.remote.stash.compress.RemoteStashCompressedData.ymltests/orm/test_fields/fields_aiida.data.core.remote.stash.custom.RemoteStashCustomData.ymltests/orm/test_fields/fields_aiida.data.core.remote.stash.folder.RemoteStashFolderData.ymltests/orm/test_fields/fields_aiida.data.core.singlefile.SinglefileData.ymltests/orm/test_fields/fields_aiida.data.core.str.Str.ymltests/orm/test_fields/fields_aiida.data.core.structure.StructureData.ymltests/orm/test_fields/fields_aiida.data.core.upf.UpfData.ymltests/orm/test_fields/fields_aiida.node.data.Data.ymltests/orm/test_fields/fields_aiida.node.process.ProcessNode.ymltests/orm/test_fields/fields_aiida.node.process.calculation.CalculationNode.ymltests/orm/test_fields/fields_aiida.node.process.calculation.calcfunction.CalcFunctionNode.ymltests/orm/test_fields/fields_aiida.node.process.calculation.calcjob.CalcJobNode.ymltests/orm/test_fields/fields_aiida.node.process.workflow.WorkflowNode.ymltests/orm/test_fields/fields_aiida.node.process.workflow.workchain.WorkChainNode.ymltests/orm/test_fields/fields_aiida.node.process.workflow.workfunction.WorkFunctionNode.yml
|
@GeigerJ2 two comments:
|
|
Interesting. That test passes locally no problem. UpdateMay have been due to running that test in isolation. When running the full suite, assigned PKs may be different. Using labels instead to uniquly identify the tested nodes! |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
tests/orm/test_fields.py (1)
252-252: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winPrevent potential test flakiness by making the assertion order-independent.
Without an explicit
order_byclause in the query, relational databases do not guarantee the order of the returned rows. Comparing the result directly to the list[True, False]could lead to intermittent test failures if the backend returns the rows in a different order (e.g.,[False, True]).Consider using a
setto perform an order-independent comparison.♻️ Proposed fix
- assert result == [True, False] + assert set(result) == {True, False}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/orm/test_fields.py` at line 252, Make the assertion in the affected test order-independent by comparing the result as a set to the expected boolean values. Preserve the existing query and expected contents while allowing either database row order.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@tests/orm/test_fields.py`:
- Line 252: Make the assertion in the affected test order-independent by
comparing the result as a set to the expected boolean values. Preserve the
existing query and expected contents while allowing either database row order.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: d4479947-ea86-46d0-8e1c-0b5c9c9fefe5
📒 Files selected for processing (2)
src/aiida/orm/fields.pytests/orm/test_fields.py
🚧 Files skipped from review as they are similar to previous changes (1)
- src/aiida/orm/fields.py
201ad01 to
89c8941
Compare
89c8941 to
5f67d22
Compare
|
Guys this is an API extension, you cannot put it into a patch release. |
agoscinski
left a comment
There was a problem hiding this comment.
there should be at least some small update in the RTD i guess?
| title='Numeric value', | ||
| description='The value of the numeric data', | ||
| ) | ||
|
|
There was a problem hiding this comment.
why was this change only done in this pr and not in the bigger pydantic upgrade?
| user: QbNumericField('user', dtype=<class 'int'>, doc='The PK of the user who owns | ||
| the node') | ||
| uuid: QbAnyField('uuid', dtype=<class 'uuid.UUID'>, doc='The UUID of the node') | ||
| uuid: QbStrField('uuid', dtype=<class 'uuid.UUID'>, doc='The UUID of the node') |
There was a problem hiding this comment.
why also the update to str, i thought u only add bool in this PR
There was a problem hiding this comment.
Please refer to the PR description
Just to be clear, it is an API extension, not a breaking change, correct? If so, I don't see a reason not to add it to the upcoming 2.9 release 🙂 |
Fine to leave this off the release if too stressful 🧘🏻♂️ |
GeigerJ2
left a comment
There was a problem hiding this comment.
Just had a look at the Python files so far. I expect the YAML changes will be correct and mechanical. One point to address, already posting now, while I glance over the YAML files.
QbField type assignmentsQbField issues
GeigerJ2
left a comment
There was a problem hiding this comment.
Great, thanks a lot, @edan-bainglass! Just one comment on test_attribute_field_access, but already approving now :)
5684d2e to
2a174c3
Compare
Some booleans are optional and may be absent, not false.
`KpointsData` is marked for removal. Also, the issue of sparse boolean attributes is a subtle one, so a more detailed test is warranted. The new test uses the internal `CalculationNode` class, testing its `paused` sparse boolean attribute.
2a174c3 to
10daf08
Compare
This PR fixes the following incorrect
QbAnyFieldassignments:boolQbBoolFieldUUIDQbStrFieldSequenceQbArrayFieldRegarding the new
QbBoolField, this now allows for the following:filters=CalcJobNode.fields.pausedfilters=... & CalcJobNode.fields.paused(or|)filters=CalcJobNode.fields.paused & ...(or|)filters=~CalcJobNode.fields.paused(implemented as "not True" instead of "is False" - see reason)In other words, boolean-based queries are now supported!
For
Enumfield annotations, I keep it asQbAnyField, as the value can be anything (we haveint,str, andtuple[str]in core). Also, I was thinking of falling back toQbFieldif the annotation is not matched but decided in the end to keep it all-permissive, i.e.,QbAnyField.Lastly, this PR also addresses the issue that
attributes['value']doesn't return the sameQbFieldasattributes.valuewhenvalueis a defined attribute on the node model. When the key is not a defined attribute, we defer to theQbDictFieldindexing behavior of returning aQbAnyField.This addresses a part of #7461 but does not yet close it.