Skip to content

Commit 58de949

Browse files
committed
fix: allow camelCase for accessing
Signed-off-by: Frost Ming <me@frostming.com>
1 parent d77ea0e commit 58de949

File tree

4 files changed

+21
-5
lines changed

4 files changed

+21
-5
lines changed

scripts/gen_schema.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import re
77
import subprocess
88
import sys
9+
import textwrap
910
from collections.abc import Callable
1011
from dataclasses import dataclass
1112
from pathlib import Path
@@ -327,11 +328,20 @@ def _ensure_custom_base_model(content: str) -> str:
327328
if not has_config:
328329
new_imports.append("ConfigDict")
329330
lines[idx] = "from pydantic import " + ", ".join(new_imports)
331+
to_insert = textwrap.dedent("""\
332+
class BaseModel(_BaseModel):
333+
model_config = ConfigDict(populate_by_name=True)
334+
335+
def __getattr__(self, item: str) -> Any:
336+
if item.lower() != item:
337+
snake_cased = "".join("_" + c.lower() if c.isupper() and i > 0 else c.lower() for i, c in enumerate(item))
338+
return getattr(self, snake_cased)
339+
raise AttributeError(f"'{type(self).__name__}' object has no attribute '{item}'")
340+
""")
330341
insert_idx = idx + 1
331342
lines.insert(insert_idx, "")
332-
lines.insert(insert_idx + 1, "class BaseModel(_BaseModel):")
333-
lines.insert(insert_idx + 2, " model_config = ConfigDict(populate_by_name=True)")
334-
lines.insert(insert_idx + 3, "")
343+
for offset, line in enumerate(to_insert.splitlines(), 1):
344+
lines.insert(insert_idx + offset, line)
335345
break
336346
return "\n".join(lines) + "\n"
337347

src/acp/agent/connection.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def __init__(
6161
agent = to_agent(cast(Client, self)) if callable(to_agent) else to_agent
6262
if not isinstance(input_stream, asyncio.StreamWriter) or not isinstance(output_stream, asyncio.StreamReader):
6363
raise TypeError(_AGENT_CONNECTION_ERROR)
64-
handler = build_agent_router(agent) # type: ignore[arg-type]
64+
handler = build_agent_router(cast(Agent, agent))
6565
self._conn = Connection(handler, input_stream, output_stream, listening=listening, **connection_kwargs)
6666
if on_connect := getattr(agent, "on_connect", None):
6767
on_connect(self)

src/acp/client/connection.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def __init__(
5656
if not isinstance(input_stream, asyncio.StreamWriter) or not isinstance(output_stream, asyncio.StreamReader):
5757
raise TypeError(_CLIENT_CONNECTION_ERROR)
5858
client = to_client(cast(Agent, self)) if callable(to_client) else to_client
59-
handler = build_client_router(client) # type: ignore[arg-type]
59+
handler = build_client_router(cast(Client, client))
6060
self._conn = Connection(handler, input_stream, output_stream, **connection_kwargs)
6161
if on_connect := getattr(client, "on_connect", None):
6262
on_connect(self)

src/acp/schema.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@
1919
class BaseModel(_BaseModel):
2020
model_config = ConfigDict(populate_by_name=True)
2121

22+
def __getattr__(self, item: str) -> Any:
23+
if item.lower() != item:
24+
snake_cased = "".join("_" + c.lower() if c.isupper() and i > 0 else c.lower() for i, c in enumerate(item))
25+
return getattr(self, snake_cased)
26+
raise AttributeError(f"'{type(self).__name__}' object has no attribute '{item}'")
27+
2228

2329
class Jsonrpc(Enum):
2430
field_2_0 = "2.0"

0 commit comments

Comments
 (0)