from typing import Generic, Optional, TypeVar
from q2_sdk.models.recursive_encoder import JsonSerializable
T = TypeVar("T")
[docs]
class DbConfig(Generic[T], JsonSerializable):
"""Written to database during ``q2 install`` or ``q2 update_installed``"""
def __init__(
self,
name: str,
default: T,
description: Optional[str] = None,
required: bool = True,
):
"""
:param name: Key written to the database
:param default: Suggested value to write to the database (can be overridden at install time).
May be another ``DbConfig`` or a ``DbConfigList`` to represent nested configuration.
:param description: Helpful text to guide implementer
:param required: If True, will raise errors at runtime when unset. Consider using False
when DbConfigs are added to an already deployed extension
"""
self.name = name
self.default = default
self.description = description
self.required = required
@property
def resolved_default(self):
"""
Returns the default value with any nested ``DbConfig`` or ``DbConfigList`` instances
recursively resolved into plain dicts, suitable for use as a config dict entry.
"""
return DbConfig._resolve(self.default)
@staticmethod
def _resolve(value):
"""Recursively resolve a value that may be a DbConfig or DbConfigList into a plain dict."""
# Import here to avoid circular imports at module level
from q2_sdk.hq.models.db_config.db_config_list import DbConfigList
if isinstance(value, DbConfigList):
return {
cfg.name: DbConfig._resolve(cfg.default) for cfg in value.db_configs
}
elif isinstance(value, DbConfig):
return {value.name: DbConfig._resolve(value.default)}
return value
@staticmethod
def _detailed(value):
"""
Recursively serialize a value that may be a DbConfig or DbConfigList into a
detail-preserving structure (including description and required).
"""
from q2_sdk.hq.models.db_config.db_config_list import DbConfigList
if isinstance(value, DbConfigList):
return value.to_json()
elif isinstance(value, DbConfig):
return value.to_json()
return value
[docs]
def to_json(self):
"""Json representation of class.
When ``default`` is a ``DbConfigList`` or ``DbConfig``, the full detail
(name, default, description, required) is preserved for nested configs.
For plain scalar/dict defaults the value is returned as-is.
"""
return {
"name": self.name,
"default": DbConfig._detailed(self.default),
"description": self.description,
"required": self.required,
}
[docs]
def is_valid(self, value):
"""Meant to be overridden. Verifies value is a valid input"""
return True
@staticmethod
def from_dict(optional_configs: dict):
optional = [DbConfig(x, y, required=False) for x, y in optional_configs.items()]
return optional