[SYNPY-1880] feat: added per row validation to Grid data class #1428
[SYNPY-1880] feat: added per row validation to Grid data class #1428linglp wants to merge 29 commits into
Conversation
…; add them to documentation; add GridQueryValidationResult data class; add a lot of examples to validate_rows
| `Synapse.allow_client_caching(False)` this will use the last created | ||
| instance from the Synapse class constructor. | ||
|
|
||
| Returns: |
There was a problem hiding this comment.
All these changes are confusing. I did not delete these and they are still there if you use VS code to see.
| syn = Synapse() | ||
| syn.login() | ||
|
|
||
| # Export modified grid data back to the record set |
There was a problem hiding this comment.
All these changes are confusing. I did not delete these and they are still there if you use VS code to see.
| return self | ||
| return None | ||
|
|
||
| def synchronize( |
There was a problem hiding this comment.
Same above. The function is still there.
|
|
||
| @skip_async_to_sync | ||
| @asynccontextmanager | ||
| async def connect_async( |
There was a problem hiding this comment.
Based on John Hill's suggestion here, we will need to use connect function to interact with the replica.
| timeout=timeout, synapse_client=synapse_client | ||
| ) | ||
|
|
||
| if not request.query_result or not request.query_result.rows: |
There was a problem hiding this comment.
Initially I raised it as an error but eventually decided that here it should be a warning. It could be that there's no row to validate or the Filter or SelectColumn didn't return anything.
There was a problem hiding this comment.
The typing isn't quite right then. It says it returns a GridQueryResult, but if GridQueryJobRequest.query_result is None, that is what will be returned. All the examples assume it will not be None as well. I would strongly consider raising an exception here.
| @otel_trace_method( | ||
| method_to_trace_name=lambda self, **kwargs: f"Grid_Validate_Rows_Session_ID: {self.session_id}" | ||
| ) | ||
| async def validate_rows_async( |
There was a problem hiding this comment.
This is also important to review. Examples in the docstring demonstrated how you could use this function with connect.
There was a problem hiding this comment.
Pull request overview
Adds structured Grid query support to the experimental curator models so callers can query a Grid session and retrieve per-row JSON-schema validation results, including support for creating/binding Grid replicas via a new API endpoint and convenience connect context managers.
Changes:
- Added new Grid query/validation dataclasses (SelectItem/Filter hierarchies, QueryRequest, query result models) and a new
GridQueryJobRequestasync job type. - Added Grid replica support end-to-end: new REST API call, replica/request models, and
Grid.create_replica_asyncplusGrid.connect_async/connectto bind a replica for a session scope. - Added async unit tests and updated experimental reference docs to surface the new APIs.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/synapseclient/models/async/unit_test_curation_async.py | Adds unit tests covering new Grid query/validation dataclasses, replica creation, connect context manager, and row validation flow. |
| synapseclient/models/mixins/asynchronous_job.py | Registers the async job endpoint mapping for GridQueryJobRequest. |
| synapseclient/models/curation.py | Implements the new Grid query/validation dataclasses, replica workflow, connect context managers, and validate_rows_async. |
| synapseclient/models/init.py | Re-exports newly added curator models/enums for the public synapseclient.models namespace. |
| synapseclient/core/constants/concrete_types.py | Adds concreteType constants for the new Grid query and filter/select item types. |
| synapseclient/api/curation_services.py | Adds create_grid_replica REST API wrapper (POST /grid/session/{sessionId}/replica). |
| synapseclient/api/init.py | Exposes the new create_grid_replica API function via the API package. |
| docs/reference/experimental/sync/curator.md | Updates experimental sync reference to include new Grid methods and types. |
| docs/reference/experimental/async/curator.md | Updates experimental async reference to include new Grid methods and types. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| grid_replica = await create_grid_replica( | ||
| session_id=self.session_id, | ||
| create_replica_request=CreateReplicaRequest( | ||
| self.session_id | ||
| ).to_synapse_request(), | ||
| synapse_client=synapse_client, | ||
| ) | ||
| replica_data = grid_replica.get("replica") | ||
| if not replica_data: | ||
| raise ValueError( | ||
| f"Replica could not be created for grid session '{self.session_id}': " | ||
| f"no replica was returned in the Synapse response." | ||
| ) | ||
| return GridReplica().fill_from_dict(replica_data) |
| synapse_client=synapse_client, | ||
| ) | ||
|
|
||
| replica = self.create_replica(synapse_client=synapse_client) |
There was a problem hiding this comment.
Shouldn't this be checking if a replica already exists for this session before creating a new one?
There was a problem hiding this comment.
When I looked at the front-end code here, they always create a brand-new replica regardless of whether the session is new or pre-existing, and they also don't check if the replicas exist for this session or not. I think here we should match the front-end behavior.
|
@andrewelamb Per Nick's comment here, I think maybe there's no harsh enforcement of the replica limit? But based on my understanding of John Hill's comment here, we shouldn't create replica IDs wastefully (i.e. per function call). There's no way from the client side at least to "delete" a replica, and every replica created just becomes permanent part of the document (see his comment here) To answer your second question: the idea here is that we reuse one replica for the lifetime of one with block — every |
BryanFauble
left a comment
There was a problem hiding this comment.
Let's look to add a few end-to-end integration tests, the rest of the logic looks good to me!
| timeout=timeout, synapse_client=synapse_client | ||
| ) | ||
|
|
||
| if not request.query_result or not request.query_result.rows: |
There was a problem hiding this comment.
The typing isn't quite right then. It says it returns a GridQueryResult, but if GridQueryJobRequest.query_result is None, that is what will be returned. All the examples assume it will not be None as well. I would strongly consider raising an exception here.
|
|
||
| Attributes: | ||
| grid_session_id: The ID of the grid session. | ||
| replica: Information about a replica. Populated after calling the |
There was a problem hiding this comment.
This doesn't seem to be a real attribute?
| A grid replica is an in-memory document that represents a 'copy' of the | ||
| grid. Each replica is identified by a unique replicaId, issued by the | ||
| 'hub'. A user can have more than one replica at a time (i.e. using | ||
| multiple browser tabs/machines). A user is limited to 10 replicas |
There was a problem hiding this comment.
I thought we determined this limit didn't exist?
| A grid replica is an in-memory document that represents a 'copy' of the | ||
| grid. Each replica is identified by a unique replicaId, issued by the | ||
| 'hub'. A user can have more than one replica at a time (i.e. using | ||
| multiple browser tabs/machines). A user is limited to 10 replicas |
| https://rest-docs.synapse.org/rest/POST/grid/session/sessionId/replica.html | ||
|
|
||
| Note: Only the user that started the grid session may create a replica. | ||
| A user is limited to 10 replicas per-hour per-grid-session. |
There was a problem hiding this comment.
I thought we determined this limit doesn't exist?
BryanFauble
left a comment
There was a problem hiding this comment.
Thanks for the updates! Nothing additional beyond what has already been flagged.
Problem:
Add the ability to query rows in a Synapse Grid session and retrieve row level validation results
Solution:
All dataclasses added:
Please note that some data classes are renamed to avoid name collision with the data classes in table (i.e. Query -> GridQuery)
GridQuery Query
QueryRequest QueryRequest
GridQueryJobRequest GridQueryJobRequest / GridQueryJobResponse
GridQueryResult QueryResult
GridRow Row
SelectColumn SelectColumn
GridQueryValidationResult ValidationResults
SelectItem SelectItem
SelectByName SelectByName
SelectAll SelectAll
CountStar CountStar
SelectSelection SelectSelection
Filter Filter
RowValidationResultFilter RowValidationResultFilter
CellValueFilter CellValueFilter
RowSelectionFilter RowSelectionFilter
RowIsValidFilter RowIsValidFilter
RowIdFilter RowIdFilter
ValidationOperator ValidationOperator
CellValueOperator CellValueOperator
GridReplica GridReplica
CreateReplicaRequest CreateReplicaRequest
Replica support
Grid.validate_rows_async / validate_rows
New method that submits a QueryRequest against a grid session and returns per-row validation results
Grid.connect_async / connect