Skip to content

feat(files): Migrate consumers to the new FilesClient - #584

Merged
matthewgrossman merged 15 commits into
mainfrom
mgrossman/aircore-840-migrate-files-consumers-from-filesetssubresource-to
Jul 8, 2026
Merged

feat(files): Migrate consumers to the new FilesClient#584
matthewgrossman merged 15 commits into
mainfrom
mgrossman/aircore-840-migrate-files-consumers-from-filesetssubresource-to

Conversation

@matthewgrossman

@matthewgrossman matthewgrossman commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Migrates Files consumers from the Stainless SDK's FilesetsSubResource/AsyncFilesetsSubResource to the new typed FilesClient/AsyncFilesClient HTTP clients (92 files, +2232/-2293).

What changed

  • Consumer migration: All Files consumers now use client_from_platform(sdk, FilesClient) (or AsyncFilesClient) instead of sdk.files.filesets.*
  • FilesetFileSystem: Constructor changed from sdk= kwarg to client= kwarg, accepting FilesClient or AsyncFilesClient directly
  • FilesResource: Accepts optional files_client= kwarg for Stainless-agnostic construction; sdk.files still works as backward-compatible sugar (delegates to FilesClient internally)
  • Error handling: Files-related error types now imported from nemo_platform_plugin.client.errors instead of nemo_platform
  • Request/response types: Uses CreateFilesetRequest, UpdateFilesetRequest, FilesetOutput, ListFilesetsQueryParams etc. from nemo_platform_plugin.files.types
  • Pagination: list_filesets() returns NemoPaginatedResponse with .items() / .pages() / .page() methods; non-paginated responses unwrapped with .data()
  • Timeout/retry: with_options(timeout=float, retry=RetryPolicy(...)) replaces httpx.Timeout and integer retry counts
  • CLI commands: nemo files filesets create/list/get/update/delete all migrated to FilesClient. The list command now uses ListFilesetsQueryParams and NemoPaginatedResponse directly instead of the Stainless fetch_all_pages helper

Deleted infrastructure

  • FilesetsSubResource / AsyncFilesetsSubResource
  • _RemappingFilesClient / _RemappingAsyncFilesClient
  • _raw_client on Files resources

What still uses sdk.files

~30 production files still call through sdk.files.* (which now delegates to FilesClient internally). These are future migration targets. Non-files Stainless error imports (entities, models, jobs) remain intentionally.

Test plan

  • make test-unit passes
  • uv run --frozen pytest packages/nmp_common/tests/jobs/test_file_manager.py — 22 passed
  • uv run --frozen pytest packages/nemo_platform_ext/tests/cli/integration/test_filesets.py — 10 passed
  • uv run --frozen pytest plugins/nemo-evaluator/tests/ passes
  • uv run --frozen pytest plugins/nemo-data-designer/tests/ passes
  • CLI nemo files filesets create, nemo files filesets list work correctly against running platform
  • E2E files tests pass against running platform

🤖 Generated with Claude Code

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
@matthewgrossman
matthewgrossman requested review from a team as code owners July 6, 2026 22:46
@github-actions github-actions Bot added the feat label Jul 6, 2026
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor
Suite Lines Covered Line Rate Branch Rate
Unit Tests 23349/30529 76.5% 61.3%
Integration Tests 13616/29209 46.6% 19.8%

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR migrates fileset operations from legacy SDK files APIs to plugin FilesClient/AsyncFilesClient adapters, typed request bodies, and plugin error types across production code, CLI, e2e, and tests.

Changes

Files client migration

Layer / File(s) Summary
Core filesystem and resources
packages/filesets/src/filesets/filesystem/filesystem.py, packages/filesets/src/filesets/resources.py, packages/nemo_platform_plugin/src/nemo_platform_plugin/jobs/file_manager.py, packages/nmp_common/tests/jobs/*
FilesetFileSystem, FilesResource, and AsyncFilesResource now use explicit plugin files clients, and job file-manager wiring and common job tests follow the same client-based construction path.
Data designer and personas
packages/data_designer_nemo/src/...*, packages/data_designer_nemo/tests/...*, plugins/nemo-data-designer/src/...*, plugins/nemo-data-designer/tests/...*, e2e/test_data_designer.py
Seed validation, persona creation, DuckDB filesystem setup, and personas-related tests switch to plugin files clients and typed create/get/delete calls.
Jobs, cleanup, and task validation
services/core/jobs/...*, services/core/entities/...*, services/automodel/...*, services/rl/...*, services/unsloth/...*, services/hello-world/...*, packages/nmp_customization_common/...*
Job fileset lifecycle, workspace cleanup, and task-level fileset validation move to plugin async/sync clients with typed requests and mapped exceptions.
Models and auth flows
services/core/models/...*, services/core/models/tests/...*
Model/fileset access checks, model-spec generation, and model-auth/isolation tests use plugin files clients and typed fileset outputs.
Core files service, CLI, and e2e
services/core/files/...*, packages/nemo_platform_ext/...*, tools/nemo-platform-sdk-tools/...*, e2e/files/*
Migration scripts, FilesResource integration, CLI commands, and e2e coverage all switch to FilesClient adapters and typed request/response flows.
Evaluator and safe synthesizer
plugins/nemo-evaluator/...*, plugins/nemo-safe-synthesizer/...*
Evaluator bundle storage/download and safe-synthesizer fileset setup use async plugin files clients and updated test doubles.

Possibly related PRs

Suggested labels: feat

Suggested reviewers: maxdubrinsky

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: migrating files consumers to the new FilesClient.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch mgrossman/aircore-840-migrate-files-consumers-from-filesetssubresource-to

Comment @coderabbitai help to get the list of available commands.

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/nemo_platform_plugin/src/nemo_platform_plugin/jobs/file_manager.py (1)

166-184: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Handle ConflictError when creating the fileset. create_fileset doesn’t support exist_ok; if another process wins the race, catch ConflictError and treat the fileset as already present.

🤖 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 `@packages/nemo_platform_plugin/src/nemo_platform_plugin/jobs/file_manager.py`
around lines 166 - 184, _handle_storage validation in _validate_storage should
tolerate a race when create_fileset is called. Update the
FileManager._validate_storage flow so that the create_fileset call for both
AsyncFilesClient and FilesClient catches ConflictError and treats it as an
already-existing fileset instead of failing, while leaving the FileNotFoundError
and FileStorageDoesNotExist behavior unchanged.
🧹 Nitpick comments (9)
plugins/nemo-data-designer/tests/integration/test_personas_cli.py (1)

260-266: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Mock created without spec.

Mock() for the patched FilesClient has no spec, so a typo'd method name (e.g. wrong signature on create_fileset) wouldn't be caught by the test. Consider Mock(spec=FilesClient).

🤖 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 `@plugins/nemo-data-designer/tests/integration/test_personas_cli.py` around
lines 260 - 266, The mocked FilesClient in
test_make_fileset_create_fileset_internal_error_surfaces_clearly is created
without a spec, so the test won’t catch typos or invalid method usage. Update
the mock setup to use a spec based on FilesClient when creating mock_files,
keeping the existing create_fileset side effect and patch of
client_from_platform intact so the test still exercises the same error path with
interface validation.
e2e/files/test_storage_backends.py (1)

47-68: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

API usage matches new contract.

create_fileset/delete_fileset calls and storage config wiring line up with the plugin endpoint signatures. No functional issues.

Minor DRY note: files = client_from_platform(sdk, FilesClient) is instantiated separately in ngc_fileset, hf_fileset, test_create_error, test_create_error_nonexistent_secret, and test_error_nonexistent_repo. A shared files_client fixture would cut the repetition.

♻️ Suggested fixture
+@pytest.fixture
+def files_client(sdk: NeMoPlatform) -> FilesClient:
+    return client_from_platform(sdk, FilesClient)

Also applies to: 93-115, 206-241, 297-308

🤖 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 `@e2e/files/test_storage_backends.py` around lines 47 - 68, The repeated
FilesClient setup is duplicated across ngc_fileset, hf_fileset,
test_create_error, test_create_error_nonexistent_secret, and
test_error_nonexistent_repo, so extract client_from_platform(sdk, FilesClient)
into a shared files_client fixture and update those helpers/tests to depend on
it instead of creating the client locally.
packages/data_designer_nemo/src/data_designer_nemo/person_reader.py (1)

23-33: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Docstring is stale. It claims FilesetFileSystem flips to asynchronous=True when handed an AsyncNeMoPlatform, but it now takes a FilesClient, not an SDK. Update to describe the sync-SDK→FilesClient path.

🤖 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 `@packages/data_designer_nemo/src/data_designer_nemo/person_reader.py` around
lines 23 - 33, The docstring in the person reader is stale and still describes
passing an AsyncNeMoPlatform into FilesetFileSystem, but the current flow uses a
sync SDK to build a FilesClient instead. Update the text around the
person_reader construction path to match the new sync-SDK→FilesClient behavior,
keeping the explanation aligned with the FilesetFileSystem and FilesClient
symbols.
plugins/nemo-evaluator/tests/api/service/test_metric_service.py (1)

35-54: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate _FakeAsyncFilesClient across 4 test files.

Identical (or near-identical) fake defined in test_metrics_routes.py, test_metric_refs.py, and test_metric_storage.py. Consider extracting to a shared conftest/fixture module.

🤖 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 `@plugins/nemo-evaluator/tests/api/service/test_metric_service.py` around lines
35 - 54, The _FakeAsyncFilesClient test double is duplicated across multiple
metric test modules, so extract the shared fake into a common test helper or
conftest fixture and reuse it from test_metric_service alongside
test_metrics_routes, test_metric_refs, and test_metric_storage. Keep the
behavior in _FakeAsyncFilesClient identical, but centralize the class definition
so future changes to create_fileset, delete_fileset, upload_file, and
download_file only need to be made once.
plugins/nemo-evaluator/tests/api/v2/test_metrics_routes.py (1)

55-62: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Inline _Resp class is inconsistent with sibling test fakes.

Other test files (e.g. test_metric_storage.py) use a top-level _FakeResponse(data) class. Prefer reusing that shape here for consistency instead of defining a nested class with a manually-assigned _data attribute.

🤖 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 `@plugins/nemo-evaluator/tests/api/v2/test_metrics_routes.py` around lines 55 -
62, The inline _Resp fake in download_file is inconsistent with the shared test
fake shape used elsewhere. Replace the nested class in download_file with the
existing top-level _FakeResponse(data) pattern (or equivalent shared fake) and
return it directly using the stored bytes for the requested (workspace, name,
path), so the test helpers stay consistent across files.
packages/nemo_platform_plugin/src/nemo_platform_plugin/jobs/file_manager.py (1)

144-180: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate sync/async branching + redundant client construction.

isinstance(self.sdk, AsyncNeMoPlatform) branching is duplicated between __post_init__ (lines 145-148) and _validate_storage (lines 173-179). _validate_storage also constructs a brand-new client via client_from_platform instead of reusing the one already built in __post_init__ and stored inside self._fs.

♻️ Extract a shared helper
+    def _files_client(self) -> "AsyncFilesClient | FilesClient":
+        if isinstance(self.sdk, AsyncNeMoPlatform):
+            return client_from_platform(self.sdk, AsyncFilesClient)
+        return client_from_platform(self.sdk, FilesClient)
+
     def __post_init__(self):
-        if isinstance(self.sdk, AsyncNeMoPlatform):
-            files_client = client_from_platform(self.sdk, AsyncFilesClient)
-        else:
-            files_client = client_from_platform(self.sdk, FilesClient)
-        self._fs = FilesetFileSystem(client=files_client)
+        self._fs = FilesetFileSystem(client=self._files_client())
                 logger.info(f"Creating new fileset: [{self.fileset_name}] in workspace [{self.workspace}]")
-                if isinstance(self.sdk, AsyncNeMoPlatform):
-                    files = client_from_platform(self.sdk, AsyncFilesClient)
-                    await files.create_fileset(
-                        body=CreateFilesetRequest(name=self.fileset_name), workspace=self.workspace
-                    )
-                else:
-                    files = client_from_platform(self.sdk, FilesClient)
-                    files.create_fileset(body=CreateFilesetRequest(name=self.fileset_name), workspace=self.workspace)
+                files = self._files_client()
+                if isinstance(self.sdk, AsyncNeMoPlatform):
+                    await files.create_fileset(
+                        body=CreateFilesetRequest(name=self.fileset_name), workspace=self.workspace
+                    )
+                else:
+                    files.create_fileset(body=CreateFilesetRequest(name=self.fileset_name), workspace=self.workspace)
🤖 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 `@packages/nemo_platform_plugin/src/nemo_platform_plugin/jobs/file_manager.py`
around lines 144 - 180, The sync/async client selection is duplicated in
__post_init__ and _validate_storage, and _validate_storage is recreating a new
platform client instead of reusing the one already initialized through
FilesetFileSystem. Extract the AsyncNeMoPlatform/FilesClient vs AsyncFilesClient
selection into a shared helper or reuse the existing client from self._fs in
FileManager, then update __post_init__ and _validate_storage to call that shared
path so the branching and client construction live in one place.
services/core/jobs/tests/test_dispatcher.py (1)

647-698: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate mock-files-client boilerplate across tests.

The same ~8-line block (mock_files = AsyncMock(), mock_fileset_obj, mock_resp.data.return_value, patch("...client_from_platform", ...)) is repeated 3 times in this file and again in test_job_logs.py's dispatcher fixture. Consider extracting a small helper (e.g. make_mock_files_client()) shared via conftest to cut duplication.

♻️ Example helper
def make_mock_files_client(fileset_name: str = "test-fileset-id") -> AsyncMock:
    mock_files = AsyncMock()
    mock_fileset_obj = MagicMock()
    mock_fileset_obj.name = fileset_name
    mock_resp = MagicMock()
    mock_resp.data.return_value = mock_fileset_obj
    mock_files.create_fileset.return_value = mock_resp
    return mock_files

Also applies to: 778-787, 817-868

🤖 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 `@services/core/jobs/tests/test_dispatcher.py` around lines 647 - 698, The mock
files-client setup is duplicated across multiple dispatcher tests, including the
repeated AsyncMock/MagicMock create_fileset boilerplate and the
client_from_platform patch. Extract that setup into a small shared helper such
as make_mock_files_client() in a common test utility or conftest, then reuse it
from the dispatcher tests and the test_job_logs fixture to keep the test code
DRY. Use the existing dispatcher-related test helpers and the
client_from_platform patch point as the main places to update.
services/core/files/tests/integration/conftest.py (1)

170-173: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider a shared files_client fixture.

client_from_platform(sdk, FilesClient) is re-created inline across almost every test file in this cohort (test_ngc_storage.py, test_files_sdk.py, test_filesets_allowed_hosts.py, tests_filesets_with_auth_secrets.py). A single fixture here would cut repeated boilerplate.

♻️ Proposed fixture
+@pytest.fixture
+def files_client(sdk: NeMoPlatform) -> FilesClient:
+    return client_from_platform(sdk, FilesClient)
+
+
 def fileset_cleanup(sdk: NeMoPlatform) -> Iterator[Callable[[str], None]]:
🤖 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 `@services/core/files/tests/integration/conftest.py` around lines 170 - 173,
Create a shared `files_client` fixture in `conftest.py` instead of constructing
`client_from_platform(sdk, FilesClient)` inline in each test file. Update the
existing cleanup/setup flow around `to_cleanup` and the `files` client usage so
tests can depend on the fixture directly, and then replace the repeated client
creation in the affected tests with that fixture to remove boilerplate and
centralize client setup.
services/automodel/src/nmp/automodel/tasks/file_io/run.py (1)

391-436: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Duplicate fileset-create/conflict-patch logic across services.

_create_fileset_with_retry (and its retry policy) is duplicated near-verbatim in services/rl/src/nmp/rl/tasks/file_io/run.py, and likely services/unsloth/.../file_io/run.py per the PR stack. Worth extracting into a shared helper (e.g. in nmp_common) so retry/exception handling for fileset creation doesn't drift across services.

Also note: passthrough=(ConflictError,) on create_fileset's sdk_error_handler (line 391) is now dead — ConflictError is always swallowed inside _create_fileset_with_retry and never propagates.

🤖 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 `@services/automodel/src/nmp/automodel/tasks/file_io/run.py` around lines 391 -
436, The fileset-create retry/conflict handling in _create_fileset_with_retry is
duplicated across services and the ConflictError passthrough in the surrounding
sdk_error_handler is no longer used. Move the shared create/patch/retry behavior
into a common helper (for example in nmp_common) and update callers like
_create_fileset_with_retry to use it. Then remove ConflictError from the
passthrough on create_fileset, since ConflictError is already handled internally
by the helper.
🤖 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.

Inline comments:
In `@plugins/nemo-data-designer/tests/integration/test_personas_cli.py`:
- Around line 80-86: The FilesClient pagination usage in the persona CLI
integration test should rely on the page’s data collection rather than a
non-existent items() API. Update the assertions around files.list_filesets in
test_personas_cli.py to use the returned page’s data() results consistently, and
keep the existing FilesClient and get_fileset checks unchanged.

In `@plugins/nemo-safe-synthesizer/scripts/setup_model_filesets.py`:
- Around line 108-114: The fileset lookup in create_filesets only handles
NotFoundError, so other NemoHTTPError subclasses can escape and stop the batch.
Update the try/except around files.get_fileset to catch the broader
NemoHTTPError as well, matching the create_fileset error handling, and keep the
existing flow that logs the issue and continues processing the remaining
filesets.

In `@services/core/jobs/tests/conftest.py`:
- Around line 246-259: Add the missing pytest fixture decoration to
_mock_files_client in conftest so mock_nmp_client can resolve it as a fixture
dependency. Keep the existing helper behavior intact, but make
_mock_files_client discoverable by pytest alongside mock_nmp_client.

In `@services/core/models/tests/integration/test_chat_template_tool_calling.py`:
- Around line 191-201: The `updated_fileset` mock used in the integration test
is missing a `storage` attribute, which causes `analyze_checkpoint` to fail when
it inspects the returned fileset. Update the `updated_fileset` setup in the test
to include a `storage` value compatible with the code path in
`analyze_checkpoint` (the logic that checks `fs.storage` against storage config
types). Keep the mock aligned with what `get_fileset().data()` returns so the
test reaches the `sdk.models.update` flow instead of raising `AttributeError`.

---

Outside diff comments:
In `@packages/nemo_platform_plugin/src/nemo_platform_plugin/jobs/file_manager.py`:
- Around line 166-184: _handle_storage validation in _validate_storage should
tolerate a race when create_fileset is called. Update the
FileManager._validate_storage flow so that the create_fileset call for both
AsyncFilesClient and FilesClient catches ConflictError and treats it as an
already-existing fileset instead of failing, while leaving the FileNotFoundError
and FileStorageDoesNotExist behavior unchanged.

---

Nitpick comments:
In `@e2e/files/test_storage_backends.py`:
- Around line 47-68: The repeated FilesClient setup is duplicated across
ngc_fileset, hf_fileset, test_create_error,
test_create_error_nonexistent_secret, and test_error_nonexistent_repo, so
extract client_from_platform(sdk, FilesClient) into a shared files_client
fixture and update those helpers/tests to depend on it instead of creating the
client locally.

In `@packages/data_designer_nemo/src/data_designer_nemo/person_reader.py`:
- Around line 23-33: The docstring in the person reader is stale and still
describes passing an AsyncNeMoPlatform into FilesetFileSystem, but the current
flow uses a sync SDK to build a FilesClient instead. Update the text around the
person_reader construction path to match the new sync-SDK→FilesClient behavior,
keeping the explanation aligned with the FilesetFileSystem and FilesClient
symbols.

In `@packages/nemo_platform_plugin/src/nemo_platform_plugin/jobs/file_manager.py`:
- Around line 144-180: The sync/async client selection is duplicated in
__post_init__ and _validate_storage, and _validate_storage is recreating a new
platform client instead of reusing the one already initialized through
FilesetFileSystem. Extract the AsyncNeMoPlatform/FilesClient vs AsyncFilesClient
selection into a shared helper or reuse the existing client from self._fs in
FileManager, then update __post_init__ and _validate_storage to call that shared
path so the branching and client construction live in one place.

In `@plugins/nemo-data-designer/tests/integration/test_personas_cli.py`:
- Around line 260-266: The mocked FilesClient in
test_make_fileset_create_fileset_internal_error_surfaces_clearly is created
without a spec, so the test won’t catch typos or invalid method usage. Update
the mock setup to use a spec based on FilesClient when creating mock_files,
keeping the existing create_fileset side effect and patch of
client_from_platform intact so the test still exercises the same error path with
interface validation.

In `@plugins/nemo-evaluator/tests/api/service/test_metric_service.py`:
- Around line 35-54: The _FakeAsyncFilesClient test double is duplicated across
multiple metric test modules, so extract the shared fake into a common test
helper or conftest fixture and reuse it from test_metric_service alongside
test_metrics_routes, test_metric_refs, and test_metric_storage. Keep the
behavior in _FakeAsyncFilesClient identical, but centralize the class definition
so future changes to create_fileset, delete_fileset, upload_file, and
download_file only need to be made once.

In `@plugins/nemo-evaluator/tests/api/v2/test_metrics_routes.py`:
- Around line 55-62: The inline _Resp fake in download_file is inconsistent with
the shared test fake shape used elsewhere. Replace the nested class in
download_file with the existing top-level _FakeResponse(data) pattern (or
equivalent shared fake) and return it directly using the stored bytes for the
requested (workspace, name, path), so the test helpers stay consistent across
files.

In `@services/automodel/src/nmp/automodel/tasks/file_io/run.py`:
- Around line 391-436: The fileset-create retry/conflict handling in
_create_fileset_with_retry is duplicated across services and the ConflictError
passthrough in the surrounding sdk_error_handler is no longer used. Move the
shared create/patch/retry behavior into a common helper (for example in
nmp_common) and update callers like _create_fileset_with_retry to use it. Then
remove ConflictError from the passthrough on create_fileset, since ConflictError
is already handled internally by the helper.

In `@services/core/files/tests/integration/conftest.py`:
- Around line 170-173: Create a shared `files_client` fixture in `conftest.py`
instead of constructing `client_from_platform(sdk, FilesClient)` inline in each
test file. Update the existing cleanup/setup flow around `to_cleanup` and the
`files` client usage so tests can depend on the fixture directly, and then
replace the repeated client creation in the affected tests with that fixture to
remove boilerplate and centralize client setup.

In `@services/core/jobs/tests/test_dispatcher.py`:
- Around line 647-698: The mock files-client setup is duplicated across multiple
dispatcher tests, including the repeated AsyncMock/MagicMock create_fileset
boilerplate and the client_from_platform patch. Extract that setup into a small
shared helper such as make_mock_files_client() in a common test utility or
conftest, then reuse it from the dispatcher tests and the test_job_logs fixture
to keep the test code DRY. Use the existing dispatcher-related test helpers and
the client_from_platform patch point as the main places to update.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 03f7cb33-51d6-4ff1-9f16-3cf9bacee16f

📥 Commits

Reviewing files that changed from the base of the PR and between 954c403 and 0465287.

⛔ Files ignored due to path filters (5)
  • sdk/python/nemo-platform/src/nemo_platform/cli/commands/api/files/__init__.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/cli/commands/api/files/filesets.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/filesets/filesystem/filesystem.py is excluded by !sdk/**
  • sdk/python/nemo-platform/src/nemo_platform/filesets/resources.py is excluded by !sdk/**
  • sdk/python/nemo-platform/tests/vendored/nemo_platform_ext/cli/integration/test_filesets.py is excluded by !sdk/**
📒 Files selected for processing (84)
  • e2e/files/test_files.py
  • e2e/files/test_storage_backends.py
  • e2e/test_data_designer.py
  • e2e/test_jobs_auth.py
  • packages/data_designer_nemo/src/data_designer_nemo/fileset_file_seed_reader.py
  • packages/data_designer_nemo/src/data_designer_nemo/nemotron_personas.py
  • packages/data_designer_nemo/src/data_designer_nemo/person_reader.py
  • packages/data_designer_nemo/src/data_designer_nemo/person_sampling.py
  • packages/data_designer_nemo/src/data_designer_nemo/seed.py
  • packages/data_designer_nemo/tests/unit/test_fileset_file_seed_reader.py
  • packages/data_designer_nemo/tests/unit/test_person_sampling.py
  • packages/filesets/src/filesets/filesystem/filesystem.py
  • packages/filesets/src/filesets/resources.py
  • packages/nemo_platform_ext/src/nemo_platform_ext/cli/commands/api/files/__init__.py
  • packages/nemo_platform_ext/src/nemo_platform_ext/cli/commands/api/files/filesets.py
  • packages/nemo_platform_ext/tests/cli/integration/test_filesets.py
  • packages/nemo_platform_plugin/src/nemo_platform_plugin/jobs/file_manager.py
  • packages/nemo_platform_plugin/src/nemo_platform_plugin/scheduler.py
  • packages/nmp_common/tests/jobs/conftest.py
  • packages/nmp_common/tests/jobs/test_file_manager.py
  • packages/nmp_customization_common/src/nmp/customization_common/service/platform_client.py
  • plugins/nemo-data-designer/src/nemo_data_designer_plugin/testing/utils.py
  • plugins/nemo-data-designer/tests/integration/test_personas_cli.py
  • plugins/nemo-evaluator/examples/plugin_examples.py
  • plugins/nemo-evaluator/src/nemo_evaluator/filesets.py
  • plugins/nemo-evaluator/src/nemo_evaluator/metric_storage.py
  • plugins/nemo-evaluator/tests/api/service/test_metric_service.py
  • plugins/nemo-evaluator/tests/api/v2/test_metrics_routes.py
  • plugins/nemo-evaluator/tests/test_filesets.py
  • plugins/nemo-evaluator/tests/test_metric_refs.py
  • plugins/nemo-evaluator/tests/test_metric_storage.py
  • plugins/nemo-safe-synthesizer/scripts/setup_model_filesets.py
  • plugins/nemo-safe-synthesizer/src/nemo_safe_synthesizer_plugin/api/v2/jobs/endpoints.py
  • plugins/nemo-safe-synthesizer/tests/unit/test_jobs.py
  • services/automodel/src/nmp/automodel/tasks/file_io/run.py
  • services/automodel/src/nmp/automodel/tasks/model_entity/run.py
  • services/automodel/tests/test_compiler.py
  • services/core/entities/src/nmp/core/entities/controllers/workspace_cleanup.py
  • services/core/entities/tests/controllers/test_workspace_cleanup.py
  • services/core/files/script/v2_migration.py
  • services/core/files/src/nmp/core/files/testing/utils.py
  • services/core/files/tests/integration/conftest.py
  • services/core/files/tests/integration/external_storage/test_huggingface_storage.py
  • services/core/files/tests/integration/external_storage/test_ngc_storage.py
  • services/core/files/tests/integration/external_storage/test_s3_storage.py
  • services/core/files/tests/integration/test_files_basic.py
  • services/core/files/tests/integration/test_files_sdk.py
  • services/core/files/tests/integration/test_fileset_filesystem.py
  • services/core/files/tests/integration/test_filesets_allowed_hosts.py
  • services/core/files/tests/integration/test_huggingface_endpoints.py
  • services/core/files/tests/integration/test_otlp_endpoints.py
  • services/core/files/tests/integration/tests_filesets_with_auth_secrets.py
  • services/core/jobs/src/nmp/core/jobs/app/dispatcher.py
  • services/core/jobs/tests/conftest.py
  • services/core/jobs/tests/test_dispatcher.py
  • services/core/jobs/tests/test_job_logs.py
  • services/core/jobs/tests/test_jobs_api.py
  • services/core/models/src/nmp/core/models/api/permissions.py
  • services/core/models/src/nmp/core/models/api/service/model_entity_service.py
  • services/core/models/src/nmp/core/models/tasks/model_spec/run.py
  • services/core/models/tests/integration/test_chat_template_tool_calling.py
  • services/core/models/tests/integration/test_model_entity_service_integration.py
  • services/core/models/tests/integration/test_models_with_auth.py
  • services/core/models/tests/integration/test_workspace_iam_models_isolation.py
  • services/core/models/tests/unit/test_model_entity_service_unit.py
  • services/hello-world/src/nmp/hello_world/tasks/access_fileset/run.py
  • services/rl/src/nmp/rl/tasks/file_io/run.py
  • services/rl/src/nmp/rl/tasks/model_entity/run.py
  • services/unsloth/src/nmp/unsloth/tasks/file_io/run.py
  • services/unsloth/src/nmp/unsloth/tasks/model_entity/run.py
  • services/unsloth/tests/test_file_io.py
  • services/unsloth/tests/test_model_entity.py
  • tests/agentic-use/customizer-lora-job-cli/tests/test_outputs.py
  • tests/agentic-use/evaluator-llm-judge-cli-easy/tests/test_outputs.py
  • tests/agentic-use/evaluator-llm-judge-cli/tests/test_outputs.py
  • tests/agentic-use/evaluator-simple-job-cli-easy/tests/test_outputs.py
  • tests/agentic-use/evaluator-simple-job-cli/tests/test_outputs.py
  • tests/agentic-use/evaluator-tool-calling-cli/tests/test_outputs.py
  • tests/agentic-use/evaluator-zero-config-judge-cli/tests/test_outputs.py
  • tests/agentic-use/files-crud-cli-easy/tests/test_outputs.py
  • tests/agentic-use/files-crud-cli/tests/test_outputs.py
  • tests/agentic-use/files-upload-dataset-cli-easy/tests/test_outputs.py
  • tests/agentic-use/files-upload-dataset-cli/tests/test_outputs.py
  • tools/nemo-platform-sdk-tools/src/nemo_platform_sdk_tools/sdk/cli_generator/overrides/files/upload.py
💤 Files with no reviewable changes (1)
  • services/automodel/tests/test_compiler.py

Comment thread plugins/nemo-data-designer/tests/integration/test_personas_cli.py
Comment thread plugins/nemo-safe-synthesizer/scripts/setup_model_filesets.py
Comment thread services/core/jobs/tests/conftest.py
matthewgrossman and others added 10 commits July 6, 2026 18:50
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
…s-from-filesetssubresource-to

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Tests that mock the NeMoPlatform SDK need to account for
client_from_platform accessing _custom_headers and _client.headers.
Patch the adapter function in test_schema, test_jobs, and
test_models_api to return mock FilesClient instances.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
These error aliases from nemo_platform_plugin.client.errors are not
files-specific — they come from the generic typed HTTP client. Rename
to Client* to reflect that.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
…s-from-filesetssubresource-to

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
…s-from-filesetssubresource-to

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
@matthewgrossman
matthewgrossman added this pull request to the merge queue Jul 8, 2026
Merged via the queue into main with commit ae7e9fb Jul 8, 2026
53 checks passed
@matthewgrossman
matthewgrossman deleted the mgrossman/aircore-840-migrate-files-consumers-from-filesetssubresource-to branch July 8, 2026 22:12
arpitsardhana pushed a commit that referenced this pull request Jul 9, 2026
* feat(files): Add OTLP to new nemoclient endpoints

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>

* lint

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>

* remove these

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>

* feat(files): Migrate consumers to the new FilesClient

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>

* code review

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>

* fixes

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>

* fixes

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>

* fixes

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>

* fix

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>

* lint fix

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>

* fix(tests): patch client_from_platform in tests that mock SDK internals

Tests that mock the NeMoPlatform SDK need to account for
client_from_platform accessing _custom_headers and _client.headers.
Patch the adapter function in test_schema, test_jobs, and
test_models_api to return mock FilesClient instances.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>

* refactor: rename Files*Error aliases to Client*Error

These error aliases from nemo_platform_plugin.client.errors are not
files-specific — they come from the generic typed HTTP client. Rename
to Client* to reflect that.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>

---------

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
matthewgrossman added a commit that referenced this pull request Jul 13, 2026
…o-nemoclient-typed-http-client

Brings in the merged NemoClient migrations from main:
- #584 (Files consumers -> FilesClient)
- #609 (Secrets service + consumers -> SecretsClient)
- #614 (plugin-client URL encoding)

Resolved 4 conflicts where the Jobs consumer migration (AIRCORE-874)
overlapped the Files/Secrets migrations in multi-service files:

- services/core/entities/.../workspace_cleanup.py: combined both migrations
  (jobs via AsyncJobsClient, filesets via AsyncFilesClient); switched
  PlatformJobStatus to the plugin type and built the terminal-status set from
  enum members.
- services/core/entities/tests/.../test_workspace_cleanup.py: adopted #584's
  tuple-return _make_sdk + _MockAsyncPaginatedResponse; added a dispatching
  _patch_clients() so the combined _async_step test routes
  client_from_platform to the jobs vs files mock by client class.
- plugins/nemo-safe-synthesizer/.../api/v2/jobs/endpoints.py test: dropped the
  now-orphaned Stainless NotFoundError/PermissionDeniedError import (both uses
  migrated across the two PRs); made _patch_jobs_client dispatch jobs vs files
  clients by class.
- plugins/nemo-data-designer/.../testing/utils.py: kept both the jobs
  (CreatePlatformJobRequest) and secrets (SecretsClient) imports.

All affected suites green; jobs service unchanged (5 pre-existing env failures).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants