Files
wehub-resource-sync dc6079821b
Docs Tests / Check for file changes (push) Has been cancelled
Docs Tests / Test Documentation (push) Has been cancelled
Docs Tests / Documentation Linting Checks (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-policies) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (ubuntu-24.04, 3.10) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (ubuntu-24.04, 3.8) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (ubuntu-24.04, 3.9) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (windows-2022, 3.10) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (windows-2022, 3.8) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (windows-2022, 3.9) (push) Has been cancelled
Continuous Integration / Check for file changes (push) Has been cancelled
Continuous Integration / Wait for docs tests (push) Has been cancelled
Continuous Integration / Code Quality (push) Has been cancelled
Continuous Integration / Check for changelog (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Upload coverage reports to codeclimate (push) Has been cancelled
Continuous Integration / Run Non-Sequential Integration Tests (push) Has been cancelled
Continuous Integration / Run Broker Integration Tests (push) Has been cancelled
Continuous Integration / Run Sequential Integration Tests (push) Has been cancelled
Continuous Integration / Build Docker base images and setup environment (push) Has been cancelled
Continuous Integration / Build Docker (default) (push) Has been cancelled
Continuous Integration / Build Docker (full) (push) Has been cancelled
Continuous Integration / Build Docker (mitie-en) (push) Has been cancelled
Continuous Integration / Build Docker (spacy-de) (push) Has been cancelled
Continuous Integration / Build Docker (spacy-en) (push) Has been cancelled
Continuous Integration / Build Docker (spacy-it) (push) Has been cancelled
Continuous Integration / Deploy to PyPI (push) Has been cancelled
Continuous Integration / Notify Slack & Publish Release Notes (push) Has been cancelled
Publish Documentation / Evaluate release tag (push) Has been cancelled
Publish Documentation / Prebuild Docs (push) Has been cancelled
Publish Documentation / Preview Docs (push) Has been cancelled
Publish Documentation / Check for file changes (push) Has been cancelled
Publish Documentation / Publish Docs (push) Has been cancelled
Automatic PR Merger / mergepal (push) Has been cancelled
CI Github Actions / Run Tests (push) Has been cancelled
Semgrep / Semgrep Workflow Security Scan (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:24:47 +08:00

592 lines
19 KiB
Python

import copy
import inspect
import logging
import logging.config
import logging.handlers
import os
import shutil
import tempfile
import warnings
from pathlib import Path
from socket import SOCK_DGRAM, SOCK_STREAM
from types import TracebackType
from typing import (
Any,
Coroutine,
Dict,
List,
Optional,
Text,
Type,
TypeVar,
Union,
ContextManager,
Set,
Tuple,
)
import numpy as np
import rasa.shared.utils.io
import rasa.utils.io
from rasa.constants import (
DEFAULT_LOG_LEVEL_LIBRARIES,
ENV_LOG_LEVEL_LIBRARIES,
ENV_LOG_LEVEL_MATPLOTLIB,
ENV_LOG_LEVEL_RABBITMQ,
ENV_LOG_LEVEL_KAFKA,
)
from rasa.shared.constants import DEFAULT_LOG_LEVEL, ENV_LOG_LEVEL, TCP_PROTOCOL
from rasa.shared.exceptions import RasaException
logger = logging.getLogger(__name__)
T = TypeVar("T")
EXPECTED_PILLOW_DEPRECATION_WARNINGS: List[Tuple[Type[Warning], str]] = [
# Keras uses deprecated Pillow features
# cf. https://github.com/keras-team/keras/issues/16639
(DeprecationWarning, f"{method} is deprecated and will be removed in Pillow 10 .*")
for method in ["BICUBIC", "NEAREST", "BILINEAR", "HAMMING", "BOX", "LANCZOS"]
]
EXPECTED_WARNINGS: List[Tuple[Type[Warning], str]] = [
# TODO (issue #9932)
(
np.VisibleDeprecationWarning,
"Creating an ndarray from ragged nested sequences.*",
),
# cf. https://github.com/tensorflow/tensorflow/issues/38168
(
UserWarning,
"Converting sparse IndexedSlices.* to a dense Tensor of unknown "
"shape. This may consume a large amount of memory.",
),
(UserWarning, "Slot auto-fill has been removed in 3.0 .*"),
# This warning is caused by the flatbuffers package
# The import was fixed on Github, but the latest version
# is not available on PyPi, so we cannot pin the newer version.
# cf. https://github.com/google/flatbuffers/issues/6957
(DeprecationWarning, "the imp module is deprecated in favour of importlib.*"),
# Cannot fix this deprecation warning since we need to support two
# numpy versions as long as we keep python 37 around
(DeprecationWarning, "the `interpolation=` argument to quantile was renamed"),
# the next two warnings are triggered by adding 3.10 support,
# for more info: https://docs.python.org/3.10/whatsnew/3.10.html#deprecated
(DeprecationWarning, "the load_module*"),
(ImportWarning, "_SixMetaPathImporter.find_spec*"),
# 3.10 specific warning: https://github.com/pytest-dev/pytest-asyncio/issues/212
(DeprecationWarning, "There is no current event loop"),
# UserWarning which is always issued if the default value for
# assistant_id key in config file is not changed
(UserWarning, "is missing a unique value for the 'assistant_id' mandatory key.*"),
(
DeprecationWarning,
"non-integer arguments to randrange\\(\\) have been deprecated since",
),
]
EXPECTED_WARNINGS.extend(EXPECTED_PILLOW_DEPRECATION_WARNINGS)
PYTHON_LOGGING_SCHEMA_DOCS = (
"https://docs.python.org/3/library/logging.config.html#dictionary-schema-details"
)
class TempDirectoryPath(str, ContextManager):
"""Represents a path to an temporary directory.
When used as a context manager, it erases the contents of the directory on exit.
"""
def __enter__(self) -> "TempDirectoryPath":
return self
def __exit__(
self,
_exc: Optional[Type[BaseException]],
_value: Optional[BaseException],
_tb: Optional[TracebackType],
) -> None:
if os.path.exists(self):
shutil.rmtree(self)
def get_temp_dir_name() -> Text:
"""Returns the path name of a newly created temporary directory."""
tempdir_name = tempfile.mkdtemp()
return decode_bytes(tempdir_name)
def decode_bytes(name: Union[Text, bytes]) -> Text:
"""Converts bytes object to string."""
if isinstance(name, bytes):
name = name.decode("UTF-8")
return name
def read_global_config(path: Text) -> Dict[Text, Any]:
"""Read global Rasa configuration.
Args:
path: Path to the configuration
Returns:
The global configuration
"""
# noinspection PyBroadException
try:
return rasa.shared.utils.io.read_config_file(path)
except Exception:
# if things go south we pretend there is no config
return {}
def configure_logging_from_file(logging_config_file: Text) -> None:
"""Parses YAML file content to configure logging.
Args:
logging_config_file: YAML file containing logging configuration to handle
custom formatting
"""
logging_config_dict = rasa.shared.utils.io.read_yaml_file(logging_config_file)
try:
logging.config.dictConfig(logging_config_dict)
except (ValueError, TypeError, AttributeError, ImportError) as e:
logger.debug(
f"The logging config file {logging_config_file} could not "
f"be applied because it failed validation against "
f"the built-in Python logging schema. "
f"More info at {PYTHON_LOGGING_SCHEMA_DOCS}.",
exc_info=e,
)
def configure_logging_and_warnings(
log_level: Optional[int] = None,
logging_config_file: Optional[Text] = None,
warn_only_once: bool = True,
filter_repeated_logs: bool = True,
) -> None:
"""Sets log levels of various loggers and sets up filters for warnings and logs.
Args:
log_level: The log level to be used for the 'Rasa' logger. Pass `None` to use
either the environment variable 'LOG_LEVEL' if it is specified, or the
default log level otherwise.
logging_config_file: YAML file containing logging configuration to handle
custom formatting
warn_only_once: determines whether user warnings should be filtered by the
`warnings` module to appear only "once"
filter_repeated_logs: determines whether `RepeatedLogFilter`s are added to
the handlers of the root logger
"""
if logging_config_file is not None:
configure_logging_from_file(logging_config_file)
if log_level is None: # Log level NOTSET is 0 so we use `is None` here
log_level_name = os.environ.get(ENV_LOG_LEVEL, DEFAULT_LOG_LEVEL)
# Change log level from str to int (note that log_level in function parameter
# int already, coming from CLI argparse parameter).
log_level = logging.getLevelName(log_level_name)
logging.getLogger("rasa").setLevel(log_level)
# Assign log level to env variable in str format (not int). Why do we assign?
os.environ[ENV_LOG_LEVEL] = logging.getLevelName(log_level)
configure_library_logging()
if filter_repeated_logs:
for handler in logging.getLogger().handlers:
handler.addFilter(RepeatedLogFilter())
_filter_warnings(log_level=log_level, warn_only_once=warn_only_once)
def _filter_warnings(log_level: Optional[int], warn_only_once: bool = True) -> None:
"""Sets up filters for warnings.
Args:
log_level: the current log level. Certain warnings will only be filtered out
if we're not in debug mode.
warn_only_once: determines whether user warnings should be filtered by the
`warnings` module to appear only "once"
"""
if warn_only_once:
warnings.filterwarnings("once", category=UserWarning)
if log_level and log_level > logging.DEBUG:
for warning_type, warning_message in EXPECTED_WARNINGS:
warnings.filterwarnings(
"ignore", message=f".*{warning_message}", category=warning_type
)
def configure_library_logging() -> None:
"""Configures log levels of used libraries such as kafka, matplotlib, pika."""
library_log_level = os.environ.get(
ENV_LOG_LEVEL_LIBRARIES, DEFAULT_LOG_LEVEL_LIBRARIES
)
update_tensorflow_log_level()
update_asyncio_log_level()
update_apscheduler_log_level()
update_socketio_log_level()
update_matplotlib_log_level(library_log_level)
update_kafka_log_level(library_log_level)
update_rabbitmq_log_level(library_log_level)
def update_apscheduler_log_level() -> None:
"""Configures the log level of `apscheduler.*` loggers."""
log_level = os.environ.get(ENV_LOG_LEVEL_LIBRARIES, DEFAULT_LOG_LEVEL_LIBRARIES)
apscheduler_loggers = [
"apscheduler",
"apscheduler.scheduler",
"apscheduler.executors",
"apscheduler.executors.default",
]
for logger_name in apscheduler_loggers:
logging.getLogger(logger_name).setLevel(log_level)
logging.getLogger(logger_name).propagate = False
def update_socketio_log_level() -> None:
"""Set the log level of socketio."""
log_level = os.environ.get(ENV_LOG_LEVEL_LIBRARIES, DEFAULT_LOG_LEVEL_LIBRARIES)
socketio_loggers = ["websockets.protocol", "engineio.server", "socketio.server"]
for logger_name in socketio_loggers:
logging.getLogger(logger_name).setLevel(log_level)
logging.getLogger(logger_name).propagate = False
def update_tensorflow_log_level() -> None:
"""Sets Tensorflow log level based on env variable 'LOG_LEVEL_LIBRARIES'."""
# Disables libvinfer, tensorRT, cuda, AVX2 and FMA warnings (CPU support).
# This variable needs to be set before the
# first import since some warnings are raised on the first import.
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
log_level = os.environ.get(ENV_LOG_LEVEL_LIBRARIES, DEFAULT_LOG_LEVEL_LIBRARIES)
if not log_level:
log_level = "ERROR"
logging.getLogger("tensorflow").setLevel(log_level)
logging.getLogger("tensorflow").propagate = False
def update_sanic_log_level(
log_file: Optional[Text] = None,
use_syslog: Optional[bool] = False,
syslog_address: Optional[Text] = None,
syslog_port: Optional[int] = None,
syslog_protocol: Optional[Text] = None,
) -> None:
"""Set the log level to 'LOG_LEVEL_LIBRARIES' environment variable ."""
from sanic.log import logger, error_logger, access_logger
log_level = os.environ.get(ENV_LOG_LEVEL_LIBRARIES, DEFAULT_LOG_LEVEL_LIBRARIES)
logger.setLevel(log_level)
error_logger.setLevel(log_level)
access_logger.setLevel(log_level)
logger.propagate = False
error_logger.propagate = False
access_logger.propagate = False
if log_file is not None:
formatter = logging.Formatter("%(asctime)s [%(levelname)-5.5s] %(message)s")
file_handler = logging.FileHandler(log_file)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
error_logger.addHandler(file_handler)
access_logger.addHandler(file_handler)
if use_syslog:
formatter = logging.Formatter(
"%(asctime)s [%(levelname)-5.5s] [%(process)d]" " %(message)s"
)
socktype = SOCK_STREAM if syslog_protocol == TCP_PROTOCOL else SOCK_DGRAM
syslog_handler = logging.handlers.SysLogHandler(
address=(syslog_address, syslog_port), socktype=socktype
)
syslog_handler.setFormatter(formatter)
logger.addHandler(syslog_handler)
error_logger.addHandler(syslog_handler)
access_logger.addHandler(syslog_handler)
def update_asyncio_log_level() -> None:
"""Set the log level of asyncio to the log level.
Uses the log level specified in the environment variable 'LOG_LEVEL_LIBRARIES'.
"""
log_level = os.environ.get(ENV_LOG_LEVEL_LIBRARIES, DEFAULT_LOG_LEVEL_LIBRARIES)
logging.getLogger("asyncio").setLevel(log_level)
def update_matplotlib_log_level(library_log_level: Text) -> None:
"""Set the log level of matplotlib.
Uses the library specific log level or the general libraries log level.
"""
log_level = os.environ.get(ENV_LOG_LEVEL_MATPLOTLIB, library_log_level)
logging.getLogger("matplotlib").setLevel(log_level)
def update_kafka_log_level(library_log_level: Text) -> None:
"""Set the log level of kafka.
Uses the library specific log level or the general libraries log level.
"""
log_level = os.environ.get(ENV_LOG_LEVEL_KAFKA, library_log_level)
logging.getLogger("kafka").setLevel(log_level)
def update_rabbitmq_log_level(library_log_level: Text) -> None:
"""Set the log level of pika.
Uses the library specific log level or the general libraries log level.
"""
log_level = os.environ.get(ENV_LOG_LEVEL_RABBITMQ, library_log_level)
logging.getLogger("aio_pika").setLevel(log_level)
logging.getLogger("aiormq").setLevel(log_level)
def sort_list_of_dicts_by_first_key(dicts: List[Dict]) -> List[Dict]:
"""Sorts a list of dictionaries by their first key."""
return sorted(dicts, key=lambda d: list(d.keys())[0])
def write_global_config_value(name: Text, value: Any) -> bool:
"""Read global Rasa configuration.
Args:
name: Name of the configuration key
value: Value the configuration key should be set to
Returns:
`True` if the operation was successful.
"""
# need to use `rasa.constants.GLOBAL_USER_CONFIG_PATH` to allow patching
# in tests
config_path = rasa.constants.GLOBAL_USER_CONFIG_PATH
try:
os.makedirs(os.path.dirname(config_path), exist_ok=True)
c = read_global_config(config_path)
c[name] = value
rasa.shared.utils.io.write_yaml(c, rasa.constants.GLOBAL_USER_CONFIG_PATH)
return True
except Exception as e:
logger.warning(f"Failed to write global config. Error: {e}. Skipping.")
return False
def read_global_config_value(name: Text, unavailable_ok: bool = True) -> Any:
"""Read a value from the global Rasa configuration."""
def not_found() -> None:
if unavailable_ok:
return None
else:
raise ValueError(f"Configuration '{name}' key not found.")
# need to use `rasa.constants.GLOBAL_USER_CONFIG_PATH` to allow patching
# in tests
config_path = rasa.constants.GLOBAL_USER_CONFIG_PATH
if not os.path.exists(config_path):
return not_found()
c = read_global_config(config_path)
if name in c:
return c[name]
else:
return not_found()
def update_existing_keys(
original: Dict[Any, Any], updates: Dict[Any, Any]
) -> Dict[Any, Any]:
"""Iterate through all the updates and update a value in the original dictionary.
If the updates contain a key that is not present in the original dict, it will
be ignored.
"""
updated = original.copy()
for k, v in updates.items():
if k in updated:
updated[k] = v
return updated
def override_defaults(
defaults: Optional[Dict[Text, Any]], custom: Optional[Dict[Text, Any]]
) -> Dict[Text, Any]:
"""Override default config with the given config.
We cannot use `dict.update` method because configs contain nested dicts.
Args:
defaults: default config
custom: user config containing new parameters
Returns:
updated config
"""
config = copy.deepcopy(defaults) if defaults else {}
if not custom:
return config
for key in custom.keys():
if isinstance(config.get(key), dict):
config[key].update(custom[key])
continue
config[key] = custom[key]
return config
class RepeatedLogFilter(logging.Filter):
"""Filter repeated log records."""
last_log = None
def filter(self, record: logging.LogRecord) -> bool:
"""Determines whether current log is different to last log."""
current_log = (
record.levelno,
record.pathname,
record.lineno,
record.msg,
record.args,
)
if current_log != self.last_log:
self.last_log = current_log
return True
return False
async def call_potential_coroutine(
coroutine_or_return_value: Union[Any, Coroutine]
) -> Any:
"""Awaits coroutine or returns value directly if it's not a coroutine.
Args:
coroutine_or_return_value: Either the return value of a synchronous function
call or a coroutine which needs to be await first.
Returns:
The return value of the function.
"""
if inspect.iscoroutine(coroutine_or_return_value):
return await coroutine_or_return_value
return coroutine_or_return_value
def directory_size_in_mb(
path: Path, filenames_to_exclude: Optional[List[Text]] = None
) -> float:
"""Calculates the size of a directory.
Args:
path: The path to the directory.
filenames_to_exclude: Allows excluding certain files from the calculation.
Returns:
Directory size in MiB.
"""
filenames_to_exclude = filenames_to_exclude or []
size = 0.0
for root, _dirs, files in os.walk(path):
for filename in files:
if filename in filenames_to_exclude:
continue
size += (Path(root) / filename).stat().st_size
# bytes to MiB
return size / 1_048_576
def copy_directory(source: Path, destination: Path) -> None:
"""Copies the content of one directory into another.
Args:
source: The directory whose contents should be copied to `destination`.
destination: The directory which should contain the content `source` in the end.
Raises:
ValueError: If destination is not empty.
"""
if not destination.exists():
destination.mkdir(parents=True)
if list(destination.glob("*")):
raise ValueError(
f"Destination path '{destination}' is not empty. Directories "
f"can only be copied to empty directories."
)
shutil.copytree(source, destination, dirs_exist_ok=True)
def find_unavailable_packages(package_names: List[Text]) -> Set[Text]:
"""Tries to import all package names and returns the packages where it failed.
Args:
package_names: The package names to import.
Returns:
Package names that could not be imported.
"""
import importlib
failed_imports = set()
for package in package_names:
try:
importlib.import_module(package)
except ImportError:
failed_imports.add(package)
return failed_imports
def module_path_from_class(clazz: Type) -> Text:
"""Return the module path of an instance's class."""
return clazz.__module__ + "." + clazz.__name__
def get_bool_env_variable(variable_name: str, default_variable_value: bool) -> bool:
"""Fetch bool value stored in environment variable.
If environment variable is set but value is
not of boolean nature, an exception will be raised.
Args: variable_name:
Name of the environment variable.
default_variable_value: Value to be returned if environment variable is not set.
Returns:
A boolean value stored in the environment variable
or default value if environment variable is not set.
"""
true_values = (str(True).lower(), str(1).lower())
false_values = (str(False).lower(), str(0).lower())
value = os.getenv(variable_name, default=str(default_variable_value))
if value.lower() not in true_values + false_values:
raise RasaException(
f"Invalid value `{value}` for variable `{variable_name}`. "
f"Available values are `{true_values + false_values}`"
)
return value.lower() in true_values