Skip to content

feat: make BaseService methods async#474

Merged
olivermeyer merged 8 commits intomainfrom
feat/bridge-baseservice
Mar 20, 2026
Merged

feat: make BaseService methods async#474
olivermeyer merged 8 commits intomainfrom
feat/bridge-baseservice

Conversation

@olivermeyer
Copy link
Collaborator

@olivermeyer olivermeyer commented Mar 13, 2026

Unifying the BaseService with Bridge.

The main changes are:

  • Add a get_service method for FastAPI injection and a settings method
  • Make the health and info methods async + adjusting concrete services
  • Wrap service calls to these methods in CLI commands in asyncio.run()
  • Update GUI calls to health and info

I am not making all methods on the various service implementations async.

Copilot AI review requested due to automatic review settings March 13, 2026 10:21
Copy link

Copilot AI left a 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 converts the BaseService contract to an async interface (health() / info()), propagates that change across service implementations and key call sites (CLI/GUI), and adds a new FastAPI DI helper (BaseService.get_service()) plus a settings accessor.

Changes:

  • Make BaseService.health() / BaseService.info() async and update all service implementations accordingly.
  • Update system CLI/GUI and platform tests to await or run async health/info calls.
  • Add BaseService.get_service() (FastAPI dependency factory), BaseService.settings(), and accompanying tests/docs.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
tests/aignostics/utils/service_test.py Adds tests for BaseService.get_service() caching/behavior and settings() accessor.
tests/aignostics/platform/service_test.py Updates platform service health test to async def + await.
src/aignostics/utils/_service.py Makes base API async; adds get_service() and settings().
src/aignostics/utils/CLAUDE.md Updates docs/examples for async services and DI helper.
src/aignostics/platform/_service.py Converts platform service health/info to async signature.
src/aignostics/system/_service.py Converts system service health_static/health/info to async and awaits discovered services.
src/aignostics/system/_gui.py Switches GUI health/info loading to await the async service methods.
src/aignostics/system/_cli.py Runs async health/info via asyncio.run(...) in CLI commands.
src/aignostics/application/_service.py Converts application service health/info to async signature.
src/aignostics/application/_cli.py Runs async system health check via asyncio.run(...) before submitting runs.
src/aignostics/application/_gui/_page_application_describe.py Updates GUI to call async system health (currently via asyncio.run).
src/aignostics/bucket/_service.py Converts bucket service health/info to async signature.
src/aignostics/dataset/_service.py Converts dataset service health/info to async signature.
src/aignostics/notebook/_service.py Converts notebook service health/info to async signature.
src/aignostics/qupath/_service.py Converts QuPath service health/info to async signature.
src/aignostics/wsi/_service.py Converts WSI service health/info to async signature.
src/aignostics/CLAUDE.md Updates root docs’ service examples to async signatures.

@codecov
Copy link

codecov bot commented Mar 13, 2026

Codecov Report

❌ Patch coverage is 95.45455% with 4 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/aignostics/system/_service.py 88.57% 2 Missing and 2 partials ⚠️
Files with missing lines Coverage Δ
src/aignostics/application/_cli.py 69.84% <100.00%> (+0.57%) ⬆️
...ics/application/_gui/_page_application_describe.py 72.13% <100.00%> (ø)
src/aignostics/application/_service.py 60.55% <100.00%> (ø)
src/aignostics/bucket/_service.py 77.77% <100.00%> (ø)
src/aignostics/dataset/_service.py 76.71% <100.00%> (ø)
src/aignostics/gui/_frame.py 75.61% <100.00%> (-2.07%) ⬇️
src/aignostics/notebook/_service.py 87.50% <100.00%> (ø)
src/aignostics/platform/_service.py 83.76% <100.00%> (-0.80%) ⬇️
src/aignostics/qupath/_service.py 57.29% <100.00%> (ø)
src/aignostics/system/_cli.py 84.48% <100.00%> (+0.13%) ⬆️
... and 4 more

... and 3 files with indirect coverage changes

Copilot AI review requested due to automatic review settings March 17, 2026 15:50
@olivermeyer olivermeyer force-pushed the feat/bridge-baseservice branch from b8c68d2 to 67cf115 Compare March 17, 2026 15:50
@olivermeyer olivermeyer changed the base branch from feat/health-degraded to main March 17, 2026 15:50
@olivermeyer olivermeyer force-pushed the feat/bridge-baseservice branch from 67cf115 to b17bd91 Compare March 17, 2026 15:52
Copy link

Copilot AI left a 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 updates the SDK’s service abstraction (BaseService) to use async health() / info() methods, and propagates that change through service implementations and key call sites (system aggregation, CLI, and GUI). It also adds a FastAPI dependency helper (get_service()) and a public settings accessor.

Changes:

  • Make BaseService.health() / BaseService.info() async and update all BaseService subclasses accordingly.
  • Add BaseService.get_service() (cached FastAPI dependency factory) and BaseService.settings() accessor.
  • Update system CLI/GUI and selected GUI pages to call async health/info, and add unit tests for the new BaseService helpers.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/aignostics/utils/service_test.py Adds unit coverage for BaseService.get_service() caching/DI behavior and settings().
tests/aignostics/platform/service_test.py Updates platform service health test to await the new async API.
src/aignostics/utils/_service.py Converts abstract methods to async; adds get_service() DI helper and settings() accessor.
src/aignostics/utils/CLAUDE.md Updates utils module docs/examples for async service methods and new helpers.
src/aignostics/CLAUDE.md Updates top-level docs/examples for async service methods.
src/aignostics/application/_service.py Converts service health() / info() to async.
src/aignostics/bucket/_service.py Converts service health() / info() to async.
src/aignostics/dataset/_service.py Converts service health() / info() to async.
src/aignostics/notebook/_service.py Converts service health() / info() to async.
src/aignostics/platform/_service.py Converts service health() / info() to async.
src/aignostics/qupath/_service.py Converts service health() / info() to async.
src/aignostics/wsi/_service.py Converts service health() / info() to async.
src/aignostics/system/_service.py Makes system aggregation APIs async and awaits discovered services’ health/info.
src/aignostics/system/_cli.py Bridges async health/info via asyncio.run() for Typer CLI commands.
src/aignostics/system/_gui.py Updates system GUI page to await async health/info.
src/aignostics/gui/_frame.py Updates launchpad health polling to await async system health.
src/aignostics/application/_cli.py Bridges async system health check via asyncio.run() in CLI.
src/aignostics/application/_gui/_page_application_describe.py Updates application describe page to await async system health.

@olivermeyer olivermeyer added the claude Trigger Claude Code automation label Mar 17, 2026
@olivermeyer
Copy link
Collaborator Author

olivermeyer commented Mar 17, 2026

One reply to all Copilot comments above: making all calls async is out of scope here, I just want to unify the BaseService interface between Python SDK and Bridge.

@claude

This comment was marked as outdated.

Copilot AI review requested due to automatic review settings March 18, 2026 08:28
@olivermeyer olivermeyer marked this pull request as ready for review March 18, 2026 08:29
@olivermeyer olivermeyer added claude Trigger Claude Code automation and removed claude Trigger Claude Code automation labels Mar 18, 2026
Copy link

Copilot AI left a 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 aligns the SDK’s BaseService interface with Bridge by making health()/info() async, adding a FastAPI-friendly dependency factory (get_service) plus a settings accessor (settings), and updating service callers across CLI/GUI to accommodate the async contract.

Changes:

  • Make BaseService.health() and BaseService.info() async and update concrete service implementations accordingly.
  • Add BaseService.get_service() (cached FastAPI dependency factory) and BaseService.settings() accessor, plus new unit tests.
  • Update CLI/GUI call sites to use await/asyncio.run(...) for async health/info retrieval.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/aignostics/utils/service_test.py Adds unit tests for get_service() caching/behavior and settings(), plus coroutine assertions for health/info.
tests/aignostics/platform/service_test.py Updates the platform service health test to await the async health().
src/aignostics/wsi/_service.py Converts health()/info() to async to match BaseService.
src/aignostics/utils/_service.py Introduces get_service() and settings(), and makes health()/info() async abstract methods.
src/aignostics/utils/CLAUDE.md Updates service examples/docs to reflect async methods and new DI/settings helpers.
src/aignostics/system/_service.py Makes health_static, health, and info async and updates internal aggregation calls to await.
src/aignostics/system/_gui.py Updates GUI to await async health/info calls (removes previous run.cpu_bound usage).
src/aignostics/system/_cli.py Wraps async service calls in asyncio.run() for CLI execution.
src/aignostics/qupath/_service.py Converts health()/info() to async.
src/aignostics/platform/_service.py Converts health()/info() to async.
src/aignostics/notebook/_service.py Converts health()/info() to async.
src/aignostics/gui/_frame.py Updates periodic health polling to await async SystemService.health_static().
src/aignostics/dataset/_service.py Converts health()/info() to async.
src/aignostics/bucket/_service.py Converts health()/info() to async.
src/aignostics/application/_service.py Converts health()/info() to async.
src/aignostics/application/_gui/_page_application_describe.py Updates GUI flow to await system health check once during page load.
src/aignostics/application/_cli.py Uses asyncio.run(SystemService.health_static()) in the sync CLI path.
src/aignostics/CLAUDE.md Updates top-level docs to reflect async service method signatures.
Comments suppressed due to low confidence (1)

src/aignostics/system/_gui.py:91

  • await Service.info(...) does blocking system calls (psutil.cpu_percent(interval=...), etc.) inside Service.info. Running it directly on the NiceGUI event loop can stall the UI during the measurement interval. Consider running info collection in a worker thread (nicegui.run.io_bound/cpu_bound) or refactor the implementation to avoid blocking calls in the async path.
                                editor.set_visibility(False)
                                spinner.set_visibility(True)
                                mask_secrets_switch.set_visibility(False)
                                info = await Service.info(include_environ=True, mask_secrets=mask_secrets)
                                if info is None:
                                    properties["content"] = {"json": "Info retrieval failed."}  # type: ignore[unreachable]
                                else:
                                    properties["content"] = {"json": info}

Copilot AI review requested due to automatic review settings March 19, 2026 07:33
@olivermeyer olivermeyer force-pushed the feat/bridge-baseservice branch from ff75bfc to 3613113 Compare March 19, 2026 07:33
Copy link

Copilot AI left a 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 updates the SDK’s service abstraction to align BaseService with Bridge by adding FastAPI-friendly dependency injection helpers and converting the core health()/info() contract to async, then propagating those signature changes through services, CLI, GUI, and tests.

Changes:

  • Added BaseService.get_service() (FastAPI dependency factory) and BaseService.settings() accessor.
  • Made BaseService.health() / BaseService.info() async and updated concrete service implementations + affected call sites (CLI/GUI/system aggregation).
  • Added/updated unit tests to cover the new service helpers and async behavior.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/aignostics/utils/service_test.py New tests for BaseService.get_service() caching semantics, settings(), and async method shape.
tests/aignostics/platform/service_test.py Updates a platform health test to async def and awaits Service.health().
src/aignostics/utils/_service.py Introduces get_service() + settings() and makes abstract health/info async.
src/aignostics/utils/CLAUDE.md Updates documentation examples for async health/info and documents get_service() + settings().
src/aignostics/wsi/_service.py Updates service to async health/info to satisfy new BaseService contract.
src/aignostics/platform/_service.py Updates platform service to async health/info.
src/aignostics/bucket/_service.py Updates bucket service to async health/info.
src/aignostics/dataset/_service.py Updates dataset service to async health/info.
src/aignostics/application/_service.py Updates application service to async health/info.
src/aignostics/qupath/_service.py Updates qupath service to async health/info.
src/aignostics/notebook/_service.py Updates notebook service to async health/info.
src/aignostics/system/_service.py Updates system aggregation/service methods (health_static, health, info) to async and awaits discovered services.
src/aignostics/system/_cli.py Wraps async service calls via asyncio.run() in CLI commands.
src/aignostics/application/_cli.py Wraps SystemService.health_static() via asyncio.run() for CLI preflight health check.
src/aignostics/system/_gui.py Updates GUI to await async health_static() / info() directly.
src/aignostics/gui/_frame.py Updates periodic health UI to await SystemService.health_static() directly.
src/aignostics/application/_gui/_page_application_describe.py Updates application describe page to await SystemService.health_static() and uses the result in stepper logic.
src/aignostics/CLAUDE.md Updates top-level docs examples to use async health/info.

@olivermeyer olivermeyer force-pushed the feat/bridge-baseservice branch from 3613113 to 8279335 Compare March 19, 2026 11:44
Copilot AI review requested due to automatic review settings March 19, 2026 14:38
Copy link

Copilot AI left a 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 updates the SDK’s service abstraction to better align with Bridge by making BaseService.health() / BaseService.info() asynchronous, adding a FastAPI DI helper (get_service) plus a settings() accessor, and updating CLI/GUI/tests to use the new async contract.

Changes:

  • Make BaseService.health() and BaseService.info() async, and update all concrete service implementations accordingly.
  • Add BaseService.get_service() (cached FastAPI dependency factory) and BaseService.settings() accessor + unit tests.
  • Update CLI/GUI/test call sites to await service calls or wrap them via asyncio.run(); migrate platform/system health checks from urllib3 to httpx async client.

Reviewed changes

Copilot reviewed 21 out of 21 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/aignostics/utils/service_test.py Adds unit tests for get_service() caching, settings(), and async coroutine behavior.
tests/aignostics/system/service_pooling_test.py Removes pooling tests corresponding to removal of urllib3 pool usage.
tests/aignostics/system/cli_test.py Updates mocks to AsyncMock for async health().
tests/aignostics/platform/service_test.py Converts tests to async and updates mocking for httpx.AsyncClient.
tests/aignostics/application/gui_test.py Runs blocking CliRunner.invoke via asyncio.to_thread in async GUI tests.
src/aignostics/utils/_service.py Adds get_service() + settings() and makes health()/info() async abstract methods.
src/aignostics/utils/CLAUDE.md Updates docs/examples for async service methods + DI usage.
src/aignostics/system/_service.py Makes health/info async, switches network calls to httpx, and avoids blocking CPU sampling by using asyncio.sleep.
src/aignostics/system/_gui.py Updates GUI to await async health_static() / info().
src/aignostics/system/_cli.py Wraps async service calls with asyncio.run() for synchronous Typer commands.
src/aignostics/platform/_service.py Migrates health checks from urllib3 to async httpx and makes service methods async.
src/aignostics/application/_service.py Makes health() / info() async.
src/aignostics/application/_gui/_page_application_describe.py Updates system health usage to async/await.
src/aignostics/application/_cli.py Wraps async system health check with asyncio.run().
src/aignostics/bucket/_service.py Makes health() / info() async.
src/aignostics/dataset/_service.py Makes health() / info() async.
src/aignostics/wsi/_service.py Makes health() / info() async.
src/aignostics/qupath/_service.py Makes health() / info() async.
src/aignostics/notebook/_service.py Makes health() / info() async.
src/aignostics/gui/_frame.py Updates periodic health check to await async SystemService.health_static().
src/aignostics/CLAUDE.md Updates top-level docs to reflect async service API.

@olivermeyer olivermeyer force-pushed the feat/bridge-baseservice branch from f1d0f72 to dcc8028 Compare March 19, 2026 15:34
Copilot AI review requested due to automatic review settings March 20, 2026 07:32
Copy link

Copilot AI left a 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 updates the SDK’s service abstraction to support async health() / info() methods (to align with Bridge), adds FastAPI-friendly service injection via BaseService.get_service(), and updates affected CLI/GUI codepaths plus tests accordingly.

Changes:

  • Make BaseService.health() / BaseService.info() async and update all concrete service implementations.
  • Add BaseService.get_service() (FastAPI dependency factory) and BaseService.settings() accessor.
  • Update CLI/GUI callers and tests for async behavior; migrate some health/info networking to httpx.AsyncClient.

Reviewed changes

Copilot reviewed 23 out of 23 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/aignostics/utils/service_test.py Adds unit tests for BaseService.get_service() caching and settings() accessor; verifies coroutine nature of health/info.
tests/aignostics/system/service_test.py Adds unit tests for new CPU frequency helper behavior.
tests/aignostics/system/service_pooling_test.py Removes tests tied to the deleted urllib3 pool behavior.
tests/aignostics/system/cli_test.py Updates CLI tests to mock async health() using AsyncMock.
tests/aignostics/platform/service_test.py Converts platform service health tests to async and updates mocking to httpx.AsyncClient.
tests/aignostics/application/gui_test.py Runs CliRunner.invoke in a thread to avoid event-loop conflicts with asyncio.run in CLI commands.
tests/aignostics/application/cli_test.py Adjusts a run submission test to include --force.
src/aignostics/utils/_service.py Introduces get_service() + settings() and makes health/info abstract methods async.
src/aignostics/utils/CLAUDE.md Updates docs for async service methods and documents FastAPI DI + settings accessor.
src/aignostics/system/_service.py Switches system health/info to async and migrates network calls to httpx; adds CPU frequency helper.
src/aignostics/system/_gui.py Updates GUI to await async system health/info methods.
src/aignostics/system/_cli.py Wraps async system service calls with asyncio.run() for sync Typer commands.
src/aignostics/platform/_service.py Migrates platform health checks from urllib3 to httpx and makes health async.
src/aignostics/application/_cli.py Wraps SystemService.health_static() with asyncio.run() for sync CLI preflight.
src/aignostics/application/_service.py Makes health/info async for application service.
src/aignostics/application/_gui/_page_application_describe.py Awaits system health in application describe flow; updates force-option logic accordingly.
src/aignostics/gui/_frame.py Updates launchpad health indicator to await async system health.
src/aignostics/bucket/_service.py Makes health/info async for bucket service.
src/aignostics/dataset/_service.py Makes health/info async for dataset service.
src/aignostics/wsi/_service.py Makes health/info async for WSI service.
src/aignostics/qupath/_service.py Makes health/info async for QuPath service.
src/aignostics/notebook/_service.py Makes health/info async for notebook service.
src/aignostics/CLAUDE.md Updates top-level docs to reflect async health/info.
Comments suppressed due to low confidence (2)

src/aignostics/system/_gui.py:56

  • Service.health_static() is typed to always return Health, so the if health is None: branch is now dead code after switching from run.cpu_bound(...) to a direct await. Consider removing the None check (and the type: ignore), or wrap the await in try/except and set health=None explicitly on failure if you want to keep the fallback UI.
                            health = await Service.health_static()
                            if health is None:
                                properties["content"] = {"json": "Health check failed."}  # type: ignore[unreachable]
                            else:
                                properties["content"] = {"json": health.model_dump()}

src/aignostics/system/_gui.py:91

  • Service.info(...) now returns a dict (non-optional), so if info is None: is unreachable in normal execution. Consider removing the None branch, or catch exceptions around the await and display the fallback message only on error.
                                info = await Service.info(include_environ=True, mask_secrets=mask_secrets)
                                if info is None:
                                    properties["content"] = {"json": "Info retrieval failed."}  # type: ignore[unreachable]
                                else:
                                    properties["content"] = {"json": info}

Copy link
Contributor

@arne-aignx arne-aignx left a comment

Choose a reason for hiding this comment

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

If I correctly grasped the scope here
the MR focuses on aligning the BaseService implementation with the one in bridge.

This requires us to make some methods async.

Good switch to httpx

There are some minor refactorings sprinkled into the MR. 👍

With the switch from urllib3 to httpx the test setup can be improved by using pytest-httpx to define the mock queries. but thats beyond the scope

One minor question added.

olivermeyer and others added 6 commits March 20, 2026 14:00
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… checks

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extract CPU frequency measurement into a dedicated private static method
to reduce cognitive complexity of Service.info() from 17 to 10.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace 9 inline occurrences of the patch target string
"aignostics.platform._service.httpx.AsyncClient" with a single
module-level constant _PATCH_HTTPX_ASYNC_CLIENT, following the
existing _PATCH_AUTH_GETTER convention.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 20, 2026 13:00
@olivermeyer olivermeyer force-pushed the feat/bridge-baseservice branch from c4e9bd5 to a3aeec0 Compare March 20, 2026 13:00
Copy link

Copilot AI left a 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 23 out of 23 changed files in this pull request and generated 1 comment.

@olivermeyer olivermeyer force-pushed the feat/bridge-baseservice branch from a3aeec0 to 47031f2 Compare March 20, 2026 13:35
@sonarqubecloud
Copy link

@olivermeyer olivermeyer requested a review from arne-aignx March 20, 2026 14:21
Copy link
Contributor

@arne-aignx arne-aignx left a comment

Choose a reason for hiding this comment

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

LGTM

@olivermeyer olivermeyer merged commit 84c826a into main Mar 20, 2026
29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

claude Trigger Claude Code automation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants