Source code for biothings.cli

import importlib
import importlib.util
import logging
import os
import pathlib
import sys

try:
    import typer
    from rich.logging import RichHandler

    typer_avail = True
except ImportError:
    typer_avail = False

from biothings.utils.common import DummyConfig
from biothings.utils.configuration import ConfigurationError

CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])

if typer_avail:
    # prevent dimming the help text from the 2nd line
    # see: https://github.com/tiangolo/typer/issues/437#issuecomment-1224149402
    typer.rich_utils.STYLE_HELPTEXT = ""

    # Typer already support an env variable to disable rich tracebacks using _TYPER_STANDARD_TRACEBACK=1
    # This supports a similar BTCLI_RICH_TRACEBACK=1 env variable to turn it on when default is off in our case
    # Relevant ref: https://github.com/tiangolo/typer/issues/525 and https://github.com/tiangolo/typer/discussions/612
    # and BTCLI_DEBUG=1 env varible to turn on both rich tracebacks and show locals
    if os.environ.get("BTCLI_DEBUG"):
        pretty_exceptions_enable = True
        pretty_exceptions_show_locals = True
        default_logging_level = logging.DEBUG
    else:
        if os.environ.get("BTCLI_RICH_TRACEBACK"):
            pretty_exceptions_enable = True
        else:
            pretty_exceptions_enable = False
            sys.tracebacklimit = 1  # only show the last traceback, default is 1000
        pretty_exceptions_show_locals = False
        default_logging_level = logging.INFO

    cli = typer.Typer(
        help="[green]BioThings Admin CLI to test your local data plugins. See helps for each command for specific usage.[/green]",
        rich_help_panel="Help and Others",
        rich_markup_mode="rich",
        context_settings=CONTEXT_SETTINGS,
        no_args_is_help=True,
        pretty_exceptions_show_locals=pretty_exceptions_show_locals,
        pretty_exceptions_enable=pretty_exceptions_enable,
    )

    logging.basicConfig(
        level="INFO",
        format="%(message)s",
        datefmt="[%X]",
        handlers=[
            # we don't need to turn on rich_tracebacks since typer creates it already
            RichHandler(
                level=default_logging_level,
                rich_tracebacks=False,
                tracebacks_suppress=[typer],
                show_path=False,
            ),
        ],
    )

logger = logging.getLogger("cli")


[docs] def setup_config(): """Setup a config module necessary to launch the CLI""" working_dir = pathlib.Path().resolve() _config = DummyConfig("config") _config.HUB_DB_BACKEND = { "module": "biothings.utils.sqlite3", "sqlite_db_folder": ".biothings_hub", } _config.DATA_SRC_DATABASE = ".data_src_database" _config.DATA_ARCHIVE_ROOT = ".biothings_hub/archive" # _config.LOG_FOLDER = ".biothings_hub/logs" _config.LOG_FOLDER = None # disable file logging, only log to stdout _config.DATA_PLUGIN_FOLDER = f"{working_dir}" _config.hub_db = importlib.import_module(_config.HUB_DB_BACKEND["module"]) try: config_mod = importlib.import_module("config") for attr in dir(config_mod): value = getattr(config_mod, attr) if isinstance(value, ConfigurationError): raise ConfigurationError("%s: %s" % (attr, str(value))) setattr(_config, attr, value) except ModuleNotFoundError: logger.debug("The config.py does not exists in the working directory, use default biothings.config") sys.modules["config"] = _config sys.modules["biothings.config"] = _config
[docs] def main(): """The main entry point for running the BioThings CLI to test your local data plugins.""" if not typer_avail: logger.error( '"typer" package is required for CLI feature. Use "pip install biothings[cli]" or "pip install typer[all]" to install.' ) return setup_config() from .dataplugin import app as dataplugin_app from .dataplugin_hub import app as dataplugin_hub_app cli.add_typer(dataplugin_app, name="dataplugin") cli.add_typer(dataplugin_hub_app, name="dataplugin-hub") return cli()