@@ -185,6 +185,12 @@ async def sample_tools():
185185 ]
186186
187187
188+ @pytest .fixture
189+ def isolated_communication_protocols (monkeypatch ):
190+ """Isolates the CommunicationProtocol registry for each test."""
191+ monkeypatch .setattr (CommunicationProtocol , "communication_protocols" , {})
192+
193+
188194@pytest_asyncio .fixture
189195async def utcp_client ():
190196 """Fixture for UtcpClient."""
@@ -245,7 +251,7 @@ async def test_create_with_utcp_config(self):
245251 assert client .config is config
246252
247253 @pytest .mark .asyncio
248- async def test_register_manual (self , utcp_client , sample_tools ):
254+ async def test_register_manual (self , utcp_client , sample_tools , isolated_communication_protocols ):
249255 """Test registering a manual."""
250256 http_call_template = HttpCallTemplate (
251257 name = "test_manual" ,
@@ -286,7 +292,7 @@ async def test_register_manual_unsupported_type(self, utcp_client):
286292 await utcp_client .register_manual (call_template )
287293
288294 @pytest .mark .asyncio
289- async def test_register_manual_name_sanitization (self , utcp_client , sample_tools ):
295+ async def test_register_manual_name_sanitization (self , utcp_client , sample_tools , isolated_communication_protocols ):
290296 """Test that manual names are sanitized."""
291297 call_template = HttpCallTemplate (
292298 name = "test-manual.with/special@chars" ,
@@ -306,7 +312,7 @@ async def test_register_manual_name_sanitization(self, utcp_client, sample_tools
306312 assert result .manual .tools [0 ].name == "test_manual_with_special_chars.http_tool"
307313
308314 @pytest .mark .asyncio
309- async def test_deregister_manual (self , utcp_client , sample_tools ):
315+ async def test_deregister_manual (self , utcp_client , sample_tools , isolated_communication_protocols ):
310316 """Test deregistering a manual."""
311317 call_template = HttpCallTemplate (
312318 name = "test_manual" ,
@@ -341,7 +347,7 @@ async def test_deregister_nonexistent_manual(self, utcp_client):
341347 assert result is False
342348
343349 @pytest .mark .asyncio
344- async def test_call_tool (self , utcp_client , sample_tools ):
350+ async def test_call_tool (self , utcp_client , sample_tools , isolated_communication_protocols ):
345351 """Test calling a tool."""
346352 client = utcp_client
347353 call_template = HttpCallTemplate (
@@ -375,7 +381,7 @@ async def test_call_tool_nonexistent_manual(self, utcp_client):
375381 await client .call_tool ("nonexistent.tool" , {"param" : "value" })
376382
377383 @pytest .mark .asyncio
378- async def test_call_tool_nonexistent_tool (self , utcp_client , sample_tools ):
384+ async def test_call_tool_nonexistent_tool (self , utcp_client , sample_tools , isolated_communication_protocols ):
379385 """Test calling a nonexistent tool."""
380386 client = utcp_client
381387 call_template = HttpCallTemplate (
@@ -396,7 +402,7 @@ async def test_call_tool_nonexistent_tool(self, utcp_client, sample_tools):
396402 await client .call_tool ("test_manual.nonexistent" , {"param" : "value" })
397403
398404 @pytest .mark .asyncio
399- async def test_search_tools (self , utcp_client , sample_tools ):
405+ async def test_search_tools (self , utcp_client , sample_tools , isolated_communication_protocols ):
400406 """Test searching for tools."""
401407 client = utcp_client
402408 # Clear any existing manuals from other tests to ensure a clean slate
@@ -422,7 +428,7 @@ async def test_search_tools(self, utcp_client, sample_tools):
422428 assert "http" in results [0 ].name .lower () or "http" in results [0 ].description .lower ()
423429
424430 @pytest .mark .asyncio
425- async def test_get_required_variables_for_manual_and_tools (self , utcp_client ):
431+ async def test_get_required_variables_for_manual_and_tools (self , utcp_client , isolated_communication_protocols ):
426432 """Test getting required variables for a manual."""
427433 client = utcp_client
428434 call_template = HttpCallTemplate (
@@ -477,7 +483,7 @@ class TestUtcpClientManualCallTemplateLoading:
477483 """Test call template loading functionality."""
478484
479485 @pytest .mark .asyncio
480- async def test_load_manual_call_templates_from_file (self ):
486+ async def test_load_manual_call_templates_from_file (self , isolated_communication_protocols ):
481487 """Test loading call templates from a JSON file."""
482488 config_data = {
483489 "manual_call_templates" : [
@@ -536,7 +542,7 @@ async def test_load_manual_call_templates_invalid_json(self):
536542 os .unlink (temp_file )
537543
538544 @pytest .mark .asyncio
539- async def test_load_manual_call_templates_with_variables (self ):
545+ async def test_load_manual_call_templates_with_variables (self , isolated_communication_protocols ):
540546 """Test loading call templates with variable substitution."""
541547 config_data = {
542548 "variables" : {
@@ -663,7 +669,7 @@ async def test_empty_call_template_file(self):
663669 os .unlink (temp_file )
664670
665671 @pytest .mark .asyncio
666- async def test_register_manual_with_existing_name (self , utcp_client ):
672+ async def test_register_manual_with_existing_name (self , utcp_client , isolated_communication_protocols ):
667673 """Test registering a manual with an existing name should raise an error."""
668674 client = utcp_client
669675 template1 = HttpCallTemplate (
@@ -717,3 +723,36 @@ async def test_load_call_templates_wrong_format(self):
717723 await UtcpClient .create (config = temp_file )
718724 finally :
719725 os .unlink (temp_file )
726+
727+
728+ class TestToolSerialization :
729+ """Test Tool and JsonSchema serialization."""
730+
731+ def test_json_schema_serialization_by_alias (self ):
732+ """Test that JsonSchema serializes using field aliases."""
733+ schema = JsonSchema (
734+ schema_ = "http://json-schema.org/draft-07/schema#" ,
735+ id_ = "test_schema" ,
736+ type = "object" ,
737+ properties = {
738+ "param" : JsonSchema (type = "string" )
739+ }
740+ )
741+
742+ serialized_schema = schema .model_dump ()
743+
744+ assert "$schema" in serialized_schema
745+ assert "$id" in serialized_schema
746+ assert serialized_schema ["$schema" ] == "http://json-schema.org/draft-07/schema#"
747+ assert serialized_schema ["$id" ] == "test_schema"
748+
749+ def test_tool_serialization_by_alias (self , sample_tools ):
750+ """Test that Tool serializes its JsonSchema fields by alias."""
751+ tool = sample_tools [0 ]
752+ tool .inputs .schema_ = "http://json-schema.org/draft-07/schema#"
753+
754+ serialized_tool = tool .model_dump ()
755+
756+ assert "inputs" in serialized_tool
757+ assert "$schema" in serialized_tool ["inputs" ]
758+ assert serialized_tool ["inputs" ]["$schema" ] == "http://json-schema.org/draft-07/schema#"
0 commit comments