lagom icon indicating copy to clipboard operation
lagom copied to clipboard

Allow auto resolving partial constructor arguments in lambda

Open sasq64 opened this issue 4 months ago • 2 comments

When you need to be explicit about just some constructor argument, it would be nice to not have to specify all other constructor arguments. Ie from the documentation

container[SomeClass] = lambda c: SomeClass(c[SomeOtherDep], "spinning")

could be changed to something like;

container[SomeClass] = lambda c: SomeClass(text="spinning", **c.resolve_args[SomeClass])

Convenient when your class has a lot of injections, and more importantly avoids the coupling of having to depend on all constructor arguments at bind time.

sasq64 avatar Aug 25 '25 08:08 sasq64

I realized that maybe this only works if the particular argument can not be resolved so it is guaranteed to not be included in what resolve_args() returns. But that is the standard use case.

Another, maybe cleaner way to solve it would be something like this;

container[SomeClass] = lambda c: (c[str] = "spinning")[SomeClass]

... not sure on the best syntax, but basically doing a local bind just for the lambda.

sasq64 avatar Aug 25 '25 10:08 sasq64

This is the current I hack I've come up with. Not great but it works;

@dataclass
class Resolver:
    parent: Container
    c: Container
    def setup[T](self, typ: Type[T]) -> T:
        self.c[typ] = typ
        self.parent[typ] = lambda : self.c.resolve(typ)

def bind[T](self: Container, typ: Type[T], t: T) -> Resolver:
    cc = self.clone()
    cc[typ] = t
    return Resolver(self, cc)


setattr(Container, "bind", bind)

# ...

# FileCache will be bound to img_cache whenever ImageGenerator needs to be resolved
container.bind(FileCache, img_cache).setup(ImageGenerator)
container.bind(FileCache, mp3_cache).setup(AudioGenerator)

sasq64 avatar Aug 28 '25 20:08 sasq64