Skip to content
This repository was archived by the owner on Jan 10, 2023. It is now read-only.
This repository was archived by the owner on Jan 10, 2023. It is now read-only.

[Enhancement] Allow calling methods and injecting their parameters #62

@cal-pratt

Description

@cal-pratt

Problem

A lot of times I just want to call a function which has arguments that need to be injected. In order to call the function like thisI basically have to create a wrapper class for the function which specifies the arguments required, and then call some method on the wrapper to pass in the injected arguments. This works but is a lot of boilerplate. e.g.

def foobar(foo: Foo) -> int:
    ...
    
class FoobarWrapper:
    def __init__(foo: Foo) -> None:
        self.foo = foo
    def call(self): -> int:
        return foobar(self.foo)

obj_graph = new_object_graph()
print("foobar returns:", obj_graph.provide(FoobarWrapper).call())

Solution

I want to be able to call functions with arbitrary parameters and have pinject construct all of the necessary inputs for me.
It seems like the library is set up nicely to support this, however, it requires me to access private members of the ObjectGraph instance.

Proof of Concept

After browsing through the implementation, I've been able to achieve my goal with the following 3 line hack. I provide a helper method around it to keep things simple and type-safe.

from typing import TypeVar, Callable
from pinject.object_graph import ObjectGraph

T = TypeVar("T")


def inject_func(obj_graph: ObjectGraph, func: Callable[..., T]) -> T:
    context = obj_graph._injection_context_factory.new(func)
    args, kwargs = obj_graph._obj_provider.get_injection_pargs_kwargs(func, context, [], {})
    return func(*args, **kwargs)

And here's how you'd call it:

class Bar:
    def __init__(self) -> None:
        self.a = 1


class Foo:
    def __init__(self, bar: Bar) -> None:
        self.bar = bar


def foobar(foo: Foo) -> int:
    return foo.bar.a


obj_graph = new_object_graph()
print("foobar returns:", inject_func(obj_graph, foobar))
foobar returns: 1

Desired Implementation

What I'd like to see is something like this at the same level as ObjectGraph.provide. Maybe ObjectGraph.invoke

obj_graph = new_object_graph()
print("foobar returns:", obj_graph.invoke(foobar))

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions