Skip to content

Commit f6119fd

Browse files
committed
Use cached properties, match, string methods
1 parent c11c979 commit f6119fd

3 files changed

Lines changed: 53 additions & 47 deletions

File tree

apywire/runtime.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import asyncio
1111
import importlib
1212
import re
13+
from functools import cached_property
1314
from operator import itemgetter
1415
from typing import Awaitable, Callable, Protocol, cast, final
1516

@@ -108,17 +109,15 @@ def __getattr__(self, name: str) -> Accessor:
108109
f"'{type(self).__name__}' object has no attribute '{name}'"
109110
)
110111

111-
@property
112+
@cached_property
112113
def aio(self) -> "AioAccessor":
113114
"""Return a wrapper object providing async accessors.
114115
115116
Use `await wired.aio.name()` to obtain the instantiated value
116117
asynchronously. We use `aio` to avoid the reserved keyword
117118
`async` (so `wired.async` would be invalid syntax).
118119
"""
119-
if not hasattr(self, "_aio_accessor"):
120-
self._aio_accessor = AioAccessor(self)
121-
return self._aio_accessor
120+
return AioAccessor(self)
122121

123122
def _instantiate_attr(
124123
self,
@@ -274,12 +273,15 @@ def _resolve_runtime(
274273
# Call the accessor `self.name()` to get the runtime value.
275274
return cast(object, getattr(self, o.name)())
276275

277-
elif isinstance(o, dict):
278-
return {k: self._resolve_runtime(v, context) for k, v in o.items()}
279-
elif isinstance(o, list):
280-
return [self._resolve_runtime(v, context) for v in o]
281-
elif isinstance(o, tuple):
282-
return tuple(self._resolve_runtime(v, context) for v in o)
276+
match o:
277+
case dict():
278+
return {
279+
k: self._resolve_runtime(v, context) for k, v in o.items()
280+
}
281+
case list():
282+
return [self._resolve_runtime(v, context) for v in o]
283+
case tuple():
284+
return tuple(self._resolve_runtime(v, context) for v in o)
283285
return o
284286

285287
def _format_string_constant(

apywire/wiring.py

Lines changed: 38 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -289,26 +289,28 @@ def _extract_placeholder_name(self, s: str) -> str:
289289
Returns:
290290
The placeholder name without braces
291291
"""
292-
return s[len(PLACEHOLDER_START) : -len(PLACEHOLDER_END)]
292+
return s.removeprefix(PLACEHOLDER_START).removesuffix(PLACEHOLDER_END)
293293

294294
def _resolve(self, obj: _SpecValue) -> _ResolvedValue:
295295
"""Resolve placeholders into `_WiredRef` markers for runtime.
296296
297297
Replaces strings of the form "{name}" with a `_WiredRef(name)`
298298
for later resolution.
299299
"""
300-
if isinstance(obj, str):
301-
if self._is_placeholder(obj):
302-
ref_name = self._extract_placeholder_name(obj)
303-
return _WiredRef(ref_name)
304-
return obj
305-
elif isinstance(obj, dict):
306-
return {k: self._resolve(v) for k, v in obj.items()}
307-
elif isinstance(obj, list):
308-
return [self._resolve(v) for v in obj]
309-
elif isinstance(obj, tuple):
310-
return tuple(self._resolve(v) for v in obj)
311-
return obj
300+
match obj:
301+
case str():
302+
if self._is_placeholder(obj):
303+
ref_name = self._extract_placeholder_name(obj)
304+
return _WiredRef(ref_name)
305+
return obj
306+
case dict():
307+
return {k: self._resolve(v) for k, v in obj.items()}
308+
case list():
309+
return [self._resolve(v) for v in obj]
310+
case tuple():
311+
return tuple(self._resolve(v) for v in obj)
312+
case _:
313+
return obj
312314

313315
def _interpolate_placeholders(
314316
self,
@@ -354,16 +356,17 @@ def _find_placeholder_names(self, obj: _SpecValue) -> set[str]:
354356
Set of placeholder names found
355357
"""
356358
names: set[str] = set()
357-
if isinstance(obj, str):
358-
# Find all placeholders in the string (embedded or not)
359-
matches: list[str] = re.findall(self._placeholder_pattern, obj)
360-
names.update(matches)
361-
elif isinstance(obj, dict):
362-
for v in obj.values():
363-
names.update(self._find_placeholder_names(v))
364-
elif isinstance(obj, (list, tuple)):
365-
for v in obj:
366-
names.update(self._find_placeholder_names(v))
359+
match obj:
360+
case str():
361+
# Find all placeholders in the string (embedded or not)
362+
matches: list[str] = re.findall(self._placeholder_pattern, obj)
363+
names.update(matches)
364+
case dict():
365+
for v in obj.values():
366+
names.update(self._find_placeholder_names(v))
367+
case list() | tuple():
368+
for v in obj:
369+
names.update(self._find_placeholder_names(v))
367370
return names
368371

369372
def _topological_sort(
@@ -454,13 +457,16 @@ def _resolve_constant(
454457

455458
# Handle embedded placeholders via string interpolation
456459
return self._interpolate_placeholders(value, resolved, "constant")
457-
elif isinstance(value, dict):
458-
return {
459-
k: self._resolve_constant(v, resolved)
460-
for k, v in value.items()
461-
}
462-
elif isinstance(value, list):
463-
return [self._resolve_constant(v, resolved) for v in value]
464-
elif isinstance(value, tuple):
465-
return tuple(self._resolve_constant(v, resolved) for v in value)
460+
match value:
461+
case dict():
462+
return {
463+
k: self._resolve_constant(v, resolved)
464+
for k, v in value.items()
465+
}
466+
case list():
467+
return [self._resolve_constant(v, resolved) for v in value]
468+
case tuple():
469+
return tuple(
470+
self._resolve_constant(v, resolved) for v in value
471+
)
466472
return value

tests/test_edge_cases.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -195,15 +195,13 @@ def failing_maker() -> None:
195195

196196

197197
def test_wiring_aio_lazy_init() -> None:
198-
"""Test lazy initialization of aio property."""
198+
"""Test initialization of aio accessor with @cached_property."""
199199
from apywire import Wiring
200200

201201
wired = Wiring({}, thread_safe=False)
202-
# Access internal attribute to verify it's not there yet
203-
assert not hasattr(wired, "_aio_accessor")
204-
# Access property
202+
# Access property (cached_property handles caching automatically)
205203
aio = wired.aio
206-
assert hasattr(wired, "_aio_accessor")
204+
# Verify same object is returned (caching works)
207205
assert wired.aio is aio
208206

209207

0 commit comments

Comments
 (0)