diff --git a/src/a2a/_base.py b/src/a2a/_base.py index fc100442..6c50734c 100644 --- a/src/a2a/_base.py +++ b/src/a2a/_base.py @@ -1,7 +1,3 @@ -import warnings - -from typing import Any, ClassVar - from pydantic import BaseModel, ConfigDict from pydantic.alias_generators import to_camel @@ -40,64 +36,3 @@ class A2ABaseModel(BaseModel): serialize_by_alias=True, alias_generator=to_camel_custom, ) - - # Cache for the alias -> field_name mapping. - # It starts as None and is populated on first access. - _alias_to_field_name_map: ClassVar[dict[str, str] | None] = None - - @classmethod - def _get_alias_map(cls) -> dict[str, str]: - """Lazily builds and returns the alias-to-field-name mapping for the class. - - The map is cached on the class object to avoid re-computation. - """ - if cls._alias_to_field_name_map is None: - cls._alias_to_field_name_map = { - field.alias: field_name - for field_name, field in cls.model_fields.items() - if field.alias is not None - } - return cls._alias_to_field_name_map - - def __setattr__(self, name: str, value: Any) -> None: - """Allow setting attributes via their camelCase alias.""" - # Get the map and find the corresponding snake_case field name. - field_name = type(self)._get_alias_map().get(name) # noqa: SLF001 - - if field_name and field_name != name: - # An alias was used, issue a warning. - warnings.warn( - ( - f"Setting field '{name}' via its camelCase alias is deprecated and will be removed in version 0.3.0 " - f"Use the snake_case name '{field_name}' instead." - ), - DeprecationWarning, - stacklevel=2, - ) - - # If an alias was used, field_name will be set; otherwise, use the original name. - super().__setattr__(field_name or name, value) - - def __getattr__(self, name: str) -> Any: - """Allow getting attributes via their camelCase alias.""" - # Get the map and find the corresponding snake_case field name. - field_name = type(self)._get_alias_map().get(name) # noqa: SLF001 - - if field_name and field_name != name: - # An alias was used, issue a warning. - warnings.warn( - ( - f"Accessing field '{name}' via its camelCase alias is deprecated and will be removed in version 0.3.0 " - f"Use the snake_case name '{field_name}' instead." - ), - DeprecationWarning, - stacklevel=2, - ) - - # If an alias was used, retrieve the actual snake_case attribute. - return getattr(self, field_name) - - # If it's not a known alias, it's a genuine missing attribute. - raise AttributeError( - f"'{type(self).__name__}' object has no attribute '{name}'" - ) diff --git a/src/a2a/utils/proto_utils.py b/src/a2a/utils/proto_utils.py index ddaa4f9e..f4d9e70e 100644 --- a/src/a2a/utils/proto_utils.py +++ b/src/a2a/utils/proto_utils.py @@ -363,6 +363,12 @@ def security_scheme( flows=cls.oauth2_flows(scheme.root.flows), ) ) + if isinstance(scheme.root, types.MutualTLSSecurityScheme): + return a2a_pb2.SecurityScheme( + mtls_security_scheme=a2a_pb2.MutualTlsSecurityScheme( + description=scheme.root.description, + ) + ) return a2a_pb2.SecurityScheme( open_id_connect_security_scheme=a2a_pb2.OpenIdConnectSecurityScheme( description=scheme.root.description, diff --git a/tests/test_types.py b/tests/test_types.py index c7e4efba..73e6af7b 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -1556,7 +1556,11 @@ def test_use_get_task_push_notification_params_for_request() -> None: ) -def test_camelCase() -> None: +def test_camelCase_access_raises_attribute_error() -> None: + """ + Tests that accessing or setting fields via their camelCase alias + raises an AttributeError. + """ skill = AgentSkill( id='hello_world', name='Returns hello world', @@ -1565,6 +1569,7 @@ def test_camelCase() -> None: examples=['hi', 'hello world'], ) + # Initialization with camelCase still works due to Pydantic's populate_by_name config agent_card = AgentCard( name='Hello World Agent', description='Just a hello world agent', @@ -1577,21 +1582,33 @@ def test_camelCase() -> None: supportsAuthenticatedExtendedCard=True, # type: ignore ) - # Test setting an attribute via camelCase alias - with pytest.warns( - DeprecationWarning, - match="Setting field 'supportsAuthenticatedExtendedCard'", + # --- Test that using camelCase aliases raises errors --- + + # Test setting an attribute via camelCase alias raises AttributeError + with pytest.raises( + ValueError, + match='"AgentCard" object has no field "supportsAuthenticatedExtendedCard"', ): agent_card.supportsAuthenticatedExtendedCard = False - # Test getting an attribute via camelCase alias - with pytest.warns( - DeprecationWarning, match="Accessing field 'defaultInputModes'" + # Test getting an attribute via camelCase alias raises AttributeError + with pytest.raises( + AttributeError, + match="'AgentCard' object has no attribute 'defaultInputModes'", ): - default_input_modes = agent_card.defaultInputModes + _ = agent_card.defaultInputModes - # Assert the functionality still works as expected + # --- Test that using snake_case names works correctly --- + + # The value should be unchanged because the camelCase setattr failed + assert agent_card.supports_authenticated_extended_card is True + + # Now, set it correctly using the snake_case name + agent_card.supports_authenticated_extended_card = False assert agent_card.supports_authenticated_extended_card is False + + # Get the attribute correctly using the snake_case name + default_input_modes = agent_card.default_input_modes assert default_input_modes == ['text'] assert agent_card.default_input_modes == ['text']