-
Notifications
You must be signed in to change notification settings - Fork 90
fix: DH-20658: Complete wrapping of the structured Filters in Core Py API #7482
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?
fix: DH-20658: Complete wrapping of the structured Filters in Core Py API #7482
Conversation
No docs changes detected for f28bd08 |
cpwright
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.
I think leaving literal out of the API makes perfect sense. I do think that we should think about more general expressions, so we can interact with QST-like things.
| raise DHError(e, "failed to create a pattern filter.") from e | ||
|
|
||
|
|
||
| def in_(col: str, values: Sequence[Union[bool, int, float, str]]) -> Filter: |
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 wonder if this should be inverted, i.e. a union of the different sequence types? It seems mixing types might be odd.
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.
deephaven-core/engine/table/src/test/java/io/deephaven/engine/table/impl/select/WhereFilterTest.java
Line 298 in 01da8df
| public void testInLiteralsDifferentTypes() { |
I was influenced by this test in Java, and that we allow columns of the generic Object type. The fact that we are not as limiting as the inverted version is also a positive.
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 completes the wrapping of structured filters in the Core Python API by adding support for comparison operators (eq, ne, lt, le, gt, ge) and the in_ filter. A new ColumnName string subclass is introduced to distinguish column references from literal values in filter expressions. The implementation delegates to Java filter APIs while avoiding wrapping of cyclic Expression and Literal classes in favor of native Python types.
- Added comparison filter functions (
eq,ne,lt,le,gt,ge) with support for both literals and column names - Added
in_filter function for membership testing - Introduced
ColumnNameclass to differentiate column references from string literals - Updated
not_function to use static Java method instead of instance method
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| py/server/deephaven/filters.py | Adds comparison and in_ filter functions, introduces ColumnName class, fixes grammar in module docstring, and updates not_ implementation |
| py/server/tests/test_filters.py | Adds comprehensive test coverage for new in_ and comparison filter functions |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
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
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
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
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| from deephaven.jcompat import _to_sequence | ||
|
|
||
| _JFilter = jpy.get_type("io.deephaven.api.filter.Filter") | ||
| _JFilterNot = jpy.get_type("io.deephaven.api.filter.FilterNot") |
Copilot
AI
Dec 19, 2025
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 import JFilterNot is unused. It was likely added as part of the refactoring but is not actually used in the implementation since the not() function and Filter.not_() method both use getattr(_JFilter, "not") instead.
| _JFilterNot = jpy.get_type("io.deephaven.api.filter.FilterNot") |
| def eq( | ||
| left: Union[bool, int, float, str, ColumnName], | ||
| right: Union[bool, int, float, str, ColumnName], | ||
| ) -> Filter: | ||
| """Creates a new filter that evaluates to true when the left operand is equal to the right operand. | ||
| Args: | ||
| left (Union[bool, int, float, str, ColumnName]): the left operand, either a literal value or a column name | ||
| right (Union[bool, int, float, str, ColumnName]): the right operand, either a literal value or a column name | ||
| Returns: | ||
| Filter: a new equality filter | ||
| """ | ||
| return Filter(j_filter=_j_filter_comparison("eq", left=left, right=right)) | ||
|
|
||
|
|
||
| def ne( | ||
| left: Union[bool, int, float, str, ColumnName], | ||
| right: Union[bool, int, float, str, ColumnName], | ||
| ) -> Filter: | ||
| """Creates a new filter that evaluates to true when the left operand is not equal to the right operand. | ||
| Args: | ||
| left (Union[bool, int, float, str, ColumnName]): the left operand, either a literal value or a column name | ||
| right (Union[bool, int, float, str, ColumnName]): the right operand, either a literal value or a column name | ||
| Returns: | ||
| Filter: a new inequality filter | ||
| """ | ||
| return Filter(j_filter=_j_filter_comparison("ne", left=left, right=right)) | ||
|
|
||
|
|
||
| def lt( | ||
| left: Union[bool, int, float, str, ColumnName], | ||
| right: Union[bool, int, float, str, ColumnName], | ||
| ) -> Filter: | ||
| """Creates a new filter that evaluates to true when the left operand is less than the right operand. | ||
| Args: | ||
| left (Union[bool, int, float, str, ColumnName]): the left operand, either a literal value or a column name | ||
| right (Union[bool, int, float, str, ColumnName]): the right operand, either a literal value or a column name | ||
| Returns: | ||
| Filter: a new less-than filter | ||
| """ | ||
| return Filter(j_filter=_j_filter_comparison("lt", left=left, right=right)) | ||
|
|
||
|
|
||
| def le( | ||
| left: Union[bool, int, float, str, ColumnName], | ||
| right: Union[bool, int, float, str, ColumnName], | ||
| ) -> Filter: | ||
| """Creates a new filter that evaluates to true when the left operand is less than or equal to the right operand. | ||
| Args: | ||
| left (Union[bool, int, float, str, ColumnName]): the left operand, either a literal value or a column name | ||
| right (Union[bool, int, float, str, ColumnName]): the right operand, either a literal value or a column name | ||
| Returns: | ||
| Filter: a new less-than-or-equal filter | ||
| """ | ||
| return Filter(j_filter=_j_filter_comparison("le", left=left, right=right)) | ||
|
|
||
|
|
||
| def gt( | ||
| left: Union[bool, int, float, str, ColumnName], | ||
| right: Union[bool, int, float, str, ColumnName], | ||
| ) -> Filter: | ||
| """Creates a new filter that evaluates to true when the left operand is greater than the right operand. | ||
| Args: | ||
| left (Union[bool, int, float, str, ColumnName]): the left operand, either a literal value or a column name | ||
| right (Union[bool, int, float, str, ColumnName]): the right operand, either a literal value or a column name | ||
| Returns: | ||
| Filter: a new greater-than filter | ||
| """ | ||
| return Filter(j_filter=_j_filter_comparison("gt", left=left, right=right)) | ||
|
|
||
|
|
||
| def ge( | ||
| left: Union[bool, int, float, str, ColumnName], | ||
| right: Union[bool, int, float, str, ColumnName], | ||
| ) -> Filter: | ||
| """Creates a new filter that evaluates to true when the left operand is greater than or equal to the right operand. | ||
| Args: | ||
| left (Union[bool, int, float, str, ColumnName]): the left operand, either a literal value or a column name | ||
| right (Union[bool, int, float, str, ColumnName]): the right operand, either a literal value or a column name | ||
| Returns: | ||
| Filter: a new greater-than-or-equal filter | ||
| """ | ||
| return Filter(j_filter=_j_filter_comparison("ge", left=left, right=right)) |
Copilot
AI
Dec 19, 2025
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 comparison filter functions (eq, ne, lt, le, gt, ge) lack error handling. Unlike other filter creation functions in this module (in_, pattern, is_null, etc.), these functions don't wrap their Java calls in try-except blocks to raise DHError on failure. This is inconsistent with the established error handling pattern in this module.
| raise DHError(e, "failed to create an in filter.") from e | ||
|
|
||
|
|
||
| _FILTER_COMPARISON_MAP: dict = { |
Copilot
AI
Dec 19, 2025
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 type annotation for _FILTER_COMPARISON_MAP is incomplete. It should specify the key and value types, e.g., dict[str, Callable] or more specifically dict[str, Any] if the exact Java method type cannot be expressed in Python typing.
| t.where(filter_in) | ||
| print(cm.exception) | ||
|
|
||
| # inconsistent behavior observed, should fail with https://deephaven.atlassian.net/browse/DH-21232 fixed |
Copilot
AI
Dec 19, 2025
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 comment mentions there's a ticket DH-21232 that should fix inconsistent behavior, but the test code doesn't clearly demonstrate what the expected behavior should be once the ticket is fixed. Consider adding a TODO comment or skipping this test case until the inconsistency is resolved, or at least document what the expected behavior should be after the fix.
| # inconsistent behavior observed, should fail with https://deephaven.atlassian.net/browse/DH-21232 fixed | |
| # TODO(DH-21232): Once DH-21232 is fixed, mixed-type values in an `in_` filter on a string | |
| # column (e.g., in_("B", [2, "3"])) should behave consistently with the above case for column | |
| # "A" and raise a DHError instead of returning a filtered table. At that point, update this | |
| # subtest to expect a DHError (similar to the `with self.assertRaises(DHError)` block above) | |
| # and remove or adjust the size assertion below. |
Note:
Expressionclass or theLiteralclass, in favor of the native Python typesFunctionandMethodclasses; workaround exists in the form of the class methodfrom_that takes in a raw string and returns a Filter object