Get rid of manual consumer fn unwrapping for callgraph generation
This commit is contained in:
@@ -14,19 +14,16 @@ class GraphWalker:
|
|||||||
from_types: frozenset[type],
|
from_types: frozenset[type],
|
||||||
consumer_fn: Callable) -> Optional[Callgraph]:
|
consumer_fn: Callable) -> Optional[Callgraph]:
|
||||||
|
|
||||||
into_types: frozenset[type] = extract_func_argtypes(consumer_fn)
|
|
||||||
|
|
||||||
branches: frozenset[Callgraph] = frozenset()
|
branches: frozenset[Callgraph] = frozenset()
|
||||||
|
|
||||||
for into_type in into_types:
|
# Хак, чтобы вынудить систему поставить первым преобразованием требуемый consumer
|
||||||
cg = cls.generate_callgraph_singletype(injectors, from_types, into_type)
|
# Новый TypeAliasType каждый раз будет иметь эксклюзивный хэш, вне зависимости от содержимого
|
||||||
if cg is None:
|
# При этом, TypeAliasType также выступает в роли ключа преобразования
|
||||||
return None
|
# Это позволяет переложить обработку аргументов consumer на внутренние механизмы построения графа преобразований
|
||||||
branches |= {cg}
|
type _tmp_type_for_consumer = object
|
||||||
variant = CallgraphVariant(
|
injectors |= set(ConversionPoint.from_fn(consumer_fn, _tmp_type_for_consumer))
|
||||||
ConversionPoint.from_fn(consumer_fn, NoneType)[0],
|
|
||||||
branches, frozenset())
|
return cls.generate_callgraph_singletype(injectors, from_types, _tmp_type_for_consumer)
|
||||||
return Callgraph(frozenset({variant}))
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_callgraph_singletype(cls,
|
def generate_callgraph_singletype(cls,
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class ConversionPoint:
|
|||||||
return inspect.iscoroutinefunction(self.fn) or is_async_context_manager_factory(self.fn)
|
return inspect.iscoroutinefunction(self.fn) or is_async_context_manager_factory(self.fn)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_fn(cls, func: Callable, rettype: Optional[type] = None):
|
def from_fn(cls, func: Callable, rettype: Optional[type] = None) -> list[ConversionPoint]:
|
||||||
if rettype is None:
|
if rettype is None:
|
||||||
annot = get_type_hints(func)
|
annot = get_type_hints(func)
|
||||||
rettype = annot.get('return')
|
rettype = annot.get('return')
|
||||||
|
|||||||
@@ -38,3 +38,33 @@ def test_basic():
|
|||||||
fn2 = repo.get_conversion((int,), consumer, force_commutative=True, force_async=False, allow_async=False)
|
fn2 = repo.get_conversion((int,), consumer, force_commutative=True, force_async=False, allow_async=False)
|
||||||
dep = fn2(123)
|
dep = fn2(123)
|
||||||
assert dep == 123
|
assert dep == 123
|
||||||
|
|
||||||
|
|
||||||
|
def test_union_deps():
|
||||||
|
repo = ConvRepo()
|
||||||
|
|
||||||
|
@repo.mark_injector()
|
||||||
|
def b_to_a(b: B) -> A:
|
||||||
|
return A(int(b.b))
|
||||||
|
|
||||||
|
@repo.mark_injector()
|
||||||
|
def a_to_b(a: A) -> B:
|
||||||
|
return B(float(a.a))
|
||||||
|
|
||||||
|
@repo.mark_injector()
|
||||||
|
def int_to_a(i: int) -> A:
|
||||||
|
return A(i)
|
||||||
|
|
||||||
|
def consumer(dep: A | B) -> int:
|
||||||
|
if isinstance(dep, A):
|
||||||
|
return dep.a
|
||||||
|
else:
|
||||||
|
return int(dep.b)
|
||||||
|
|
||||||
|
fn1 = repo.get_conversion((B,), consumer, force_commutative=True, force_async=False, allow_async=False)
|
||||||
|
dep = fn1(B(42.1))
|
||||||
|
assert dep == 42
|
||||||
|
|
||||||
|
fn2 = repo.get_conversion((int,), consumer, force_commutative=True, force_async=False, allow_async=False)
|
||||||
|
dep = fn2(123)
|
||||||
|
assert dep == 123
|
||||||
|
|||||||
Reference in New Issue
Block a user