Skip to content

Commit e3a3f86

Browse files
committed
chore: default to pytest asyncio-mode=auto
previously, developers who ran `./scripts/unit-tests.sh` would get `asyncio-mode=auto`, which meant `@pytest.mark.asyncio` and `@pytest_asyncio.fixture` were redundent. developers who ran `pytest` directly would get pytest's default (strict mode), would run into errors leading them to add `@pytest.mark.asyncio` / `@pytest_asyncio.fixture` to their code. with this change - - `asyncio_mode=auto` is included in `pyproject.toml` making behavior consistent for all invocations of pytest - removes all redundant `@pytest_asyncio.fixture` and `@pytest.mark.asyncio` - for good measure, requires `pytest>=8.4` and `pytest-asyncio>=1.0`
1 parent 2ebc172 commit e3a3f86

35 files changed

+29
-239
lines changed

pyproject.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ ui = [
5858

5959
[dependency-groups]
6060
dev = [
61-
"pytest",
61+
"pytest>=8.4",
6262
"pytest-timeout",
63-
"pytest-asyncio",
63+
"pytest-asyncio>=1.0",
6464
"pytest-cov",
6565
"pytest-html",
6666
"pytest-json-report",
@@ -339,3 +339,6 @@ warn_required_dynamic_aliases = true
339339

340340
[tool.ruff.lint.pep8-naming]
341341
classmethod-decorators = ["classmethod", "pydantic.field_validator"]
342+
343+
[tool.pytest.ini_options]
344+
asyncio_mode = "auto"

scripts/unit-tests.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@ if [ $FOUND_PYTHON -ne 0 ]; then
1616
uv python install "$PYTHON_VERSION"
1717
fi
1818

19-
uv run --python "$PYTHON_VERSION" --with-editable . --group unit pytest --asyncio-mode=auto -s -v tests/unit/ $@
19+
uv run --python "$PYTHON_VERSION" --with-editable . --group unit pytest -s -v tests/unit/ $@

tests/integration/agents/test_persistence.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ def common_params(inference_model):
4444
)
4545

4646

47-
@pytest.mark.asyncio
4847
@pytest.mark.skip(reason="This test needs to be migrated to api / client-sdk world")
4948
async def test_delete_agents_and_sessions(self, agents_stack, common_params):
5049
agents_impl = agents_stack.impls[Api.agents]
@@ -73,7 +72,6 @@ async def test_delete_agents_and_sessions(self, agents_stack, common_params):
7372
assert agent_response is None
7473

7574

76-
@pytest.mark.asyncio
7775
@pytest.mark.skip(reason="This test needs to be migrated to api / client-sdk world")
7876
async def test_get_agent_turns_and_steps(self, agents_stack, sample_messages, common_params):
7977
agents_impl = agents_stack.impls[Api.agents]

tests/integration/inspect/test_inspect.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,17 @@
44
# This source code is licensed under the terms described in the LICENSE file in
55
# the root directory of this source tree.
66

7-
import pytest
87
from llama_stack_client import LlamaStackClient
98

109
from llama_stack import LlamaStackAsLibraryClient
1110

1211

1312
class TestInspect:
14-
@pytest.mark.asyncio
1513
def test_health(self, llama_stack_client: LlamaStackAsLibraryClient | LlamaStackClient):
1614
health = llama_stack_client.inspect.health()
1715
assert health is not None
1816
assert health.status == "OK"
1917

20-
@pytest.mark.asyncio
2118
def test_version(self, llama_stack_client: LlamaStackAsLibraryClient | LlamaStackClient):
2219
version = llama_stack_client.inspect.version()
2320
assert version is not None

tests/integration/providers/test_providers.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,12 @@
44
# This source code is licensed under the terms described in the LICENSE file in
55
# the root directory of this source tree.
66

7-
import pytest
87
from llama_stack_client import LlamaStackClient
98

109
from llama_stack import LlamaStackAsLibraryClient
1110

1211

1312
class TestProviders:
14-
@pytest.mark.asyncio
1513
def test_providers(self, llama_stack_client: LlamaStackAsLibraryClient | LlamaStackClient):
1614
provider_list = llama_stack_client.providers.list()
1715
assert provider_list is not None

tests/integration/providers/utils/sqlstore/test_authorized_sqlstore.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ async def cleanup_records(sql_store, table_name, record_ids):
8888
pass
8989

9090

91-
@pytest.mark.asyncio
9291
@pytest.mark.parametrize("backend_config", BACKEND_CONFIGS)
9392
@patch("llama_stack.providers.utils.sqlstore.authorized_sqlstore.get_authenticated_user")
9493
async def test_authorized_store_attributes(mock_get_authenticated_user, authorized_store, request):
@@ -183,7 +182,6 @@ async def test_authorized_store_attributes(mock_get_authenticated_user, authoriz
183182
await cleanup_records(authorized_store.sql_store, table_name, ["1", "2", "3", "4", "5", "6"])
184183

185184

186-
@pytest.mark.asyncio
187185
@pytest.mark.parametrize("backend_config", BACKEND_CONFIGS)
188186
@patch("llama_stack.providers.utils.sqlstore.authorized_sqlstore.get_authenticated_user")
189187
async def test_user_ownership_policy(mock_get_authenticated_user, authorized_store, request):

tests/unit/distribution/routers/test_routing_tables.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88

99
from unittest.mock import AsyncMock
1010

11-
import pytest
12-
1311
from llama_stack.apis.common.type_system import NumberType
1412
from llama_stack.apis.datasets.datasets import Dataset, DatasetPurpose, URIDataSource
1513
from llama_stack.apis.datatypes import Api
@@ -119,7 +117,6 @@ async def list_runtime_tools(self, toolgroup_id, mcp_endpoint):
119117
)
120118

121119

122-
@pytest.mark.asyncio
123120
async def test_models_routing_table(cached_disk_dist_registry):
124121
table = ModelsRoutingTable({"test_provider": InferenceImpl()}, cached_disk_dist_registry, {})
125122
await table.initialize()
@@ -161,7 +158,6 @@ async def test_models_routing_table(cached_disk_dist_registry):
161158
assert len(openai_models.data) == 0
162159

163160

164-
@pytest.mark.asyncio
165161
async def test_shields_routing_table(cached_disk_dist_registry):
166162
table = ShieldsRoutingTable({"test_provider": SafetyImpl()}, cached_disk_dist_registry, {})
167163
await table.initialize()
@@ -177,7 +173,6 @@ async def test_shields_routing_table(cached_disk_dist_registry):
177173
assert "test-shield-2" in shield_ids
178174

179175

180-
@pytest.mark.asyncio
181176
async def test_vectordbs_routing_table(cached_disk_dist_registry):
182177
table = VectorDBsRoutingTable({"test_provider": VectorDBImpl()}, cached_disk_dist_registry, {})
183178
await table.initialize()
@@ -233,7 +228,6 @@ async def test_datasets_routing_table(cached_disk_dist_registry):
233228
assert len(datasets.data) == 0
234229

235230

236-
@pytest.mark.asyncio
237231
async def test_scoring_functions_routing_table(cached_disk_dist_registry):
238232
table = ScoringFunctionsRoutingTable({"test_provider": ScoringFunctionsImpl()}, cached_disk_dist_registry, {})
239233
await table.initialize()
@@ -259,7 +253,6 @@ async def test_scoring_functions_routing_table(cached_disk_dist_registry):
259253
assert "test-scoring-fn-2" in scoring_fn_ids
260254

261255

262-
@pytest.mark.asyncio
263256
async def test_benchmarks_routing_table(cached_disk_dist_registry):
264257
table = BenchmarksRoutingTable({"test_provider": BenchmarksImpl()}, cached_disk_dist_registry, {})
265258
await table.initialize()
@@ -277,7 +270,6 @@ async def test_benchmarks_routing_table(cached_disk_dist_registry):
277270
assert "test-benchmark" in benchmark_ids
278271

279272

280-
@pytest.mark.asyncio
281273
async def test_tool_groups_routing_table(cached_disk_dist_registry):
282274
table = ToolGroupsRoutingTable({"test_provider": ToolGroupsImpl()}, cached_disk_dist_registry, {})
283275
await table.initialize()

tests/unit/distribution/test_context.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
from llama_stack.distribution.utils.context import preserve_contexts_async_generator
1414

1515

16-
@pytest.mark.asyncio
1716
async def test_preserve_contexts_with_exception():
1817
# Create context variable
1918
context_var = ContextVar("exception_var", default="initial")
@@ -41,7 +40,6 @@ async def exception_generator():
4140
context_var.reset(token)
4241

4342

44-
@pytest.mark.asyncio
4543
async def test_preserve_contexts_empty_generator():
4644
# Create context variable
4745
context_var = ContextVar("empty_var", default="initial")
@@ -66,7 +64,6 @@ async def empty_generator():
6664
context_var.reset(token)
6765

6866

69-
@pytest.mark.asyncio
7067
async def test_preserve_contexts_across_event_loops():
7168
"""
7269
Test that context variables are preserved across event loop boundaries with nested generators.

tests/unit/files/test_files.py

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77

88
import pytest
9-
import pytest_asyncio
109

1110
from llama_stack.apis.common.responses import Order
1211
from llama_stack.apis.files import OpenAIFilePurpose
@@ -29,7 +28,7 @@ async def read(self):
2928
return self.content
3029

3130

32-
@pytest_asyncio.fixture
31+
@pytest.fixture
3332
async def files_provider(tmp_path):
3433
"""Create a files provider with temporary storage for testing."""
3534
storage_dir = tmp_path / "files"
@@ -68,7 +67,6 @@ def large_file():
6867
class TestOpenAIFilesAPI:
6968
"""Test suite for OpenAI Files API endpoints."""
7069

71-
@pytest.mark.asyncio
7270
async def test_upload_file_success(self, files_provider, sample_text_file):
7371
"""Test successful file upload."""
7472
# Upload file
@@ -82,7 +80,6 @@ async def test_upload_file_success(self, files_provider, sample_text_file):
8280
assert result.created_at > 0
8381
assert result.expires_at > result.created_at
8482

85-
@pytest.mark.asyncio
8683
async def test_upload_different_purposes(self, files_provider, sample_text_file):
8784
"""Test uploading files with different purposes."""
8885
purposes = list(OpenAIFilePurpose)
@@ -93,7 +90,6 @@ async def test_upload_different_purposes(self, files_provider, sample_text_file)
9390
uploaded_files.append(result)
9491
assert result.purpose == purpose
9592

96-
@pytest.mark.asyncio
9793
async def test_upload_different_file_types(self, files_provider, sample_text_file, sample_json_file, large_file):
9894
"""Test uploading different types and sizes of files."""
9995
files_to_test = [
@@ -107,7 +103,6 @@ async def test_upload_different_file_types(self, files_provider, sample_text_fil
107103
assert result.filename == expected_filename
108104
assert result.bytes == len(file_obj.content)
109105

110-
@pytest.mark.asyncio
111106
async def test_list_files_empty(self, files_provider):
112107
"""Test listing files when no files exist."""
113108
result = await files_provider.openai_list_files()
@@ -117,7 +112,6 @@ async def test_list_files_empty(self, files_provider):
117112
assert result.first_id == ""
118113
assert result.last_id == ""
119114

120-
@pytest.mark.asyncio
121115
async def test_list_files_with_content(self, files_provider, sample_text_file, sample_json_file):
122116
"""Test listing files when files exist."""
123117
# Upload multiple files
@@ -132,7 +126,6 @@ async def test_list_files_with_content(self, files_provider, sample_text_file, s
132126
assert file1.id in file_ids
133127
assert file2.id in file_ids
134128

135-
@pytest.mark.asyncio
136129
async def test_list_files_with_purpose_filter(self, files_provider, sample_text_file):
137130
"""Test listing files with purpose filtering."""
138131
# Upload file with specific purpose
@@ -146,7 +139,6 @@ async def test_list_files_with_purpose_filter(self, files_provider, sample_text_
146139
assert result.data[0].id == uploaded_file.id
147140
assert result.data[0].purpose == OpenAIFilePurpose.ASSISTANTS
148141

149-
@pytest.mark.asyncio
150142
async def test_list_files_with_limit(self, files_provider, sample_text_file):
151143
"""Test listing files with limit parameter."""
152144
# Upload multiple files
@@ -157,7 +149,6 @@ async def test_list_files_with_limit(self, files_provider, sample_text_file):
157149
result = await files_provider.openai_list_files(limit=3)
158150
assert len(result.data) == 3
159151

160-
@pytest.mark.asyncio
161152
async def test_list_files_with_order(self, files_provider, sample_text_file):
162153
"""Test listing files with different order."""
163154
# Upload multiple files
@@ -178,7 +169,6 @@ async def test_list_files_with_order(self, files_provider, sample_text_file):
178169
# Oldest should be first
179170
assert result_asc.data[0].created_at <= result_asc.data[1].created_at <= result_asc.data[2].created_at
180171

181-
@pytest.mark.asyncio
182172
async def test_retrieve_file_success(self, files_provider, sample_text_file):
183173
"""Test successful file retrieval."""
184174
# Upload file
@@ -197,13 +187,11 @@ async def test_retrieve_file_success(self, files_provider, sample_text_file):
197187
assert retrieved_file.created_at == uploaded_file.created_at
198188
assert retrieved_file.expires_at == uploaded_file.expires_at
199189

200-
@pytest.mark.asyncio
201190
async def test_retrieve_file_not_found(self, files_provider):
202191
"""Test retrieving a non-existent file."""
203192
with pytest.raises(ValueError, match="File with id file-nonexistent not found"):
204193
await files_provider.openai_retrieve_file("file-nonexistent")
205194

206-
@pytest.mark.asyncio
207195
async def test_retrieve_file_content_success(self, files_provider, sample_text_file):
208196
"""Test successful file content retrieval."""
209197
# Upload file
@@ -217,13 +205,11 @@ async def test_retrieve_file_content_success(self, files_provider, sample_text_f
217205
# Verify content
218206
assert content.body == sample_text_file.content
219207

220-
@pytest.mark.asyncio
221208
async def test_retrieve_file_content_not_found(self, files_provider):
222209
"""Test retrieving content of a non-existent file."""
223210
with pytest.raises(ValueError, match="File with id file-nonexistent not found"):
224211
await files_provider.openai_retrieve_file_content("file-nonexistent")
225212

226-
@pytest.mark.asyncio
227213
async def test_delete_file_success(self, files_provider, sample_text_file):
228214
"""Test successful file deletion."""
229215
# Upload file
@@ -245,13 +231,11 @@ async def test_delete_file_success(self, files_provider, sample_text_file):
245231
with pytest.raises(ValueError, match=f"File with id {uploaded_file.id} not found"):
246232
await files_provider.openai_retrieve_file(uploaded_file.id)
247233

248-
@pytest.mark.asyncio
249234
async def test_delete_file_not_found(self, files_provider):
250235
"""Test deleting a non-existent file."""
251236
with pytest.raises(ValueError, match="File with id file-nonexistent not found"):
252237
await files_provider.openai_delete_file("file-nonexistent")
253238

254-
@pytest.mark.asyncio
255239
async def test_file_persistence_across_operations(self, files_provider, sample_text_file):
256240
"""Test that files persist correctly across multiple operations."""
257241
# Upload file
@@ -279,7 +263,6 @@ async def test_file_persistence_across_operations(self, files_provider, sample_t
279263
files_list = await files_provider.openai_list_files()
280264
assert len(files_list.data) == 0
281265

282-
@pytest.mark.asyncio
283266
async def test_multiple_files_operations(self, files_provider, sample_text_file, sample_json_file):
284267
"""Test operations with multiple files."""
285268
# Upload multiple files
@@ -302,7 +285,6 @@ async def test_multiple_files_operations(self, files_provider, sample_text_file,
302285
content = await files_provider.openai_retrieve_file_content(file2.id)
303286
assert content.body == sample_json_file.content
304287

305-
@pytest.mark.asyncio
306288
async def test_file_id_uniqueness(self, files_provider, sample_text_file):
307289
"""Test that each uploaded file gets a unique ID."""
308290
file_ids = set()
@@ -316,7 +298,6 @@ async def test_file_id_uniqueness(self, files_provider, sample_text_file):
316298
file_ids.add(uploaded_file.id)
317299
assert uploaded_file.id.startswith("file-")
318300

319-
@pytest.mark.asyncio
320301
async def test_file_no_filename_handling(self, files_provider):
321302
"""Test handling files with no filename."""
322303
file_without_name = MockUploadFile(b"content", None) # No filename
@@ -327,7 +308,6 @@ async def test_file_no_filename_handling(self, files_provider):
327308

328309
assert uploaded_file.filename == "uploaded_file" # Default filename
329310

330-
@pytest.mark.asyncio
331311
async def test_after_pagination_works(self, files_provider, sample_text_file):
332312
"""Test that 'after' pagination works correctly."""
333313
# Upload multiple files to test pagination

tests/unit/fixtures.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
# This source code is licensed under the terms described in the LICENSE file in
55
# the root directory of this source tree.
66

7-
import pytest_asyncio
7+
import pytest
88

99
from llama_stack.distribution.store.registry import CachedDiskDistributionRegistry, DiskDistributionRegistry
1010
from llama_stack.providers.utils.kvstore.config import SqliteKVStoreConfig
1111
from llama_stack.providers.utils.kvstore.sqlite import SqliteKVStoreImpl
1212

1313

14-
@pytest_asyncio.fixture(scope="function")
14+
@pytest.fixture(scope="function")
1515
async def sqlite_kvstore(tmp_path):
1616
db_path = tmp_path / "test_kv.db"
1717
kvstore_config = SqliteKVStoreConfig(db_path=db_path.as_posix())
@@ -20,14 +20,14 @@ async def sqlite_kvstore(tmp_path):
2020
yield kvstore
2121

2222

23-
@pytest_asyncio.fixture(scope="function")
23+
@pytest.fixture(scope="function")
2424
async def disk_dist_registry(sqlite_kvstore):
2525
registry = DiskDistributionRegistry(sqlite_kvstore)
2626
await registry.initialize()
2727
yield registry
2828

2929

30-
@pytest_asyncio.fixture(scope="function")
30+
@pytest.fixture(scope="function")
3131
async def cached_disk_dist_registry(sqlite_kvstore):
3232
registry = CachedDiskDistributionRegistry(sqlite_kvstore)
3333
await registry.initialize()

0 commit comments

Comments
 (0)