Skip to content

test: configure explicit asyncio fixture loop scopes - #17640

Merged
dmitry-tokarev-nv merged 1 commit into
ai-dynamo:mainfrom
Pranjulcr7:pranjul/pytest-asyncio-fixture-loop-scope
Oct 30, 2026
Merged

dmitry-tokarev-nv merged 1 commit into
ai-dynamo:mainfrom
Pranjulcr7:pranjul/pytest-asyncio-fixture-loop-scope

Conversation

@Pranjulcr7

@Pranjulcr7 Pranjulcr7 commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Overview

Replace the pytest-asyncio unset-loop-scope warning suppression with explicit fixture loop configuration. Function-scoped async fixtures keep per-test loops, and the hello-world server retains its module-scoped loop.

Key Changes

Two configuration/decorator changes plus one import; no production runtime changes.

  • pyproject.toml: set asyncio_default_fixture_loop_scope = "function" and remove the unset-scope warning filter added in ci(test): OPS-9043 keep the pytest-asyncio loop scope notice nonfatal under pytest 9.2 #17519. With the option set, pytest-asyncio no longer emits that warning.
  • lib/bindings/python/tests/test_example_hello_world.py: use pytest_asyncio.fixture(scope="module", loop_scope="module") for server_process. It yields a subprocess handle, so sharing it across per-test event loops preserves its existing lifecycle.

An AST audit of all 1,975 tracked Python files found 28 async fixtures. This server fixture is the only one with a cache scope broader than function; the other 27 already use function scope.

Validation

Python 3.13.16 and the CI-qualified Kustomize 5.8.1:

Check Result
Exact Recipe Check pytest command, pytest 9.2.0 / pytest-asyncio 1.4.1 351 passed, no skips
Same command, container-pinned pytest 9.0.3 / pytest-asyncio 1.3.0 351 passed, no skips
Imported real server fixture, shared across two tests and checked after module teardown 2 passed on each version pair
Negative control removing the module-loop override Reproduces ScopeMismatch on both pairs
Negative control leaving the default unset without the warning filter Reproduces pytest 9.2 startup PytestDeprecationWarning
scripts/kustomize-matrix.py check Passed

The lifecycle probe uses a minimal subprocess and was kept outside the repository; it does not run the full hello-world service. Full runtime/NVIDIA CI remains to be run. Recipe Check's path filter excludes these two changed paths, so its result above is local validation.

Issues and Ongoing Work

Pull Request Checklist
  • I used Dynamo's /pr-checklist skill.

Summary by CodeRabbit

  • Tests
    • Updated asynchronous test setup to use a consistent event-loop scope.
    • Pytest now explicitly uses a function-scoped event loop, and warnings about an unset default scope are no longer suppressed.

Set function-scoped fixture loops explicitly and preserve the hello-world
server fixture's module loop. Remove the unset-scope warning suppression
now that pytest-asyncio no longer emits it.

Refs OPS-9043

Signed-off-by: Pranjul Gupta <pranjulgupta0203@gmail.com>
@Pranjulcr7
Pranjulcr7 requested review from a team as code owners October 30, 2026 00:36
@copy-pr-bot

copy-pr-bot Bot commented Oct 30, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@Pranjulcr7
Pranjulcr7 temporarily deployed to external_collaborator October 30, 2026 00:36 — with GitHub Actions Inactive
@Pranjulcr7
Pranjulcr7 temporarily deployed to external_collaborator October 30, 2026 00:36 — with GitHub Actions Inactive
@github-actions

Copy link
Copy Markdown
Contributor

👋 Hi Pranjulcr7! Thank you for contributing to ai-dynamo/dynamo.

Just a reminder: The NVIDIA Test Github Validation CI runs an essential subset of the testing framework to quickly catch errors.Your PR reviewers may elect to test the changes comprehensively before approving your changes.

🚀

@coderabbitai

coderabbitai Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Walkthrough

The pytest configuration now sets the default asyncio fixture loop scope to function. The asynchronous server fixture uses pytest_asyncio.fixture with a module-scoped loop.

Changes

Async fixture loop configuration

Layer / File(s) Summary
Set asyncio fixture loop scopes
pyproject.toml, lib/bindings/python/tests/test_example_hello_world.py
Pytest’s default fixture loop scope is set to function. The server fixture uses pytest_asyncio.fixture with loop_scope="module". The warning filter for an unset default scope is removed.

Priority: Low

Estimated code review effort: 1 (Trivial) | ~5 minutes

Merge Risk: Minimal · up to 584e0

No actionable merge-blocking risk is evident in this configuration-only change.

Pre-merge checks: Passed 5
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: configuring explicit asyncio fixture loop scopes.
Description check Passed The description includes all required sections, explains the configuration changes, reports validation results, identifies remaining work, and includes the checklist.
Docstring Coverage Passed No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat…
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.
Full details: Docstring Coverage

Explanation

No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 0 functions across 1 files. (1 skipped: 1 unsupported.)

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@dmitry-tokarev-nv

Copy link
Copy Markdown
Contributor

/ok to test 584e0de

@dmitry-tokarev-nv dmitry-tokarev-nv 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.

No P0 or P1 found, and this review has no other findings.

Head reviewed: 584e0dee0c5d85fb3c1e56d6171260c7bf1d893e.

Open item: Recipe Check does not run on this pull request, because its path filter does not match the two changed files. The pytest 9.2.0 results below come from local runs.

The head gives the same results as the base, and each new line is needed.

The Recipe Check test command from .github/workflows/pre-merge.yml ran unchanged in each tree, on Python 3.12.9. A small wrapper supplied Kustomize v5.8.1 through kubectl kustomize (kubectl v1.36.3).

pytest / pytest-asyncio base 108cbfa758 head 584e0dee0c head without the new option
9.2.0 / 1.4.1 351 passed 351 passed exit 3, INTERNALERROR> pytest.PytestDeprecationWarning: The configuration option "asyncio_default_fixture_loop_scope" is unset.
9.0.3 / 1.3.0 351 passed 351 passed 351 passed

scripts/kustomize-matrix.py check exited 0 in every cell.

A test module imported the real server_process fixture into two async tests, with a stub hello_world.py as the server. A small pytest plugin recorded the loop scope that pytest-asyncio picked.

tree 9.2.0 / 1.4.1 9.0.3 / 1.3.0
base module loop, 3 passed module loop, 3 passed
head module loop, 3 passed module loop, 3 passed
head without loop_scope="module" ScopeMismatch ScopeMismatch

Both tests got the same process, and a third test found the process stopped after module teardown.

A syntax-tree scan of the 1,975 tracked Python files at the head found 28 async fixtures, under every import alias of pytest.fixture and pytest_asyncio.fixture. Only server_process has a caching scope broader than function. The scan found the same 28 fixtures after a merge with main at c10c8797d2, and that merge had no conflicts. A planted module-scoped async fixture without loop_scope ran in a module loop with the base configuration. With the head configuration, it failed at setup with ScopeMismatch. So a future fixture of that kind stops at setup. It does not run in a different loop without notice.

In CI on this head, dynamo-runtime / test / sequential ran lib/bindings/python/tests/test_example_hello_world.py::test_hello_world with pytest 9.0.3, pytest-asyncio 1.3.0 and the new option. The test passed on amd64 and on arm64.

Every CI job that installs pytest-asyncio uses version 1.0 or later, and version 0.24.0 added asyncio_default_fixture_loop_scope. Two jobs run pytest with the root configuration but without pytest-asyncio, and they clear addopts and filterwarnings with --override-ini. In those runs, the new option adds one PytestConfigWarning, and the tests pass on both trees.

@dmitry-tokarev-nv
dmitry-tokarev-nv merged commit 3057891 into ai-dynamo:main Oct 30, 2026
194 of 196 checks passed

This branch was previously deployed

1 inactive deployment
external_collaborator — 584e0dee Deployed Oct 30, 2026 by Pranjulcr7 via pr_reminder #14733
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

external-contribution Pull request is from an external contributor size/XS test

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants