Source code for simstack.util.config_reader
from pathlib import Path
from typing import List, TYPE_CHECKING, Union
from simstack.core.resources import allowed_resources
from simstack.models.parameters import Resource
from simstack.models.resource_definition import ResourceDefinition, GitRepo
from simstack.util.transform_file_name import transform_file_name
from simstack.util.init_data_source import initialize_resource_from_db
from simstack.util.toml_reader import TomlReader
from simstack.util.database_information import DatabaseInformation
if TYPE_CHECKING:
from simstack.util.db import Database
[docs]
class ConfigReader(DatabaseInformation):
"""
Represents a configuration reader that integrates with a database and a resource
definition system.
"""
def __init__(
self,
db_info: Union[DatabaseInformation, "Database"],
resource_definition: ResourceDefinition,
*,
project_root: Path,
git_list: list[GitRepo] | None = None,
):
db_temp_info = DatabaseInformation.from_db_info_or_db(db_info)
super().__init__(*db_temp_info.get_information())
self._project_root = project_root
self._resource_definition = resource_definition
self._git_list = list(git_list or [])
self._resource_str = resource_definition.resource_str
[docs]
@classmethod
async def create(
cls,
resource_str,
db: "Database",
toml_reader: TomlReader,
project_root: Path,
**kwargs,
):
"""
the idea here is to attempt to get:
1) all required data from the kwargs, if available
2) if the data is not all available, get it from the database
"""
import logging
logger = logging.getLogger("config-reader") # do this here because the calling function sets the logger up
required_keys = [
"python_paths",
"workdir",
"environment_start",
]
init_done = True
workdir_self = None
config = {"project_root": project_root}
for key in required_keys:
if key in kwargs:
config[key] = kwargs.get(key)
if key == "workdir":
workdir_self = kwargs.get("workdir")
logger.info(f"Init from kwargs: {key}: {kwargs.get(key)}")
else:
init_done = False
for key in ["server_url", "server_token"]: # these are optional
if key in kwargs:
config[key] = kwargs.get(key)
logger.info(f"Init from kwargs: {key}: {kwargs.get(key)}")
git_list = []
if not init_done:
if toml_reader is None:
raise ValueError("ConfigReader: No toml_reader provided.")
workdir_self = kwargs.get("workdir", None)
if workdir_self is None:
workdir_self = toml_reader.get("parameters.general.workdir_self", None)
if workdir_self is None:
workdir_self = toml_reader.get("resources.self.workdir", None)
if workdir_self is None:
# raise ValueError("No workdir for self specified in config file or keyword arguments.")
workdir_self = project_root / "simstack" # Default to project_root / simstack if not found
else:
workdir_self = Path(workdir_self)
resource_definition = await initialize_resource_from_db(resource_str, db, workdir_self)
# else:
# raise RuntimeError("initialization from toml file is deprecated")
# allowed_resources_list = toml_reader.get_allowed_resources()
# allowed_resources.set_resources(allowed_resources_list)
# resource_definition = toml_reader.get_resource_definition(resource_str)
# git_list = toml_reader.get_git_list()
# toml_reader.build_routes()
if resource_definition is None:
raise ValueError("No valid resource definition found.")
# override the values in resource definition with those from the keyword arguments
for key in resource_definition.__class__.model_fields.keys():
if key in config:
logger.info(f"Overriding {key} from kwargs to: {config[key]}")
resource_definition.__setattr__(key, config[key])
del config[key]
del required_keys[required_keys.index(key)]
project_root = config.pop("project_root")
git_list_final = config.pop("git_list", git_list)
if config:
logger.warning(
f"Ignoring unused ConfigReader init keys: {sorted(config.keys())}"
)
log_msg = f"Resource: {resource_definition.resource_str}"
for key, value in resource_definition.__dict__.items():
if key in ["workdir", "git-branch", "environment_start"]:
log_msg += f" {key}: {value}"
logger.info(log_msg)
return cls(
db, resource_definition, project_root=project_root, git_list=git_list_final
)
@property
def server_url(self) -> str:
return self._server_url
@property
def server_token(self) -> str:
return self._server_token
@property
def git_list(self) -> List[GitRepo]:
return self._git_list
@property
def resource(self) -> Resource:
return Resource(value=self._resource_str)
@property
def workdir(self) -> Path:
return transform_file_name(self._resource_definition.workdir, self.project_root)
@property
def environment_start(self) -> str:
return self._resource_definition.environment_start
@property
def python_paths(self) -> List[Path]:
return [transform_file_name(p) for p in self._resource_definition.python_paths]
@property
def ssh_key(self) -> Path:
return transform_file_name(self._resource_definition.ssh_key)
@property
def hostname(self):
return self._resource_definition.hostname
@resource.setter
def resource(self, value: str):
raise ValueError("ConfigReader: Resource cannot be set directly")
@property
def project_root(self) -> Path:
return self._project_root
@property
def docker(self) -> bool:
return False