ets-labs/python-dependency-injector

AttributeError: 'Config' object has no attribute 'get' Pydantic Config

Closed this issue · 3 comments

class Config(BaseSettings):
    server_id: int
    model_config = SettingsConfigDict(env_nested_delimiter="__")


@lru_cache
def get_config()->Config:
    return Config()
class Services(containers.DeclarativeContainer):
    config: Config = providers.Configuration()
    gateways = providers.DependenciesContainer()
    repositories = providers.DependenciesContainer()
    cache = providers.Factory(CacheService, memcache_repository=repositories.memcache)
 
class MainApplication(containers.DeclarativeContainer):
    args = providers.Callable(parse_arguments)
   config = providers.Configuration()
    core = providers.Container(Core)
    gateways = providers.Container(Gateways, config=config)
    repositories = providers.Container(Repositories, gateways=gateways, config=config)
    services = providers.Container(Services, config=config, gateways=gateways, repositories=repositories)
if __name__ == "__main__":
    config = get_config()
    application = MainApplication(config=config)
    application.core.init_resources()

What are you doing is roughly equivalent to the following:

if __name__ == "__main__":
    config = get_config()
    application = MainApplication()
    application.override_providers(config=config)
    application.core.init_resources()

But you want:

if __name__ == "__main__":
    config = get_config()
    application = MainApplication()
    application.config.from_pydantic(config)
    application.core.init_resources()

For details, refer to the documentation:

What are you doing is roughly equivalent to the following:

if name == "main":
config = get_config()
application = MainApplication()
application.override_providers(config=config)
application.core.init_resources()
But you want:

if name == "main":
config = get_config()
application = MainApplication()
application.config.from_pydantic(config)
application.core.init_resources()
For details, refer to the documentation:

why should I call a variable as a function instead of passing a parameter ?

class Gateways(containers.DeclarativeContainer):
    config: Config = providers.Configuration()
    database = providers.Singleton(Database, db_url=config.database.url)
    memcache_client = providers.ThreadLocalSingleton(MemCacheClient, server=(config.memcache_client.host,
                                                                             config.memcache_client.port))
class Gateways(containers.DeclarativeContainer):
    config: Config = providers.Configuration()
    database = providers.Singleton(Database, db_url=config.database.url())
    memcache_client = providers.ThreadLocalSingleton(MemCacheClient, server=(config.memcache_client.host(),
                                                                             config.memcache_client.port()))

why should I call a variable as a function instead of passing a parameter ?

You don't. If you call ConfigurationOption here, you'll get None because your config is not loaded yet.

This is correct version:

class Gateways(containers.DeclarativeContainer):
    config = providers.Configuration()
    database = providers.Singleton(Database, db_url=config.database.url)
    memcache_client = providers.ThreadLocalSingleton(
        MemCacheClient,
        server=providers.List(
            config.memcache_client.host,
            config.memcache_client.port,
        ),
    )