Skip to content

feat(records): filter endpoint#2699

Open
andersfylling wants to merge 4 commits into
masterfrom
andersf/records/list5654
Open

feat(records): filter endpoint#2699
andersfylling wants to merge 4 commits into
masterfrom
andersf/records/list5654

Conversation

@andersfylling

@andersfylling andersfylling commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Adds the filter records endpoint to the SDK.
documentation: https://api-docs.cognite.com/20230101/tag/Records/operation/filterRecords


Note

Original PR here: #2680

@haakonvt made a few comments that are still relevant:

@codecov

codecov Bot commented Jun 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.67%. Comparing base (a2722cd) to head (25548a1).

Additional details and impacted files
@@           Coverage Diff            @@
##           master    #2699    +/-   ##
========================================
  Coverage   93.67%   93.67%            
========================================
  Files         503      503            
  Lines       50696    50840   +144     
========================================
+ Hits        47488    47624   +136     
- Misses       3208     3216     +8     
Files with missing lines Coverage Δ
cognite/client/_api/data_modeling/records.py 100.00% <100.00%> (ø)
cognite/client/_sync_api/data_modeling/records.py 100.00% <100.00%> (ø)
...nite/client/data_classes/data_modeling/__init__.py 100.00% <ø> (ø)
...gnite/client/data_classes/data_modeling/records.py 98.98% <100.00%> (+1.26%) ⬆️
cognite/client/utils/_concurrency.py 92.78% <ø> (+0.24%) ⬆️
...s_unit/test_api/test_data_modeling/test_records.py 100.00% <100.00%> (ø)
tests/tests_unit/test_docstring_examples.py 100.00% <100.00%> (ø)

... and 6 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@andersfylling andersfylling force-pushed the andersf/records/list5654 branch from 664dc22 to 299928a Compare June 22, 2026 07:59
)
self._files = FileConcurrencyConfig(self, read=4, write=2, upload=5, download=5, delete=2, open_files=15)
self._records = RecordsGlobalConcurrencyConfig(self, write=20)
self._records = RecordsGlobalConcurrencyConfig(self, read=4, write=20)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 is the lowest bucket used across all query endpoints https://api-docs.cognite.com/20230101/tag/Records#section/Rate-and-concurrency-limits

@andersfylling andersfylling force-pushed the andersf/records/list5654 branch from 299928a to b5cec33 Compare June 22, 2026 08:02
@andersfylling andersfylling marked this pull request as ready for review June 22, 2026 08:31
@andersfylling andersfylling requested review from a team as code owners June 22, 2026 08:31

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

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 implements the list (filter) endpoint for stream records, introducing the Record, RecordList, TimeRange, and RecordSourceSelector data classes, read concurrency support, and corresponding unit tests. The review feedback correctly identifies three key issues: a breaking change in the RecordsGlobalConcurrencyConfig constructor signature, a potential crash if the typing field in the API response is null, and an AttributeError when dictionary-based sort parameters are passed. Additionally, the newly added unit tests for load and dump methods on the data classes violate the repository style guide, as these are tested automatically.

Comment on lines 241 to +247
def __init__(
self,
concurrency_settings: ConcurrencySettings,
read: int,
write: int,
) -> None:
super().__init__(concurrency_settings, "records", read=0, write=write, delete=0)
super().__init__(concurrency_settings, "records", read=read, write=write, delete=0)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Changing the constructor signature of RecordsGlobalConcurrencyConfig by inserting read before write is a breaking change for any external code or subclasses that instantiate this class using positional arguments. To maintain backward compatibility, keep write as the second positional argument and make read an optional keyword-only or defaulted argument placed after write.

    def __init__(\n        self,\n        concurrency_settings: ConcurrencySettings,\n        write: int,\n        read: int = 4,\n    ) -> None:\n        super().__init__(concurrency_settings, \"records\", read=read, write=write, delete=0)


@classmethod
def _load_raw_api_response(cls, responses: list[dict[str, Any]]) -> Self:
typing = next((TypeInformation._load(resp["typing"]) for resp in responses if "typing" in resp), None)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

If the API response contains a "typing" key but its value is null (None), resp["typing"] will be None, causing TypeInformation._load(None) to raise a TypeError or KeyError. Guard against this by checking if resp.get("typing") is not None.

        typing = next((TypeInformation._load(resp[\"typing\"]) for resp in responses if resp.get(\"typing\") is not None), None)

Comment on lines +250 to +252
if sort is not None:
sort_list = [sort] if isinstance(sort, InstanceSort) else list(sort)
other_params["sort"] = [spec.dump() for spec in sort_list]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

If a user passes a dictionary or a list of dictionaries for the sort parameter (which is a common pattern in the SDK), isinstance(sort, InstanceSort) will evaluate to False, and list(sort) on a dictionary will return its keys. This leads to an AttributeError when trying to call .dump() on a string key. Update the logic to support both InstanceSort and dictionary representations gracefully.

        if sort is not None:\n            sort_list = [sort] if isinstance(sort, (InstanceSort, dict)) else list(sort)\n            other_params[\"sort\"] = [spec.dump() if isinstance(spec, InstanceSort) else spec for spec in sort_list]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant