Skip to content

Commit 9d164bd

Browse files
committed
feat: add typemap apply recursive helpers
1 parent 274bff4 commit 9d164bd

File tree

1 file changed

+76
-1
lines changed

1 file changed

+76
-1
lines changed

rath/links/parsing.py

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,82 @@
11
from rath.links.base import ContinuationLink
22
from rath.operation import GraphQLResult, Operation
3-
from typing import AsyncIterator
3+
from typing import Any, AsyncIterator, Awaitable, Callable, Dict, Tuple, Type, Union
44
from rath.errors import NotComposedError
5+
import asyncio
6+
7+
8+
async def apply_recursive(
9+
func, obj, typeguard: Union[Type[Any], Tuple[Type[Any], ...]]
10+
) -> Any: # type: ignore
11+
"""
12+
Recursively applies an asynchronous function to elements in a nested structure.
13+
14+
Args:
15+
func (callable): The asynchronous function to apply.
16+
obj (any): The nested structure (dict, list, tuple, etc.) to process.
17+
typeguard (type): The type of elements to apply the function to.
18+
19+
Returns:
20+
any: The nested structure with the function applied to elements of the specified type.
21+
"""
22+
if isinstance(
23+
obj, dict
24+
): # If obj is a dictionary, recursively apply to each key-value pair
25+
return {k: await apply_recursive(func, v, typeguard) for k, v in obj.items()} # type: ignore
26+
elif isinstance(obj, list): # If obj is a list, recursively apply to each element
27+
return await asyncio.gather(
28+
*[apply_recursive(func, elem, typeguard) for elem in obj]
29+
) # type: ignore
30+
elif isinstance(
31+
obj, tuple
32+
): # If obj is a tuple, recursively apply to each element and convert back to tuple
33+
return tuple(
34+
await asyncio.gather(
35+
*[apply_recursive(func, elem, typeguard) for elem in obj]
36+
) # type: ignore
37+
)
38+
elif isinstance(obj, typeguard):
39+
return await func(obj) # type: ignore
40+
else: # If obj is not a dict, list, tuple, or matching the typeguard, return it as is
41+
return obj # type: ignore
42+
43+
44+
async def apply_typemap_recursive(
45+
obj, typefuncs: Dict[Type[Any], Callable[[Type[Any]], Awaitable[Any]]]
46+
) -> Any: # type: ignore
47+
"""
48+
Recursively applies an asynchronous function to elements in a nested structure.
49+
50+
Args:
51+
func (callable): The asynchronous function to apply.
52+
obj (any): The nested structure (dict, list, tuple, etc.) to process.
53+
typeguard (type): The type of elements to apply the function to.
54+
55+
Returns:
56+
any: The nested structure with the function applied to elements of the specified type.
57+
"""
58+
if isinstance(
59+
obj, dict
60+
): # If obj is a dictionary, recursively apply to each key-value pair
61+
return {k: await apply_typemap_recursive(v, typefuncs) for k, v in obj.items()} # type: ignore
62+
elif isinstance(obj, list): # If obj is a list, recursively apply to each element
63+
return await asyncio.gather(
64+
*[apply_typemap_recursive(elem, typefuncs) for elem in obj]
65+
) # type: ignore
66+
elif isinstance(
67+
obj, tuple
68+
): # If obj is a tuple, recursively apply to each element and convert back to tuple
69+
return tuple(
70+
await asyncio.gather(
71+
*[apply_typemap_recursive(elem, typefuncs) for elem in obj]
72+
) # type: ignore
73+
)
74+
else:
75+
applyer = typefuncs.get(type(obj), None)
76+
if applyer:
77+
return await applyer(obj) # type: ignore
78+
else:
79+
return obj # type: ignore
580

681

782
class ParsingLink(ContinuationLink):

0 commit comments

Comments
 (0)