Skip to content

Commit ac2df3c

Browse files
author
Datata1
committed
test: fix ci
1 parent 81f9a2e commit ac2df3c

File tree

5 files changed

+86
-3
lines changed

5 files changed

+86
-3
lines changed

src/codesphere/core/handler.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from typing import Any, List, Optional, Type, get_args, get_origin
44

55
import httpx
6-
from pydantic import BaseModel, PrivateAttr, ValidationError
6+
from pydantic import BaseModel, PrivateAttr, RootModel, ValidationError
77
from pydantic.fields import FieldInfo
88

99
from ..http_client import APIHttpClient
@@ -93,6 +93,14 @@ async def _make_request(
9393
def _inject_client_into_model(self, model_instance: BaseModel) -> BaseModel:
9494
if hasattr(model_instance, "_http_client"):
9595
model_instance._http_client = self.http_client
96+
97+
if isinstance(model_instance, RootModel) and isinstance(
98+
model_instance.root, list
99+
):
100+
for item in model_instance.root:
101+
if hasattr(item, "_http_client"):
102+
item._http_client = self.http_client
103+
96104
return model_instance
97105

98106
async def _parse_and_validate_response(

tests/core/test_handler.py

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import pytest
2-
from typing import Optional
2+
from typing import Optional, List
33
from unittest.mock import MagicMock
44

5-
from pydantic import BaseModel, Field, PrivateAttr
5+
from pydantic import BaseModel, Field, PrivateAttr, RootModel
66

77
from codesphere.core.handler import _APIOperationExecutor, APIRequestHandler
88
from codesphere.core.operations import APIOperation, AsyncCallable
@@ -147,3 +147,35 @@ class ModelWithClient(BaseModel):
147147
instance = ModelWithClient(id=1)
148148
handler._inject_client_into_model(instance)
149149
assert instance._http_client is mock_executor._http_client
150+
151+
@pytest.mark.asyncio
152+
async def test_inject_client_into_root_model_items(
153+
self, mock_executor, sample_operation
154+
):
155+
"""RootModel containers should have _http_client injected into each item in .root"""
156+
mock_client = MagicMock()
157+
mock_client.request = MagicMock()
158+
mock_executor._http_client = mock_client
159+
160+
handler = APIRequestHandler(
161+
executor=mock_executor,
162+
operation=sample_operation,
163+
kwargs={},
164+
)
165+
166+
class ItemWithClient(BaseModel):
167+
id: int
168+
_http_client: Optional[MagicMock] = PrivateAttr(default=None)
169+
170+
class ResourceList(RootModel[List[ItemWithClient]]):
171+
_http_client: Optional[MagicMock] = PrivateAttr(default=None)
172+
173+
item1 = ItemWithClient(id=1)
174+
item2 = ItemWithClient(id=2)
175+
resource_list = ResourceList(root=[item1, item2])
176+
177+
handler._inject_client_into_model(resource_list)
178+
179+
assert resource_list._http_client is mock_executor._http_client
180+
for item in resource_list.root:
181+
assert item._http_client is mock_executor._http_client

tests/resources/team/domain/test_domain.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,20 @@ async def test_list_domains(self, domain_manager, sample_domain_data):
3030
assert len(result) == 1
3131
assert isinstance(result[0], Domain)
3232

33+
@pytest.mark.asyncio
34+
async def test_list_items_have_http_client_injected(
35+
self, mock_http_client_for_resource, sample_domain_data
36+
):
37+
"""Items returned from list() should have _http_client injected."""
38+
mock_client = mock_http_client_for_resource([sample_domain_data])
39+
manager = TeamDomainManager(http_client=mock_client, team_id=12345)
40+
41+
result = await manager.list()
42+
43+
for domain in result:
44+
assert hasattr(domain, "_http_client")
45+
assert domain._http_client is not None
46+
3347
@pytest.mark.asyncio
3448
async def test_get_domain(self, mock_http_client_for_resource, sample_domain_data):
3549
"""Get domain should return a single Domain model."""

tests/resources/team/test_team.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,21 @@ async def test_list_teams(self, teams_resource_factory, sample_team_list_data):
1717
assert len(result) == 2
1818
assert all(isinstance(team, Team) for team in result)
1919

20+
@pytest.mark.asyncio
21+
async def test_list_items_have_http_client_injected(
22+
self, teams_resource_factory, sample_team_list_data
23+
):
24+
"""Items returned from list() should have _http_client injected."""
25+
resource, mock_client = teams_resource_factory(sample_team_list_data)
26+
27+
result = await resource.list()
28+
29+
for team in result:
30+
assert hasattr(team, "_http_client")
31+
assert team._http_client is not None
32+
# Verify sub-resources are accessible without "detached model" error
33+
_ = team.domains
34+
2035
@pytest.mark.asyncio
2136
async def test_list_teams_empty(self, teams_resource_factory):
2237
"""List teams should handle empty response."""

tests/resources/workspace/test_workspace.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,20 @@ async def test_create_workspace(
6363
assert isinstance(result, Workspace)
6464
mock_client.request.assert_awaited_once()
6565

66+
@pytest.mark.asyncio
67+
async def test_list_items_have_http_client_injected(
68+
self, workspaces_resource_factory, sample_workspace_list_data
69+
):
70+
"""Items returned from list() should have _http_client injected and be able to call instance methods."""
71+
resource, mock_client = workspaces_resource_factory(sample_workspace_list_data)
72+
73+
result = await resource.list(team_id=12345)
74+
75+
for workspace in result:
76+
assert hasattr(workspace, "_http_client")
77+
assert workspace._http_client is not None
78+
_ = workspace.env_vars
79+
6680

6781
class TestWorkspaceModel:
6882
"""Tests for the Workspace model and its methods."""

0 commit comments

Comments
 (0)