Njct is a bare-bones dependency injection utility. I wrote it some time ago for a small project.
without njct:
def fetch_news():
if config["news_source"] == "foo":
news = Foo().get_news()
elif config["news_source"] == "bar":
import bar
news = bar.get_news()with njct:
@njct.provider()
class News(Protocol):
def get_news(): ...
def fetch_news(provider: News.inject):
news = provider.get_news()
fetch_news(News()) # Automatically select an implementation
fetch_news(News["bar"]()) # or specify one manuallyTo learn more, see examples/json_provider.py
Njct is not production ready.
In particular, it assumes all implementations have the same __init__() signature, making custom config per implementation difficult (though, not impossible).
Njct is also non-intrusive. Most of it's features are type-level. In particular, njct does not interfere with instantiation or state at all. This may be underwhelming if you're used to the magic of proper DI frameworks.