Description
I encountered a strange behaviour of Configuration depending on which source the Configuration object took data from during its initialisation. This leads to a radically different interface of this class for each case.
This is unintuitive and confusing and the documentation does not cover this aspect fully.
standard behaviour (loading config from dict):
import boto3
from dependency_injector import containers, providers
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
s3_client_factory = providers.Factory(
boto3.client,
"s3",
aws_access_key_id=config.aws.access_key_id,
aws_secret_access_key=config.aws.secret_access_key,
# Notice how here we get direct access to the configuration field data directly
# after initialising the config object. No additional action is needed!
)
behaviour specific to loading configurations from pydantic settings object:
import boto3
from dependency_injector import containers, providers
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
# But we can't do that here! Because our config object does not contain fields with configuration data
# To fill the fields of our object we will have to make one more call:
config.load()
# which now isn't working and throws an error, lol:
# https://github.com/ets-labs/python-dependency-injector/issues/726
# The second option is to make another call that will return a pydantic settings object:
config, = config.get_pydantic_settings()
s3_client_factory = providers.Factory(
boto3.client,
"s3",
aws_access_key_id=config.aws.access_key_id,
aws_secret_access_key=config.aws.secret_access_key,
)
behaviour specific to loading configurations from INI file:
import boto3
from dependency_injector import containers, providers
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
# But we can't do that here! Because our config object does not contain fields with configuration data
# To fill the fields of our object we will have to make one more call:
config.load()
# which now isn't working and throws an error, lol:
# https://github.com/ets-labs/python-dependency-injector/issues/726
# The second option is to make another call that will return a raw config object:
config, = config.get_ini_files()
s3_client_factory = providers.Factory(
boto3.client,
"s3",
aws_access_key_id=config.aws.access_key_id,
aws_secret_access_key=config.aws.secret_access_key,
)
behaviour specific to loading configurations from YAML file:
import boto3
from dependency_injector import containers, providers
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
# But we can't do that here! Because our config object does not contain fields with configuration data
# To fill the fields of our object we will have to make one more call:
config.load()
# which now isn't working and throws an error, lol:
# https://github.com/ets-labs/python-dependency-injector/issues/726
# The second option is to make another call that will return a raw config object:
config, = config.get_yaml_files()
s3_client_factory = providers.Factory(
boto3.client,
"s3",
aws_access_key_id=config.aws.access_key_id,
aws_secret_access_key=config.aws.secret_access_key,
)
And so on. I think the principle is clear.....
Summary:
As you can see, a non-unique interface leads to sub-optimal code, full of extra calls and actions that could have been avoided.
Can you bring the Configuration
to a consistent behaviour and a unified interface?