CLI

Common CLI Modules

This module includes common CLI methods and parser extension

Attributes

BOLD module-attribute

BOLD = '\x1b[1m'

GRN module-attribute

GRN = '\x1b[1;32m'

NC module-attribute

NC = '\x1b[0m'

RED module-attribute

RED = '\x1b[1;31m'

YLW module-attribute

YLW = '\x1b[1;33m'

Classes

CLIArgumentParser

CLIArgumentParser(subparser, parser=None)
Source code in fedbiomed/common/cli.py
def __init__(self, subparser: argparse.ArgumentParser, parser = None):

    self._subparser = subparser
    # Parser that is going to be add using subparser
    self._parser = None

    self._main_parser = parser

Functions

default
default(args=None)

Default function for subparser command

Source code in fedbiomed/common/cli.py
def default(self, args: argparse.Namespace = None) -> None:
    """Default function for subparser command"""

    self._parser.print_help()

    return None

CommonCLI

CommonCLI()
Source code in fedbiomed/common/cli.py
def __init__(self) -> None:
    self._parser: argparse.ArgumentParser = argparse.ArgumentParser(
        prog="fedbiomed", formatter_class=argparse.RawTextHelpFormatter
    )

    self._subparsers = self._parser.add_subparsers()
    self._certificate_manager: CertificateManager = CertificateManager()
    self._description: str = ""
    self._args = None

Attributes

arguments property
arguments

Gets global parser arguments

Returns:

Type Description
Namespace

Parser arguments

config instance-attribute
config
description property writable
description

Gets description of CLI

Returns:

Type Description
str

Description (Intro) for the CLI

parser property
parser

Gets parser for CLI

Returns:

Type Description
ArgumentParser

Main argument parser object

subparsers property
subparsers

Gets subparsers of common cli

Returns:

Type Description

Subparsers of CLI parser

Functions

config_action staticmethod
config_action(this, component)

Returns CLI argument action for config file name

Source code in fedbiomed/common/cli.py
@staticmethod
def config_action(this: "CommonCLI", component: ComponentType):
    """Returns CLI argument action for config file name"""
    return ComponentDirectoryAction
error staticmethod
error(message)

Prints given error message

Parameters:

Name Type Description Default
message str

Error message

required
Source code in fedbiomed/common/cli.py
@staticmethod
def error(message: str) -> None:
    """Prints given error message

    Args:
        message: Error message
    """
    print(f"{RED}ERROR:{NC}")
    print(f"{BOLD}{message}{NC}")
    logger.critical(message)
    sys.exit(1)
initialize
initialize()

Initializes parser classes and common parser for child classes.

This parser classes will be added by child classes.

Source code in fedbiomed/common/cli.py
def initialize(self):
    """Initializes parser classes and common parser for child classes.

    This parser classes will be added by child classes.
    """

    self._parser.add_argument(
        "-y",
        action="store_true"
    )

    for arg_parser in self._arg_parsers_classes:
        p = arg_parser(self._subparsers, self._parser)
        p.initialize()
        self._arg_parsers.update({arg_parser.__name__: p})

    self.initialize_certificate_parser()
initialize_certificate_parser
initialize_certificate_parser()

Common arguments

Source code in fedbiomed/common/cli.py
def initialize_certificate_parser(self):
    """Common arguments"""

    # Add certificate sub parser (sub-command)
    certificate_parser = self._subparsers.add_parser(
        "certificate",
        help="Command to manage certificates in node and researcher components. "
        "Please see 'certificate --help' for more information.",
        prog="fedbiomed [ node | researcher ] [--path [COMPONENT_DIRECTORY]] certificate",
    )

    def print_help(args):
        certificate_parser.print_help()

    certificate_parser.set_defaults(func=print_help)

    # Create sub parser under `certificate` command
    certificate_sub_parsers = certificate_parser.add_subparsers(
        description="Commands that can be used with the option `certificate`",
        title="Subcommands",
    )

    register_parser = certificate_sub_parsers.add_parser(
        "register",
        help="Register certificate of specified party. Please run 'fedbiomed' "
            "[COMPONENT SPECIFICATION] certificate register --help'",
    )  # command register

    list_parser = certificate_sub_parsers.add_parser(
        "list", help="Lists registered certificates"
    )  # command list
    delete_parser = certificate_sub_parsers.add_parser(
        "delete", help="Deletes specified certificate from database"
    )  # command delete

    # Command `certificate generate`
    generate = certificate_sub_parsers.add_parser(
        "generate",
        help="Generates certificate for given component/party if files don't exist yet. "
        "Uses an alternate directory if '--path DIRECTORY' is given."
        " If files already exist, overwrite existing certificate.\n"
        "Certificate are here refering to the public certificate and its associated private key "
        "(the latter should remain secret and not shared to other parties)."
    )

    # Command `certificate generate`
    prepare = certificate_sub_parsers.add_parser(
        "registration-instructions",
        help="Prepares certificate of current component to send other FL participant"
             " through trusted channel.",
    )

    register_parser.set_defaults(func=self._register_certificate)
    list_parser.set_defaults(func=self._list_certificates)
    delete_parser.set_defaults(func=self._delete_certificate)
    generate.set_defaults(func=self._generate_certificate)
    prepare.set_defaults(func=self._prepare_certificate_for_registration)

    # Add arguments
    register_parser.add_argument(
        "-pk",
        "--public-key",
        metavar="PUBLIC_KEY",
        type=str,
        nargs="?",
        required=True,
        help="Certificate/key that will be registered",
    )

    register_parser.add_argument(
        "-pi",
        "--party-id",
        metavar="PUBLIC_ID",
        type=str,
        nargs="?",
        required=True,
        help="ID of the party to which the certificate is to be registered (component ID).",
    )

    register_parser.add_argument(
        "--upsert",
        action="store_true",
        help="Updates if certificate of given party id is already existing.",
    )

    generate.add_argument(
        "--path",
        type=str,
        nargs="?",
        required=False,
        help="The path to the RESEARCHER|NODE component, in which certificate will be saved."
        " By default it will overwrite existing certificate.",
    )
initialize_magic_dev_environment_parsers
initialize_magic_dev_environment_parsers()

Initializes argument parser for the option to create development environment.

Source code in fedbiomed/common/cli.py
def initialize_magic_dev_environment_parsers(self) -> None:
    """Initializes argument parser for the option to create development environment."""
    magic = self._subparsers.add_parser(
        "certificate-dev-setup",
        description="Prepares development environment by registering certificates "
                    "of each component created in a single clone of Fed-BioMed. Parses "
                    "configuration files ends with '.ini' that are created in 'etc' "
                    "directory. This setup requires to have one 'researcher' and "
                    "at least 2 nodes.",
        help="Prepares development environment by registering certificates of each "
             "component created in a single clone of Fed-BioMed.",
    )
    magic.set_defaults(func=self._create_magic_dev_environment)
initialize_optional
initialize_optional()

Initializes optional subparser

Optional subparsers are not going to be visible for the CLI that are inherited from CommonCLI class as long as intialize_optional method is not executed.

Source code in fedbiomed/common/cli.py
def initialize_optional(self):
    """Initializes optional subparser

    Optional subparsers are not going to be visible for the CLI that are
    inherited from CommonCLI class as long as `intialize_optional` method
    is not executed.
    """

    self.initialize_magic_dev_environment_parsers()
    self.initialize_version()
initialize_version
initialize_version()

Initializes argument parser for common options.

Source code in fedbiomed/common/cli.py
def initialize_version(self):
    """Initializes argument parser for common options."""
    self._parser.add_argument(
        "--version",
        "-v",
        action='version',
        version=str(__version__),
        help="Print software version",
    )
parse_args
parse_args(args_=None)

Parse arguments after adding the arguments

Attention

Please make sure this method is called after all necessary arguments are set
Source code in fedbiomed/common/cli.py
def parse_args(self, args_=None):
    """Parse arguments after adding the arguments

    !!! warning "Attention"
            Please make sure this method is called after all necessary arguments are set
    """
    args, unknown_args = self._parser.parse_known_args(args_)
    if hasattr(args, "func"):
        specs = get_method_spec(args.func)
        if specs:
            # If default function has 2 arguments
            if len(specs) > 1:
                return args.func(args, unknown_args)

            # Run parser_args to raise error for unrecognized arguments
            if unknown_args:
                args = self._parser.parse_args(args_)
            args.func(args)
        else:
            # Raise for unrecognized arguments
            if unknown_args:
                self._parser.parse_args(args_)
            args.func()
    else:
        self._parser.print_help()
success staticmethod
success(message)

Prints given message with success tag

Parameters:

Name Type Description Default
message str

Message to print as successful operation

required
Source code in fedbiomed/common/cli.py
@staticmethod
def success(message: str) -> None:
    """Prints given message with success tag

    Args:
        message: Message to print as successful operation
    """
    print(f"{GRN}Operation successful! {NC}")
    print(f"{BOLD}{message}{NC}")

ComponentDirectoryAction

ComponentDirectoryAction(*args, **kwargs)

Bases: ABC, Action

Action for the argument config

This action class gets the config file name and set config object before executing any command.

Source code in fedbiomed/common/cli.py
def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)

    # Sets config by default if option string for config is not present.
    # The default is defined by the argument parser.
    if (
        not set(self.option_strings).intersection(set(sys.argv)) and
        not set(["--help", "-h"]).intersection(set(sys.argv)) and
        len(sys.argv) > 2
    ):
        self._create_config(self.default)

    super().__init__(*args, **kwargs)

Functions

set_component abstractmethod
set_component(component_dir)

Implements configuration import

Parameters:

Name Type Description Default
component_dir str

Name of the config file for the component

required
Source code in fedbiomed/common/cli.py
@abstractmethod
def set_component(self, component_dir: str) -> None:
    """Implements configuration import

    Args:
        component_dir: Name of the config file for the component
    """

Functions