Config

Attributes

Classes

Component

Component()
Source code in fedbiomed/common/config.py
def __init__(self):
    """Test"""
    self._reference = ".fedbiomed"

Attributes

config_cls instance-attribute
config_cls

Functions

initiate
initiate(root=None, **kwargs)

Creates or initiates existing component

Parameters:

Name Type Description Default
root Optional[str]

Root directory of the component

None
component_alias

Name of the component, used for outputting the component in a user-friendly way. Defaults to default component name. (fbm-node or fbm-researcher)

required
**kwargs Any

Additional parameters that can be used for component initialization. For example, node_name for NodeComponent.

{}

Returns: Config object of the component

Source code in fedbiomed/common/config.py
def initiate(
    self, root: Optional[str] = None, **kwargs: Any
) -> Union["NodeConfig", "ResearcherConfig"]:
    """Creates or initiates existing component

    Args:
        root: Root directory of the component
        component_alias: Name of the component, used for outputting the
            component in a user-friendly way.
            Defaults to default component name. (fbm-node or fbm-researcher)
        **kwargs: Additional parameters that can be used for
            component initialization. For example, `node_name` for NodeComponent.
    Returns:
        Config object of the component
    """

    if not root:
        root = os.path.join(os.getcwd(), self._default_component_name)

    reference = self.validate(root)
    config = self.config_cls(root=root, **kwargs)
    # If component is not existing, create it
    if not os.path.isfile(reference):
        create_fedbiomed_setup_folders(root)
        with open(os.path.join(root, ".fedbiomed"), "w", encoding="UTF-8") as file_:
            file_.write(self.config_cls.COMPONENT_TYPE)
        config.generate()
        config.write()
    else:
        config.read()

    return config
is_component_existing
is_component_existing(component_dir)

Checks if component existing in the given root directory

Returns:

Type Description
bool

True if any component is instantiated in the given directory

Source code in fedbiomed/common/config.py
def is_component_existing(self, component_dir: str) -> bool:
    """Checks if component existing in the given root directory

    Returns:
        True if any component is instantiated in the given directory
    """
    ref = os.path.join(component_dir, self._reference)
    if os.path.isdir(component_dir):
        if docker_special_case(component_dir):
            return False

        if os.listdir(component_dir) and not os.path.isfile(ref):
            raise ValueError(
                f"Cannot create component. Path {component_dir} "
                "is not empty for Fed-BioMed component initialization. Please "
                f"remove folder {component_dir} or specify another path"
            )

    # Special case for docker container mounted folders
    # empty .fedbiomed is required to keep it
    if os.path.isfile(ref) and not read_file(ref):
        return False

    return os.path.isfile(ref)
validate
validate(root)

Validates given root folder is a component can be instantiated

Parameters:

Name Type Description Default
root

Root directory that Fed-BioMed component will be instantiated.

required

Returns:

Type Description
str

Full path to reference file

Source code in fedbiomed/common/config.py
def validate(self, root) -> str:
    """Validates given root folder is a component can be instantiated

    Args:
        root: Root directory that Fed-BioMed component will be instantiated.

    Returns:
        Full path to reference file
    """

    iscomp = self.is_component_existing(root)
    ref = os.path.join(root, self._reference)

    if iscomp:
        comp_type = read_file(ref)
        if comp_type != self.config_cls.COMPONENT_TYPE:
            raise ValueError(
                f"Component directory has already been initilazed for component type {comp_type}"
                " can not overwrite or reuse it for component type "
                f"{self.config_cls.COMPONENT_TYPE}"
            )

    return ref

Config

Config(root)

Base Config class

Attributes:

Name Type Description
root str

Root directory of the component.

name str

Config name (e.g config.ini or config-n1.ini).

path str

Absolute path to configuration.

vars Dict[str, Any]

A dictionary that contains configuration related variables. Such as dynamic paths that relies of component root etc.

Parameters:

Name Type Description Default
root str

Root directory for the component.

required
Source code in fedbiomed/common/config.py
def __init__(self, root: str) -> None:
    """Initializes configuration

    Args:
        root: Root directory for the component.
    """
    self._cfg = configparser.ConfigParser()
    self.load(root)

Attributes

name instance-attribute
name
path instance-attribute
path
root instance-attribute
root
vars class-attribute instance-attribute
vars = {}

Functions

COMPONENT_TYPE abstractmethod classmethod
COMPONENT_TYPE()

Abstract attribute to oblige defining component type

Source code in fedbiomed/common/config.py
@classmethod
@abstractmethod
def COMPONENT_TYPE(cls):  # pylint: disable=C0103
    """Abstract attribute to oblige defining component type"""
add_parameters abstractmethod
add_parameters()

"Component specific argument creation

Source code in fedbiomed/common/config.py
@abstractmethod
def add_parameters(self):
    """ "Component specific argument creation"""
generate
generate(id=None)

"Generate configuration file

Parameters:

Name Type Description Default
force

Overwrites existing configuration file

required
id Optional[str]

Component ID

None
Source code in fedbiomed/common/config.py
def generate(self, id: Optional[str] = None) -> None:
    """ "Generate configuration file

    Args:
        force: Overwrites existing configuration file
        id: Component ID
    """

    # Check if configuration is already existing
    if not self.is_config_existing():
        # Create default section
        component_id = id if id else f"{self.COMPONENT_TYPE}_{uuid.uuid4()}"

        self._cfg["default"] = {
            "id": component_id,
            "component": self.COMPONENT_TYPE,
            "version": str(self._CONFIG_VERSION),
        }

        db_path = os.path.join(
            self.root, VAR_FOLDER_NAME, f"{DB_PREFIX}{component_id}.json"
        )
        self._cfg["default"]["db"] = os.path.relpath(
            db_path, os.path.join(self.root, CONFIG_FOLDER_NAME)
        )

        # Calls child class add_parameterss
        self.add_parameters()
    else:
        self.read()
        # Provide migration
        self.migrate()

    self._update_vars()
get
get(section, key, **kwargs)

Returns value for given key and section

Source code in fedbiomed/common/config.py
def get(self, section, key, **kwargs) -> str:
    """Returns value for given key and section"""

    return self._get(section, key, **kwargs)
getbool
getbool(section, key, **kwargs)

Gets boolean value from config

Source code in fedbiomed/common/config.py
def getbool(self, section, key, **kwargs) -> bool:
    """Gets boolean value from config"""

    return self._get(section, key, **kwargs).lower() in ("true", "1")
getint
getint(section, key, **kwargs)

Gets int value of a given config

Source code in fedbiomed/common/config.py
def getint(self, section, key, **kwargs) -> int:
    """Gets int value of a given config"""

    return self._cfg.getint(section, key, **kwargs)
is_config_existing
is_config_existing()

Checks if config file exists

Returns:

Type Description
bool

True if config file is already existing

Source code in fedbiomed/common/config.py
def is_config_existing(self) -> bool:
    """Checks if config file exists

    Returns:
        True if config file is already existing
    """

    return os.path.isfile(self.config_path)
load
load(root)

Load configuration from given name and root

This implementation allows to load configuration after Config class is instantiated.

Parameters:

Name Type Description Default
root str

Root directory where component files will be saved configuration file.

required
Source code in fedbiomed/common/config.py
def load(
    self,
    root: str,  # pylint: disable=W0622
) -> None:
    """Load configuration from given name and root

    This implementation allows to load configuration after Config class
    is instantiated.

    Args:
        root: Root directory where component files will be saved
            configuration file.
    """

    self.root = root
    self.config_path = os.path.join(self.root, "etc", self._CONFIG_FILE_NAME)
    self.generate()
migrate abstractmethod
migrate()

Migration method to add configuration parameters

It is used for introducing new parameters for in minor version or patch to not break backward compatibility. This method has to update self._cfg directly.

An example;

self._cfg["my-section"].update({"my-new-parameter": "my-new-value"})
It should update the section only if the parameter is not existing to avoid overwriting user defined values.

Source code in fedbiomed/common/config.py
@abstractmethod
def migrate(self):
    """Migration method to add configuration parameters

    It is used for introducing  new parameters for in minor version or patch
    to not break backward compatibility. This method has to update `self._cfg`
    directly.

    An example;

    ```python
    self._cfg["my-section"].update({"my-new-parameter": "my-new-value"})
    ```
    It should update the section only if the parameter is not existing to avoid
    overwriting user defined values.
    """
read
read()

Reads configuration file that is already existing in given path

Raises version compatibility error

Source code in fedbiomed/common/config.py
def read(self) -> bool:
    """Reads configuration file that is already existing in given path

    Raises version compatibility error
    """
    self._cfg.read(self.config_path)

    # Validate config version
    raise_for_version_compatibility(
        self._cfg["default"]["version"],
        self._CONFIG_VERSION,
        f"Configuration file {self.config_path}: found version %s expected version %s",
    )

    return True
sections
sections()

Returns sections of the config

Source code in fedbiomed/common/config.py
def sections(self) -> list:
    """Returns sections of the config"""

    return self._cfg.sections()
set
set(section, key, value)

Sets config section values

Parameters:

Name Type Description Default
section

the name of the config file section as defined by the ini standard

required
key

the name of the attribute to be set

required
value

the value of the attribute to be set

required

Returns:

Name Type Description
value None

the value of the attribute that was just set

Source code in fedbiomed/common/config.py
def set(self, section, key, value) -> None:
    """Sets config section values

    Args:
        section: the name of the config file section as defined by the `ini` standard
        key: the name of the attribute to be set
        value: the value of the attribute to be set

    Returns:
        value: the value of the attribute that was just set
    """
    self._cfg.set(section, key, value)
write
write()

Writes config file

Source code in fedbiomed/common/config.py
def write(self):
    """Writes config file"""

    try:
        with open(self.config_path, "w", encoding="UTF-8") as f:
            self._cfg.write(f)
    except configparser.Error as exp:
        raise FedbiomedConfigurationError(
            f"{ErrorNumbers.FB600.value}: cannot save config file:  {self.path}"
        ) from exp

Functions

docker_special_case

docker_special_case(component_path)

Special case for docker containers.

This function makes sure that there is only .gitkeep file present in the directory that component will be initialized. It is required since component folder should be existing in run_mounts by default.

Source code in fedbiomed/common/config.py
def docker_special_case(component_path: str) -> bool:
    """Special case for docker containers.

    This function makes sure that there is only .gitkeep file present in
    the directory that component will be initialized. It is required since
    component folder should be existing in run_mounts by default.
    """

    files = os.listdir(component_path)

    return ".gitkeep" in files and len(files) == 1