Summary
renku-data-services uses multiple configuration objects for various aspects and features and some of them have default values.
Currently, most of these default values are used at the "point of use" where the configuration is required. This can be a bit surprising as reading the implementation of the configuration shows one reality (i.e. configuration is set to None because no environment variable was set) VS something is happening (i.e. builds using the default value for the build strategy although the configuration code does not indicate that).
While these defaults do make sense, having them handled in two separate places makes things harder to reason about and, sometimes, tests.
Suggestion
Move the default value handling into the configuration classes and maybe make them frozen as I don't think they are meant to be changed at run time.
Example
@dataclass
class BuildsConfig:
"""Configuration for container image builds."""
build_output_image_prefix: str
@classmethod
def from_env(cls) -> "BuildsConfig":
"""Create a config from environment variables."""
build_builder_image = os.environ.get("BUILD_BUILDER_IMAGE", constants.BUILD_DEFAULT_BUILDER_IMAGE)
This would avoid having:
builder_image = self.builds_config.build_builder_image or constants.BUILD_DEFAULT_BUILDER_IMAGE
in the db.py file
Since this is a setting that is technically mandatory we could even have:
@dataclass
class BuildsConfig:
"""Configuration for container image builds."""
build_output_image_prefix: str
@classmethod
def from_env(cls) -> "BuildsConfig":
"""Create a config from environment variables."""
build_builder_image = os.environ.get("BUILD_BUILDER_IMAGE", constants.BUILD_DEFAULT_BUILDER_IMAGE) or constants.BUILD_DEFAULT_BUILDER_IMAGE
So even in case of empty environment variable we would be good to go.
Since that would be a repeating pattern:
def get_with_default(haystack: dict[str, str], needle: str, default: str) -> str:
"""Returns the default value if needle is not found or the value is None/empty."""
return haystack.get(needle, default) or default
@dataclass
class BuildsConfig:
"""Configuration for container image builds."""
build_output_image_prefix: str
@classmethod
def from_env(cls) -> "BuildsConfig":
"""Create a config from environment variables."""
build_builder_image = get_with_default(os.environ, "BUILD_BUILDER_IMAGE", constants.BUILD_DEFAULT_BUILDER_IMAGE)
Summary
renku-data-servicesuses multiple configuration objects for various aspects and features and some of them have default values.Currently, most of these default values are used at the "point of use" where the configuration is required. This can be a bit surprising as reading the implementation of the configuration shows one reality (i.e. configuration is set to None because no environment variable was set) VS something is happening (i.e. builds using the default value for the build strategy although the configuration code does not indicate that).
While these defaults do make sense, having them handled in two separate places makes things harder to reason about and, sometimes, tests.
Suggestion
Move the default value handling into the configuration classes and maybe make them frozen as I don't think they are meant to be changed at run time.
Example
This would avoid having:
in the
db.pyfileSince this is a setting that is technically mandatory we could even have:
So even in case of empty environment variable we would be good to go.
Since that would be a repeating pattern: