Skip to content

feat(integrations): Implement Integrations API client (CRUD + sub-resources) - #2820

Draft
vikramlc-cognite wants to merge 1 commit into
integrations-part1-data-classesfrom
integrations-part2.1-core-api-impl
Draft

feat(integrations): Implement Integrations API client (CRUD + sub-resources)#2820
vikramlc-cognite wants to merge 1 commit into
integrations-part1-data-classesfrom
integrations-part2.1-core-api-impl

Conversation

@vikramlc-cognite

@vikramlc-cognite vikramlc-cognite commented Sep 7, 2026

Copy link
Copy Markdown

Summary

Adds IntegrationsAPI with core CRUD (list/create/retrieve/update/delete) and its Tasks, Errors, Config, and Actions sub-APIs, wired into CogniteClient/AsyncCogniteClient and testing.py. This is the PR where client.integrations becomes usable. Builds on the data classes from #2819. Unit tests for this surface are added in #2821.

Type of change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that changes existing behavior)
  • Refactor (no functional change)
  • Documentation update
  • Chore / tooling / CI

What changed

  • New package cognite/client/_api/integrations/: IntegrationsAPI (__init__.py) plus IntegrationTasksAPI, IntegrationErrorsAPI, IntegrationConfigAPI, IntegrationActionsAPI.
  • IntegrationsAPI: list(), __call__ (async iterator), create(), retrieve(), update(), delete() — all using the generic _list/_create_multiple/_retrieve_multiple/_update_multiple/_delete_multiple helpers.
  • IntegrationTasksAPI.list_history()/sync(), IntegrationErrorsAPI.list(), IntegrationConfigAPI create/retrieve/list revisions, IntegrationActionsAPI create/list/retrieve/cancel (manual chunking for create/cancel since the integration's external_id is a query param, not part of the item body).
  • New _beta_version_header() on BasicAsyncAPIClient (_basic_api_client.py), symmetric to the existing _alpha_version_header(), producing the cdf-version: <sub>-beta header sent on every call.
  • Wired self.integrations = IntegrationsAPI(...) into AsyncCogniteClient (_cognite_client.py); sync mirror auto-generated into _sync_cognite_client.py / _sync_api/integrations/**.
  • Registered IntegrationsAPI + all 4 sub-APIs in CogniteClientMock/AsyncCogniteClientMock (testing.py).
  • Added integrations, integrations/config, integrations/actions, integrations/actions/cancel to the non-idempotent/non-retryable POST classification in utils/_url.py.

Why it changed

  • Related issue: EDG-827
  • Related docs / discussion: modeled on SimulatorsAPI; wire schema from cognitedata/service-contracts PR #3378; field-level details confirmed against the local odin service implementation.

What to focus on during review

  • IntegrationsAPI.__init__ eagerly constructs all four sub-APIs (tasks/errors/config/actions) in the same constructor call — this is a real, hard coupling (also required by testing.py's mock) and is why the client/sub-API split isn't finer-grained.
  • api_maturity="beta", sdk_maturity="alpha" on the FeaturePreviewWarning — every call emits this warning and sends the beta cdf-version header.
  • IntegrationActionsAPI.create()/cancel() bypass the generic multi-item helpers because the integration's external_id is a query param, not part of the item body — worth double-checking the manual request construction there.
  • IntegrationConfigAPI.list() is a single call, not _list/_list_generator — the revisions-list response has no nextCursor despite accepting a cursor param.
  • This PR intentionally ships without its own new tests — they're in test(integrations): Add unit tests for Integrations API client #2821 so this diff stays focused on implementation. Existing regression suite (test_meta.py, test_testing.py, test_cognite_client.py, test_api_client.py) passes unchanged.

Test evidence

  • pytest tests/tests_unit/test_testing.py tests/tests_unit/test_meta.py tests/tests_unit/test_api_client.py tests/tests_unit/test_cognite_client.py -q → 866 passed
  • python scripts/sync_client_codegen/main.py verify → sync mirrors up to date
  • ruff check / ruff format --check → clean
  • mypy → no issues (543 source files)

Risks and unknowns

Rollout and rollback

Checklist

  • Self-reviewed the diff
  • Tests added or updated (or N/A with reason) — N/A, added in test(integrations): Add unit tests for Integrations API client #2821 to keep this diff implementation-only
  • Docs updated (or N/A) — N/A, no public docs page exists yet for this beta API
  • No secrets, credentials, or PII committed
  • Breaking changes called out above and communicated to affected teams — N/A, no breaking changes

@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 introduces the Integrations API and its sub-APIs (tasks, errors, config, and actions) to the Cognite Python SDK, including both async and auto-generated sync versions, testing support, and client registration. Feedback on the changes highlights the need to support dictionary inputs in the create methods of both IntegrationActionsAPI and IntegrationConfigAPI to maintain consistency with other SDK creation methods and prevent potential AttributeErrors.

Comment on lines +56 to +57
single_item = isinstance(action, ActionWrite)
items: list[ActionWrite] = [action] if isinstance(action, ActionWrite) else list(action)

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

The current implementation of create assumes that action is either an instance of ActionWrite or a sequence of ActionWrite instances. However, if a user passes a dict or a sequence of dicts (which is a common pattern in the Cognite SDK), isinstance(action, ActionWrite) will evaluate to False, causing the method to treat the single dict as a sequence of its keys, leading to an AttributeError when .dump() is called. To ensure consistency and robustness, we should explicitly check for sequences and support loading from dictionaries.

        if isinstance(action, Sequence) and not isinstance(action, (str, dict)):
            single_item = False
            items = [ActionWrite._load(item) if isinstance(item, dict) else item for item in action]
        else:
            single_item = True
            items = [ActionWrite._load(action) if isinstance(action, dict) else action]
References
  1. Consistency: Follow established patterns across the codebase (e.g., supporting dictionary inputs for resource creation methods). (link)

Comment on lines +48 to +49
if isinstance(config, ConfigRevision):
config = config.as_write()

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 user passes a dict representing the configuration revision, calling config.dump() will raise an AttributeError because dictionaries do not have a dump method. To maintain consistency with other SDK creation methods, we should support dictionary inputs by loading them into ConfigRevisionWrite instances.

        if isinstance(config, dict):
            config = ConfigRevisionWrite._load(config)
        elif isinstance(config, ConfigRevision):
            config = config.as_write()
References
  1. Consistency: Follow established patterns across the codebase (e.g., supporting dictionary inputs for resource creation methods). (link)

@codecov

codecov Bot commented Sep 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 75.00000% with 85 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.10%. Comparing base (b248f28) to head (33f7b9a).

Files with missing lines Patch % Lines
cognite/client/_api/integrations/actions.py 53.70% 25 Missing ⚠️
cognite/client/_api/integrations/__init__.py 75.86% 14 Missing ⚠️
cognite/client/_api/integrations/config.py 57.69% 11 Missing ⚠️
cognite/client/_api/integrations/tasks.py 60.86% 9 Missing ⚠️
cognite/client/_basic_api_client.py 14.28% 6 Missing ⚠️
cognite/client/_sync_api/integrations/__init__.py 87.50% 6 Missing ⚠️
cognite/client/_api/integrations/errors.py 76.47% 4 Missing ⚠️
cognite/client/_sync_api/integrations/actions.py 86.66% 4 Missing ⚠️
cognite/client/_sync_api/integrations/config.py 81.25% 3 Missing ⚠️
cognite/client/_sync_api/integrations/tasks.py 85.71% 2 Missing ⚠️
... and 1 more
Additional details and impacted files
@@                         Coverage Diff                         @@
##           integrations-part1-data-classes    #2820      +/-   ##
===================================================================
- Coverage                            93.14%   93.10%   -0.05%     
===================================================================
  Files                                  523      533      +10     
  Lines                                54012    54330     +318     
===================================================================
+ Hits                                 50311    50583     +272     
- Misses                                3701     3747      +46     
Files with missing lines Coverage Δ
cognite/client/_cognite_client.py 96.01% <100.00%> (+0.18%) ⬆️
cognite/client/_sync_cognite_client.py 89.09% <100.00%> (+0.20%) ⬆️
cognite/client/testing.py 100.00% <100.00%> (ø)
cognite/client/utils/_url.py 100.00% <ø> (ø)
cognite/client/_sync_api/integrations/errors.py 91.66% <91.66%> (ø)
cognite/client/_sync_api/integrations/tasks.py 85.71% <85.71%> (ø)
cognite/client/_sync_api/integrations/config.py 81.25% <81.25%> (ø)
cognite/client/_api/integrations/errors.py 76.47% <76.47%> (ø)
cognite/client/_sync_api/integrations/actions.py 86.66% <86.66%> (ø)
cognite/client/_basic_api_client.py 92.46% <14.28%> (-2.24%) ⬇️
... and 5 more

... 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.

…ources)

Adds IntegrationsAPI with core CRUD (list/create/retrieve/update/delete)
and its Tasks, Errors, Config, and Actions sub-APIs, wired into
CogniteClient/AsyncCogniteClient and testing.py. Uses the beta
'cdf-version' header via the new _beta_version_header() helper.

Unit tests for this surface are added in the following PR.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@vikramlc-cognite
vikramlc-cognite force-pushed the integrations-part2.1-core-api-impl branch from 33f7b9a to 6fdd3ea Compare September 7, 2026 12:50
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.

2 participants