punq icon indicating copy to clipboard operation
punq copied to clipboard

Enhancement: Register for Union Types

Open Zylence opened this issue 2 months ago • 0 comments

Hi, 

I have been using the library for a while now and must say I quite like it.  I initially picked it because it felt similar to dotnets DI containers. But with that comes a "weakness". Like in dotnet if we want to register classes for multiple types, we need to do that manually by resolving the previously registered instance. 

In C# specifically, this would need to happen if we used the IHostedService interface but still needed access to the service itself in other parts:

services.AddSingleton<MyHostedService>();  //required for DI in other places, service manager or watchdog for example
services.AddSingleton<IHostedService>(sp => sp.GetRequiredService<MyHostedService>());

I have faced this in similar forms with this lib now and figured since Pythons typing is more lenient with us, we may be able to enhance the current behavior by allowing subscriptions to union types; see toy example:

from typing import get_args
from punq import Container, Scope
from abc import ABC

class IA(ABC): pass
class IB(ABC): pass
class B(IB, IA): pass

c = Container()

# current approach
c.register(IA, B, scope=Scope.singleton)
c.register(IB, instance=c.resolve(IA), scope=Scope.singleton) # repeat x times for every interface we need to register for

# suggested feature / shorthand
# c.register(IA | IB, B, scope=Scope.singleton)

# internally we could use get_args to get the separate keys to register for:
# print(get_args(IA |IB))

a = c.resolve(IA)
b = c.resolve(IB)
assert a == b

If you need a more real-world scenario, I can provide an anonymized one from a private project. 

Let me know what you think of the idea. If you like it / have no objections, I'd offer to attempt implementation. 

Regards, Julian

Zylence avatar Oct 26 '25 23:10 Zylence